INT-3637: JMX Improvements Msg Sources/Handlers

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

- Message Sources
- Message Handlers

Polishing; Final Review and PR Comments

- avoid second call to System.currentTimeMillis()
- fix elapsed time in handler metrics
- expose TrackableComponent when available

INT-3637: Add @IntergrationManagedResource

Prevents beans (channels, etc), which were previously picked
up via a proxy, from being exported by a standard context
MBeanExporter.

I looked at completely eliminating the MBeanExporterHelper,
which suppresses o.s.integration beans from being exported by
a standard MBeanExporter when there is an IMBE present, but I feel
this is too much of a breaking change. There are a number of
standard beans (such as WireTap) that are @ManagedResources and
these would disappear for users that don't have an IMBE.

That said, such beans previously disappear completely when there
*is* an IMBE so now they are now annotated with both so that
they are exported by at most one of the exporters.

Polishing; Use MBE.addExludedBean instead of DFA

INT-3639: JMX (AMQP/JMS) Channel Stats

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

Module channels inherit `ChannelSendMetrics`; add
`PollableChannelManagement` for polled channels.

INT-3638: JMX Initial Stats/Counts Settings

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

Add the ability to specify the initial settings for
'enableStats' and 'enableCounts' for MBeans that
support those statistics.

Polishing; PR Comments; Add Handler Metrics Test

Also found a problem using an inner MessageSource bean in an
inbound-channel-adapter - a BeanComponentDefinition was returned
instead of a BeanDefinition.

Add @DirtiesContext to JMX Tests

The new MonitorTests failed with InstanceAlreadyExistsException for the
errorChannel.

Add @DirtiesContext to all tests using the Spring test runner to avoid caching any
contexts after the test class completes.

INT-3637: JMX Support Negated Name Match Patterns

Note: with negated matches, order matters.

Polishing for `MonitorTests`
Fix `EnableIntegrationMBeanExport` JavaDocs
This commit is contained in:
Gary Russell
2015-02-19 21:49:20 +02:00
committed by Artem Bilan
parent b56a56e8e6
commit 09c203dc6d
85 changed files with 1762 additions and 650 deletions

View File

