Repository: camel Updated Branches: refs/heads/master 6b70b70a9 -> d49617ca4
CAMEL-9795: camel-zipkin - Reuse existing span for complex eips like multicast. Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/d49617ca Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/d49617ca Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/d49617ca Branch: refs/heads/master Commit: d49617ca45aa7f1d45a1dba54f6ebb18eba8c236 Parents: 6b70b70 Author: Claus Ibsen <davscl...@apache.org> Authored: Tue Apr 5 09:00:00 2016 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Tue Apr 5 09:00:26 2016 +0200 ---------------------------------------------------------------------- .../org/apache/camel/zipkin/ZipkinState.java | 6 +- .../org/apache/camel/zipkin/ZipkinTracer.java | 22 ++++- .../ZipkinClientRecipientListRouteTest.java | 81 ++++++++++++++++ .../camel/zipkin/ZipkinMulticastRouteTest.java | 86 +++++++++++++++++ .../zipkin/ZipkinRecipientListRouteTest.java | 83 +++++++++++++++++ .../zipkin/scribe/ZipkinABCRouteScribe.java | 8 ++ .../scribe/ZipkinMulticastRouteScribe.java | 98 ++++++++++++++++++++ .../src/test/resources/log4j.properties | 2 +- 8 files changed, 377 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/d49617ca/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinState.java ---------------------------------------------------------------------- diff --git a/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinState.java b/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinState.java index a679501..6a3212e 100644 --- a/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinState.java +++ b/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinState.java @@ -5,9 +5,9 @@ * 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 - * <p/> - * http://www.apache.org/licenses/LICENSE-2.0 - * <p/> + * + * 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. http://git-wip-us.apache.org/repos/asf/camel/blob/d49617ca/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinTracer.java ---------------------------------------------------------------------- diff --git a/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinTracer.java b/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinTracer.java index f4b2aea..98e7038 100644 --- a/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinTracer.java +++ b/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinTracer.java @@ -5,9 +5,9 @@ * 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 - * <p/> - * http://www.apache.org/licenses/LICENSE-2.0 - * <p/> + * + * 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. @@ -58,7 +58,7 @@ import org.apache.camel.util.ServiceHelper; import static org.apache.camel.builder.ExpressionBuilder.routeIdExpression; /** - * To use zipkin with Camel then setup this {@link org.apache.camel.spi.EventNotifier} in your Camel application. + * To use zipkin with Camel then setup this {@link ZipkinTracer} in your Camel application. * <p/> * Events (span) are captured for incoming and outgoing messages being sent to/from Camel. * This means you need to configure which which Camel endpoints that maps to zipkin service names. @@ -82,6 +82,10 @@ import static org.apache.camel.builder.ExpressionBuilder.routeIdExpression; * <li>ZIPKIN_COLLECTOR_SERVICE_HOST - The hostname</li> * <li>ZIPKIN_COLLECTOR_SERVICE_PORT - The port number</li> * </ul> + * <p/> + * This class is implemented as both an {@link org.apache.camel.spi.EventNotifier} and {@link RoutePolicy} that allows + * to trap when Camel starts/ends an {@link Exchange} being routed using the {@link RoutePolicy} and during the routing + * if the {@link Exchange} sends messages, then we track them using the {@link org.apache.camel.spi.EventNotifier}. */ @ManagedResource(description = "Managing ZipkinTracer") public class ZipkinTracer extends EventNotifierSupport implements RoutePolicy, RoutePolicyFactory, StatefulService, CamelContextAware { @@ -450,6 +454,9 @@ public class ZipkinTracer extends EventNotifierSupport implements RoutePolicy, R @Override public void notify(EventObject event) throws Exception { + // use event notifier to track events when Camel messages to endpoints + // these events corresponds to Zipkin client events + // client events if (event instanceof ExchangeSendingEvent) { ExchangeSendingEvent ese = (ExchangeSendingEvent) event; @@ -534,7 +541,7 @@ public class ZipkinTracer extends EventNotifierSupport implements RoutePolicy, R } } - private void serverRequest(Brave brave, String serviceName, Exchange exchange) { + private ServerSpan serverRequest(Brave brave, String serviceName, Exchange exchange) { ServerSpanThreadBinder serverBinder = brave.serverSpanThreadBinder(); // reuse existing span if we do multiple requests from the same @@ -572,6 +579,8 @@ public class ZipkinTracer extends EventNotifierSupport implements RoutePolicy, R } log.debug("serverRequest [service={}, traceId={}, spanId={}, parentId={}]", serviceName, traceId, spanId, parentId); } + + return span; } private void serverResponse(Brave brave, String serviceName, Exchange exchange) { @@ -644,6 +653,9 @@ public class ZipkinTracer extends EventNotifierSupport implements RoutePolicy, R @Override public void onExchangeBegin(Route route, Exchange exchange) { + // use route policy to track events when Camel a Camel route begins/end the lifecycle of an Exchange + // these events corresponds to Zipkin server events + if (hasZipkinTraceId(exchange)) { String serviceName = getServiceName(exchange, route.getEndpoint(), true, false); Brave brave = getBrave(serviceName); http://git-wip-us.apache.org/repos/asf/camel/blob/d49617ca/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/ZipkinClientRecipientListRouteTest.java ---------------------------------------------------------------------- diff --git a/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/ZipkinClientRecipientListRouteTest.java b/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/ZipkinClientRecipientListRouteTest.java new file mode 100644 index 0000000..fa1d915 --- /dev/null +++ b/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/ZipkinClientRecipientListRouteTest.java @@ -0,0 +1,81 @@ +/** + * 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.zipkin; + +import java.util.concurrent.TimeUnit; + +import org.apache.camel.CamelContext; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.NotifyBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Test; + +public class ZipkinClientRecipientListRouteTest extends CamelTestSupport { + + private ZipkinTracer zipkin; + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + + zipkin = new ZipkinTracer(); + + zipkin.addClientServiceMapping("seda:a", "a"); + zipkin.addClientServiceMapping("seda:b", "b"); + zipkin.addClientServiceMapping("seda:c", "c"); + zipkin.addServerServiceMapping("seda:a", "a"); + zipkin.addServerServiceMapping("seda:b", "b"); + zipkin.addServerServiceMapping("seda:c", "c"); + zipkin.setSpanCollector(new ZipkinLoggingSpanCollector()); + + // attaching ourself to CamelContext + zipkin.init(context); + + return context; + } + + @Test + public void testZipkinRoute() throws Exception { + NotifyBuilder notify = new NotifyBuilder(context).whenDone(1).create(); + + template.requestBody("direct:start", "Hello World"); + + assertTrue(notify.matches(30, TimeUnit.SECONDS)); + } + + @Override + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").recipientList(constant("seda:a,seda:b,seda:c")).routeId("start"); + + from("seda:a").routeId("a") + .log("routing at ${routeId}"); + + from("seda:b").routeId("b") + .log("routing at ${routeId}") + .delay(simple("${random(1000,2000)}")); + + from("seda:c").routeId("c") + .log("routing at ${routeId}") + .delay(simple("${random(0,100)}")); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/d49617ca/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/ZipkinMulticastRouteTest.java ---------------------------------------------------------------------- diff --git a/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/ZipkinMulticastRouteTest.java b/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/ZipkinMulticastRouteTest.java new file mode 100644 index 0000000..22bd579 --- /dev/null +++ b/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/ZipkinMulticastRouteTest.java @@ -0,0 +1,86 @@ +/** + * 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.zipkin; + +import java.util.concurrent.TimeUnit; + +import org.apache.camel.CamelContext; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.NotifyBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Test; + +public class ZipkinMulticastRouteTest extends CamelTestSupport { + + private ZipkinTracer zipkin; + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + + zipkin = new ZipkinTracer(); + + zipkin.addClientServiceMapping("seda:a", "a"); + zipkin.addClientServiceMapping("seda:b", "b"); + zipkin.addClientServiceMapping("seda:c", "c"); + zipkin.addServerServiceMapping("seda:a", "a"); + zipkin.addServerServiceMapping("seda:b", "b"); + zipkin.addServerServiceMapping("seda:c", "c"); + zipkin.setSpanCollector(new ZipkinLoggingSpanCollector()); + + // attaching ourself to CamelContext + zipkin.init(context); + + return context; + } + + @Test + public void testZipkinRoute() throws Exception { + NotifyBuilder notify = new NotifyBuilder(context).whenDone(1).create(); + + template.requestBody("direct:start", "Hello World"); + + assertTrue(notify.matches(30, TimeUnit.SECONDS)); + } + + @Override + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").to("seda:a").routeId("start"); + + from("seda:a").routeId("a") + .log("routing at ${routeId}") + .multicast() + .to("seda:b") + .to("seda:c") + .end() + .log("End of routing"); + + from("seda:b").routeId("b") + .log("routing at ${routeId}") + .delay(simple("${random(1000,2000)}")); + + from("seda:c").routeId("c") + .log("routing at ${routeId}") + .delay(simple("${random(0,100)}")); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/d49617ca/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/ZipkinRecipientListRouteTest.java ---------------------------------------------------------------------- diff --git a/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/ZipkinRecipientListRouteTest.java b/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/ZipkinRecipientListRouteTest.java new file mode 100644 index 0000000..a8b6083 --- /dev/null +++ b/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/ZipkinRecipientListRouteTest.java @@ -0,0 +1,83 @@ +/** + * 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.zipkin; + +import java.util.concurrent.TimeUnit; + +import org.apache.camel.CamelContext; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.NotifyBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Test; + +public class ZipkinRecipientListRouteTest extends CamelTestSupport { + + private ZipkinTracer zipkin; + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + + zipkin = new ZipkinTracer(); + + zipkin.addClientServiceMapping("seda:a", "a"); + zipkin.addClientServiceMapping("seda:b", "b"); + zipkin.addClientServiceMapping("seda:c", "c"); + zipkin.addServerServiceMapping("seda:a", "a"); + zipkin.addServerServiceMapping("seda:b", "b"); + zipkin.addServerServiceMapping("seda:c", "c"); + zipkin.setSpanCollector(new ZipkinLoggingSpanCollector()); + + // attaching ourself to CamelContext + zipkin.init(context); + + return context; + } + + @Test + public void testZipkinRoute() throws Exception { + NotifyBuilder notify = new NotifyBuilder(context).whenDone(1).create(); + + template.requestBody("direct:start", "Hello World"); + + assertTrue(notify.matches(30, TimeUnit.SECONDS)); + } + + @Override + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").to("seda:a").routeId("start"); + + from("seda:a").routeId("a") + .log("routing at ${routeId}") + .recipientList(constant("seda:b,seda:c")) + .log("End of routing"); + + from("seda:b").routeId("b") + .log("routing at ${routeId}") + .delay(simple("${random(1000,2000)}")); + + from("seda:c").routeId("c") + .log("routing at ${routeId}") + .delay(simple("${random(0,100)}")); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/d49617ca/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinABCRouteScribe.java ---------------------------------------------------------------------- diff --git a/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinABCRouteScribe.java b/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinABCRouteScribe.java index 0fae6c4..a8f4e0d 100644 --- a/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinABCRouteScribe.java +++ b/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinABCRouteScribe.java @@ -28,6 +28,14 @@ import org.apache.camel.zipkin.ZipkinLoggingSpanCollector; import org.apache.camel.zipkin.ZipkinTracer; import org.junit.Test; +/** + * Integration test requires running Zipkin/Scribe running + * + * The easiest way is to run using zipkin-docker: https://github.com/openzipkin/docker-zipkin + * + * Adjust the IP address to what IP docker-machines have assigned, you can use + * <tt>docker-machines ls</tt> + */ public class ZipkinABCRouteScribe extends CamelTestSupport { private String ip = "192.168.99.100"; http://git-wip-us.apache.org/repos/asf/camel/blob/d49617ca/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinMulticastRouteScribe.java ---------------------------------------------------------------------- diff --git a/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinMulticastRouteScribe.java b/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinMulticastRouteScribe.java new file mode 100644 index 0000000..08596bc --- /dev/null +++ b/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinMulticastRouteScribe.java @@ -0,0 +1,98 @@ +/** + * 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.zipkin.scribe; + +import java.util.concurrent.TimeUnit; + +import com.github.kristofa.brave.scribe.ScribeSpanCollector; +import org.apache.camel.CamelContext; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.NotifyBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.apache.camel.zipkin.ZipkinLoggingSpanCollector; +import org.apache.camel.zipkin.ZipkinTracer; +import org.junit.Test; + +/** + * Integration test requires running Zipkin/Scribe running + * + * The easiest way is to run using zipkin-docker: https://github.com/openzipkin/docker-zipkin + * + * Adjust the IP address to what IP docker-machines have assigned, you can use + * <tt>docker-machines ls</tt> + */ +public class ZipkinMulticastRouteScribe extends CamelTestSupport { + + private String ip = "192.168.99.100"; + private ZipkinTracer zipkin; + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + + zipkin = new ZipkinTracer(); + + zipkin.addClientServiceMapping("seda:a", "a"); + zipkin.addClientServiceMapping("seda:b", "b"); + zipkin.addClientServiceMapping("seda:c", "c"); + zipkin.addServerServiceMapping("seda:a", "a"); + zipkin.addServerServiceMapping("seda:b", "b"); + zipkin.addServerServiceMapping("seda:c", "c"); + zipkin.setSpanCollector(new ScribeSpanCollector(ip, 9410)); + + // attaching ourself to CamelContext + zipkin.init(context); + + return context; + } + + @Test + public void testZipkinRoute() throws Exception { + NotifyBuilder notify = new NotifyBuilder(context).whenDone(1).create(); + + template.requestBody("direct:start", "Hello World"); + + assertTrue(notify.matches(30, TimeUnit.SECONDS)); + } + + @Override + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").to("seda:a").routeId("start"); + + from("seda:a").routeId("a") + .log("routing at ${routeId}") + .multicast() + .to("seda:b") + .to("seda:c") + .end() + .log("End of routing"); + + from("seda:b").routeId("b") + .log("routing at ${routeId}") + .delay(simple("${random(1000,2000)}")); + + from("seda:c").routeId("c") + .log("routing at ${routeId}") + .delay(simple("${random(0,100)}")); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/d49617ca/components/camel-zipkin/src/test/resources/log4j.properties ---------------------------------------------------------------------- diff --git a/components/camel-zipkin/src/test/resources/log4j.properties b/components/camel-zipkin/src/test/resources/log4j.properties index 538c5bd..ab7b29f 100644 --- a/components/camel-zipkin/src/test/resources/log4j.properties +++ b/components/camel-zipkin/src/test/resources/log4j.properties @@ -18,7 +18,7 @@ # # The logging properties used # -log4j.rootLogger=INFO, out +log4j.rootLogger=INFO, file #log4j.logger.org.apache.camel=DEBUG log4j.logger.org.apache.camel.zipkin=DEBUG