diff --git a/spring-integration-amqp/src/main/java/org/springframework/integration/amqp/channel/AbstractAmqpChannel.java b/spring-integration-amqp/src/main/java/org/springframework/integration/amqp/channel/AbstractAmqpChannel.java index 4a493573a1..2217601f9b 100644 --- a/spring-integration-amqp/src/main/java/org/springframework/integration/amqp/channel/AbstractAmqpChannel.java +++ b/spring-integration-amqp/src/main/java/org/springframework/integration/amqp/channel/AbstractAmqpChannel.java @@ -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. diff --git a/spring-integration-amqp/src/main/java/org/springframework/integration/amqp/channel/PollableAmqpChannel.java b/spring-integration-amqp/src/main/java/org/springframework/integration/amqp/channel/PollableAmqpChannel.java index 9e29fae6f3..1b134615a5 100644 --- a/spring-integration-amqp/src/main/java/org/springframework/integration/amqp/channel/PollableAmqpChannel.java +++ b/spring-integration-amqp/src/main/java/org/springframework/integration/amqp/channel/PollableAmqpChannel.java @@ -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."); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/channel/AbstractMessageChannel.java b/spring-integration-core/src/main/java/org/springframework/integration/channel/AbstractMessageChannel.java index 9a13dddca2..42f109f265 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/channel/AbstractMessageChannel.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/channel/AbstractMessageChannel.java @@ -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); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/channel/NullChannel.java b/spring-integration-core/src/main/java/org/springframework/integration/channel/NullChannel.java index 97ec50c39b..240b8b144f 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/channel/NullChannel.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/channel/NullChannel.java @@ -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; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/channel/management/MessageChannelMetrics.java b/spring-integration-core/src/main/java/org/springframework/integration/channel/management/MessageChannelMetrics.java index 68dae6d3f3..315ed94765 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/channel/management/MessageChannelMetrics.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/channel/management/MessageChannelMetrics.java @@ -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 diff --git a/spring-integration-core/src/main/java/org/springframework/integration/endpoint/AbstractMessageSource.java b/spring-integration-core/src/main/java/org/springframework/integration/endpoint/AbstractMessageSource.java index fc9c21df25..0da9d404a8 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/endpoint/AbstractMessageSource.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/endpoint/AbstractMessageSource.java @@ -55,6 +55,8 @@ public abstract class AbstractMessageSource extends AbstractExpressionEvaluat private volatile boolean countsEnabled; + private volatile boolean loggingEnabled = true; + public void setHeaderExpressions(Map headerExpressions) { this.headerExpressions = (headerExpressions != null) ? headerExpressions : Collections.emptyMap(); @@ -100,6 +102,16 @@ public abstract class AbstractMessageSource 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); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/endpoint/management/MessageSourceMetrics.java b/spring-integration-core/src/main/java/org/springframework/integration/endpoint/management/MessageSourceMetrics.java index be7e27a19d..cdbe3bbe48 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/endpoint/management/MessageSourceMetrics.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/endpoint/management/MessageSourceMetrics.java @@ -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 diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageHandler.java index 13c1c30592..5e6434c626 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageHandler.java @@ -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; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/management/MessageHandlerMetrics.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/management/MessageHandlerMetrics.java index ff1108e214..fc15b09a21 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/management/MessageHandlerMetrics.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/management/MessageHandlerMetrics.java @@ -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 diff --git a/spring-integration-core/src/main/java/org/springframework/integration/support/management/CountsEnablement.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationManagement.java similarity index 79% rename from spring-integration-core/src/main/java/org/springframework/integration/support/management/CountsEnablement.java rename to spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationManagement.java index 3484b1c592..76c225540c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/support/management/CountsEnablement.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationManagement.java @@ -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(); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationManagementConfigurer.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationManagementConfigurer.java new file mode 100644 index 0000000000..94b1b742cf --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationManagementConfigurer.java @@ -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. + *

+ * Exception logging (debug or otherwise) is not affected by this setting. + *

+ * 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. + *

+ * 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. + *

+ * 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 managed = this.applicationContext.getBeansOfType(IntegrationManagement.class); + for (IntegrationManagement bean : managed.values()) { + bean.setLoggingEnabled(this.defaultLoggingEnabled); + } + } + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/support/management/MetricsEnablement.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationStatsManagement.java similarity index 93% rename from spring-integration-core/src/main/java/org/springframework/integration/support/management/MetricsEnablement.java rename to spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationStatsManagement.java index d386d7dc77..babb40f90f 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/support/management/MetricsEnablement.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationStatsManagement.java @@ -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); diff --git a/spring-integration-core/src/test/java/org/springframework/integration/support/management/IntegrationManagementConfigurerTests.java b/spring-integration-core/src/test/java/org/springframework/integration/support/management/IntegrationManagementConfigurerTests.java new file mode 100644 index 0000000000..3f0cb52c89 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/support/management/IntegrationManagementConfigurerTests.java @@ -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() { + + @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 beans = new HashMap(); + 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()); + } + +} diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageHandlerMetrics.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageHandlerMetrics.java index 7d42a20837..08864b301a 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageHandlerMetrics.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageHandlerMetrics.java @@ -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); diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageSourceMetrics.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageSourceMetrics.java index be711afd92..f787396392 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageSourceMetrics.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageSourceMetrics.java @@ -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); diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/MBeanAttributeFilterTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/MBeanAttributeFilterTests.java index 12451dc371..d893ac43fb 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/MBeanAttributeFilterTests.java +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/MBeanAttributeFilterTests.java @@ -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 bean = (Map) 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 keys = new ArrayList(bean.keySet()); + Collections.sort(keys); + System.out.println(keys); + assertThat(keys, contains("LoggingEnabled", + "MaxSendDuration", + "MeanErrorRate", + "MeanErrorRatio", + "MeanSendDuration", + "MeanSendRate", + "MinSendDuration", + "StandardDeviationSendDuration", + "TimeSinceLastSend")); adapterNot.stop(); }