Refactor and document the Metrics CDI example
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/8300779a Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/8300779a Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/8300779a Branch: refs/heads/master Commit: 8300779a6ff962abc4f3ebda82375a2ca943963c Parents: 15af9f0 Author: Antonin Stefanutti <anto...@stefanutti.fr> Authored: Thu Jan 28 17:18:01 2016 +0100 Committer: Claus Ibsen <davscl...@apache.org> Committed: Thu Jan 28 18:56:20 2016 +0100 ---------------------------------------------------------------------- .../camel/example/cdi/metrics/Application.java | 134 +++++++++++++++++++ .../example/cdi/metrics/MetricsCdiConfig.java | 63 --------- .../camel/example/cdi/metrics/MetricsRoute.java | 52 ------- .../example/cdi/metrics/SuccessRatioGauge.java | 43 ------ .../example/cdi/metrics/ApplicationTest.java | 90 +++++++++++++ .../example/cdi/metrics/MetricsSampleTest.java | 90 ------------- 6 files changed, 224 insertions(+), 248 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/8300779a/examples/camel-example-cdi-metrics/src/main/java/org/apache/camel/example/cdi/metrics/Application.java ---------------------------------------------------------------------- diff --git a/examples/camel-example-cdi-metrics/src/main/java/org/apache/camel/example/cdi/metrics/Application.java b/examples/camel-example-cdi-metrics/src/main/java/org/apache/camel/example/cdi/metrics/Application.java new file mode 100644 index 0000000..423f9c7 --- /dev/null +++ b/examples/camel-example-cdi-metrics/src/main/java/org/apache/camel/example/cdi/metrics/Application.java @@ -0,0 +1,134 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.camel.example.cdi.metrics; + +import java.util.concurrent.TimeUnit; +import javax.enterprise.event.Observes; +import javax.enterprise.inject.Disposes; +import javax.enterprise.inject.Produces; +import javax.inject.Named; +import javax.inject.Singleton; + +import com.codahale.metrics.Gauge; +import com.codahale.metrics.Meter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.RatioGauge; +import com.codahale.metrics.Slf4jReporter; +import com.codahale.metrics.annotation.Metric; +import io.astefanutti.metrics.cdi.MetricsConfiguration; +import org.apache.camel.Exchange; +import org.apache.camel.LoggingLevel; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.cdi.ContextName; +import org.apache.camel.component.metrics.MetricsComponent; +import org.apache.camel.component.metrics.MetricsConstants; +import org.apache.camel.management.event.CamelContextStartedEvent; + +/** + * This example registers the following meters into the Metrics registry: + * <ul> + * <li>{@code attempt}</code>: meters the number of calls + * made to the service to process incoming events</li> + * <li>{@code error}</code>: meters the number of errors + * corresponding to the number of events that haven't been processed</li> + * <li>{@code generated}</code>: meters the number of events to be processed</li> + * <li>{@code redelivery}</code>: meters the number of retries + * made to process the events</li> + * <li>{@code success}</code>: meters the number of events successfully processed</li> + * </ul> + * The invariant being: {@code attempt = redelivery - success - error}. + * <p> In addition, a ratio gauge {@code success-ratio = success / generated} is registered. + * + */ +class Application { + + @ContextName("camel-example-metrics-cdi") + static class MetricsRoute extends RouteBuilder { + + @Override + public void configure() { + onException() + .handled(true) + .maximumRedeliveries(2) + .logStackTrace(false) + .logExhausted(false) + .log(LoggingLevel.ERROR, "Failed processing ${body}") + .to("metrics:meter:redelivery?mark=2") + // The 'error' meter + .to("metrics:meter:error"); + + from("timer:stream?period=1000") + .routeId("unreliable-service") + .setBody(header(Exchange.TIMER_COUNTER).prepend("event #")) + .log("Processing ${body}...") + // The 'generated' meter + .to("metrics:meter:generated") + .bean(UnreliableService.class) + .filter(header(Exchange.REDELIVERED)) + .log(LoggingLevel.WARN, "Processed ${body} after ${header.CamelRedeliveryCounter} retries") + .setHeader(MetricsConstants.HEADER_METER_MARK, header(Exchange.REDELIVERY_COUNTER)) + // The 'redelivery' meter + .to("metrics:meter:redelivery") + .end() + .log("Successfully processed ${body}") + // The 'success' meter + .to("metrics:meter:success"); + } + } + + @Produces + @Singleton + @Named(MetricsComponent.METRIC_REGISTRY_NAME) + // TODO: remove when Camel Metrics component looks up for the Metrics registry by type only + MetricRegistry registry = new MetricRegistry(); + + @Produces + @Metric(name = "success-ratio") + // Register a custom gauge that's the ratio of the 'success' meter on the 'generated' meter + // TODO: use a lambda expression and parameter names when Java 8 is a pre-requisite + Gauge<Double> successRatio(@Metric(name = "success") final Meter success, + @Metric(name = "generated") final Meter generated) { + return new RatioGauge() { + @Override + protected Ratio getRatio() { + return Ratio.of(success.getOneMinuteRate(), generated.getOneMinuteRate()); + } + }; + } + + @Produces + @Singleton + Slf4jReporter reporter(MetricRegistry registry) { + return Slf4jReporter.forRegistry(registry) + .convertRatesTo(TimeUnit.SECONDS) + .convertDurationsTo(TimeUnit.MILLISECONDS) + .build(); + } + + void onStart(@Observes CamelContextStartedEvent event, Slf4jReporter reporter) { + reporter.start(10L, TimeUnit.SECONDS); + } + + void onStop(@Disposes Slf4jReporter reporter) { + reporter.stop(); + } + + void configure(@Observes MetricsConfiguration config) { + // Force Metrics CDI to use absolute names + config.useAbsoluteName(true); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/8300779a/examples/camel-example-cdi-metrics/src/main/java/org/apache/camel/example/cdi/metrics/MetricsCdiConfig.java ---------------------------------------------------------------------- diff --git a/examples/camel-example-cdi-metrics/src/main/java/org/apache/camel/example/cdi/metrics/MetricsCdiConfig.java b/examples/camel-example-cdi-metrics/src/main/java/org/apache/camel/example/cdi/metrics/MetricsCdiConfig.java deleted file mode 100644 index 171838f..0000000 --- a/examples/camel-example-cdi-metrics/src/main/java/org/apache/camel/example/cdi/metrics/MetricsCdiConfig.java +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.camel.example.cdi.metrics; - -import java.util.concurrent.TimeUnit; -import javax.enterprise.context.ApplicationScoped; -import javax.enterprise.event.Observes; -import javax.enterprise.inject.Produces; -import javax.inject.Inject; -import javax.inject.Named; - -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.Slf4jReporter; -import io.astefanutti.metrics.cdi.MetricsConfiguration; -import org.apache.camel.component.metrics.MetricsComponent; -import org.apache.camel.management.event.CamelContextStartedEvent; -import org.apache.camel.management.event.CamelContextStoppedEvent; - -@ApplicationScoped -class MetricsCdiConfig { - - @Produces - @ApplicationScoped - @Named(MetricsComponent.METRIC_REGISTRY_NAME) - // TODO: remove when Camel Metrics component looks up for the Metrics registry by type only - private MetricRegistry registry = new MetricRegistry(); - - private final Slf4jReporter reporter; - - @Inject - MetricsCdiConfig(MetricRegistry registry) { - reporter = Slf4jReporter.forRegistry(registry) - .convertRatesTo(TimeUnit.SECONDS) - .convertDurationsTo(TimeUnit.MILLISECONDS) - .build(); - } - - private void onStart(@Observes CamelContextStartedEvent event) { - reporter.start(10L, TimeUnit.SECONDS); - } - - private void onStop(@Observes CamelContextStoppedEvent event) { - reporter.stop(); - } - - private void configure(@Observes MetricsConfiguration config) { - config.useAbsoluteName(true); - } -} http://git-wip-us.apache.org/repos/asf/camel/blob/8300779a/examples/camel-example-cdi-metrics/src/main/java/org/apache/camel/example/cdi/metrics/MetricsRoute.java ---------------------------------------------------------------------- diff --git a/examples/camel-example-cdi-metrics/src/main/java/org/apache/camel/example/cdi/metrics/MetricsRoute.java b/examples/camel-example-cdi-metrics/src/main/java/org/apache/camel/example/cdi/metrics/MetricsRoute.java deleted file mode 100644 index b4e8076..0000000 --- a/examples/camel-example-cdi-metrics/src/main/java/org/apache/camel/example/cdi/metrics/MetricsRoute.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.camel.example.cdi.metrics; - -import org.apache.camel.Exchange; -import org.apache.camel.LoggingLevel; -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.cdi.ContextName; -import org.apache.camel.component.metrics.MetricsConstants; - -@ContextName("camel-example-metrics-cdi") -class MetricsRoute extends RouteBuilder { - - @Override - public void configure() { - onException() - .handled(true) - .maximumRedeliveries(2) - .logStackTrace(false) - .logExhausted(false) - .log(LoggingLevel.ERROR, "Failed processing ${body}") - .to("metrics:meter:redelivery?mark=2") - .to("metrics:meter:error"); - - from("timer:stream?period=1000").routeId("unreliable-service") - .setBody(header(Exchange.TIMER_COUNTER).prepend("event #")) - .log("Processing ${body}...") - .to("metrics:meter:generated") - .bean(UnreliableService.class) - .filter(header(Exchange.REDELIVERED)) - .log(LoggingLevel.WARN, "Processed ${body} after ${header.CamelRedeliveryCounter} retries") - .setHeader(MetricsConstants.HEADER_METER_MARK, header(Exchange.REDELIVERY_COUNTER)) - .to("metrics:meter:redelivery") - .end() - .log("Successfully processed ${body}") - .to("metrics:meter:success"); - } -} http://git-wip-us.apache.org/repos/asf/camel/blob/8300779a/examples/camel-example-cdi-metrics/src/main/java/org/apache/camel/example/cdi/metrics/SuccessRatioGauge.java ---------------------------------------------------------------------- diff --git a/examples/camel-example-cdi-metrics/src/main/java/org/apache/camel/example/cdi/metrics/SuccessRatioGauge.java b/examples/camel-example-cdi-metrics/src/main/java/org/apache/camel/example/cdi/metrics/SuccessRatioGauge.java deleted file mode 100644 index 86911f5..0000000 --- a/examples/camel-example-cdi-metrics/src/main/java/org/apache/camel/example/cdi/metrics/SuccessRatioGauge.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.camel.example.cdi.metrics; - -import javax.enterprise.inject.Produces; -import javax.inject.Inject; - -import com.codahale.metrics.Gauge; -import com.codahale.metrics.Meter; -import com.codahale.metrics.RatioGauge; -import com.codahale.metrics.annotation.Metric; - -class SuccessRatioGauge { - - @Inject - private Meter generated; - - @Inject - private Meter success; - - @Produces - @Metric(name = "success-ratio") - private Gauge<Double> successRatio = new RatioGauge() { - @Override - protected Ratio getRatio() { - return Ratio.of(success.getOneMinuteRate(), generated.getOneMinuteRate()); - } - }; -} http://git-wip-us.apache.org/repos/asf/camel/blob/8300779a/examples/camel-example-cdi-metrics/src/test/java/org/apache/camel/example/cdi/metrics/ApplicationTest.java ---------------------------------------------------------------------- diff --git a/examples/camel-example-cdi-metrics/src/test/java/org/apache/camel/example/cdi/metrics/ApplicationTest.java b/examples/camel-example-cdi-metrics/src/test/java/org/apache/camel/example/cdi/metrics/ApplicationTest.java new file mode 100644 index 0000000..623c519 --- /dev/null +++ b/examples/camel-example-cdi-metrics/src/test/java/org/apache/camel/example/cdi/metrics/ApplicationTest.java @@ -0,0 +1,90 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.camel.example.cdi.metrics; + +import javax.inject.Inject; +import com.codahale.metrics.Gauge; +import com.codahale.metrics.Meter; +import com.codahale.metrics.annotation.Metric; +import io.astefanutti.metrics.cdi.MetricsExtension; +import org.apache.camel.CamelContext; +import org.apache.camel.cdi.CdiCamelExtension; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +@RunWith(Arquillian.class) +public class ApplicationTest { + + @Inject + private Meter generated; + @Inject + private Meter attempt; + @Inject + private Meter success; + @Inject + private Meter redelivery; + @Inject + private Meter error; + + @Inject + @Metric(name = "success-ratio") + private Gauge<Double> ratio; + + @Inject + private CamelContext context; + + @Deployment + public static Archive<?> deployment() { + return ShrinkWrap.create(JavaArchive.class) + // Camel CDI + .addPackage(CdiCamelExtension.class.getPackage()) + // Metrics CDI + .addPackage(MetricsExtension.class.getPackage()) + // Test classes + .addPackage(Application.class.getPackage()) + // Bean archive deployment descriptor + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); + } + + @Test + public void testContextName() { + assertThat("Context name is incorrect!", context.getName(), is(equalTo("camel-example-metrics-cdi"))); + } + + @Test + public void testMetricsValues() throws Exception { + // Wait a while so that the timer can kick in + Thread.sleep(5000); + + // And stop the Camel context so that inflight exchanges get completed + context.stop(); + + assertThat("Meter counts are not consistent!", attempt.getCount() - redelivery.getCount() - success.getCount() - error.getCount(), is(equalTo(0L))); + + assertThat("Success rate gauge value is incorrect!", ratio.getValue(), is(equalTo(success.getOneMinuteRate() / generated.getOneMinuteRate()))); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/8300779a/examples/camel-example-cdi-metrics/src/test/java/org/apache/camel/example/cdi/metrics/MetricsSampleTest.java ---------------------------------------------------------------------- diff --git a/examples/camel-example-cdi-metrics/src/test/java/org/apache/camel/example/cdi/metrics/MetricsSampleTest.java b/examples/camel-example-cdi-metrics/src/test/java/org/apache/camel/example/cdi/metrics/MetricsSampleTest.java deleted file mode 100644 index ff98b40..0000000 --- a/examples/camel-example-cdi-metrics/src/test/java/org/apache/camel/example/cdi/metrics/MetricsSampleTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.camel.example.cdi.metrics; - -import javax.inject.Inject; -import com.codahale.metrics.Gauge; -import com.codahale.metrics.Meter; -import com.codahale.metrics.annotation.Metric; -import io.astefanutti.metrics.cdi.MetricsExtension; -import org.apache.camel.CamelContext; -import org.apache.camel.cdi.CdiCamelExtension; -import org.jboss.arquillian.container.test.api.Deployment; -import org.jboss.arquillian.junit.Arquillian; -import org.jboss.shrinkwrap.api.Archive; -import org.jboss.shrinkwrap.api.ShrinkWrap; -import org.jboss.shrinkwrap.api.asset.EmptyAsset; -import org.jboss.shrinkwrap.api.spec.JavaArchive; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -@RunWith(Arquillian.class) -public class MetricsSampleTest { - - @Inject - private Meter generated; - @Inject - private Meter attempt; - @Inject - private Meter success; - @Inject - private Meter redelivery; - @Inject - private Meter error; - - @Inject - @Metric(name = "success-ratio") - private Gauge<Double> ratio; - - @Inject - private CamelContext context; - - @Deployment - public static Archive<?> deployment() { - return ShrinkWrap.create(JavaArchive.class) - // Camel CDI - .addPackage(CdiCamelExtension.class.getPackage()) - // Metrics CDI - .addPackage(MetricsExtension.class.getPackage()) - // Test classes - .addPackage(MetricsSampleTest.class.getPackage()) - // Bean archive deployment descriptor - .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); - } - - @Test - public void testContextName() { - assertThat("Context name is incorrect!", context.getName(), is(equalTo("camel-example-metrics-cdi"))); - } - - @Test - public void testMetricsValues() throws Exception { - // Wait a while so that the timer can kick in - Thread.sleep(5000); - - // And stop the Camel context so that inflight exchanges get completed - context.stop(); - - assertThat("Meter counts are not consistent!", attempt.getCount() - redelivery.getCount() - success.getCount() - error.getCount(), is(equalTo(0L))); - - assertThat("Success rate gauge value is incorrect!", ratio.getValue(), is(equalTo(success.getOneMinuteRate() / generated.getOneMinuteRate()))); - } -}