INT-3759: Ability to Disable Logging on Main Path

JIRA: https://jira.spring.io/browse/INT-3759

Add `IntegrationManagementConfigurer` to globally set the default.

This will be documented/expanded when JIRAs 3755/3756 are implemented.

Polishing; PR Comments

Test Polishing
This commit is contained in:
Gary Russell
2015-07-02 09:45:41 -04:00
committed by Artem Bilan
parent a480354210
commit 9cc0652b61
16 changed files with 271 additions and 27 deletions

View File

@@ -29,12 +29,22 @@ public abstract class AbstractAmqpChannel extends AbstractMessageChannel {
private final AmqpTemplate amqpTemplate;
private volatile boolean loggingEnabled = true;
AbstractAmqpChannel(AmqpTemplate amqpTemplate) {
Assert.notNull(amqpTemplate, "amqpTemplate must not be null");
this.amqpTemplate = amqpTemplate;
}
@Override
public boolean isLoggingEnabled() {
return this.loggingEnabled;
}
@Override
public void setLoggingEnabled(boolean loggingEnabled) {
this.loggingEnabled = loggingEnabled;
}
/**
* Subclasses may override this method to return an Exchange name.

View File

@@ -127,7 +127,7 @@ public class PollableAmqpChannel extends AbstractAmqpChannel implements Pollable
boolean counted = false;
boolean countsEnabled = isCountsEnabled();
try {
if (logger.isTraceEnabled()) {
if (isLoggingEnabled() && logger.isTraceEnabled()) {
logger.trace("preReceive on channel '" + this + "'");
}
if (interceptorList.getInterceptors().size() > 0) {
@@ -139,7 +139,7 @@ public class PollableAmqpChannel extends AbstractAmqpChannel implements Pollable
}
Object object = getAmqpTemplate().receiveAndConvert(this.queueName);
if (object == null) {
if (logger.isTraceEnabled()) {
if (isLoggingEnabled() && logger.isTraceEnabled()) {
logger.trace("postReceive on channel '" + this + "', message is null");
}
return null;
@@ -155,7 +155,7 @@ public class PollableAmqpChannel extends AbstractAmqpChannel implements Pollable
else {
message = getMessageBuilderFactory().withPayload(object).build();
}
if (logger.isDebugEnabled()) {
if (isLoggingEnabled() && logger.isDebugEnabled()) {
logger.debug("postReceive on channel '" + this + "', message: " + message);
}
if (interceptorStack != null) {
@@ -177,7 +177,7 @@ public class PollableAmqpChannel extends AbstractAmqpChannel implements Pollable
@Override
public Message<?> receive(long timeout) {
if (logger.isInfoEnabled()) {
if (isLoggingEnabled() && logger.isInfoEnabled()) {
logger.info("Calling receive with a timeout value on PollableAmqpChannel. " +
"The timeout will be ignored since no receive timeout is supported.");
}

View File

@@ -81,6 +81,8 @@ public abstract class AbstractMessageChannel extends IntegrationObjectSupport
private volatile boolean statsEnabled;
private volatile boolean loggingEnabled = true;
private volatile AbstractMessageChannelMetrics channelMetrics = new DefaultMessageChannelMetrics();
public AbstractMessageChannel() {
@@ -107,7 +109,7 @@ public abstract class AbstractMessageChannel extends IntegrationObjectSupport
@Override
public boolean isCountsEnabled() {
return countsEnabled;
return this.countsEnabled;
}
@Override
@@ -124,6 +126,16 @@ public abstract class AbstractMessageChannel extends IntegrationObjectSupport
return this.statsEnabled;
}
@Override
public boolean isLoggingEnabled() {
return this.loggingEnabled;
}
@Override
public void setLoggingEnabled(boolean loggingEnabled) {
this.loggingEnabled = loggingEnabled;
}
protected AbstractMessageChannelMetrics getMetrics() {
return this.channelMetrics;
}
@@ -413,7 +425,7 @@ public abstract class AbstractMessageChannel extends IntegrationObjectSupport
if (this.datatypes.length > 0) {
message = this.convertPayloadIfNecessary(message);
}
boolean debugEnabled = logger.isDebugEnabled();
boolean debugEnabled = this.loggingEnabled && logger.isDebugEnabled();
if (debugEnabled) {
logger.debug("preSend on channel '" + this + "', message: " + message);
}

View File

@@ -53,6 +53,8 @@ public class NullChannel implements PollableChannel, MessageChannelMetrics,
private volatile boolean statsEnabled;
private volatile boolean loggingEnabled = true;
private String beanName;
@Override
@@ -61,6 +63,16 @@ public class NullChannel implements PollableChannel, MessageChannelMetrics,
this.channelMetrics = new DefaultMessageChannelMetrics(getComponentName());
}
@Override
public boolean isLoggingEnabled() {
return this.loggingEnabled;
}
@Override
public void setLoggingEnabled(boolean loggingEnabled) {
this.loggingEnabled = loggingEnabled;
}
@Override
public String getComponentName() {
return StringUtils.hasText(this.beanName) ? this.beanName: "nullChannel";
@@ -186,7 +198,7 @@ public class NullChannel implements PollableChannel, MessageChannelMetrics,
@Override
public boolean send(Message<?> message) {
if (logger.isDebugEnabled()) {
if (this.loggingEnabled && logger.isDebugEnabled()) {
logger.debug("message sent to null channel: " + message);
}
if (this.countsEnabled) {
@@ -202,7 +214,7 @@ public class NullChannel implements PollableChannel, MessageChannelMetrics,
@Override
public Message<?> receive() {
if (logger.isDebugEnabled()) {
if (this.loggingEnabled && logger.isDebugEnabled()) {
logger.debug("receive called on null channel");
}
return null;

View File

@@ -16,7 +16,7 @@
package org.springframework.integration.channel.management;
import org.springframework.integration.support.management.MetricsEnablement;
import org.springframework.integration.support.management.IntegrationStatsManagement;
import org.springframework.integration.support.management.Statistics;
import org.springframework.jmx.export.annotation.ManagedMetric;
import org.springframework.jmx.support.MetricType;
@@ -29,7 +29,7 @@ import org.springframework.jmx.support.MetricType;
* @author Gary Russell
* @since 2.0
*/
public interface MessageChannelMetrics extends MetricsEnablement {
public interface MessageChannelMetrics extends IntegrationStatsManagement {
/**
* @return the number of successful sends

View File

@@ -55,6 +55,8 @@ public abstract class AbstractMessageSource<T> extends AbstractExpressionEvaluat
private volatile boolean countsEnabled;
private volatile boolean loggingEnabled = true;
public void setHeaderExpressions(Map<String, Expression> headerExpressions) {
this.headerExpressions = (headerExpressions != null)
? headerExpressions : Collections.<String, Expression>emptyMap();
@@ -100,6 +102,16 @@ public abstract class AbstractMessageSource<T> extends AbstractExpressionEvaluat
this.countsEnabled = countsEnabled;
}
@Override
public boolean isLoggingEnabled() {
return this.loggingEnabled;
}
@Override
public void setLoggingEnabled(boolean loggingEnabled) {
this.loggingEnabled = loggingEnabled;
}
@Override
public void reset() {
this.messageCount.set(0);

View File

@@ -13,7 +13,7 @@
package org.springframework.integration.endpoint.management;
import org.springframework.integration.support.management.CountsEnablement;
import org.springframework.integration.support.management.IntegrationManagement;
import org.springframework.jmx.export.annotation.ManagedMetric;
import org.springframework.jmx.support.MetricType;
@@ -22,7 +22,7 @@ import org.springframework.jmx.support.MetricType;
* @author Gary Russell
* @since 2.0
*/
public interface MessageSourceMetrics extends CountsEnablement {
public interface MessageSourceMetrics extends IntegrationManagement {
/**
* @return the number of successful handler calls

View File

@@ -62,6 +62,18 @@ public abstract class AbstractMessageHandler extends IntegrationObjectSupport im
private volatile String managedType;
private volatile boolean loggingEnabled = true;
@Override
public boolean isLoggingEnabled() {
return this.loggingEnabled;
}
@Override
public void setLoggingEnabled(boolean loggingEnabled) {
this.loggingEnabled = loggingEnabled;
}
@Override
public void setOrder(int order) {
this.order = order;
@@ -99,7 +111,7 @@ public abstract class AbstractMessageHandler extends IntegrationObjectSupport im
public final void handleMessage(Message<?> message) {
Assert.notNull(message, "Message must not be null");
Assert.notNull(message.getPayload(), "Message payload must not be null");//NOSONAR - false positive
if (this.logger.isDebugEnabled()) {
if (this.loggingEnabled && this.logger.isDebugEnabled()) {
this.logger.debug(this + " received message: " + message);
}
MetricsContext start = null;

View File

@@ -16,7 +16,7 @@
package org.springframework.integration.handler.management;
import org.springframework.integration.support.management.MetricsEnablement;
import org.springframework.integration.support.management.IntegrationStatsManagement;
import org.springframework.integration.support.management.Statistics;
import org.springframework.jmx.export.annotation.ManagedMetric;
import org.springframework.jmx.support.MetricType;
@@ -26,7 +26,7 @@ import org.springframework.jmx.support.MetricType;
* @author Gary Russell
* @since 2.0
*/
public interface MessageHandlerMetrics extends MetricsEnablement {
public interface MessageHandlerMetrics extends IntegrationStatsManagement {
/**
* @return the number of successful handler calls

View File

@@ -19,13 +19,19 @@ import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
/**
* Base interface containing methods to control basic statistics gathering.
* Base interface for Integration managed components.
*
* @author Gary Russell
* @since 4.2
*
*/
public interface CountsEnablement {
public interface IntegrationManagement {
@ManagedAttribute(description = "Use to disable debug logging during normal message flow")
void setLoggingEnabled(boolean enabled);
@ManagedAttribute
boolean isLoggingEnabled();
@ManagedOperation
void reset();

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.support.management;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert;
/**
* Configures beans that implement {@link IntegrationManagement}.
*
* TODO: This class will be expanded by INT-3755/3756.
*
* @author Gary Russell
* @since 4.2
*
*/
public class IntegrationManagementConfigurer implements SmartInitializingSingleton, ApplicationContextAware {
private ApplicationContext applicationContext;
private boolean defaultLoggingEnabled = true;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* Disable all logging in the normal message flow in framework components. When 'false', such logging will be
* skipped, regardless of logging level. When 'true', the logging is controlled as normal by the logging
* subsystem log level configuration.
* <p>
* Exception logging (debug or otherwise) is not affected by this setting.
* <p>
* It has been found that in high-volume messaging environments, calls to methods such as
* {@code logger.isDebuggingEnabled()} can be quite expensive and account for an inordinate amount of CPU
* time.
* <p>
* Set this to false to disable logging by default in all framework components that implement
* {@link IntegrationManagement} (channels, message handlers etc). This turns off logging such as
* "PreSend on channel", "Received message" etc.
* <p>
* After the context is initialized, individual components can have their setting changed by invoking
* {@link IntegrationManagement#setLoggingEnabled(boolean)}.
* @param defaultLoggingEnabled defaults to true.
*/
public void setDefaultLoggingEnabled(boolean defaultLoggingEnabled) {
this.defaultLoggingEnabled = defaultLoggingEnabled;
}
@Override
public void afterSingletonsInstantiated() {
Assert.state(this.applicationContext != null, "'applicationContext' must not be null");
Map<String, IntegrationManagement> managed = this.applicationContext.getBeansOfType(IntegrationManagement.class);
for (IntegrationManagement bean : managed.values()) {
bean.setLoggingEnabled(this.defaultLoggingEnabled);
}
}
}

View File

@@ -26,7 +26,7 @@ import org.springframework.jmx.export.annotation.ManagedOperation;
* @since 4.2
*
*/
public interface MetricsEnablement extends CountsEnablement {
public interface IntegrationStatsManagement extends IntegrationManagement {
@ManagedOperation(description = "Enable all statistics")
void enableStats(boolean statsEnabled);

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.support.management;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.endpoint.AbstractMessageSource;
import org.springframework.integration.handler.AbstractMessageHandler;
import org.springframework.integration.router.RecipientListRouter;
/**
* @author Gary Russell
* @since 4.2
*
*/
public class IntegrationManagementConfigurerTests {
@Test
public void testLogging() {
DirectChannel channel = new DirectChannel();
AbstractMessageHandler handler = new RecipientListRouter();
AbstractMessageSource<?> source = new AbstractMessageSource<Object>() {
@Override
public String getComponentType() {
return null;
}
@Override
protected Object doReceive() {
return null;
}
};
assertTrue(channel.isLoggingEnabled());
assertTrue(handler.isLoggingEnabled());
assertTrue(source.isLoggingEnabled());
ApplicationContext ctx = mock(ApplicationContext.class);
Map<String, IntegrationManagement> beans = new HashMap<String, IntegrationManagement>();
beans.put("foo", channel);
beans.put("bar", handler);
beans.put("baz", source);
when(ctx.getBeansOfType(IntegrationManagement.class)).thenReturn(beans);
IntegrationManagementConfigurer configurer = new IntegrationManagementConfigurer();
configurer.setApplicationContext(ctx);
configurer.setDefaultLoggingEnabled(false);
configurer.afterSingletonsInstantiated();
assertFalse(channel.isLoggingEnabled());
assertFalse(handler.isLoggingEnabled());
assertFalse(source.isLoggingEnabled());
}
}

View File

@@ -163,6 +163,16 @@ public class LifecycleMessageHandlerMetrics implements MessageHandlerMetrics, Li
return this.delegate.isCountsEnabled();
}
@Override
public void setLoggingEnabled(boolean enabled) {
this.delegate.setLoggingEnabled(enabled);
}
@Override
public boolean isLoggingEnabled() {
return this.delegate.isLoggingEnabled();
}
@Override
public void setManagedName(String name) {
this.delegate.setManagedName(name);

View File

@@ -88,25 +88,31 @@ public class LifecycleMessageSourceMetrics implements MessageSourceMetrics, Life
return this.delegate.getMessageCountLong();
}
@Override
public void enableCounts(boolean countsEnabled) {
delegate.enableCounts(countsEnabled);
}
@Override
public boolean isCountsEnabled() {
return delegate.isCountsEnabled();
}
@Override
public void setLoggingEnabled(boolean enabled) {
delegate.setLoggingEnabled(enabled);
}
@Override
public boolean isLoggingEnabled() {
return delegate.isLoggingEnabled();
}
@Override
public void setManagedName(String name) {
delegate.setManagedName(name);
}
@Override
public void setManagedType(String source) {
delegate.setManagedType(source);

View File

@@ -15,12 +15,16 @@
*/
package org.springframework.integration.jmx;
import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
@@ -105,11 +109,18 @@ public class MBeanAttributeFilterTests {
Map<String, Object> bean = (Map<String, Object>) payload
.get(domain + ":name=in,type=MessageChannel");
assertEquals(8, bean.size());
assertFalse(bean.containsKey("SendCount"));
assertFalse(bean.containsKey("SendErrorCount"));
assertFalse(bean.containsKey("SendCountLong"));
assertFalse(bean.containsKey("SendErrorCountLong"));
List<String> keys = new ArrayList<String>(bean.keySet());
Collections.sort(keys);
System.out.println(keys);
assertThat(keys, contains("LoggingEnabled",
"MaxSendDuration",
"MeanErrorRate",
"MeanErrorRatio",
"MeanSendDuration",
"MeanSendRate",
"MinSendDuration",
"StandardDeviationSendDuration",
"TimeSinceLastSend"));
adapterNot.stop();
}