Implemented metrics:timer endpoint.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/5deafafa Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/5deafafa Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/5deafafa Branch: refs/heads/master Commit: 5deafafa4d673fbce2c89ca54cfc340597cfc384 Parents: 0ad223e Author: Lauri Kimmel <lauri.kim...@gmx.com> Authored: Wed May 14 00:20:13 2014 +1000 Committer: Lauri Kimmel <lauri.kim...@gmx.com> Committed: Wed May 14 00:20:13 2014 +1000 ---------------------------------------------------------------------- .../apache/camel/metrics/MetricsComponent.java | 4 + .../camel/metrics/timer/TimerEndpoint.java | 44 +++++ .../camel/metrics/timer/TimerProducer.java | 73 +++++++++ .../metrics/MetricsComponentRouteTest.java | 5 +- .../camel/metrics/MetricsComponentTest.java | 7 +- .../camel/metrics/timer/TimerEndpointTest.java | 75 +++++++++ .../camel/metrics/timer/TimerProducerTest.java | 161 +++++++++++++++++++ 7 files changed, 365 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/5deafafa/src/main/java/org/apache/camel/metrics/MetricsComponent.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/camel/metrics/MetricsComponent.java b/src/main/java/org/apache/camel/metrics/MetricsComponent.java index 7d7d5ef..1f467c4 100644 --- a/src/main/java/org/apache/camel/metrics/MetricsComponent.java +++ b/src/main/java/org/apache/camel/metrics/MetricsComponent.java @@ -9,6 +9,7 @@ import org.apache.camel.impl.DefaultComponent; import org.apache.camel.metrics.counter.CounterEndpoint; import org.apache.camel.metrics.histogram.HistogramEndpoint; import org.apache.camel.metrics.meter.MeterEndpoint; +import org.apache.camel.metrics.timer.TimerEndpoint; import org.apache.camel.spi.Registry; import org.apache.camel.util.ObjectHelper; import org.slf4j.Logger; @@ -61,6 +62,9 @@ public class MetricsComponent extends DefaultComponent { case HISTOGRAM: endpoint = new HistogramEndpoint(registry, metricsName); break; + case TIMER: + endpoint = new TimerEndpoint(registry, metricsName); + break; default: throw new RuntimeCamelException("Metrics type \"" + type.toString() + "\" not supported"); } http://git-wip-us.apache.org/repos/asf/camel/blob/5deafafa/src/main/java/org/apache/camel/metrics/timer/TimerEndpoint.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/camel/metrics/timer/TimerEndpoint.java b/src/main/java/org/apache/camel/metrics/timer/TimerEndpoint.java new file mode 100644 index 0000000..6de4e32 --- /dev/null +++ b/src/main/java/org/apache/camel/metrics/timer/TimerEndpoint.java @@ -0,0 +1,44 @@ +package org.apache.camel.metrics.timer; + +import org.apache.camel.Producer; +import org.apache.camel.metrics.AbstractMetricsEndpoint; +import org.apache.camel.spi.UriEndpoint; +import org.apache.camel.spi.UriParam; + +import com.codahale.metrics.MetricRegistry; + +@UriEndpoint(scheme = "metrics:timer") +public class TimerEndpoint extends AbstractMetricsEndpoint { + + public static final String ENDPOINT_URI = "metrics:timer"; + + public enum TimerAction { + start, + stop; + } + + @UriParam + private TimerAction action; + + public TimerEndpoint(MetricRegistry registry, String metricsName) { + super(registry, metricsName); + } + + @Override + public Producer createProducer() throws Exception { + return new TimerProducer(this); + } + + public TimerAction getAction() { + return action; + } + + public void setAction(TimerAction action) { + this.action = action; + } + + @Override + protected String createEndpointUri() { + return ENDPOINT_URI; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/5deafafa/src/main/java/org/apache/camel/metrics/timer/TimerProducer.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/camel/metrics/timer/TimerProducer.java b/src/main/java/org/apache/camel/metrics/timer/TimerProducer.java new file mode 100644 index 0000000..f655352 --- /dev/null +++ b/src/main/java/org/apache/camel/metrics/timer/TimerProducer.java @@ -0,0 +1,73 @@ +package org.apache.camel.metrics.timer; + +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; +import org.apache.camel.impl.DefaultProducer; +import org.apache.camel.metrics.timer.TimerEndpoint.TimerAction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; + +public class TimerProducer extends DefaultProducer { + + private static final Logger LOG = LoggerFactory.getLogger(TimerProducer.class); + + public TimerProducer(Endpoint endpoint) { + super(endpoint); + } + + @Override + public void process(Exchange exchange) throws Exception { + TimerEndpoint endpoint = (TimerEndpoint) getEndpoint(); + MetricRegistry registry = endpoint.getRegistry(); + String metricsName = endpoint.getMetricsName(); + TimerAction action = endpoint.getAction(); + if (action == TimerAction.start) { + handleStart(exchange, registry, metricsName); + } + else if (action == TimerAction.stop) { + handleStop(exchange, registry, metricsName); + } + else { + LOG.warn("No action provided for timer \"{}\"", metricsName); + } + } + + void handleStart(Exchange exchange, MetricRegistry registry, String metricsName) { + String propertyName = getPropertyName(metricsName); + Timer.Context context = getTimerContextFromExchange(exchange, propertyName); + if (context == null) { + Timer timer = registry.timer(metricsName); + context = timer.time(); + exchange.setProperty(propertyName, context); + } + else { + LOG.warn("Timer \"{}\" already running", metricsName); + } + } + + void handleStop(Exchange exchange, MetricRegistry registry, String metricsName) { + String propertyName = getPropertyName(metricsName); + Timer.Context context = getTimerContextFromExchange(exchange, propertyName); + if (context != null) { + context.stop(); + exchange.removeProperty(propertyName); + } + else { + LOG.warn("Timer \"{}\" not found", metricsName); + } + } + + String getPropertyName(String metricsName) { + return new StringBuilder(TimerEndpoint.ENDPOINT_URI) + .append(":") + .append(metricsName) + .toString(); + } + + Timer.Context getTimerContextFromExchange(Exchange exchange, String propertyName) { + return exchange.getProperty(propertyName, Timer.Context.class); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/5deafafa/src/test/java/org/apache/camel/metrics/MetricsComponentRouteTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/camel/metrics/MetricsComponentRouteTest.java b/src/test/java/org/apache/camel/metrics/MetricsComponentRouteTest.java index 5ff0ed4..5af70b9 100644 --- a/src/test/java/org/apache/camel/metrics/MetricsComponentRouteTest.java +++ b/src/test/java/org/apache/camel/metrics/MetricsComponentRouteTest.java @@ -26,8 +26,7 @@ public class MetricsComponentRouteTest extends CamelTestSupport { @Override public void configure() { from("direct:start") - // .to("metrics") - // .to("metrics:") + .to("metrics:timer:T?action=start") .to("metrics:A") .to("metrics:counter://B") .to("metrics:counter:C?increment=19291") @@ -36,7 +35,9 @@ public class MetricsComponentRouteTest extends CamelTestSupport { .to("metrics:meter:D") .to("metrics:meter:D?mark=90001") .to("metrics:histogram:E") + .to("metrics:timer:T") .to("metrics:histogram:E?value=12000000031") + .to("metrics:timer:T?action=stop") .to("mock:result"); } }; http://git-wip-us.apache.org/repos/asf/camel/blob/5deafafa/src/test/java/org/apache/camel/metrics/MetricsComponentTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/camel/metrics/MetricsComponentTest.java b/src/test/java/org/apache/camel/metrics/MetricsComponentTest.java index 7c1c189..74d91c2 100644 --- a/src/test/java/org/apache/camel/metrics/MetricsComponentTest.java +++ b/src/test/java/org/apache/camel/metrics/MetricsComponentTest.java @@ -18,6 +18,7 @@ import org.apache.camel.RuntimeCamelException; import org.apache.camel.metrics.counter.CounterEndpoint; import org.apache.camel.metrics.histogram.HistogramEndpoint; import org.apache.camel.metrics.meter.MeterEndpoint; +import org.apache.camel.metrics.timer.TimerEndpoint; import org.apache.camel.spi.Registry; import org.junit.Before; import org.junit.Test; @@ -143,9 +144,11 @@ public class MetricsComponentTest { assertThat(endpoint, is(instanceOf(HistogramEndpoint.class))); } - @Test(expected = RuntimeCamelException.class) + @Test public void testCreateNewEndpointForTimer() throws Exception { - component.createNewEndpoint(metricRegistry, MetricsType.TIMER, "a name"); + Endpoint endpoint = component.createNewEndpoint(metricRegistry, MetricsType.TIMER, "a name"); + assertThat(endpoint, is(notNullValue())); + assertThat(endpoint, is(instanceOf(TimerEndpoint.class))); } @Test http://git-wip-us.apache.org/repos/asf/camel/blob/5deafafa/src/test/java/org/apache/camel/metrics/timer/TimerEndpointTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/camel/metrics/timer/TimerEndpointTest.java b/src/test/java/org/apache/camel/metrics/timer/TimerEndpointTest.java new file mode 100644 index 0000000..cb3232f --- /dev/null +++ b/src/test/java/org/apache/camel/metrics/timer/TimerEndpointTest.java @@ -0,0 +1,75 @@ +package org.apache.camel.metrics.timer; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +import org.apache.camel.Producer; +import org.apache.camel.metrics.timer.TimerEndpoint.TimerAction; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +import com.codahale.metrics.MetricRegistry; + +@RunWith(MockitoJUnitRunner.class) +public class TimerEndpointTest { + + private static final String METRICS_NAME = "metrics.name"; + + @Mock + private MetricRegistry registry; + + private TimerEndpoint endpoint; + + private InOrder inOrder; + + @Before + public void setUp() throws Exception { + endpoint = new TimerEndpoint(registry, METRICS_NAME); + inOrder = Mockito.inOrder(registry); + } + + @After + public void tearDown() throws Exception { + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testTimerEndpoint() throws Exception { + assertThat(endpoint, is(notNullValue())); + assertThat(endpoint.getRegistry(), is(registry)); + assertThat(endpoint.getMetricsName(), is(METRICS_NAME)); + } + + @Test + public void testCreateProducer() throws Exception { + Producer producer = endpoint.createProducer(); + assertThat(producer, is(notNullValue())); + assertThat(producer, is(instanceOf(TimerProducer.class))); + } + + @Test + public void testGetAction() throws Exception { + assertThat(endpoint.getAction(), is(nullValue())); + } + + @Test + public void testSetAction() throws Exception { + assertThat(endpoint.getAction(), is(nullValue())); + endpoint.setAction(TimerAction.start); + assertThat(endpoint.getAction(), is(TimerAction.start)); + } + + @Test + public void testCreateEndpointUri() throws Exception { + assertThat(endpoint.createEndpointUri(), is(TimerEndpoint.ENDPOINT_URI)); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/5deafafa/src/test/java/org/apache/camel/metrics/timer/TimerProducerTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/camel/metrics/timer/TimerProducerTest.java b/src/test/java/org/apache/camel/metrics/timer/TimerProducerTest.java new file mode 100644 index 0000000..86ec26d --- /dev/null +++ b/src/test/java/org/apache/camel/metrics/timer/TimerProducerTest.java @@ -0,0 +1,161 @@ +package org.apache.camel.metrics.timer; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.when; + +import org.apache.camel.Exchange; +import org.apache.camel.metrics.timer.TimerEndpoint.TimerAction; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; + +@RunWith(MockitoJUnitRunner.class) +public class TimerProducerTest { + + private static final String METRICS_NAME = "metrics.name"; + private static final String PROPERTY_NAME = TimerEndpoint.ENDPOINT_URI + ":" + METRICS_NAME; + + @Mock + private TimerEndpoint endpoint; + + @Mock + private Exchange exchange; + + @Mock + private MetricRegistry registry; + + @Mock + private Timer timer; + + @Mock + private Timer.Context context; + + private TimerProducer producer; + + @Mock + private InOrder inOrder; + + @Before + public void setUp() throws Exception { + producer = new TimerProducer(endpoint); + inOrder = Mockito.inOrder(endpoint, exchange, registry, timer, context); + when(endpoint.getRegistry()).thenReturn(registry); + when(endpoint.getMetricsName()).thenReturn(METRICS_NAME); + when(registry.timer(METRICS_NAME)).thenReturn(timer); + when(timer.time()).thenReturn(context); + } + + @Test + public void testTimerProducer() throws Exception { + assertThat(producer, is(notNullValue())); + assertThat(producer.getEndpoint().equals(endpoint), is(true)); + } + + @Test + public void testProcessStart() throws Exception { + when(endpoint.getAction()).thenReturn(TimerAction.start); + when(exchange.getProperty(PROPERTY_NAME, Timer.Context.class)).thenReturn(null); + producer.process(exchange); + inOrder.verify(endpoint, times(1)).getRegistry(); + inOrder.verify(endpoint, times(1)).getMetricsName(); + inOrder.verify(endpoint, times(1)).getAction(); + inOrder.verify(exchange, times(1)).getProperty(PROPERTY_NAME, Timer.Context.class); + inOrder.verify(registry, times(1)).timer(METRICS_NAME); + inOrder.verify(timer, times(1)).time(); + inOrder.verify(exchange, times(1)).setProperty(PROPERTY_NAME, context); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testProcessStop() throws Exception { + when(endpoint.getAction()).thenReturn(TimerAction.stop); + when(exchange.getProperty(PROPERTY_NAME, Timer.Context.class)).thenReturn(context); + producer.process(exchange); + inOrder.verify(endpoint, times(1)).getRegistry(); + inOrder.verify(endpoint, times(1)).getMetricsName(); + inOrder.verify(endpoint, times(1)).getAction(); + inOrder.verify(exchange, times(1)).getProperty(PROPERTY_NAME, Timer.Context.class); + inOrder.verify(context, times(1)).stop(); + inOrder.verify(exchange, times(1)).removeProperty(PROPERTY_NAME); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testProcessNoAction() throws Exception { + when(endpoint.getAction()).thenReturn(null); + producer.process(exchange); + inOrder.verify(endpoint, times(1)).getRegistry(); + inOrder.verify(endpoint, times(1)).getMetricsName(); + inOrder.verify(endpoint, times(1)).getAction(); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testHandleStart() throws Exception { + when(exchange.getProperty(PROPERTY_NAME, Timer.Context.class)).thenReturn(null); + producer.handleStart(exchange, registry, METRICS_NAME); + inOrder.verify(exchange, times(1)).getProperty(PROPERTY_NAME, Timer.Context.class); + inOrder.verify(registry, times(1)).timer(METRICS_NAME); + inOrder.verify(timer, times(1)).time(); + inOrder.verify(exchange, times(1)).setProperty(PROPERTY_NAME, context); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testHandleStartAlreadyRunning() throws Exception { + when(exchange.getProperty(PROPERTY_NAME, Timer.Context.class)).thenReturn(context); + producer.handleStart(exchange, registry, METRICS_NAME); + inOrder.verify(exchange, times(1)).getProperty(PROPERTY_NAME, Timer.Context.class); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testHandleStop() throws Exception { + when(exchange.getProperty(PROPERTY_NAME, Timer.Context.class)).thenReturn(context); + producer.handleStop(exchange, registry, METRICS_NAME); + inOrder.verify(exchange, times(1)).getProperty(PROPERTY_NAME, Timer.Context.class); + inOrder.verify(context, times(1)).stop(); + inOrder.verify(exchange, times(1)).removeProperty(PROPERTY_NAME); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testHandleStopContextNotFound() throws Exception { + when(exchange.getProperty(PROPERTY_NAME, Timer.Context.class)).thenReturn(null); + producer.handleStop(exchange, registry, METRICS_NAME); + inOrder.verify(exchange, times(1)).getProperty(PROPERTY_NAME, Timer.Context.class); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testGetPropertyName() throws Exception { + assertThat(producer.getPropertyName(METRICS_NAME), is(TimerEndpoint.ENDPOINT_URI + ":" + METRICS_NAME)); + } + + @Test + public void testGetTimerContextFromExchange() throws Exception { + when(exchange.getProperty(PROPERTY_NAME, Timer.Context.class)).thenReturn(context); + assertThat(producer.getTimerContextFromExchange(exchange, PROPERTY_NAME), is(context)); + inOrder.verify(exchange, times(1)).getProperty(PROPERTY_NAME, Timer.Context.class); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void testGetTimerContextFromExchangeNotFound() throws Exception { + when(exchange.getProperty(PROPERTY_NAME, Timer.Context.class)).thenReturn(null); + assertThat(producer.getTimerContextFromExchange(exchange, PROPERTY_NAME), is(nullValue())); + inOrder.verify(exchange, times(1)).getProperty(PROPERTY_NAME, Timer.Context.class); + inOrder.verifyNoMoreInteractions(); + } +}