Repository: camel Updated Branches: refs/heads/master b2c3b31bb -> c672d44b4
CAMEL-7696: camel-metrics - Add a route policy to expose route stats as codehale metrics. Work in progress. Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/c672d44b Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/c672d44b Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/c672d44b Branch: refs/heads/master Commit: c672d44b4f46a9a128216759059b134fc6f793ab Parents: fa7e225 Author: Claus Ibsen <davscl...@apache.org> Authored: Thu Aug 14 08:55:11 2014 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Thu Aug 14 08:55:22 2014 +0200 ---------------------------------------------------------------------- .../routepolicy/MetricsRegistryService.java | 64 ++++++++++ .../metrics/routepolicy/MetricsRoutePolicy.java | 124 +++++++++++++++++++ .../routepolicy/MetricsRoutePolicyTest.java | 65 ++++++++++ 3 files changed, 253 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/c672d44b/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/routepolicy/MetricsRegistryService.java ---------------------------------------------------------------------- diff --git a/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/routepolicy/MetricsRegistryService.java b/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/routepolicy/MetricsRegistryService.java new file mode 100644 index 0000000..efa3663 --- /dev/null +++ b/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/routepolicy/MetricsRegistryService.java @@ -0,0 +1,64 @@ +/** + * 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.component.metrics.routepolicy; + +import javax.management.MBeanServer; + +import com.codahale.metrics.JmxReporter; +import com.codahale.metrics.MetricRegistry; +import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; +import org.apache.camel.support.ServiceSupport; + +public final class MetricsRegistryService extends ServiceSupport implements CamelContextAware { + + private CamelContext camelContext; + private MetricRegistry registry; + private JmxReporter reporter; + + public MetricRegistry getRegistry() { + return registry; + } + + public CamelContext getCamelContext() { + return camelContext; + } + + public void setCamelContext(CamelContext camelContext) { + this.camelContext = camelContext; + } + + @Override + protected void doStart() throws Exception { + registry = new MetricRegistry(); + + MBeanServer server = getCamelContext().getManagementStrategy().getManagementAgent().getMBeanServer(); + if (server != null) { + String domain = "org.apache.camel.metrics." + getCamelContext().getManagementName(); + reporter = JmxReporter.forRegistry(registry).registerWith(server).inDomain(domain).build(); + reporter.start(); + } + } + + @Override + protected void doStop() throws Exception { + if (reporter != null) { + reporter.stop(); + reporter = null; + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/c672d44b/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/routepolicy/MetricsRoutePolicy.java ---------------------------------------------------------------------- diff --git a/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/routepolicy/MetricsRoutePolicy.java b/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/routepolicy/MetricsRoutePolicy.java new file mode 100644 index 0000000..f194ccb --- /dev/null +++ b/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/routepolicy/MetricsRoutePolicy.java @@ -0,0 +1,124 @@ +/** + * 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.component.metrics.routepolicy; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import com.codahale.metrics.Counter; +import com.codahale.metrics.Meter; +import com.codahale.metrics.Timer; +import org.apache.camel.Exchange; +import org.apache.camel.Route; +import org.apache.camel.impl.RoutePolicySupport; +import org.apache.camel.util.ObjectHelper; + +/** + * A {@link org.apache.camel.spi.RoutePolicy} which gathers statistics and reports them using {@link com.codahale.metrics.MetricRegistry}. + * <p/> + * The metrics is reported in JMX by default, but this can be configured. + */ +public class MetricsRoutePolicy extends RoutePolicySupport { + + // TODO: allow to configure which counters/meters/timers to capture + // TODO: allow to configur the reporer and jmx domain etc on MetricsRegistryService + // TODO: RoutePolicyFactory to make this configurable once and apply automatic for all routes + // TODO: allow to lookup and get hold of com.codahale.metrics.MetricRegistry from java api + + private MetricsRegistryService registry; + private final ConcurrentMap<Route, MetricsStatistics> statistics = new ConcurrentHashMap<Route, MetricsStatistics>(); + private Route route; + + private final static class MetricsStatistics { + private Counter total; + private Counter inflight; + private Meter requests; + private Timer responses; + + private MetricsStatistics(Counter total, Counter inflight, Meter requests, Timer responses) { + this.total = total; + this.inflight = inflight; + this.requests = requests; + this.responses = responses; + } + + public void onExchangeBegin(Exchange exchange) { + total.inc(); + inflight.inc(); + requests.mark(); + + Timer.Context context = responses.time(); + exchange.setProperty("MetricsRoutePolicy", context); + } + + public void onExchangeDone(Exchange exchange) { + inflight.dec(); + + Timer.Context context = exchange.getProperty("MetricsRoutePolicy", Timer.Context.class); + if (context != null) { + context.stop(); + } + } + } + + @Override + public void onInit(Route route) { + super.onInit(route); + + this.route = route; + try { + registry = route.getRouteContext().getCamelContext().hasServiceByType(MetricsRegistryService.class); + if (registry == null) { + registry = new MetricsRegistryService(); + route.getRouteContext().getCamelContext().addService(registry); + } + } catch (Exception e) { + throw ObjectHelper.wrapRuntimeCamelException(e); + } + + MetricsStatistics stats = statistics.get(route); + if (stats == null) { + Counter total = registry.getRegistry().counter(createName("total")); + Counter inflight = registry.getRegistry().counter(createName("inflight")); + Meter requests = registry.getRegistry().meter(createName("requests")); + Timer responses = registry.getRegistry().timer(createName("responses")); + stats = new MetricsStatistics(total, inflight, requests, responses); + statistics.putIfAbsent(route, stats); + } + } + + private String createName(String type) { + return route.getRouteContext().getCamelContext().getManagementName() + "-" + route.getId() + "-" + type; + } + + @Override + public void onExchangeBegin(Route route, Exchange exchange) { + MetricsStatistics stats = statistics.get(route); + if (stats != null) { + stats.onExchangeBegin(exchange); + } + } + + @Override + public void onExchangeDone(Route route, Exchange exchange) { + MetricsStatistics stats = statistics.get(route); + if (stats != null) { + stats.onExchangeDone(exchange); + } + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/c672d44b/components/camel-metrics/src/test/java/org/apache/camel/component/metrics/routepolicy/MetricsRoutePolicyTest.java ---------------------------------------------------------------------- diff --git a/components/camel-metrics/src/test/java/org/apache/camel/component/metrics/routepolicy/MetricsRoutePolicyTest.java b/components/camel-metrics/src/test/java/org/apache/camel/component/metrics/routepolicy/MetricsRoutePolicyTest.java new file mode 100644 index 0000000..8903131 --- /dev/null +++ b/components/camel-metrics/src/test/java/org/apache/camel/component/metrics/routepolicy/MetricsRoutePolicyTest.java @@ -0,0 +1,65 @@ +/** + * 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.component.metrics.routepolicy; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.spi.RoutePolicy; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Test; + +public class MetricsRoutePolicyTest extends CamelTestSupport { + + @Override + protected boolean useJmx() { + return true; + } + + @Test + public void testMetricsRoutePolicy() throws Exception { + getMockEndpoint("mock:result").expectedMessageCount(10); + + for (int i = 0; i < 50; i++) { + if (i % 2 == 0) { + template.sendBody("seda:foo", "Hello " + i); + } else { + template.sendBody("seda:bar", "Hello " + i); + } + } + + assertMockEndpointsSatisfied(); + + // TODO: assert the jmx mbeans + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + RoutePolicy policy = new MetricsRoutePolicy(); + + from("seda:foo").routeId("foo").routePolicy(policy) + .delayer(100) + .to("mock:result"); + + from("seda:bar").routeId("bar").routePolicy(policy) + .delayer(250) + .to("mock:result"); + } + }; + } +}