CAMEL-9759: camel-zipkin - Instrument Camel. 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/ddfecf07 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/ddfecf07 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/ddfecf07 Branch: refs/heads/master Commit: ddfecf079d4f4f4b3f804d8cc4aa95c1093e0d36 Parents: c445edc Author: Claus Ibsen <davscl...@apache.org> Authored: Tue Mar 29 17:28:45 2016 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Tue Mar 29 17:28:45 2016 +0200 ---------------------------------------------------------------------- components/camel-zipkin/pom.xml | 18 ++++- .../camel/zipkin/ZipkinEventNotifier.java | 41 +++++++++++- .../scribe/ZipkinAutoConfigureScribe.java | 69 ++++++++++++++++++++ 3 files changed, 125 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/ddfecf07/components/camel-zipkin/pom.xml ---------------------------------------------------------------------- diff --git a/components/camel-zipkin/pom.xml b/components/camel-zipkin/pom.xml index 0027d3a..be6ab4b 100644 --- a/components/camel-zipkin/pom.xml +++ b/components/camel-zipkin/pom.xml @@ -15,7 +15,8 @@ See the License for the specific language governing permissions and limitations under the License. --> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> @@ -68,6 +69,21 @@ </dependencies> + <build> + <plugins> + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <!-- needed for testing auto configure --> + <environmentVariables> + <ZIPKIN_SERVICE_HOST>192.168.99.100</ZIPKIN_SERVICE_HOST> + <ZIPKIN_SERVICE_PORT>9401</ZIPKIN_SERVICE_PORT> + </environmentVariables> + </configuration> + </plugin> + </plugins> + </build> + <profiles> <profile> <id>scribe-test</id> http://git-wip-us.apache.org/repos/asf/camel/blob/ddfecf07/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinEventNotifier.java ---------------------------------------------------------------------- diff --git a/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinEventNotifier.java b/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinEventNotifier.java index 5dd38e7..ed3efa7 100644 --- a/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinEventNotifier.java +++ b/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinEventNotifier.java @@ -29,8 +29,10 @@ import com.github.kristofa.brave.Sampler; import com.github.kristofa.brave.ServerSpan; import com.github.kristofa.brave.ServerSpanThreadBinder; import com.github.kristofa.brave.SpanCollector; +import com.github.kristofa.brave.scribe.ScribeSpanCollector; import com.twitter.zipkin.gen.Span; import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.StatefulService; @@ -44,6 +46,7 @@ import org.apache.camel.management.event.ExchangeSentEvent; import org.apache.camel.support.EventNotifierSupport; import org.apache.camel.util.EndpointHelper; import org.apache.camel.util.IOHelper; +import org.apache.camel.util.ObjectHelper; import org.apache.camel.util.ServiceHelper; import static org.apache.camel.builder.ExpressionBuilder.routeIdExpression; @@ -66,10 +69,18 @@ import static org.apache.camel.builder.ExpressionBuilder.routeIdExpression; * If no mapping has been configured then Camel will fallback and use endpoint uri's as service names. * However its recommended to configure service mappings so you can use human logic names instead of Camel * endpoint uris in the names. + * <p/> + * Camel will auto-configure a {@link ScribeSpanCollector} if no SpanCollector has explict been configured, and + * if the hostname and port has been configured as environment variables + * <ul> + * <li>ZIPKIN_SERVICE_HOST - The hostname</li> + * <li>ZIPKIN_SERVICE_PORT - The port number</li> + * </ul> */ @ManagedResource(description = "Managing ZipkinEventNotifier") -public class ZipkinEventNotifier extends EventNotifierSupport implements StatefulService { +public class ZipkinEventNotifier extends EventNotifierSupport implements StatefulService, CamelContextAware { + private CamelContext camelContext; private float rate = 1.0f; private SpanCollector spanCollector; private Map<String, String> serviceMappings = new HashMap<>(); @@ -81,6 +92,14 @@ public class ZipkinEventNotifier extends EventNotifierSupport implements Statefu public ZipkinEventNotifier() { } + public CamelContext getCamelContext() { + return camelContext; + } + + public void setCamelContext(CamelContext camelContext) { + this.camelContext = camelContext; + } + public float getRate() { return rate; } @@ -130,7 +149,7 @@ public class ZipkinEventNotifier extends EventNotifierSupport implements Statefu * See more details at the class javadoc. * * @param pattern the pattern such as route id, endpoint url - * @param serviceName the zpkin service name + * @param serviceName the zipkin service name */ public void addServiceMapping(String pattern, String serviceName) { serviceMappings.put(pattern, serviceName); @@ -146,6 +165,8 @@ public class ZipkinEventNotifier extends EventNotifierSupport implements Statefu /** * Adds an exclude pattern that will disable tracing with zipkin for Camel messages that matches the pattern. + * + * @param pattern the pattern such as route id, endpoint url */ public void addExcludePattern(String pattern) { excludePatterns.add(pattern); @@ -171,6 +192,22 @@ public class ZipkinEventNotifier extends EventNotifierSupport implements Statefu protected void doStart() throws Exception { super.doStart(); + ObjectHelper.notNull(camelContext, "CamelContext", this); + + if (spanCollector == null) { + // is there a zipkin service setup as ENV variable to auto register a scribe span collector + // use the {{service:name}} function that resolves this for us + String host = camelContext.resolvePropertyPlaceholders("{{service.host:zipkin}}"); + String port = camelContext.resolvePropertyPlaceholders("{{service.port:zipkin}}"); + if (ObjectHelper.isNotEmpty(host) && ObjectHelper.isNotEmpty(port)) { + log.info("Auto-configuring ZipkinScribeSpanCollector using host: {} and port: {}", host, port); + int num = camelContext.getTypeConverter().mandatoryConvertTo(Integer.class, port); + spanCollector = new ScribeSpanCollector(host, num); + } + } + + ObjectHelper.notNull(spanCollector, "SpanCollector", this); + if (serviceMappings.isEmpty()) { log.warn("No service name(s) has been configured. Camel will fallback and use endpoint uris as service names."); useFallbackServiceNames = true; http://git-wip-us.apache.org/repos/asf/camel/blob/ddfecf07/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinAutoConfigureScribe.java ---------------------------------------------------------------------- diff --git a/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinAutoConfigureScribe.java b/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinAutoConfigureScribe.java new file mode 100644 index 0000000..db70c62 --- /dev/null +++ b/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinAutoConfigureScribe.java @@ -0,0 +1,69 @@ +/** + * 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 org.apache.camel.CamelContext; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.apache.camel.zipkin.ZipkinEventNotifier; +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 ZipkinAutoConfigureScribe extends CamelTestSupport { + + private ZipkinEventNotifier zipkin; + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + + zipkin = new ZipkinEventNotifier(); + // we have one route as service + zipkin.addServiceMapping("seda:cat", "cat"); + // should auto configure as we have not setup a spanCollector + context.getManagementStrategy().addEventNotifier(zipkin); + + return context; + } + + @Test + public void testZipkinRoute() throws Exception { + template.requestBody("direct:start", "Hello Cat"); + } + + @Override + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").to("seda:cat"); + + from("seda:cat").routeId("cat") + .log("routing at ${routeId}") + .delay(simple("${random(1000,2000)}")); + } + }; + } +}