@@ -33,8 +33,8 @@ import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.integration.history.MessageHistory;
import org.springframework.integration.history.TrackableComponent;
import org.springframework.integration.support.converter.DefaultDatatypeChannelMessageConverter;
import org.springframework.integration.support.management.IntegrationManagedResource;
import org.springframework.integration.support.management.Statistics;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageDeliveryException;
@@ -42,7 +42,6 @@ import org.springframework.messaging.MessagingException;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.util.Assert;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;
/**
@@ -56,7 +55,7 @@ import org.springframework.util.StringUtils;
* @author Gary Russell
* @author Artem Bilan
*/
@ManagedResource
@IntegrationManagedResource
public abstract class AbstractMessageChannel extends IntegrationObjectSupport
implements MessageChannel, TrackableComponent, ChannelInterceptorAware, MessageChannelMetrics {
@@ -72,6 +71,8 @@ public abstract class AbstractMessageChannel extends IntegrationObjectSupport
private volatile MessageConverter messageConverter;
private volatile boolean countsEnabled;
private volatile boolean statsEnabled;
private volatile ChannelSendMetrics channelMetrics;
@@ -86,9 +87,28 @@ public abstract class AbstractMessageChannel extends IntegrationObjectSupport
this.shouldTrack = shouldTrack;
}
@Override
public void enableCounts(boolean countsEnabled) {
this.countsEnabled = countsEnabled;
if (!countsEnabled) {
this.statsEnabled = false;
}
}
@Override
public boolean isCountsEnabled() {
return countsEnabled;
}
@Override
public void enableStats(boolean statsEnabled) {
if (statsEnabled) {
this.countsEnabled = true;
}
this.statsEnabled = statsEnabled;
if (this.channelMetrics != null) {
this.channelMetrics.setFullStatsEnabled(statsEnabled);
}
}
@Override
@@ -314,6 +334,7 @@ public abstract class AbstractMessageChannel extends IntegrationObjectSupport
protected void setChannelMetrics(ChannelSendMetrics channelMetrics) {
this.channelMetrics = channelMetrics;
this.channelMetrics.setFullStatsEnabled(this.statsEnabled);
}
/**
@@ -373,7 +394,7 @@ public abstract class AbstractMessageChannel extends IntegrationObjectSupport
Deque<ChannelInterceptor> interceptorStack = null;
boolean sent = false;
boolean statsProcessed = false;
StopWatch timer = null;
long start = 0;
try {
if (this.datatypes.length > 0) {
message = this.convertPayloadIfNecessary(message);
@@ -385,12 +406,12 @@ public abstract class AbstractMessageChannel extends IntegrationObjectSupport
return false;
}
}
if (this.statsEnabled) {
timer = this.channelMetrics.beforeSend();
if (this.countsEnabled) {
start = this.channelMetrics.beforeSend();
}
sent = this.doSend(message, timeout);
if (this.statsEnabled) {
this.channelMetrics.afterSend(timer, sent);
if (this.countsEnabled) {
this.channelMetrics.afterSend(start, sent);
statsProcessed = true;
}
this.interceptors.postSend(message, this, sent);
@@ -400,8 +421,8 @@ public abstract class AbstractMessageChannel extends IntegrationObjectSupport
return sent;
}
catch (Exception e) {
if (this.statsEnabled && !statsProcessed) {
this.channelMetrics.afterSend(timer, false);
if (this.countsEnabled && !statsProcessed) {
this.channelMetrics.afterSend(start, false);
}
if (interceptorStack != null) {
this.interceptors.afterSendCompletion(message, this, sent, e, interceptorStack);

View File

@@ -95,6 +95,7 @@ public abstract class AbstractPollableChannel extends AbstractMessageChannel imp
public final Message<?> receive(long timeout) {
ChannelInterceptorList interceptorList = getInterceptors();
Deque<ChannelInterceptor> interceptorStack = null;
boolean counted = false;
try {
if (interceptorList.getInterceptors().size() > 0) {
interceptorStack = new ArrayDeque<ChannelInterceptor>();
@@ -104,8 +105,9 @@ public abstract class AbstractPollableChannel extends AbstractMessageChannel imp
}
}
Message<?> message = this.doReceive(timeout);
if (isStatsEnabled()) {
if (isCountsEnabled()) {
getMetrics().afterReceive();
counted = true;
}
message = interceptorList.postReceive(message, this);
if (interceptorStack != null) {
@@ -114,7 +116,7 @@ public abstract class AbstractPollableChannel extends AbstractMessageChannel imp
return message;
}
catch (RuntimeException e) {
if (isStatsEnabled()) {
if (isCountsEnabled() && !counted) {
getMetrics().afterError();
}
if (interceptorStack != null) {

View File

@@ -23,8 +23,8 @@ import org.springframework.beans.factory.BeanNameAware;
import org.springframework.integration.channel.management.ChannelSendMetrics;
import org.springframework.integration.channel.management.MessageChannelMetrics;
import org.springframework.integration.support.context.NamedComponent;
import org.springframework.integration.support.management.IntegrationManagedResource;
import org.springframework.integration.support.management.Statistics;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.messaging.Message;
import org.springframework.messaging.PollableChannel;
import org.springframework.util.StringUtils;
@@ -38,12 +38,14 @@ import org.springframework.util.StringUtils;
* @author Mark Fisher
* @author Gary Russell
*/
@ManagedResource
@IntegrationManagedResource
public class NullChannel implements PollableChannel, MessageChannelMetrics, BeanNameAware, NamedComponent {
private final Log logger = LogFactory.getLog(this.getClass());
private volatile ChannelSendMetrics metrics = new ChannelSendMetrics("nullChannel");
private volatile ChannelSendMetrics channelMetrics = new ChannelSendMetrics("nullChannel");
private volatile boolean countsEnabled;
private volatile boolean statsEnabled;
@@ -52,7 +54,7 @@ public class NullChannel implements PollableChannel, MessageChannelMetrics, Bean
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
this.metrics = new ChannelSendMetrics(getComponentName());
this.channelMetrics = new ChannelSendMetrics(getComponentName());
}
@Override
@@ -67,12 +69,29 @@ public class NullChannel implements PollableChannel, MessageChannelMetrics, Bean
@Override
public void reset() {
this.metrics.reset();
this.channelMetrics.reset();
}
@Override
public void enableCounts(boolean countsEnabled) {
this.countsEnabled = countsEnabled;
if (!countsEnabled) {
this.statsEnabled = false;
}
}
@Override
public boolean isCountsEnabled() {
return this.countsEnabled;
}
@Override
public void enableStats(boolean statsEnabled) {
if (statsEnabled) {
this.countsEnabled = true;
}
this.statsEnabled = statsEnabled;
this.channelMetrics.setFullStatsEnabled(statsEnabled);
}
@Override
@@ -82,77 +101,77 @@ public class NullChannel implements PollableChannel, MessageChannelMetrics, Bean
@Override
public int getSendCount() {
return this.metrics.getSendCount();
return this.channelMetrics.getSendCount();
}
@Override
public long getSendCountLong() {
return this.metrics.getSendCountLong();
return this.channelMetrics.getSendCountLong();
}
@Override
public int getSendErrorCount() {
return this.metrics.getSendErrorCount();
return this.channelMetrics.getSendErrorCount();
}
@Override
public long getSendErrorCountLong() {
return this.metrics.getSendErrorCountLong();
return this.channelMetrics.getSendErrorCountLong();
}
@Override
public double getTimeSinceLastSend() {
return this.metrics.getTimeSinceLastSend();
return this.channelMetrics.getTimeSinceLastSend();
}
@Override
public double getMeanSendRate() {
return this.metrics.getMeanSendRate();
return this.channelMetrics.getMeanSendRate();
}
@Override
public double getMeanErrorRate() {
return this.metrics.getMeanErrorRate();
return this.channelMetrics.getMeanErrorRate();
}
@Override
public double getMeanErrorRatio() {
return this.metrics.getMeanErrorRatio();
return this.channelMetrics.getMeanErrorRatio();
}
@Override
public double getMeanSendDuration() {
return this.metrics.getMeanSendDuration();
return this.channelMetrics.getMeanSendDuration();
}
@Override
public double getMinSendDuration() {
return this.metrics.getMinSendDuration();
return this.channelMetrics.getMinSendDuration();
}
@Override
public double getMaxSendDuration() {
return this.metrics.getMaxSendDuration();
return this.channelMetrics.getMaxSendDuration();
}
@Override
public double getStandardDeviationSendDuration() {
return this.metrics.getStandardDeviationSendDuration();
return this.channelMetrics.getStandardDeviationSendDuration();
}
@Override
public Statistics getSendDuration() {
return this.metrics.getSendDuration();
return this.channelMetrics.getSendDuration();
}
@Override
public Statistics getSendRate() {
return this.metrics.getSendRate();
return this.channelMetrics.getSendRate();
}
@Override
public Statistics getErrorRate() {
return this.metrics.getErrorRate();
return this.channelMetrics.getErrorRate();
}
@Override
@@ -160,8 +179,8 @@ public class NullChannel implements PollableChannel, MessageChannelMetrics, Bean
if (logger.isDebugEnabled()) {
logger.debug("message sent to null channel: " + message);
}
if (this.statsEnabled) {
this.metrics.afterSend(this.metrics.beforeSend(), true);
if (this.countsEnabled) {
this.channelMetrics.afterSend(this.channelMetrics.beforeSend(), true);
}
return true;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-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.
@@ -22,6 +22,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.context.Lifecycle;
import org.springframework.integration.channel.ChannelInterceptorAware;
import org.springframework.integration.core.MessageSelector;
import org.springframework.integration.support.management.IntegrationManagedResource;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
@@ -39,6 +40,7 @@ import org.springframework.util.Assert;
* @author Gary Russell
*/
@ManagedResource
@IntegrationManagedResource
public class WireTap extends ChannelInterceptorAdapter implements Lifecycle, VetoCapableInterceptor {
private static final Log logger = LogFactory.getLog(WireTap.class);

View File

@@ -22,8 +22,6 @@ import org.springframework.integration.support.management.ExponentialMovingAvera
import org.springframework.integration.support.management.ExponentialMovingAverageRate;
import org.springframework.integration.support.management.ExponentialMovingAverageRatio;
import org.springframework.integration.support.management.Statistics;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.util.StopWatch;
/**
* Registers all message channels, and accumulates statistics about their performance. The statistics are then published
@@ -34,7 +32,6 @@ import org.springframework.util.StopWatch;
* @author Gary Russell
* @since 2.0
*/
@ManagedResource
public class ChannelSendMetrics {
protected final Log logger = LogFactory.getLog(getClass());
@@ -63,11 +60,16 @@ public class ChannelSendMetrics {
private final String name;
private volatile boolean fullStatsEnabled;
public ChannelSendMetrics(String name) {
this.name = name;
}
public void setFullStatsEnabled(boolean fullStatsEnabled) {
this.fullStatsEnabled = fullStatsEnabled;
}
public void destroy() {
if (logger.isDebugEnabled()) {
@@ -79,33 +81,38 @@ public class ChannelSendMetrics {
return name;
}
public StopWatch beforeSend() {
public long beforeSend() {
if (logger.isTraceEnabled()) {
logger.trace("Recording send on channel(" + this.name + ")");
}
final StopWatch timer = new StopWatch(this.name + ".send:execution");
timer.start();
long start = 0;
if (this.fullStatsEnabled) {
start = System.currentTimeMillis();
this.sendRate.increment();
}
this.sendCount.incrementAndGet();
this.sendRate.increment();
return timer;
return start;
}
public void afterSend(StopWatch timer, boolean result) {
if (timer != null) {
timer.stop();
if (result) {
sendSuccessRatio.success();
sendDuration.append(timer.getTotalTimeMillis());
public void afterSend(long start, boolean result) {
if (start > 0) {
long now = System.currentTimeMillis();
long elapsed = now - start;
if (result && this.fullStatsEnabled) {
sendSuccessRatio.success(now);
sendDuration.append(elapsed);
}
else {
sendSuccessRatio.failure();
sendErrorCount.incrementAndGet();
if (this.fullStatsEnabled) {
sendSuccessRatio.failure(now);
sendErrorCount.incrementAndGet();
}
sendErrorRate.increment();
}
if (logger.isTraceEnabled()) {
logger.trace(timer);
logger.trace("Elapsed: " + this.name + ": " + elapsed);
}
}
}

View File

@@ -16,10 +16,9 @@
package org.springframework.integration.channel.management;
import org.springframework.integration.support.management.MetricsEnablement;
import org.springframework.integration.support.management.Statistics;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedMetric;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.support.MetricType;
/**
@@ -30,16 +29,7 @@ import org.springframework.jmx.support.MetricType;
* @author Gary Russell
* @since 2.0
*/
public interface MessageChannelMetrics {
@ManagedOperation
void reset();
@ManagedOperation
void enableStats(boolean statsEnabled);
@ManagedAttribute
boolean isStatsEnabled();
public interface MessageChannelMetrics extends MetricsEnablement {
/**
* @return the number of successful sends

View File

@@ -0,0 +1,4 @@
/**
* Provides classes related to channel management.
*/
package org.springframework.integration.channel.management;

View File

@@ -150,7 +150,7 @@ public abstract class AbstractMethodAnnotationPostProcessor<T extends Annotation
((Advised) handler).addAdvisor(advisor);
}
else {
ProxyFactory proxyFactory = new ProxyFactory(bean);
ProxyFactory proxyFactory = new ProxyFactory(handler);
proxyFactory.addAdvisor(advisor);
handler = (MessageHandler) proxyFactory.getProxy(this.beanFactory.getBeanClassLoader());
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-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.
@@ -42,6 +42,7 @@ import org.springframework.util.xml.DomUtils;
*
* @author Mark Fisher
* @author Artem Bilan
* @author Gary Russell
*/
public class DefaultInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser {
@@ -79,7 +80,7 @@ public class DefaultInboundChannelAdapterParser extends AbstractPollingInboundCh
result = this.parseMethodInvokingSource(innnerBeanDef, methodName, element, parserContext);
}
else {
result = innnerBeanDef;
result = innnerBeanDef.getBeanDefinition();
}
}
else if (hasScriptElement) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-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.
@@ -19,12 +19,15 @@ package org.springframework.integration.endpoint;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
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.util.AbstractExpressionEvaluator;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessagingException;
@@ -33,15 +36,25 @@ import org.springframework.util.CollectionUtils;
/**
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Gary Russell
* @since 2.0
*/
@IntegrationManagedResource
public abstract class AbstractMessageSource<T> extends AbstractExpressionEvaluator implements MessageSource<T>,
NamedComponent, BeanNameAware {
MessageSourceMetrics, NamedComponent, BeanNameAware {
private final AtomicLong messageCount = new AtomicLong();
private volatile Map<String, Expression> headerExpressions = Collections.emptyMap();
private volatile String beanName;
private volatile String managedType;
private volatile String managedName;
private volatile boolean countsEnabled;
public void setHeaderExpressions(Map<String, Expression> headerExpressions) {
this.headerExpressions = (headerExpressions != null)
? headerExpressions : Collections.<String, Expression>emptyMap();
@@ -52,11 +65,56 @@ public abstract class AbstractMessageSource<T> extends AbstractExpressionEvaluat
this.beanName = name;
}
@Override
public void setManagedType(String managedType) {
this.managedType = managedType;
}
@Override
public String getManagedType() {
return this.managedType;
}
@Override
public void setManagedName(String managedName) {
this.managedName = managedName;
}
@Override
public String getManagedName() {
return this.managedName;
}
@Override
public String getComponentName() {
return this.beanName;
}
@Override
public boolean isCountsEnabled() {
return this.countsEnabled;
}
@Override
public void enableCounts(boolean countsEnabled) {
this.countsEnabled = countsEnabled;
}
@Override
public void reset() {
this.messageCount.set(0);
}
@Override
public int getMessageCount() {
return (int) this.messageCount.get();
}
@Override
public long getMessageCountLong() {
return this.messageCount.get();
}
@Override
@SuppressWarnings("unchecked")
public final Message<T> receive() {
@@ -91,6 +149,9 @@ public abstract class AbstractMessageSource<T> extends AbstractExpressionEvaluat
}
message = builder.build();
}
if (this.countsEnabled && message != null) {
this.messageCount.incrementAndGet();
}
return message;
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2002-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.endpoint.management;
import org.springframework.integration.support.management.CountsEnablement;
import org.springframework.jmx.export.annotation.ManagedMetric;
import org.springframework.jmx.support.MetricType;
/**
* @author Dave Syer
* @author Gary Russell
* @since 2.0
*/
public interface MessageSourceMetrics extends CountsEnablement {
/**
* @return the number of successful handler calls
*/
@ManagedMetric(metricType = MetricType.COUNTER, displayName = "Message Source Message Count")
int getMessageCount();
/**
* @return the number of successful handler calls
* @since 3.0
*/
@ManagedMetric(metricType = MetricType.COUNTER, displayName = "Message Source Message Count")
long getMessageCountLong();
void setManagedName(String name);
String getManagedName();
void setManagedType(String source);
String getManagedType();
}

View File

@@ -0,0 +1,4 @@
/**
* Provides classes related to endpoint management.
*/
package org.springframework.integration.endpoint.management;

View File

@@ -19,8 +19,12 @@ package org.springframework.integration.handler;
import org.springframework.core.Ordered;
import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.integration.context.Orderable;
import org.springframework.integration.handler.management.MessageHandlerMetrics;
import org.springframework.integration.handler.management.SimpleMessageHandlerMetrics;
import org.springframework.integration.history.MessageHistory;
import org.springframework.integration.history.TrackableComponent;
import org.springframework.integration.support.management.IntegrationManagedResource;
import org.springframework.integration.support.management.Statistics;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessageHandlingException;
@@ -37,12 +41,23 @@ import org.springframework.util.Assert;
* @author Oleg Zhurakousky
* @author Gary Russell
*/
public abstract class AbstractMessageHandler extends IntegrationObjectSupport implements MessageHandler, TrackableComponent, Orderable {
@IntegrationManagedResource
public abstract class AbstractMessageHandler extends IntegrationObjectSupport implements MessageHandler,
MessageHandlerMetrics, TrackableComponent, Orderable {
private volatile boolean shouldTrack = false;
private volatile int order = Ordered.LOWEST_PRECEDENCE;
private final SimpleMessageHandlerMetrics handlerMetrics = new SimpleMessageHandlerMetrics();
private volatile boolean statsEnabled;
private volatile boolean countsEnabled;
private volatile String managedName;
private volatile String managedType;
@Override
public void setOrder(int order) {
@@ -71,13 +86,19 @@ public abstract class AbstractMessageHandler extends IntegrationObjectSupport im
if (this.logger.isDebugEnabled()) {
this.logger.debug(this + " received message: " + message);
}
long start = 0;
try {
if (message != null && this.shouldTrack) {
message = MessageHistory.write(message, this, this.getMessageBuilderFactory());
}
if (this.countsEnabled) {
start = this.handlerMetrics.beforeHandle(message);
}
this.handleMessageInternal(message);
this.handlerMetrics.afterHandle(start, true);
}
catch (Exception e) {
this.handlerMetrics.afterHandle(start, false);
if (e instanceof MessagingException) {
throw (MessagingException) e;
}
@@ -87,4 +108,113 @@ public abstract class AbstractMessageHandler extends IntegrationObjectSupport im
protected abstract void handleMessageInternal(Message<?> message) throws Exception;
@Override
public void reset() {
this.handlerMetrics.reset();
}
@Override
public long getHandleCountLong() {
return this.handlerMetrics.getHandleCountLong();
}
@Override
public int getHandleCount() {
return this.handlerMetrics.getHandleCount();
}
@Override
public int getErrorCount() {
return this.handlerMetrics.getErrorCount();
}
@Override
public long getErrorCountLong() {
return this.handlerMetrics.getErrorCountLong();
}
@Override
public double getMeanDuration() {
return this.handlerMetrics.getMeanDuration();
}
@Override
public double getMinDuration() {
return this.handlerMetrics.getMinDuration();
}
@Override
public double getMaxDuration() {
return this.handlerMetrics.getMaxDuration();
}
@Override
public double getStandardDeviationDuration() {
return this.handlerMetrics.getStandardDeviationDuration();
}
@Override
public int getActiveCount() {
return this.handlerMetrics.getActiveCount();
}
@Override
public long getActiveCountLong() {
return this.handlerMetrics.getActiveCountLong();
}
@Override
public Statistics getDuration() {
return this.handlerMetrics.getDuration();
}
@Override
public void enableStats(boolean statsEnabled) {
if (statsEnabled) {
this.countsEnabled = true;
}
this.statsEnabled = statsEnabled;
if (this.handlerMetrics != null) {
this.handlerMetrics.setFullStatsEnabled(statsEnabled);
}
}
@Override
public boolean isStatsEnabled() {
return this.statsEnabled;
}
@Override
public void enableCounts(boolean countsEnabled) {
this.countsEnabled = countsEnabled;
if (!countsEnabled) {
this.statsEnabled = false;
}
}
@Override
public boolean isCountsEnabled() {
return this.countsEnabled;
}
@Override
public void setManagedName(String managedName) {
this.managedName = managedName;
}
@Override
public String getManagedName() {
return this.managedName;
}
@Override
public void setManagedType(String managedType) {
this.managedType = managedType;
}
@Override
public String getManagedType() {
return this.managedType;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-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.
@@ -38,6 +38,7 @@ import org.springframework.integration.store.MessageGroupStore;
import org.springframework.integration.store.MessageStore;
import org.springframework.integration.store.SimpleMessageGroup;
import org.springframework.integration.store.SimpleMessageStore;
import org.springframework.integration.support.management.IntegrationManagedResource;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
@@ -74,10 +75,12 @@ import org.springframework.util.CollectionUtils;
*
* @author Mark Fisher
* @author Artem Bilan
* @author Gary Russell
* @since 1.0.3
*/
@ManagedResource
@IntegrationManagedResource
public class DelayHandler extends AbstractReplyProducingMessageHandler implements DelayHandlerManagement,
ApplicationListener<ContextRefreshedEvent> {

View File

@@ -0,0 +1,100 @@
/*
* Copyright 2002-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.handler.management;
import org.springframework.integration.support.management.MetricsEnablement;
import org.springframework.integration.support.management.Statistics;
import org.springframework.jmx.export.annotation.ManagedMetric;
import org.springframework.jmx.support.MetricType;
/**
* @author Dave Syer
* @author Gary Russell
* @since 2.0
*/
public interface MessageHandlerMetrics extends MetricsEnablement {
/**
* @return the number of successful handler calls
*/
@ManagedMetric(metricType = MetricType.COUNTER, displayName = "Handler Execution Count")
int getHandleCount();
/**
* @return the number of successful handler calls
* @since 3.0
*/
@ManagedMetric(metricType = MetricType.COUNTER, displayName = "Handler Execution Count")
long getHandleCountLong();
/**
* @return the number of failed handler calls
*/
@ManagedMetric(metricType = MetricType.COUNTER, displayName = "Handler Error Count")
int getErrorCount();
/**
* @return the number of failed handler calls
* @since 3.0
*/
@ManagedMetric(metricType = MetricType.COUNTER, displayName = "Handler Error Count")
long getErrorCountLong();
/**
* @return the mean handler duration (milliseconds)
*/
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Handler Mean Duration in Milliseconds")
double getMeanDuration();
/**
* @return the minimum handler duration (milliseconds)
*/
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Handler Min Duration in Milliseconds")
double getMinDuration();
/**
* @return the maximum handler duration (milliseconds)
*/
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Handler Max Duration in Milliseconds")
double getMaxDuration();
/**
* @return the standard deviation handler duration (milliseconds)
*/
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Handler Standard Deviation Duration in Milliseconds")
double getStandardDeviationDuration();
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Handler Active Execution Count")
int getActiveCount();
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Handler Active Execution Count")
long getActiveCountLong();
/**
* @return summary statistics about the handler duration (milliseconds)
*/
Statistics getDuration();
void setManagedName(String name);
String getManagedName();
void setManagedType(String source);
String getManagedType();
}

View File

@@ -0,0 +1,136 @@
/*
* Copyright 2002-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.handler.management;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.integration.support.management.ExponentialMovingAverage;
import org.springframework.integration.support.management.Statistics;
import org.springframework.messaging.Message;
/**
* @author Dave Syer
* @author Gary Russell
* @since 2.0
*/
public class SimpleMessageHandlerMetrics {
private static final Log logger = LogFactory.getLog(SimpleMessageHandlerMetrics.class);
private static final int DEFAULT_MOVING_AVERAGE_WINDOW = 10;
private final AtomicLong activeCount = new AtomicLong();
private final AtomicLong handleCount = new AtomicLong();
private final AtomicLong errorCount = new AtomicLong();
private final ExponentialMovingAverage duration = new ExponentialMovingAverage(DEFAULT_MOVING_AVERAGE_WINDOW);
private volatile String name;
private volatile boolean fullStatsEnabled;
public void setName(String name) {
this.name = name;
}
public void setFullStatsEnabled(boolean fullStatsEnabled) {
this.fullStatsEnabled = fullStatsEnabled;
}
public long beforeHandle(Message<?> message) throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("messageHandler(" + this.name + ") message(" + message + ") :");
}
long start = 0;
if (this.fullStatsEnabled) {
start = System.currentTimeMillis();
}
this.handleCount.incrementAndGet();
this.activeCount.incrementAndGet();
return start;
}
public void afterHandle(long start, boolean success) {
this.activeCount.decrementAndGet();
if (this.fullStatsEnabled && success) {
this.duration.append(System.currentTimeMillis() - start);
}
else if (!success) {
this.errorCount.incrementAndGet();
}
}
public synchronized void reset() {
this.duration.reset();
this.errorCount.set(0);
this.handleCount.set(0);
}
public long getHandleCountLong() {
if (logger.isTraceEnabled()) {
logger.trace("Getting Handle Count:" + this);
}
return this.handleCount.get();
}
public int getHandleCount() {
return (int) getHandleCountLong();
}
public int getErrorCount() {
return (int) this.errorCount.get();
}
public long getErrorCountLong() {
return this.errorCount.get();
}
public double getMeanDuration() {
return this.duration.getMean();
}
public double getMinDuration() {
return this.duration.getMin();
}
public double getMaxDuration() {
return this.duration.getMax();
}
public double getStandardDeviationDuration() {
return this.duration.getStandardDeviation();
}
public int getActiveCount() {
return (int) this.activeCount.get();
}
public long getActiveCountLong() {
return this.activeCount.get();
}
public Statistics getDuration() {
return this.duration.getStatistics();
}
}

View File

@@ -0,0 +1,4 @@
/**
* Provides classes related to handler management.
*/
package org.springframework.integration.handler.management;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-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.
@@ -31,6 +31,7 @@ import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionValidationException;
import org.springframework.context.SmartLifecycle;
import org.springframework.integration.support.management.IntegrationManagedResource;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
@@ -46,6 +47,7 @@ import org.springframework.util.StringUtils;
* @since 2.0
*/
@ManagedResource
@IntegrationManagedResource
public class MessageHistoryConfigurer implements SmartLifecycle, BeanFactoryAware {
private final Log logger = LogFactory.getLog(this.getClass());

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-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.
@@ -17,14 +17,15 @@
package org.springframework.integration.history;
import org.springframework.integration.support.context.NamedComponent;
import org.springframework.integration.support.management.IntegrationManagedResource;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
/**
* @author Mark Fisher
* @author Gary Russell
* @since 2.0
*/
@ManagedResource
@IntegrationManagedResource
public interface TrackableComponent extends NamedComponent {
@ManagedOperation

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-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.
@@ -16,6 +16,7 @@
package org.springframework.integration.metadata;
import org.springframework.integration.support.management.IntegrationManagedResource;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
@@ -26,9 +27,11 @@ import org.springframework.jmx.export.annotation.ManagedResource;
* @author Josh Long
* @author Oleg Zhurakousky
* @author Mark Fisher
* @author Gary Russell
* @since 2.0
*/
@ManagedResource
@IntegrationManagedResource
public interface MetadataStore {
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-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.
@@ -24,6 +24,7 @@ import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.integration.channel.NullChannel;
import org.springframework.integration.core.MessagingTemplate;
import org.springframework.integration.handler.AbstractMessageHandler;
import org.springframework.integration.support.management.IntegrationManagedResource;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
@@ -43,6 +44,7 @@ import org.springframework.util.Assert;
* @author Artem Bilan
*/
@ManagedResource
@IntegrationManagedResource
public abstract class AbstractMessageRouter extends AbstractMessageHandler {
private volatile MessageChannel defaultOutputChannel;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014 the original author or authors.
* 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.
@@ -20,6 +20,7 @@ import java.util.Map;
import java.util.Properties;
import org.springframework.integration.router.RecipientListRouter.Recipient;
import org.springframework.integration.support.management.IntegrationManagedResource;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
@@ -29,10 +30,12 @@ import org.springframework.jmx.export.annotation.ManagedResource;
* RecipientListRouter. This can be used with a control-bus and JMX.
*
* @author Liujiong
* @author Gary Russell
* @since 4.1
*
*/
@ManagedResource
@IntegrationManagedResource
public interface RecipientListRouterManagement {
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-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
@@ -23,6 +23,7 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.integration.support.DefaultMessageBuilderFactory;
import org.springframework.integration.support.MessageBuilderFactory;
import org.springframework.integration.support.management.IntegrationManagedResource;
import org.springframework.integration.support.utils.IntegrationUtils;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
@@ -37,6 +38,7 @@ import org.springframework.messaging.Message;
*
*/
@ManagedResource
@IntegrationManagedResource
public abstract class AbstractMessageGroupStore implements MessageGroupStore, Iterable<MessageGroup>,
BeanFactoryAware {

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.support.management;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
/**
* Base interface containing methods to control basic statistics gathering.
*
* @author Gary Russell
* @since 4.2
*
*/
public interface CountsEnablement {
@ManagedOperation
void reset();
@ManagedOperation(description = "Enable message counting statistics")
void enableCounts(boolean countsEnabled);
@ManagedAttribute
boolean isCountsEnabled();
}

View File

@@ -57,14 +57,30 @@ public class ExponentialMovingAverageRatio {
* Add a new event with successful outcome.
*/
public void success() {
append(1);
append(1, System.currentTimeMillis());
}
/**
* Add a new event with successful outcome.
* @param t The current timestamp.
*/
public void success(long t) {
append(1, t);
}
/**
* Add a new event with failed outcome.
*/
public void failure() {
append(0);
append(0, System.currentTimeMillis());
}
/**
* Add a new event with failed outcome.
* @param t the current timestamp.
*/
public void failure(long t) {
append(0, t);
}
public synchronized void reset() {
@@ -74,8 +90,7 @@ public class ExponentialMovingAverageRatio {
cumulative.reset();
}
private synchronized void append(int value) {
long t = System.currentTimeMillis();
private synchronized void append(int value, long t) {
double alpha = Math.exp((t0 - t) * lapse);
t0 = t;
sum = alpha * sum + value;

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.support.management;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.jmx.export.annotation.ManagedResource;
/**
* Clone of {@link ManagedResource} limiting beans thus annoated so that they
* will only be exported by the {@code IntegrationMBeanExporter}.
*
* @author Gary Russell
* @since 4.2
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface IntegrationManagedResource {
/**
* The annotation value is equivalent to the {@code objectName}
* attribute, for simple default usage.
* @return the value.
*/
String value() default "";
String objectName() default "";
String description() default "";
int currencyTimeLimit() default -1;
boolean log() default false;
String logFile() default "";
String persistPolicy() default "";
int persistPeriod() default -1;
String persistName() default "";
String persistLocation() default "";
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.support.management;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
/**
* Base interface containing methods to control complete statistics gathering.
*
* @author Gary Russell
* @since 4.2
*
*/
public interface MetricsEnablement extends CountsEnablement {
@ManagedOperation(description = "Enable all statistics")
void enableStats(boolean statsEnabled);
@ManagedAttribute
boolean isStatsEnabled();
}

View File

@@ -0,0 +1,4 @@
/**
* Provides classes related to management.
*/
package org.springframework.integration.support.management;