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 42f109f265..15f39fa51f 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 @@ -100,7 +100,7 @@ public abstract class AbstractMessageChannel extends IntegrationObjectSupport } @Override - public void enableCounts(boolean countsEnabled) { + public void setCountsEnabled(boolean countsEnabled) { this.countsEnabled = countsEnabled; if (!countsEnabled) { this.statsEnabled = false; @@ -113,7 +113,7 @@ public abstract class AbstractMessageChannel extends IntegrationObjectSupport } @Override - public void enableStats(boolean statsEnabled) { + public void setStatsEnabled(boolean statsEnabled) { if (statsEnabled) { this.countsEnabled = true; } 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 240b8b144f..467a14ed81 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 @@ -95,7 +95,7 @@ public class NullChannel implements PollableChannel, MessageChannelMetrics, } @Override - public void enableCounts(boolean countsEnabled) { + public void setCountsEnabled(boolean countsEnabled) { this.countsEnabled = countsEnabled; if (!countsEnabled) { this.statsEnabled = false; @@ -108,7 +108,7 @@ public class NullChannel implements PollableChannel, MessageChannelMetrics, } @Override - public void enableStats(boolean statsEnabled) { + public void setStatsEnabled(boolean statsEnabled) { if (statsEnabled) { this.countsEnabled = true; } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/AggregatorFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/config/AggregatorFactoryBean.java index e620989922..bb5f1ee8cf 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/AggregatorFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/AggregatorFactoryBean.java @@ -102,12 +102,12 @@ public class AggregatorFactoryBean extends AbstractSimpleMessageHandlerFactoryBe this.aggregator.setChannelResolver(channelResolver); } - public void enableStats(boolean statsEnabled) { - this.aggregator.enableStats(statsEnabled); + public void setStatsEnabled(boolean statsEnabled) { + this.aggregator.setStatsEnabled(statsEnabled); } - public void enableCounts(boolean countsEnabled) { - this.aggregator.enableCounts(countsEnabled); + public void setCountsEnabled(boolean countsEnabled) { + this.aggregator.setCountsEnabled(countsEnabled); } public void setLockRegistry(LockRegistry lockRegistry) { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/EnableIntegrationManagement.java b/spring-integration-core/src/main/java/org/springframework/integration/config/EnableIntegrationManagement.java new file mode 100644 index 0000000000..171b362893 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/EnableIntegrationManagement.java @@ -0,0 +1,119 @@ +/* + * Copyright 2014-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.config; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Import; +import org.springframework.integration.support.management.IntegrationManagement; +import org.springframework.integration.support.management.IntegrationManagementConfigurer; + +/** + * Enables default configuring of management in Spring Integration components in an existing application. + * + *

The resulting {@link IntegrationManagementConfigurer} + * bean is defined under the name {@code integrationManagementConfigurer}. + * + * @author Gary Russell + * @since 4.2 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Import(IntegrationManagementConfiguration.class) +public @interface EnableIntegrationManagement { + + /** + * A list of simple patterns for component names for which message counts will be + * enabled (defaults to '*'). Enables message + * counting (`sendCount`, `errorCount`, `receiveCount`) for those components that + * support counters (channels, message handlers, etc). This is the initial setting + * only, individual components can have counts enabled/disabled at runtime. May be + * overridden by an entry in {@link #statsEnabled() statsEnabled} which is additional + * functionality over simple counts. If a pattern starts with `!`, counts are disabled + * for matches. For components that match multiple patterns, the first pattern wins. + * Disabling counts at runtime also disables stats. + * Defaults to no components, unless JMX is enabled in which case, defaults to all + * components. Overrides {@link #defaultCountsEnabled()} for matching bean names. + * @return the patterns. + */ + String[] countsEnabled() default ""; + + /** + * A list of simple patterns for component names for which message statistics will be + * enabled (response times, rates etc), as well as counts (a positive match here + * overrides {@link #countsEnabled() countsEnabled}, you can't have statistics without + * counts). (defaults to '*'). Enables + * statistics for those components that support statistics (channels - when sending, + * message handlers, etc). This is the initial setting only, individual components can + * have stats enabled/disabled at runtime. If a pattern starts with `!`, stats (and + * counts) are disabled for matches. Note: this means that '!foo' here will disable + * stats and counts for 'foo' even if counts are enabled for 'foo' in + * {@link #countsEnabled() countsEnabled}. For components + * that match multiple patterns, the first pattern wins. Enabling stats at runtime + * also enables counts. + * Defaults to no components, unless JMX is enabled in which case, defaults to all + * components. + * @return the patterns. + */ + String[] statsEnabled() default ""; + + /** + * The default setting for enabling counts when a bean name is not matched by + * {@link #countsEnabled() countsEnabled}. + * @return the value; false by default, or true when JMX is enabled. + */ + String defaultCountsEnabled() default "false"; + + /** + * The default setting for enabling statistics when a bean name is not matched by + * {@link #statsEnabled() statsEnabled}. + * @return the value; false by default, or true when JMX is enabled. + */ + String defaultStatsEnabled() default "false"; + + /** + * Use to disable all logging in the main 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. + *

+ * 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)}. + * @return the value; true by default. + */ + String defaultLoggingEnabled() default "true"; + + /** + * The bean name of a {@code MetricsFactory}. The {@code DefaultMetricsFactory} is used + * if omitted. + * @return the bean name. + */ + String metricsFactory() default ""; + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationManagementConfiguration.java b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationManagementConfiguration.java new file mode 100644 index 0000000000..4f01e816eb --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationManagementConfiguration.java @@ -0,0 +1,106 @@ +/* + * 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.config; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.EnvironmentAware; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportAware; +import org.springframework.context.annotation.Role; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.integration.support.management.IntegrationManagementConfigurer; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * {@code @Configuration} class that registers a {@link IntegrationManagementConfigurer} bean. + * + *

This configuration class is automatically imported when using the + * {@link EnableIntegrationManagement} annotation. See its javadoc for complete usage details. + * + * @author Artem Bilan + * @author Gary Russell + * @since 4.2 + */ +@Configuration +public class IntegrationManagementConfiguration implements ImportAware, EnvironmentAware { + + private AnnotationAttributes attributes; + + private Environment environment; + + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public void setImportMetadata(AnnotationMetadata importMetadata) { + Map map = importMetadata.getAnnotationAttributes(EnableIntegrationManagement.class.getName()); + this.attributes = AnnotationAttributes.fromMap(map); + Assert.notNull(this.attributes, + "@EnableIntegrationManagement is not present on importing class " + importMetadata.getClassName()); + } + + @Bean(name = IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME) + @Role(BeanDefinition.ROLE_INFRASTRUCTURE) + public IntegrationManagementConfigurer managementConfigurer() { + IntegrationManagementConfigurer configurer = new IntegrationManagementConfigurer(); + setupCountsEnabledNamePatterns(configurer); + setupStatsEnabledNamePatterns(configurer); + configurer.setDefaultLoggingEnabled( + Boolean.parseBoolean(this.environment.resolvePlaceholders( + (String) this.attributes.get("defaultLoggingEnabled")))); + configurer.setDefaultCountsEnabled( + Boolean.parseBoolean(this.environment.resolvePlaceholders( + (String) this.attributes.get("defaultCountsEnabled")))); + configurer.setDefaultStatsEnabled( + Boolean.parseBoolean(this.environment.resolvePlaceholders( + (String) this.attributes.get("defaultStatsEnabled")))); + configurer.setMetricsFactoryBeanName((String) this.attributes.get("metricsFactory")); + return configurer; + } + + private void setupCountsEnabledNamePatterns(IntegrationManagementConfigurer configurer) { + List patterns = new ArrayList(); + String[] countsEnabled = this.attributes.getStringArray("countsEnabled"); + for (String managedComponent : countsEnabled) { + String pattern = this.environment.resolvePlaceholders(managedComponent); + patterns.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(pattern))); + } + configurer.setEnabledCountsPatterns(patterns.toArray(new String[patterns.size()])); + } + + private void setupStatsEnabledNamePatterns(IntegrationManagementConfigurer exporter) { + List patterns = new ArrayList(); + String[] statsEnabled = this.attributes.getStringArray("statsEnabled"); + for (String managedComponent : statsEnabled) { + String pattern = this.environment.resolvePlaceholders(managedComponent); + patterns.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(pattern))); + } + exporter.setEnabledStatsPatterns(patterns.toArray(new String[patterns.size()])); + } + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationManagementParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationManagementParser.java new file mode 100644 index 0000000000..2171ee1bd6 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationManagementParser.java @@ -0,0 +1,63 @@ +/* + * 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.config.xml; + +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.support.management.IntegrationManagementConfigurer; + +import org.w3c.dom.Element; + +/** + * Parser for the <management/> element. + * + * @author Gary Russell + * @since 4.2 + */ +public class IntegrationManagementParser extends AbstractBeanDefinitionParser { + + + @Override + protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) + throws BeanDefinitionStoreException { + return IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME; + } + + @Override + protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { + BeanDefinitionBuilder builder = + BeanDefinitionBuilder.genericBeanDefinition(IntegrationManagementConfigurer.class); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "default-logging-enabled"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "default-counts-enabled"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "default-stats-enabled"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "counts-enabled-patterns", + "enabledCountsPatterns"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "stats-enabled-patterns", + "enabledStatsPatterns"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "metrics-factory"); + return builder.getBeanDefinition(); + } + + @Override + protected boolean shouldFireEvents() { + return false; + } + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceHandler.java index adc0a34a4c..8b2a631c94 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceHandler.java @@ -83,6 +83,7 @@ public class IntegrationNamespaceHandler extends AbstractIntegrationNamespaceHan registerBeanDefinitionParser("retry-advice", retryParser); registerBeanDefinitionParser("scatter-gather", new ScatterGatherParser()); registerBeanDefinitionParser("idempotent-receiver", new IdempotentReceiverInterceptorParser()); + registerBeanDefinitionParser("management", new IntegrationManagementParser()); } } 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 0da9d404a8..d6d63c536d 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 @@ -24,10 +24,10 @@ import java.util.concurrent.atomic.AtomicLong; import org.springframework.beans.factory.BeanNameAware; import org.springframework.expression.Expression; import org.springframework.integration.core.MessageSource; -import org.springframework.integration.endpoint.management.MessageSourceMetrics; import org.springframework.integration.support.AbstractIntegrationMessageBuilder; import org.springframework.integration.support.context.NamedComponent; import org.springframework.integration.support.management.IntegrationManagedResource; +import org.springframework.integration.support.management.MessageSourceMetrics; import org.springframework.integration.util.AbstractExpressionEvaluator; import org.springframework.messaging.Message; import org.springframework.messaging.MessagingException; @@ -98,7 +98,7 @@ public abstract class AbstractMessageSource extends AbstractExpressionEvaluat } @Override - public void enableCounts(boolean countsEnabled) { + public void setCountsEnabled(boolean countsEnabled) { this.countsEnabled = countsEnabled; } 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 5e6434c626..818a983606 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 @@ -21,11 +21,11 @@ import org.springframework.integration.context.IntegrationObjectSupport; import org.springframework.integration.context.Orderable; import org.springframework.integration.handler.management.AbstractMessageHandlerMetrics; import org.springframework.integration.handler.management.DefaultMessageHandlerMetrics; -import org.springframework.integration.handler.management.MessageHandlerMetrics; import org.springframework.integration.history.MessageHistory; import org.springframework.integration.history.TrackableComponent; import org.springframework.integration.support.management.ConfigurableMetricsAware; import org.springframework.integration.support.management.IntegrationManagedResource; +import org.springframework.integration.support.management.MessageHandlerMetrics; import org.springframework.integration.support.management.MetricsContext; import org.springframework.integration.support.management.Statistics; import org.springframework.messaging.Message; @@ -203,7 +203,7 @@ public abstract class AbstractMessageHandler extends IntegrationObjectSupport im } @Override - public void enableStats(boolean statsEnabled) { + public void setStatsEnabled(boolean statsEnabled) { if (statsEnabled) { this.countsEnabled = true; } @@ -219,7 +219,7 @@ public abstract class AbstractMessageHandler extends IntegrationObjectSupport im } @Override - public void enableCounts(boolean countsEnabled) { + public void setCountsEnabled(boolean countsEnabled) { this.countsEnabled = countsEnabled; if (!countsEnabled) { this.statsEnabled = false; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/management/AggregatingMessageHandlerMetrics.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/management/AggregatingMessageHandlerMetrics.java index c6cb917383..a3159f29fc 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/management/AggregatingMessageHandlerMetrics.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/management/AggregatingMessageHandlerMetrics.java @@ -20,11 +20,12 @@ import org.springframework.integration.support.management.ExponentialMovingAvera import org.springframework.integration.support.management.MetricsContext; /** - * An implementation of {@link MessageHandlerMetrics} that aggregates the total response + * An implementation of {@link org.springframework.integration.support.management.MessageHandlerMetrics} + * that aggregates the total response * time over a sample, to avoid fetching the system time twice for every message. * * @author Gary Russell - * @since 2.0 + * @since 4.2 */ public class AggregatingMessageHandlerMetrics extends DefaultMessageHandlerMetrics { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMappingMessageRouter.java b/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMappingMessageRouter.java index 7eea927970..5acbcb516c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMappingMessageRouter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMappingMessageRouter.java @@ -28,6 +28,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.springframework.beans.factory.BeanFactory; import org.springframework.integration.support.channel.BeanFactoryChannelResolver; +import org.springframework.integration.support.management.MappingMessageRouterManagement; import org.springframework.jmx.export.annotation.ManagedAttribute; import org.springframework.jmx.export.annotation.ManagedOperation; import org.springframework.messaging.Message; diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/AggregatingMetricsFactory.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/AggregatingMetricsFactory.java similarity index 96% rename from spring-integration-jmx/src/main/java/org/springframework/integration/monitor/AggregatingMetricsFactory.java rename to spring-integration-core/src/main/java/org/springframework/integration/support/management/AggregatingMetricsFactory.java index f30a571535..a16f1d1dc7 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/AggregatingMetricsFactory.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/AggregatingMetricsFactory.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.integration.monitor; +package org.springframework.integration.support.management; import org.springframework.integration.channel.management.AbstractMessageChannelMetrics; import org.springframework.integration.channel.management.AggregatingMessageChannelMetrics; diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/DefaultMetricsFactory.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/DefaultMetricsFactory.java similarity index 95% rename from spring-integration-jmx/src/main/java/org/springframework/integration/monitor/DefaultMetricsFactory.java rename to spring-integration-core/src/main/java/org/springframework/integration/support/management/DefaultMetricsFactory.java index e59c3ef3ba..f436c5392c 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/DefaultMetricsFactory.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/DefaultMetricsFactory.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.integration.monitor; +package org.springframework.integration.support.management; import org.springframework.integration.channel.management.AbstractMessageChannelMetrics; import org.springframework.integration.channel.management.DefaultMessageChannelMetrics; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationManagement.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationManagement.java index 76c225540c..ed78c2ff1d 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationManagement.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationManagement.java @@ -36,8 +36,8 @@ public interface IntegrationManagement { @ManagedOperation void reset(); - @ManagedOperation(description = "Enable message counting statistics") - void enableCounts(boolean countsEnabled); + @ManagedAttribute(description = "Enable message counting statistics") + void setCountsEnabled(boolean countsEnabled); @ManagedAttribute boolean isCountsEnabled(); 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 index 94b1b742cf..3983a0b4f4 100644 --- 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 @@ -15,34 +15,141 @@ */ package org.springframework.integration.support.management; +import java.util.Arrays; import java.util.Map; +import java.util.Map.Entry; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.integration.channel.management.AbstractMessageChannelMetrics; +import org.springframework.integration.channel.management.MessageChannelMetrics; +import org.springframework.integration.handler.management.AbstractMessageHandlerMetrics; import org.springframework.util.Assert; +import org.springframework.util.PatternMatchUtils; + /** * Configures beans that implement {@link IntegrationManagement}. - * - * TODO: This class will be expanded by INT-3755/3756. + * Configures counts, stats, logging for all (or selected) components. * * @author Gary Russell * @since 4.2 * */ -public class IntegrationManagementConfigurer implements SmartInitializingSingleton, ApplicationContextAware { +public class IntegrationManagementConfigurer implements SmartInitializingSingleton, ApplicationContextAware, + BeanNameAware { + + public static final String MANAGEMENT_CONFIGURER_NAME = "integrationManagementConfigurer"; private ApplicationContext applicationContext; + private String beanName; + private boolean defaultLoggingEnabled = true; + private Boolean defaultCountsEnabled = false; + + private Boolean defaultStatsEnabled = false; + + private MetricsFactory metricsFactory = new DefaultMetricsFactory(); + + private String metricsFactoryBeanName; + + private String[] enabledCountsPatterns = { }; + + private String[] enabledStatsPatterns = { }; + + @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } + @Override + public void setBeanName(String name) { + this.beanName = name; + } + + /** + * Set a metrics factory. + * @param metricsFactory the factory. + * @since 4.2 + */ + public void setMetricsFactory(MetricsFactory metricsFactory) { + this.metricsFactory = metricsFactory; + } + + public void setMetricsFactoryBeanName(String metricsFactory) { + this.metricsFactoryBeanName = metricsFactory; + } + + /** + * Set the array of simple patterns for component names for which message counts will + * be enabled (defaults to '*'). + * Enables message counting (`sendCount`, `errorCount`, `receiveCount`) + * for those components that support counters (channels, message handlers, etc). + * This is the initial setting only, individual components can have counts + * enabled/disabled at runtime. May be overridden by an entry in + * {@link #setEnabledStatsPatterns(String[]) enabledStatsPatterns} which is additional + * functionality over simple counts. If a pattern starts with `!`, counts are disabled + * for matches. For components that match multiple patterns, the first pattern wins. + * Disabling counts at runtime also disables stats. + * @param enabledCountsPatterns the patterns. + */ + public void setEnabledCountsPatterns(String[] enabledCountsPatterns) { + Assert.notEmpty(enabledCountsPatterns, "enabledCountsPatterns must not be empty"); + this.enabledCountsPatterns = Arrays.copyOf(enabledCountsPatterns, enabledCountsPatterns.length); + } + + /** + * Set the array of simple patterns for component names for which message statistics + * will be enabled (response times, rates etc), as well as counts (a positive match + * here overrides {@link #setEnabledCountsPatterns(String[]) enabledCountsPatterns}, + * you can't have statistics without counts). (defaults to '*'). + * Enables statistics for those components that support statistics + * (channels - when sending, message handlers, etc). This is the initial setting only, + * individual components can have stats enabled/disabled at runtime. If a pattern + * starts with `!`, stats (and counts) are disabled for matches. Note: this means that + * '!foo' here will disable stats and counts for 'foo' even if counts are enabled for + * 'foo' in {@link #setEnabledCountsPatterns(String[]) enabledCountsPatterns}. For + * components that match multiple patterns, the first pattern wins. Enabling stats at + * runtime also enables counts. + * @param enabledStatsPatterns the patterns. + */ + public void setEnabledStatsPatterns(String[] enabledStatsPatterns) { + Assert.notEmpty(enabledStatsPatterns, "componentNamePatterns must not be empty"); + this.enabledStatsPatterns = Arrays.copyOf(enabledStatsPatterns, enabledStatsPatterns.length); + } + + /** + * Set whether managed components maintain message counts by default. + * Defaults to false, unless an Integration MBean Exporter is configured. + * @param defaultCountsEnabled true to enable. + */ + public void setDefaultCountsEnabled(Boolean defaultCountsEnabled) { + this.defaultCountsEnabled = defaultCountsEnabled; + } + + public Boolean getDefaultCountsEnabled() { + return defaultCountsEnabled; + } + + /** + * Set whether managed components maintain message statistics by default. + * Defaults to false, unless an Integration MBean Exporter is configured. + * @param defaultStatsEnabled true to enable. + */ + public void setDefaultStatsEnabled(Boolean defaultStatsEnabled) { + this.defaultStatsEnabled = defaultStatsEnabled; + } + + public Boolean getDefaultStatsEnabled() { + return defaultStatsEnabled; + } + /** * 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 @@ -69,10 +176,133 @@ public class IntegrationManagementConfigurer implements SmartInitializingSinglet @Override public void afterSingletonsInstantiated() { Assert.state(this.applicationContext != null, "'applicationContext' must not be null"); + Assert.state(MANAGEMENT_CONFIGURER_NAME.equals(this.beanName), getClass().getSimpleName() + + " bean name must be " + MANAGEMENT_CONFIGURER_NAME); + if (this.metricsFactoryBeanName != null) { + this.metricsFactory = this.applicationContext.getBean(this.metricsFactoryBeanName, MetricsFactory.class); + } Map managed = this.applicationContext.getBeansOfType(IntegrationManagement.class); - for (IntegrationManagement bean : managed.values()) { + for (Entry entry : managed.entrySet()) { + IntegrationManagement bean = entry.getValue(); bean.setLoggingEnabled(this.defaultLoggingEnabled); + if (bean instanceof MessageChannelMetrics) { + configureChannelMetrics(entry.getKey(), (MessageChannelMetrics) bean); + } + else if (bean instanceof MessageHandlerMetrics) { + configureHandlerMetrics(entry.getKey(), (MessageHandlerMetrics) bean); + } + else if (bean instanceof MessageSourceMetrics) { + configureSourceMetrics(entry.getKey(), (MessageSourceMetrics) bean); + } } } + @SuppressWarnings("unchecked") + private void configureChannelMetrics(String name, MessageChannelMetrics bean) { + AbstractMessageChannelMetrics metrics = this.metricsFactory.createChannelMetrics(name); + Assert.state(metrics != null, "'metrics' must not be null"); + Boolean enabled = smartMatch(this.enabledCountsPatterns, name); + if (enabled != null) { + bean.setCountsEnabled(enabled); + } + else { + bean.setCountsEnabled(this.defaultCountsEnabled); + } + enabled = smartMatch(this.enabledStatsPatterns, name); + if (enabled != null) { + bean.setStatsEnabled(enabled); + metrics.setFullStatsEnabled(enabled); + } + else { + bean.setStatsEnabled(this.defaultStatsEnabled); + metrics.setFullStatsEnabled(this.defaultStatsEnabled); + } + if (bean instanceof ConfigurableMetricsAware) { + ((ConfigurableMetricsAware) bean).configureMetrics(metrics); + } + } + + @SuppressWarnings("unchecked") + private void configureHandlerMetrics(String name, MessageHandlerMetrics bean) { + AbstractMessageHandlerMetrics metrics = this.metricsFactory.createHandlerMetrics(name); + Assert.state(metrics != null, "'metrics' must not be null"); + Boolean enabled = smartMatch(this.enabledCountsPatterns, name); + if (enabled != null) { + bean.setCountsEnabled(enabled); + } + else { + bean.setCountsEnabled(this.defaultCountsEnabled); + } + enabled = smartMatch(this.enabledStatsPatterns, name); + if (enabled != null) { + bean.setStatsEnabled(enabled); + metrics.setFullStatsEnabled(enabled); + } + else { + bean.setStatsEnabled(this.defaultStatsEnabled); + metrics.setFullStatsEnabled(this.defaultStatsEnabled); + } + if (bean instanceof ConfigurableMetricsAware) { + ((ConfigurableMetricsAware) bean).configureMetrics(metrics); + } + } + + private void configureSourceMetrics(String name, MessageSourceMetrics bean) { + Boolean enabled = smartMatch(this.enabledCountsPatterns, name); + if (enabled != null) { + bean.setCountsEnabled(enabled); + } + else { + bean.setCountsEnabled(this.defaultCountsEnabled); + } + } + + /** + * Simple pattern match against the supplied patterns; also supports negated ('!') + * patterns. First match wins (positive or negative). + * @param patterns the patterns. + * @param name the name to match. + * @return null if no match; true for positive match; false for negative match. + */ + private Boolean smartMatch(String[] patterns, String name) { + if (patterns != null) { + for (String pattern : patterns) { + boolean reverse = false; + String patternToUse = pattern; + if (pattern.startsWith("!")) { + reverse = true; + patternToUse = pattern.substring(1); + } + else if (pattern.startsWith("\\")) { + patternToUse = pattern.substring(1); + } + if (PatternMatchUtils.simpleMatch(patternToUse, name)) { + return !reverse; + } + } + } + return null; + } + + public MessageChannelMetrics getChannelMetrics(String name) { + if (this.applicationContext.containsBean(name)) { + return this.applicationContext.getBean(name, MessageChannelMetrics.class); + } + return null; + } + + public MessageHandlerMetrics getHandlerMetrics(String name) { + if (this.applicationContext.containsBean(name)) { + return this.applicationContext.getBean(name, MessageHandlerMetrics.class); + } + return null; + } + + public MessageSourceMetrics getSourceMetrics(String name) { + if (this.applicationContext.containsBean(name)) { + return this.applicationContext.getBean(name, MessageSourceMetrics.class); + } + return null; + } + } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationStatsManagement.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationStatsManagement.java index babb40f90f..f3ddddd084 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationStatsManagement.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/IntegrationStatsManagement.java @@ -16,7 +16,6 @@ package org.springframework.integration.support.management; import org.springframework.jmx.export.annotation.ManagedAttribute; -import org.springframework.jmx.export.annotation.ManagedOperation; /** @@ -28,8 +27,8 @@ import org.springframework.jmx.export.annotation.ManagedOperation; */ public interface IntegrationStatsManagement extends IntegrationManagement { - @ManagedOperation(description = "Enable all statistics") - void enableStats(boolean statsEnabled); + @ManagedAttribute(description = "Enable all statistics") + void setStatsEnabled(boolean statsEnabled); @ManagedAttribute boolean isStatsEnabled(); diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageHandlerMetrics.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/LifecycleMessageHandlerMetrics.java similarity index 87% rename from spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageHandlerMetrics.java rename to spring-integration-core/src/main/java/org/springframework/integration/support/management/LifecycleMessageHandlerMetrics.java index 08864b301a..f547464f37 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageHandlerMetrics.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/LifecycleMessageHandlerMetrics.java @@ -14,14 +14,10 @@ * limitations under the License. */ -package org.springframework.integration.monitor; +package org.springframework.integration.support.management; import org.springframework.context.Lifecycle; import org.springframework.integration.handler.management.AbstractMessageHandlerMetrics; -import org.springframework.integration.handler.management.MessageHandlerMetrics; -import org.springframework.integration.support.management.ConfigurableMetricsAware; -import org.springframework.integration.support.management.IntegrationManagedResource; -import org.springframework.integration.support.management.Statistics; import org.springframework.jmx.export.annotation.ManagedAttribute; import org.springframework.jmx.export.annotation.ManagedOperation; @@ -144,13 +140,13 @@ public class LifecycleMessageHandlerMetrics implements MessageHandlerMetrics, Li } @Override - public void enableStats(boolean statsEnabled) { - this.delegate.enableStats(statsEnabled); + public void setStatsEnabled(boolean statsEnabled) { + this.delegate.setStatsEnabled(statsEnabled); } @Override - public void enableCounts(boolean countsEnabled) { - this.delegate.enableCounts(countsEnabled); + public void setCountsEnabled(boolean countsEnabled) { + this.delegate.setCountsEnabled(countsEnabled); } @Override diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageSourceMetrics.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/LifecycleMessageSourceMetrics.java similarity index 89% rename from spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageSourceMetrics.java rename to spring-integration-core/src/main/java/org/springframework/integration/support/management/LifecycleMessageSourceMetrics.java index f787396392..2744d88c72 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageSourceMetrics.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/LifecycleMessageSourceMetrics.java @@ -14,11 +14,9 @@ * limitations under the License. */ -package org.springframework.integration.monitor; +package org.springframework.integration.support.management; import org.springframework.context.Lifecycle; -import org.springframework.integration.endpoint.management.MessageSourceMetrics; -import org.springframework.integration.support.management.IntegrationManagedResource; import org.springframework.jmx.export.annotation.ManagedAttribute; import org.springframework.jmx.export.annotation.ManagedOperation; @@ -89,8 +87,8 @@ public class LifecycleMessageSourceMetrics implements MessageSourceMetrics, Life } @Override - public void enableCounts(boolean countsEnabled) { - delegate.enableCounts(countsEnabled); + public void setCountsEnabled(boolean countsEnabled) { + delegate.setCountsEnabled(countsEnabled); } @Override diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleTrackableMessageHandlerMetrics.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/LifecycleTrackableMessageHandlerMetrics.java similarity index 88% rename from spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleTrackableMessageHandlerMetrics.java rename to spring-integration-core/src/main/java/org/springframework/integration/support/management/LifecycleTrackableMessageHandlerMetrics.java index d66818bd3c..9c6f38d1a0 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleTrackableMessageHandlerMetrics.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/LifecycleTrackableMessageHandlerMetrics.java @@ -14,12 +14,10 @@ * limitations under the License. */ -package org.springframework.integration.monitor; +package org.springframework.integration.support.management; import org.springframework.context.Lifecycle; -import org.springframework.integration.handler.management.MessageHandlerMetrics; import org.springframework.integration.history.TrackableComponent; -import org.springframework.integration.support.management.IntegrationManagedResource; import org.springframework.util.Assert; /** diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleTrackableMessageSourceMetrics.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/LifecycleTrackableMessageSourceMetrics.java similarity index 88% rename from spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleTrackableMessageSourceMetrics.java rename to spring-integration-core/src/main/java/org/springframework/integration/support/management/LifecycleTrackableMessageSourceMetrics.java index fb28d85796..e191e52bf9 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleTrackableMessageSourceMetrics.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/LifecycleTrackableMessageSourceMetrics.java @@ -14,12 +14,10 @@ * limitations under the License. */ -package org.springframework.integration.monitor; +package org.springframework.integration.support.management; import org.springframework.context.Lifecycle; -import org.springframework.integration.endpoint.management.MessageSourceMetrics; import org.springframework.integration.history.TrackableComponent; -import org.springframework.integration.support.management.IntegrationManagedResource; import org.springframework.util.Assert; /** diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/MappingMessageRouterManagement.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/MappingMessageRouterManagement.java similarity index 97% rename from spring-integration-core/src/main/java/org/springframework/integration/router/MappingMessageRouterManagement.java rename to spring-integration-core/src/main/java/org/springframework/integration/support/management/MappingMessageRouterManagement.java index c717d85cac..28136995d4 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/router/MappingMessageRouterManagement.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/MappingMessageRouterManagement.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.integration.router; +package org.springframework.integration.support.management; import java.util.Map; import java.util.Properties; 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/support/management/MessageHandlerMetrics.java similarity index 93% rename from spring-integration-core/src/main/java/org/springframework/integration/handler/management/MessageHandlerMetrics.java rename to spring-integration-core/src/main/java/org/springframework/integration/support/management/MessageHandlerMetrics.java index fc15b09a21..f336a31a48 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/support/management/MessageHandlerMetrics.java @@ -14,10 +14,8 @@ * limitations under the License. */ -package org.springframework.integration.handler.management; +package org.springframework.integration.support.management; -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; 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/support/management/MessageSourceMetrics.java similarity index 90% rename from spring-integration-core/src/main/java/org/springframework/integration/endpoint/management/MessageSourceMetrics.java rename to spring-integration-core/src/main/java/org/springframework/integration/support/management/MessageSourceMetrics.java index cdbe3bbe48..845eeef81f 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/support/management/MessageSourceMetrics.java @@ -11,9 +11,8 @@ * specific language governing permissions and limitations under the License. */ -package org.springframework.integration.endpoint.management; +package org.springframework.integration.support.management; -import org.springframework.integration.support.management.IntegrationManagement; import org.springframework.jmx.export.annotation.ManagedMetric; import org.springframework.jmx.support.MetricType; diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/MetricsFactory.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/MetricsFactory.java similarity index 95% rename from spring-integration-jmx/src/main/java/org/springframework/integration/monitor/MetricsFactory.java rename to spring-integration-core/src/main/java/org/springframework/integration/support/management/MetricsFactory.java index 3e9ebaef0b..2a74a0ffb9 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/MetricsFactory.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/MetricsFactory.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.integration.monitor; +package org.springframework.integration.support.management; import org.springframework.integration.channel.management.AbstractMessageChannelMetrics; import org.springframework.integration.handler.management.AbstractMessageHandlerMetrics; diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/RouterMetrics.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/RouterMetrics.java similarity index 89% rename from spring-integration-jmx/src/main/java/org/springframework/integration/monitor/RouterMetrics.java rename to spring-integration-core/src/main/java/org/springframework/integration/support/management/RouterMetrics.java index 349fd52c3f..5d7b58391e 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/RouterMetrics.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/RouterMetrics.java @@ -13,14 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.integration.monitor; +package org.springframework.integration.support.management; import java.util.Map; import java.util.Properties; import org.springframework.context.Lifecycle; -import org.springframework.integration.handler.management.MessageHandlerMetrics; -import org.springframework.integration.router.MappingMessageRouterManagement; /** * Allows Router operations to appear in the same MBean as statistics. diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/TrackableRouterMetrics.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/TrackableRouterMetrics.java similarity index 92% rename from spring-integration-jmx/src/main/java/org/springframework/integration/monitor/TrackableRouterMetrics.java rename to spring-integration-core/src/main/java/org/springframework/integration/support/management/TrackableRouterMetrics.java index bb35855718..0febcb1a2c 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/TrackableRouterMetrics.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/TrackableRouterMetrics.java @@ -14,11 +14,10 @@ * limitations under the License. */ -package org.springframework.integration.monitor; +package org.springframework.integration.support.management; import org.springframework.context.Lifecycle; import org.springframework.integration.history.TrackableComponent; -import org.springframework.integration.router.MappingMessageRouterManagement; import org.springframework.util.Assert; /** diff --git a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-4.2.xsd b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-4.2.xsd index 5825bec27f..80157e160c 100644 --- a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-4.2.xsd +++ b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-4.2.xsd @@ -4482,6 +4482,82 @@ The list of component name patterns you want to track (e.g., tracked-components + + + + + + Set false, to disable all main-path debug logging for components that implement + 'IntegrationManagement' (channels, message handlers etc). For high-volume environments + avoiding calls to 'isDebuggingEnabled()` can improve performance. + + + + + + + The default value for components that don't match 'counts-enabled-patterns'. + Defaults to false, or true when an Integration MBean Exporter is provided. + + + + + + + The default value for components that don't match 'stats-enabled-patterns'. + Defaults to false, or true when an Integration MBean Exporter is provided. + + + + + + + Comma separated list of simple patterns for component names for which message counts + will be enabled (defaults to '*'). Only patterns that also match 'managed-components' + will be considered. Enables message counting (`sendCount`, `errorCount`, `receiveCount`) + for those components that support counters (channels, message handlers, etc). + This is the initial setting only, individual components can have counts enabled/disabled + at runtime. May be overridden by an entry in 'stats-enabled' which is additional + functionality over simple counts. If a pattern starts with `!`, counts are disabled + for matches. For components with names that match multiple patterns, the first pattern wins. + Disabling counts at runtime also disables stats. + + + + + + + Comma separated list of simple patterns for component names for which message statistics + will be enabled (response times, rates etc), as well as counts (a positive match here + overrides `counts-enabled`, you can't have statistics without counts). + (defaults to '*'). Only patterns that also match 'managed-components' + will be considered. Enables statistics for those components that support + statistics (channels - when sending, message handlers, etc). + This is the initial setting only, individual components can have stats enabled/disabled + at runtime. If a pattern starts with `!`, stats (and counts) are disabled + for matches. Note: this means that '!foo' here will disable stats + and counts for 'foo' even if counts are enabled for 'foo' in 'counts-enabled'. + For components with names that match multiple patterns, the first pattern wins. + Enabling stats at runtime also enables counts. + + + + + + + + + + + + A MetricsFactory responsible for creating objects that maintain metrics for message + channels and message handlers. + + + + + + patterns = new ArrayList(); - String[] countsEnabled = this.attributes.getStringArray("countsEnabled"); - for (String managedComponent : countsEnabled) { - String pattern = this.environment.resolvePlaceholders(managedComponent); - patterns.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(pattern))); - } - exporter.setEnabledCountsPatterns(patterns.toArray(new String[patterns.size()])); - } - - private void setupStatsEnabledNamePatterns(IntegrationMBeanExporter exporter) { - List patterns = new ArrayList(); - String[] statsEnabled = this.attributes.getStringArray("statsEnabled"); - for (String managedComponent : statsEnabled) { - String pattern = this.environment.resolvePlaceholders(managedComponent); - patterns.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(pattern))); - } - exporter.setEnabledStatsPatterns(patterns.toArray(new String[patterns.size()])); - } - } diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterParser.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterParser.java index 1353840187..dac943df52 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterParser.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterParser.java @@ -58,9 +58,6 @@ public class MBeanExporterParser extends AbstractSingleBeanDefinitionParser { IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "default-domain"); IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "object-name-static-properties"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "managed-components", "componentNamePatterns"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "counts-enabled", "enabledCountsPatterns"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "stats-enabled", "enabledStatsPatterns"); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "metrics-factory"); IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "object-naming-strategy", "namingStrategy"); builder.addPropertyValue("server", mbeanServer); diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java index 40c720a3c3..83727d022b 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java @@ -43,24 +43,28 @@ import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.context.Lifecycle; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.integration.channel.QueueChannel; -import org.springframework.integration.channel.management.AbstractMessageChannelMetrics; import org.springframework.integration.channel.management.MessageChannelMetrics; import org.springframework.integration.channel.management.PollableChannelManagement; import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.context.OrderlyShutdownCapable; import org.springframework.integration.core.MessageProducer; import org.springframework.integration.endpoint.AbstractEndpoint; -import org.springframework.integration.endpoint.management.MessageSourceMetrics; import org.springframework.integration.handler.AbstractMessageProducingHandler; -import org.springframework.integration.handler.management.AbstractMessageHandlerMetrics; -import org.springframework.integration.handler.management.MessageHandlerMetrics; import org.springframework.integration.history.MessageHistoryConfigurer; import org.springframework.integration.history.TrackableComponent; -import org.springframework.integration.router.MappingMessageRouterManagement; import org.springframework.integration.support.context.NamedComponent; -import org.springframework.integration.support.management.ConfigurableMetricsAware; import org.springframework.integration.support.management.IntegrationManagedResource; +import org.springframework.integration.support.management.IntegrationManagementConfigurer; +import org.springframework.integration.support.management.LifecycleMessageHandlerMetrics; +import org.springframework.integration.support.management.LifecycleMessageSourceMetrics; +import org.springframework.integration.support.management.LifecycleTrackableMessageHandlerMetrics; +import org.springframework.integration.support.management.LifecycleTrackableMessageSourceMetrics; +import org.springframework.integration.support.management.MappingMessageRouterManagement; +import org.springframework.integration.support.management.MessageHandlerMetrics; +import org.springframework.integration.support.management.MessageSourceMetrics; +import org.springframework.integration.support.management.RouterMetrics; import org.springframework.integration.support.management.Statistics; +import org.springframework.integration.support.management.TrackableRouterMetrics; import org.springframework.jmx.export.MBeanExporter; import org.springframework.jmx.export.UnableToRegisterMBeanException; import org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource; @@ -158,18 +162,12 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati private String[] componentNamePatterns = { "*" }; - private String[] enabledCountsPatterns = { "*" }; - - private String[] enabledStatsPatterns = { "*" }; - private volatile long shutdownDeadline; private final AtomicBoolean shuttingDown = new AtomicBoolean(); private StringValueResolver embeddedValueResolver; - private MetricsFactory metricsFactory = new DefaultMetricsFactory(); - public IntegrationMBeanExporter() { super(); @@ -215,48 +213,6 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati this.componentNamePatterns = Arrays.copyOf(componentNamePatterns, componentNamePatterns.length); } - /** - * Set the array of simple patterns for component names for which message counts will - * be enabled (defaults to '*'). Only patterns that also match - * {@link #setComponentNamePatterns(String[]) componentNamePatterns} will be - * considered. Enables message counting (`sendCount`, `errorCount`, `receiveCount`) - * for those components that support counters (channels, message handlers, etc). - * This is the initial setting only, individual components can have counts - * enabled/disabled at runtime. May be overridden by an entry in - * {@link #setEnabledStatsPatterns(String[]) enabledStatsPatterns} which is additional - * functionality over simple counts. If a pattern starts with `!`, counts are disabled - * for matches. For components that match multiple patterns, the first pattern wins. - * Disabling counts at runtime also disables stats. - * @param enabledCountsPatterns the patterns. - * @since 4.2 - */ - public void setEnabledCountsPatterns(String[] enabledCountsPatterns) { - Assert.notEmpty(enabledCountsPatterns, "enabledCountsPatterns must not be empty"); - this.enabledCountsPatterns = Arrays.copyOf(enabledCountsPatterns, enabledCountsPatterns.length); - } - - /** - * Set the array of simple patterns for component names for which message statistics - * will be enabled (response times, rates etc), as well as counts (a positive match - * here overrides {@link #setEnabledCountsPatterns(String[]) enabledCountsPatterns}, - * you can't have statistics without counts). (defaults to '*'). Only patterns that - * also match {@link #setComponentNamePatterns(String[]) componentNamePatterns} will - * be considered. Enables statistics for those components that support statistics - * (channels - when sending, message handlers, etc). This is the initial setting only, - * individual components can have stats enabled/disabled at runtime. If a pattern - * starts with `!`, stats (and counts) are disabled for matches. Note: this means that - * '!foo' here will disable stats and counts for 'foo' even if counts are enabled for - * 'foo' in {@link #setEnabledCountsPatterns(String[]) enabledCountsPatterns}. For - * components that match multiple patterns, the first pattern wins. Enabling stats at - * runtime also enables counts. - * @param enabledStatsPatterns the patterns. - * @since 4.2 - */ - public void setEnabledStatsPatterns(String[] enabledStatsPatterns) { - Assert.notEmpty(enabledStatsPatterns, "componentNamePatterns must not be empty"); - this.enabledStatsPatterns = Arrays.copyOf(enabledStatsPatterns, enabledStatsPatterns.length); - } - @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { @@ -269,15 +225,6 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati this.embeddedValueResolver = resolver; } - /** - * Set a metrics factory. - * @param metricsFactory the factory. - * @since 4.2 - */ - public void setMetricsFactory(MetricsFactory metricsFactory) { - this.metricsFactory = metricsFactory; - } - @Override public void afterSingletonsInstantiated() { Map messageHandlers = @@ -341,6 +288,14 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati IntegrationContextUtils.INTEGRATION_MESSAGE_HISTORY_CONFIGURER_BEAN_NAME); } } + if (!this.applicationContext.containsBean(IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME)) { + IntegrationManagementConfigurer config = new IntegrationManagementConfigurer(); + config.setDefaultCountsEnabled(true); + config.setDefaultStatsEnabled(true); + config.setApplicationContext(this.applicationContext); + config.setBeanName(IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME); + config.afterSingletonsInstantiated(); + } } catch (RuntimeException e) { unregisterBeans(); @@ -709,7 +664,6 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati return null; } - @SuppressWarnings("unchecked") private void registerChannels() { for (MessageChannelMetrics monitor : channels) { String name = ((NamedComponent) monitor).getComponentName(); @@ -724,26 +678,11 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati if (name != null) { channelsByName.put(name, monitor); } - AbstractMessageChannelMetrics metrics = this.metricsFactory.createChannelMetrics(name); - Assert.state(metrics != null, "'metrics' must not be null"); - Boolean enabled = smartMatch(this.enabledCountsPatterns, name); - if (enabled != null) { - monitor.enableCounts(enabled); - } - enabled = smartMatch(this.enabledStatsPatterns, name); - if (enabled != null) { - monitor.enableStats(enabled); - metrics.setFullStatsEnabled(enabled); - } - if (monitor instanceof ConfigurableMetricsAware) { - ((ConfigurableMetricsAware) monitor).configureMetrics(metrics); - } registerBeanNameOrInstance(monitor, beanKey); } } } - @SuppressWarnings("unchecked") private void registerHandlers() { for (MessageHandlerMetrics handler : handlers) { MessageHandlerMetrics monitor = enhanceHandlerMonitor(handler); @@ -758,20 +697,6 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati if (name != null) { handlersByName.put(name, monitor); } - AbstractMessageHandlerMetrics metrics = this.metricsFactory.createHandlerMetrics(name); - Assert.state(metrics != null, "'metrics' must not be null"); - Boolean enabled = smartMatch(this.enabledCountsPatterns, name); - if (enabled != null) { - monitor.enableCounts(enabled); - } - enabled = smartMatch(this.enabledStatsPatterns, name); - if (enabled != null) { - monitor.enableStats(enabled); - metrics.setFullStatsEnabled(enabled); - } - if (monitor instanceof ConfigurableMetricsAware) { - ((ConfigurableMetricsAware) monitor).configureMetrics(metrics); - } registerBeanNameOrInstance(monitor, beanKey); } } @@ -791,10 +716,6 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati if (name != null) { sourcesByName.put(name, monitor); } - Boolean enabled = smartMatch(this.enabledCountsPatterns, name); - if (enabled != null) { - monitor.enableCounts(enabled); - } registerBeanNameOrInstance(monitor, beanKey); } } diff --git a/spring-integration-jmx/src/main/resources/org/springframework/integration/jmx/config/spring-integration-jmx-4.2.xsd b/spring-integration-jmx/src/main/resources/org/springframework/integration/jmx/config/spring-integration-jmx-4.2.xsd index f65f8490b4..3676b45747 100644 --- a/spring-integration-jmx/src/main/resources/org/springframework/integration/jmx/config/spring-integration-jmx-4.2.xsd +++ b/spring-integration-jmx/src/main/resources/org/springframework/integration/jmx/config/spring-integration-jmx-4.2.xsd @@ -188,52 +188,6 @@ - - - - Comma separated list of simple patterns for component names for which message counts - will be enabled (defaults to '*'). Only patterns that also match 'managed-components' - will be considered. Enables message counting (`sendCount`, `errorCount`, `receiveCount`) - for those components that support counters (channels, message handlers, etc). - This is the initial setting only, individual components can have counts enabled/disabled - at runtime. May be overridden by an entry in 'stats-enabled' which is additional - functionality over simple counts. If a pattern starts with `!`, counts are disabled - for matches. For components with names that match multiple patterns, the first pattern wins. - Disabling counts at runtime also disables stats. - - - - - - - Comma separated list of simple patterns for component names for which message statistics - will be enabled (response times, rates etc), as well as counts (a positive match here - overrides `counts-enabled`, you can't have statistics without counts). - (defaults to '*'). Only patterns that also match 'managed-components' - will be considered. Enables statistics for those components that support - statistics (channels - when sending, message handlers, etc). - This is the initial setting only, individual components can have stats enabled/disabled - at runtime. If a pattern starts with `!`, stats (and counts) are disabled - for matches. Note: this means that '!foo' here will disable stats - and counts for 'foo' even if counts are enabled for 'foo' in 'counts-enabled'. - For components with names that match multiple patterns, the first pattern wins. - Enabling stats at runtime also enables counts. - - - - - - - - - - - - A MetricsFactory responsible for creating objects that maintain metrics for message - channels and message handlers. - - - diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests-context.xml b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests-context.xml index 73a485e79a..86395e2b68 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests-context.xml +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests-context.xml @@ -20,11 +20,16 @@ default-domain="tests.MBeanExpoerterParser" object-name-static-properties="appProperties" object-naming-strategy="keyNamer" - counts-enabled="foo, !baz, ba*" - stats-enabled="fiz, buz" - managed-components="\!excluded, f*, b*, q*, t*" - metrics-factory="mf" /> - + managed-components="\!excluded, f*, b*, q*, t*" /> + + + foo bar diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests.java index 282538a76f..97f2aec898 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests.java +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests.java @@ -36,12 +36,13 @@ import org.springframework.integration.channel.management.DefaultMessageChannelM import org.springframework.integration.channel.management.MessageChannelMetrics; import org.springframework.integration.handler.management.AbstractMessageHandlerMetrics; import org.springframework.integration.handler.management.DefaultMessageHandlerMetrics; -import org.springframework.integration.handler.management.MessageHandlerMetrics; import org.springframework.integration.monitor.IntegrationMBeanExporter; -import org.springframework.integration.monitor.MetricsFactory; import org.springframework.integration.support.management.ExponentialMovingAverage; import org.springframework.integration.support.management.ExponentialMovingAverageRate; import org.springframework.integration.support.management.ExponentialMovingAverageRatio; +import org.springframework.integration.support.management.IntegrationManagementConfigurer; +import org.springframework.integration.support.management.MessageHandlerMetrics; +import org.springframework.integration.support.management.MetricsFactory; import org.springframework.integration.test.util.TestUtils; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; @@ -99,11 +100,13 @@ public class MBeanExporterParserTests { assertFalse(metrics.isStatsEnabled()); checkCustomized(metrics); MetricsFactory factory = context.getBean(MetricsFactory.class); - assertSame(factory, TestUtils.getPropertyValue(exporter, "metricsFactory")); + IntegrationManagementConfigurer configurer = context.getBean(IntegrationManagementConfigurer.class); + assertSame(factory, TestUtils.getPropertyValue(configurer, "metricsFactory")); exporter.destroy(); } private void checkCustomized(MessageChannelMetrics metrics) { + assertFalse(metrics.isLoggingEnabled()); assertEquals(20, TestUtils.getPropertyValue(metrics, "channelMetrics.sendDuration.window")); assertEquals(1000000., TestUtils.getPropertyValue(metrics, "channelMetrics.sendDuration.factor", Double.class), .01); diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/configuration/EnableMBeanExportTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/configuration/EnableMBeanExportTests.java index d79df13596..d9c6095e78 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/configuration/EnableMBeanExportTests.java +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/configuration/EnableMBeanExportTests.java @@ -16,7 +16,9 @@ package org.springframework.integration.jmx.configuration; +import static org.hamcrest.Matchers.arrayContaining; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; @@ -29,7 +31,6 @@ import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; -import org.hamcrest.Matchers; import org.junit.Test; import org.junit.runner.RunWith; @@ -41,8 +42,12 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.support.GenericApplicationContext; import org.springframework.integration.channel.QueueChannel; import org.springframework.integration.config.EnableIntegration; +import org.springframework.integration.config.EnableIntegrationManagement; import org.springframework.integration.jmx.config.EnableIntegrationMBeanExport; import org.springframework.integration.monitor.IntegrationMBeanExporter; +import org.springframework.integration.support.management.DefaultMetricsFactory; +import org.springframework.integration.support.management.IntegrationManagementConfigurer; +import org.springframework.integration.support.management.MetricsFactory; import org.springframework.integration.test.util.TestUtils; import org.springframework.jmx.support.MBeanServerFactoryBean; import org.springframework.mock.env.MockEnvironment; @@ -69,17 +74,27 @@ public class EnableMBeanExportTests { @Autowired private MBeanServer mBeanServer; + @Autowired + private IntegrationManagementConfigurer configurer; + + @Autowired + private MetricsFactory myMetricsFactory; + @SuppressWarnings("unchecked") @Test public void testEnableMBeanExport() throws MalformedObjectNameException, ClassNotFoundException { assertSame(this.mBeanServer, this.exporter.getServer()); String[] componentNamePatterns = TestUtils.getPropertyValue(this.exporter, "componentNamePatterns", String[].class); - assertThat(componentNamePatterns, Matchers.arrayContaining("input", "inputX", "in*")); - String[] enabledCounts = TestUtils.getPropertyValue(this.exporter, "enabledCountsPatterns", String[].class); - assertThat(enabledCounts, Matchers.arrayContaining("foo", "bar", "baz")); - String[] enabledStatts = TestUtils.getPropertyValue(this.exporter, "enabledStatsPatterns", String[].class); - assertThat(enabledStatts, Matchers.arrayContaining("qux", "!*")); + assertThat(componentNamePatterns, arrayContaining("input", "inputX", "in*")); + String[] enabledCounts = TestUtils.getPropertyValue(this.configurer, "enabledCountsPatterns", String[].class); + assertThat(enabledCounts, arrayContaining("foo", "bar", "baz")); + String[] enabledStatts = TestUtils.getPropertyValue(this.configurer, "enabledStatsPatterns", String[].class); + assertThat(enabledStatts, arrayContaining("qux", "!*")); + assertFalse(TestUtils.getPropertyValue(this.configurer, "defaultLoggingEnabled", Boolean.class)); + assertTrue(TestUtils.getPropertyValue(this.configurer, "defaultCountsEnabled", Boolean.class)); + assertTrue(TestUtils.getPropertyValue(this.configurer, "defaultStatsEnabled", Boolean.class)); + assertSame(this.myMetricsFactory, TestUtils.getPropertyValue(this.configurer, "metricsFactory")); Set names = this.mBeanServer.queryNames(ObjectName.getInstance("FOO:type=MessageChannel,*"), null); // Only one registered (out of >2 available) @@ -106,9 +121,14 @@ public class EnableMBeanExportTests { @EnableIntegration @EnableIntegrationMBeanExport(server = "#{mbeanServer}", defaultDomain = "${managed.domain}", - managedComponents = {"input", "${managed.component}"}, - countsEnabled = { "foo", "${count.patterns}" }, - statsEnabled = { "qux", "!*" }) + managedComponents = {"input", "${managed.component}"}) + @EnableIntegrationManagement( + defaultLoggingEnabled = "false", + defaultCountsEnabled = "true", + defaultStatsEnabled = "true", + countsEnabled = { "foo", "${count.patterns}" }, + statsEnabled = { "qux", "!*" }, + metricsFactory = "myMetricsFactory") public static class ContextConfiguration { @Bean @@ -126,6 +146,11 @@ public class EnableMBeanExportTests { return new QueueChannel(); } + @Bean + public MetricsFactory myMetricsFactory() { + return new DefaultMetricsFactory(); + } + } public static class EnvironmentApplicationContextInitializer implements ApplicationContextInitializer { diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/monitor/AggregatingMetricsTests-context.xml b/spring-integration-jmx/src/test/java/org/springframework/integration/monitor/AggregatingMetricsTests-context.xml index d513159e94..1727a8f3f9 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration/monitor/AggregatingMetricsTests-context.xml +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/monitor/AggregatingMetricsTests-context.xml @@ -11,7 +11,9 @@ - + + + @@ -21,7 +23,8 @@ - + diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/monitor/AggregatingMetricsTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/monitor/AggregatingMetricsTests.java index 4fac604c46..7fc410d9a2 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration/monitor/AggregatingMetricsTests.java +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/monitor/AggregatingMetricsTests.java @@ -80,9 +80,9 @@ public class AggregatingMetricsTests { public void testElapsed() { int sampleSize = 2; this.delay.configureMetrics(new AggregatingMessageChannelMetrics("foo", sampleSize)); - this.delay.enableStats(true); + this.delay.setStatsEnabled(true); this.delayer.configureMetrics(new AggregatingMessageHandlerMetrics("bar", sampleSize)); - this.delayer.enableStats(true); + this.delayer.setStatsEnabled(true); GenericMessage message = new GenericMessage("foo"); int count = 4; for (int i = 0; i < count; i++) { diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/monitor/ChannelIntegrationTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/monitor/ChannelIntegrationTests.java index 10c7ec64f1..cd1c04c4a6 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration/monitor/ChannelIntegrationTests.java +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/monitor/ChannelIntegrationTests.java @@ -21,7 +21,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.integration.handler.management.MessageHandlerMetrics; +import org.springframework.integration.support.management.MessageHandlerMetrics; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageDeliveryException; import org.springframework.messaging.PollableChannel; diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/Int2307Tests.java b/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/Int2307Tests.java index ea3002b8c1..e00256edb2 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/Int2307Tests.java +++ b/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/Int2307Tests.java @@ -54,11 +54,11 @@ public class Int2307Tests { int count = 0; for (ObjectInstance mbean : mbeans) { Thread.sleep(500); //Added in order to pass test with Java 8 - if (mbean.toString().startsWith("org.springframework.integration.monitor.LifecycleTrackableMessageHandlerMetrics[test.domain:type=MessageHandler,name=rlr,bean=endpoint,random=")) { + if (mbean.toString().startsWith("org.springframework.integration.support.management.LifecycleTrackableMessageHandlerMetrics[test.domain:type=MessageHandler,name=rlr,bean=endpoint,random=")) { bits |= 2; count++; } - else if (mbean.toString().startsWith("org.springframework.integration.monitor.TrackableRouterMetrics[test.domain:type=MessageHandler,name=hvr,bean=endpoint,random=")) { + else if (mbean.toString().startsWith("org.springframework.integration.support.management.TrackableRouterMetrics[test.domain:type=MessageHandler,name=hvr,bean=endpoint,random=")) { bits |= 8; count++; } diff --git a/src/reference/asciidoc/jmx.adoc b/src/reference/asciidoc/jmx.adoc index c08e73f215..c498542a99 100644 --- a/src/reference/asciidoc/jmx.adoc +++ b/src/reference/asciidoc/jmx.adoc @@ -301,107 +301,6 @@ NOTE: The default naming strategy is a http://docs.spring.io/spring/docs/current The exporter propagates the `default-domain` to that object to allow it to generate a fallback object name if parsing of the bean key fails. If your custom naming strategy is a `MetadataNamingStrategy` (or subclass), the exporter will *not* propagate the `default-domain`; you will need to configure it on your strategy bean. -[[jmx-channel-features]] -===== MessageChannel MBean Features - -Message channels report metrics according to their concrete type. -If you are looking at a `DirectChannel`, you will see statistics for the send operation. -If it is a `QueueChannel`, you will also see statistics for the receive operation, as well as the count of messages that are currently buffered by this `QueueChannel`. -In both cases there are some metrics that are simple counters (message count and error count), and some that are estimates of averages of interesting quantities. -The algorithms used to calculate these estimates are described briefly in the section below. - -.MessageChannel Metrics - - -[cols="1,2,3", options="header"] -|=== -| Metric Type -| Example -| Algorithm - -| Count -| Send Count -| Simple incrementer. -Increases by one when an event occurs. - -| Error Count -| Send Error Count -| Simple incrementer. -Increases by one when an send results in an error. - -| Duration -| Send Duration (method execution time in milliseconds) -| Exponential Moving Average with decay factor (10 by default). -Average of the method execution time over roughly the last 10 (default) measurements. - -| Rate -| Send Rate (number of operations per second) -| Inverse of Exponential Moving Average of the interval between events with decay in time (lapsing over 60 seconds by default) and per measurement (last 10 events by default). - -| Error Rate -| Send Error Rate (number of errors per second) -| Inverse of Exponential Moving Average of the interval between error events with decay in time (lapsing over 60 seconds by default) and per measurement (last 10 events by default). - -| Ratio -| Send Success Ratio (ratio of successful to total sends) -| Estimate the success ratio as the Exponential Moving Average of the series composed of values 1 for success and 0 for failure (decaying as per the rate measurement over time and events by default). -Error ratio is 1 - success ratio. - -|=== - -[[jmx-handler-features]] -===== MessageHandler MBean Features - -The following table shows the statistics maintained for message handlers. -Some metrics are simple counters (message count and error count), and one is an estimate of averages of send duration. -The algorithms used to calculate these estimates are described briefly in the table below: - -.MessageHandlerMetrics - -[cols="1,2,3", options="header"] -|=== -| Metric Type -| Example -| Algorithm - -| Count -| Handle Count -| Simple incrementer. -Increases by one when an event occurs. - -| Error Count -| Handler Error Count -| Simple incrementer. -Increases by one when an invocation results in an error. - -| Active Count -| Handler Active Count -| Indicates the number of currently active threads currently invoking the handler (or any downstream synchronous flow). - -| Duration -| Handle Duration (method execution time in milliseconds) -| Exponential Moving Average with decay factor (10 by default). -Average of the method execution time over roughly the last 10 (default) measurements. - -|=== - -[[jmx-statistics]] -===== Time-Based Average Estimates - -A feature of the time-based average estimates is that they decay with time if no new measurements arrive. -To help interpret the behaviour over time, the time (in seconds) since the last measurement is also exposed as a metric. - -There are two basic exponential models: decay per measurement (appropriate for duration and anything where the number of measurements is part of the metric), and decay per time unit (more suitable for rate measurements where the time in between measurements is part of the metric). -Both models depend on the fact that - -`S(n) = sum(i=0,i=n) w(i) x(i)`has a special form when `w(i) = r^i`, with `r=constant`: - -`S(n) = x(n) + r S(n-1)`(so you only have to store `S(n-1)`, not the whole series `x(i)`, to generate a new metric estimate from the last measurement). -The algorithms used in the duration metrics use `r=exp(-1/M)` with `M=10`. -The net effect is that the estimate `S(n)` is more heavily weighted to recent measurements and is composed roughly of the last `M` measurements. -So `M` is the "window" or lapse rate of the estimate In the case of the vanilla moving average, `i` is a counter over the number of measurements. -In the case of the rate we interpret `i` as the elapsed time, or a combination of elapsed time and a counter (so the metric estimate contains contributions roughly from the last `M` measurements and the last `T` seconds). - [[jmx-42-improvements]] ===== JMX Improvements @@ -414,7 +313,7 @@ These changes are detailed below, with a *caution* where necessary. Previously, `MessageSource`, `MessageChannel` and `MessageHandler` metrics were captured by wrapping the object in a JDK dynamic proxy to intercept appropriate method calls and capture the statistics. The proxy was added when an integration MBean exporter was declared in the context. -Now, the statistics are captured by the beans themselves; but they are still enabled (by default) only if the integration MBean exporter is declared. +Now, the statistics are captured by the beans themselves; see <> for more information. WARNING: This change means that you no longer automatically get an MBean or statistics for custom `MessageHandler` implementations, unless those custom handlers extend `AbstractMessageHandler`. The simplest way to resolve this is to extend `AbstractMessageHandler`. @@ -441,17 +340,7 @@ It is now possible to control whether the statisics are enabled on an individual Further, it is possible to capture simple counts on `MessageChannel` s and `MessageHandler` s instead of the complete time-based statistics. This can have significant performance implications because you can selectively configure where you need detailed statistics, as well as enable/disable at runtime. -Two new attributes have been added to the ``. -`counts-enabled` is a list of bean name patterns where simple message counts will be enabled. -`stats-enabled` is a list of bean name patterns where full time-based statistics will be enabled. -These are initial settings only and each component can have its settings changed at runtime, using JMX or a using the `enableCounts()` and `enableStats()` operations. -*Note:* stats is a superset of counts, enabling stats will enable counts (this is true for the initial setting via the patterns and at runtime). -Disabling counts at runtime will also disable stats. - -A pattern can be negated by preceding it with `!`; patterns are evaluated left to right; the first match (positive or negative) wins and the remaining patterns won't be evaluated against that bean. -If your bean name begins with `!`, the `!` in the pattern can be escaped. -`"\!foo"` will positively match a bean named `"!foo"`. - +See <>. * *@IntegrationManagedResource* @@ -501,89 +390,10 @@ If you have a bean `"!foo"`*and* you included a pattern `"!foo"` in your MBean e In this case, you can escape the `!` in the pattern with `\`. The pattern `"\!foo"` means match a bean named `"!foo"`. - -* *Replacing the Default Channel/Handler Statistics* - -A new strategy interface `MetricsFactory` has been introduced allowing you to provide custom channel metrics for your `MessageChannel` s and `MessageHandler` s. -By default, a `DefaultMetricsFactory` provides default implementation of `MessageChannelMetrics` and `MessageHandlerMetrics` which are described in the next bullet. -To override the default `MetricsFactory` use the MBean exporter's `metrics-factory` attribute to provide a reference to your `MetricsFactory` bean instance. -You can either customize the default implementations as described in the next bullet, or provide completely different implementations by overriding `AbstractMessageChannelMetrics` and/or `AbstractMessageHandlerMetrics`. - -In addition to the default metrics factory described above, the framework provides the `AggregatingMetricsFactory`. -This factory creates `AggregatingMessageChannelMetrics` and `AggregatingMessageHandlerMetrics`. -In very high volume scenarios, the cost of capturing statistics can be prohibitive (2 calls to the system time and -storing the data). -The aggregating metrics aggregate the response time over a sample of messages. -This can save significant CPU time. - -CAUTION: The statistics will be skewed if messages arrive in bursts. -These metrics are intended for use with high, constant-volume, message rates. - -[source, xml] ----- - - - - - - - ----- - -The above configuration aggregates the response time over 1000 messages. -Counts (send, error) are maintained per-message but the statistics are per 1000 messages. - -* *Customizing the Default Channel/Handler Statistics* - -See <> and the Javadocs for the `ExponentialMovingAverage*` classes for more information about these values. - -By default, the `DefaultMessageChannelMetrics` and `DefaultMessageHandlerMetrics` use a `window` of 10 measurements, a rate period of 1 second (rate per second) and a decay lapse period of 1 minute. - -If you wish to override these defaults, you can provide a custom `MetricsFactory` that returns appropriately configured metrics and provide a reference to it to the MBean exporter as described above. - -Example: - -[source,java] ----- -public static class CustomMetrics implements MetricsFactory { - - @Override - public AbstractMessageChannelMetrics createChannelMetrics(String name) { - return new DefaultMessageChannelMetrics(name, - new ExponentialMovingAverage(20, 1000000.), - new ExponentialMovingAverageRate(2000, 120000, 30, true), - new ExponentialMovingAverageRatio(130000, 40, true), - new ExponentialMovingAverageRate(3000, 140000, 50, true)); - } - - @Override - public AbstractMessageHandlerMetrics createHandlerMetrics(String name) { - return new DefaultMessageHandlerMetrics(name, new ExponentialMovingAverage(20, 1000000.)); - } - -} ----- - - -* *Advanced Customization* - -The customizations described above are wholesale and will apply to all appropriate beans exported by the MBean exporter. -This is the extent of customization available using XML configuration. - -Individual beans can be provided with different implementations using java `@Configuration` or programmatically at runtime, after the application context has been refreshed, by invoking the `configureMetrics` methods on `AbstractMessageChannel` and `AbstractMessageHandler`. - - -* *Performance Improvement* - -Previously, the time-based metrics (see <>) were calculated in real time. -The statistics are now calculated when retrieved instead. -This resulted in a significant performance improvement, at the expense of a small amount of additional memory for each statistic. -As discussed in the bullet above, the statistics can be disabled altogether, while retaining the MBean allowing the invocation of `Lifecycle` methods. - - * *IntegrationMBeanExporter changes* -The `IntegrationMBeanExporter` no longer implements `SmartLifecycle`; this means that `start()` and `stop()` operations are no longer available to register/unregister MBeans. +The `IntegrationMBeanExporter` no longer implements `SmartLifecycle`; this means that `start()` and `stop()` operations +are no longer available to register/unregister MBeans. The MBeans are now registered during context initialization and unregistered when the context is destroyed. diff --git a/src/reference/asciidoc/metrics.adoc b/src/reference/asciidoc/metrics.adoc new file mode 100644 index 0000000000..c8e69e663c --- /dev/null +++ b/src/reference/asciidoc/metrics.adoc @@ -0,0 +1,269 @@ +[[metrics-management]] +=== Metrics and Management + +==== Configuring Metrics Capture + +NOTE: Prior to _version 4.2_ metrics were only available when JMX was enabled. +See <>. + +To enable `MessageSource`, `MessageChannel` and `MessageHandler` metrics, add an `` bean to the +application context, or annotate one of your `@Configuration` classes with `@EnableIntegrationManagement`. +`MessageSource` s only maintain counts, `MessageChannel` s and `MessageHandler` s maintain duration statistics in +addition to counts. +See <> and <> below. + +This causes the automatic registration of the `IntegrationManagementConfigurer` bean in the application context. +Only one such bean can exist in the context and it must have the bean name `integrationManagementConfigurer` +if registered manually via a `` definition. + +In addition to metrics, you can control *debug* logging in the main message flow. +It has been found that in very high volume applications, even calls to `isDebugEnabled()` can be quite expensive with +some logging subsystems. +You can disable all such logging to avoid this overhead; exception logging (debug or otherwise) are not affected +by this setting. + +A number of options are available: + +[source, xml] +---- + + default-counts-enabled="false" <2> + default-stats-enabled="false" <3> + counts-enabled-patterns="foo, !baz, ba*" <4> + stats-enabled-patterns="fiz, buz" <5> + metrics-factory="myMetricsFactory" /> <6> +---- + +[source, java] +---- +@Configuration +@EnableIntegration +@EnableIntegrationManagement( + defaultLoggingEnabled = "false", <1> + defaultCountsEnabled = "false", <2> + defaultStatsEnabled = "false", <3> + countsEnabled = { "foo", "${count.patterns}" }, <4> + statsEnabled = { "qux", "!*" }, <5> + MetricsFactory = "myMetricsFactory") <6> +public static class ContextConfiguration { +... +} +---- + +<1> Set to `false` to disable all logging in the main message flow, regardless of the log system category settings. +Set to 'true' to enable debug logging (if also enabled by the logging subsystem). + +<2> Enable or disable count metrics for components not matching one of the patterns in <4>. + +<3> Enable or disable statistical metrics for components not matching one of the patterns in <5>. + +<4> A comma-delimited list of patterns for beans for which counts should be enabled; negate the pattern with `!`. +First match wins (positive or negative). +In the unlikely event that you have a bean name starting with `!`, escape the `!` in the pattern: `\!foo` positively +matches a bean named `!foo`. + +<5> A comma-delimited list of patterns for beans for which statistical metrics should be enabled; negate the pattern +with `!`. +First match wins (positive or negative). +In the unlikely event that you have a bean name starting with `!`, escape the `!` in the pattern: `\!foo` positively +matches a bean named `!foo`. +Stats implies counts. + +<6> A reference to a `MetricsFactory`. +See <>. + +At runtime, counts and statistics can be obtained by calling `IntegrationManagementConfigurer` `getChannelMetrics`, +`getHandlerMetrics` and `getSourceMetrics`, returning `MessageChannelMetrics`, `MessageHandlerMetrics` and +`MessageSourceMetrics` respectively. + +See the javadocs for complete information about these classes. + +When JMX is enabled (see <>), these metrics are also exposed by the `IntegrationMBeanExporter`. + +[[mgmt-channel-features]] +==== MessageChannel Metric Features + +Message channels report metrics according to their concrete type. +If you are looking at a `DirectChannel`, you will see statistics for the send operation. +If it is a `QueueChannel`, you will also see statistics for the receive operation, as well as the count of messages that are currently buffered by this `QueueChannel`. +In both cases there are some metrics that are simple counters (message count and error count), and some that are estimates of averages of interesting quantities. +The algorithms used to calculate these estimates are described briefly in the section below. + +.MessageChannel Metrics + + +[cols="1,2,3", options="header"] +|=== +| Metric Type +| Example +| Algorithm + +| Count +| Send Count +| Simple incrementer. +Increases by one when an event occurs. + +| Error Count +| Send Error Count +| Simple incrementer. +Increases by one when an send results in an error. + +| Duration +| Send Duration (method execution time in milliseconds) +| Exponential Moving Average with decay factor (10 by default). +Average of the method execution time over roughly the last 10 (default) measurements. + +| Rate +| Send Rate (number of operations per second) +| Inverse of Exponential Moving Average of the interval between events with decay in time (lapsing over 60 seconds by default) and per measurement (last 10 events by default). + +| Error Rate +| Send Error Rate (number of errors per second) +| Inverse of Exponential Moving Average of the interval between error events with decay in time (lapsing over 60 seconds by default) and per measurement (last 10 events by default). + +| Ratio +| Send Success Ratio (ratio of successful to total sends) +| Estimate the success ratio as the Exponential Moving Average of the series composed of values 1 for success and 0 for failure (decaying as per the rate measurement over time and events by default). +Error ratio is 1 - success ratio. + +|=== + +[[mgmt-handler-features]] +==== MessageHandler Metric Features + +The following table shows the statistics maintained for message handlers. +Some metrics are simple counters (message count and error count), and one is an estimate of averages of send duration. +The algorithms used to calculate these estimates are described briefly in the table below: + +.MessageHandlerMetrics + +[cols="1,2,3", options="header"] +|=== +| Metric Type +| Example +| Algorithm + +| Count +| Handle Count +| Simple incrementer. +Increases by one when an event occurs. + +| Error Count +| Handler Error Count +| Simple incrementer. +Increases by one when an invocation results in an error. + +| Active Count +| Handler Active Count +| Indicates the number of currently active threads currently invoking the handler (or any downstream synchronous flow). + +| Duration +| Handle Duration (method execution time in milliseconds) +| Exponential Moving Average with decay factor (10 by default). +Average of the method execution time over roughly the last 10 (default) measurements. + +|=== + +[[mgmt-statistics]] +==== Time-Based Average Estimates + +A feature of the time-based average estimates is that they decay with time if no new measurements arrive. +To help interpret the behaviour over time, the time (in seconds) since the last measurement is also exposed as a metric. + +There are two basic exponential models: decay per measurement (appropriate for duration and anything where the number of measurements is part of the metric), and decay per time unit (more suitable for rate measurements where the time in between measurements is part of the metric). +Both models depend on the fact that + +`S(n) = sum(i=0,i=n) w(i) x(i)` has a special form when `w(i) = r^i`, with `r=constant`: + +`S(n) = x(n) + r S(n-1)` (so you only have to store `S(n-1)`, not the whole series `x(i)`, to generate a new metric estimate from the last measurement). +The algorithms used in the duration metrics use `r=exp(-1/M)` with `M=10`. +The net effect is that the estimate `S(n)` is more heavily weighted to recent measurements and is composed roughly of the last `M` measurements. +So `M` is the "window" or lapse rate of the estimate In the case of the vanilla moving average, `i` is a counter over the number of measurements. +In the case of the rate we interpret `i` as the elapsed time, or a combination of elapsed time and a counter (so the metric estimate contains contributions roughly from the last `M` measurements and the last `T` seconds). + + +[[mgmt-metrics-factory]] +==== Metrics Factory + +A new strategy interface `MetricsFactory` has been introduced allowing you to provide custom channel metrics for your +`MessageChannel` s and `MessageHandler` s. +By default, a `DefaultMetricsFactory` provides default implementation of `MessageChannelMetrics` and +`MessageHandlerMetrics` which are described in the next bullet. +To override the default `MetricsFactory` configure it as described above, by providing a reference to your +`MetricsFactory` bean instance. +You can either customize the default implementations as described in the next bullet, or provide completely different +implementations by extending `AbstractMessageChannelMetrics` and/or `AbstractMessageHandlerMetrics`. + +In addition to the default metrics factory described above, the framework provides the `AggregatingMetricsFactory`. +This factory creates `AggregatingMessageChannelMetrics` and `AggregatingMessageHandlerMetrics`. +In very high volume scenarios, the cost of capturing statistics can be prohibitive (2 calls to the system time and +storing the data for each message). +The aggregating metrics aggregate the response time over a sample of messages. +This can save significant CPU time. + +CAUTION: The statistics will be skewed if messages arrive in bursts. +These metrics are intended for use with high, constant-volume, message rates. + +[source, xml] +---- + + + +---- + +The above configuration aggregates the duration over 1000 messages. +Counts (send, error) are maintained per-message but the statistics are per 1000 messages. + +* *Customizing the Default Channel/Handler Statistics* + +See <> and the Javadocs for the `ExponentialMovingAverage*` classes for more information about these +values. + +By default, the `DefaultMessageChannelMetrics` and `DefaultMessageHandlerMetrics` use a `window` of 10 measurements, +a rate period of 1 second (rate per second) and a decay lapse period of 1 minute. + +If you wish to override these defaults, you can provide a custom `MetricsFactory` that returns appropriately configured +metrics and provide a reference to it to the MBean exporter as described above. + +Example: + +[source,java] +---- +public static class CustomMetrics implements MetricsFactory { + + @Override + public AbstractMessageChannelMetrics createChannelMetrics(String name) { + return new DefaultMessageChannelMetrics(name, + new ExponentialMovingAverage(20, 1000000.), + new ExponentialMovingAverageRate(2000, 120000, 30, true), + new ExponentialMovingAverageRatio(130000, 40, true), + new ExponentialMovingAverageRate(3000, 140000, 50, true)); + } + + @Override + public AbstractMessageHandlerMetrics createHandlerMetrics(String name) { + return new DefaultMessageHandlerMetrics(name, new ExponentialMovingAverage(20, 1000000.)); + } + +} +---- + + +* *Advanced Customization* + +The customizations described above are wholesale and will apply to all appropriate beans exported by the MBean exporter. +This is the extent of customization available using XML configuration. + +Individual beans can be provided with different implementations using java `@Configuration` or programmatically at +runtime, after the application context has been refreshed, by invoking the `configureMetrics` methods on +`AbstractMessageChannel` and `AbstractMessageHandler`. + + +* *Performance Improvement* + +Previously, the time-based metrics (see <>) were calculated in real time. +The statistics are now calculated when retrieved instead. +This resulted in a significant performance improvement, at the expense of a small amount of additional memory for each statistic. +As discussed in the bullet above, the statistics can be disabled altogether, while retaining the MBean allowing the invocation of `Lifecycle` methods. diff --git a/src/reference/asciidoc/system-management.adoc b/src/reference/asciidoc/system-management.adoc index 195088c17a..23b63efb7d 100644 --- a/src/reference/asciidoc/system-management.adoc +++ b/src/reference/asciidoc/system-management.adoc @@ -2,6 +2,8 @@ == System Management // BE SURE TO PRECEDE ALL include:: with a blank line - see https://github.com/asciidoctor/asciidoctor/issues/1297 +include::./metrics.adoc[] + include::./jmx.adoc[] include::./message-history.adoc[] diff --git a/src/reference/asciidoc/whats-new.adoc b/src/reference/asciidoc/whats-new.adoc index 56ce487a5e..f5bd133860 100644 --- a/src/reference/asciidoc/whats-new.adoc +++ b/src/reference/asciidoc/whats-new.adoc @@ -8,14 +8,15 @@ If you are interested in more details, please see the Issue Tracker tickets that === New Components [[x4.2-JMX]] -==== Major JMX Rework +==== Major Management/JMX Rework A new `MetricsFactory` strategy interface has been introduced. -This, together with other changes in the JMX infrastructure provides much more control over JMX configuration and runtime performance. +This, together with other changes in the JMX and management infrastructure provides much more control over management +configuration and runtime performance. However, this has some important implications for (some) user environments. -For complete details, see <>. +For complete details, see <> and <>. [[x4.2-mongodb-metadata-store]] ==== MongodDB Metadata Store