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/7153f3c3 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/7153f3c3 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/7153f3c3 Branch: refs/heads/master Commit: 7153f3c3fcee3a653ecc0572a3790e918415df98 Parents: 70ff21b Author: Claus Ibsen <davscl...@apache.org> Authored: Tue Mar 29 13:33:39 2016 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Tue Mar 29 14:41:54 2016 +0200 ---------------------------------------------------------------------- .../zipkin/ZipkinClientRequestAdapter.java | 30 ++++++++++--- .../zipkin/ZipkinClientResponseAdaptor.java | 42 ++++++++++++++--- .../camel/zipkin/ZipkinEventNotifier.java | 37 +++++++++++---- .../zipkin/ZipkinServerRequestAdapter.java | 30 ++++++++++--- .../zipkin/ZipkinServerResponseAdapter.java | 47 +++++++++++++++++--- .../zipkin/scribe/ZipkinTwoRouteScribe.java | 8 +++- .../src/test/resources/log4j.properties | 2 +- 7 files changed, 161 insertions(+), 35 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/7153f3c3/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinClientRequestAdapter.java ---------------------------------------------------------------------- diff --git a/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinClientRequestAdapter.java b/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinClientRequestAdapter.java index b3c80b1..824d58d 100644 --- a/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinClientRequestAdapter.java +++ b/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinClientRequestAdapter.java @@ -16,8 +16,10 @@ */ package org.apache.camel.zipkin; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.List; import java.util.Locale; import com.github.kristofa.brave.ClientRequestAdapter; @@ -27,17 +29,20 @@ import com.github.kristofa.brave.SpanId; import com.github.kristofa.brave.internal.Nullable; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; +import org.apache.camel.util.MessageHelper; import org.apache.camel.util.URISupport; public final class ZipkinClientRequestAdapter implements ClientRequestAdapter { + private final ZipkinEventNotifier eventNotifier; private final String serviceName; private final Exchange exchange; private final Endpoint endpoint; private final String spanName; private final String url; - public ZipkinClientRequestAdapter(String serviceName, Exchange exchange, Endpoint endpoint) { + public ZipkinClientRequestAdapter(ZipkinEventNotifier eventNotifier, String serviceName, Exchange exchange, Endpoint endpoint) { + this.eventNotifier = eventNotifier; this.serviceName = serviceName; this.exchange = exchange; this.endpoint = endpoint; @@ -66,12 +71,23 @@ public final class ZipkinClientRequestAdapter implements ClientRequestAdapter { @Override public Collection<KeyValueAnnotation> requestAnnotations() { - String id = exchange.getExchangeId(); - String mep = exchange.getPattern().name(); - KeyValueAnnotation key1 = KeyValueAnnotation.create("camel.client.endpoint.url", url); - KeyValueAnnotation key2 = KeyValueAnnotation.create("camel.client.exchange.id", id); - KeyValueAnnotation key3 = KeyValueAnnotation.create("camel.client.exchange.pattern", mep); - return Arrays.asList(key1, key2, key3); + KeyValueAnnotation key2 = KeyValueAnnotation.create("camel.client.exchange.id", exchange.getExchangeId()); + KeyValueAnnotation key3 = KeyValueAnnotation.create("camel.client.exchange.pattern", exchange.getPattern().name()); + + KeyValueAnnotation key4 = null; + if (eventNotifier.isIncludeMessageBody()) { + String body = MessageHelper.extractBodyForLogging(exchange.hasOut() ? exchange.getOut() : exchange.getIn(), ""); + key4 = KeyValueAnnotation.create("camel.client.exchange.message.request.body", body); + } + + List<KeyValueAnnotation> list = new ArrayList<>(); + list.add(key1); + list.add(key2); + list.add(key3); + if (key4 != null) { + list.add(key4); + } + return list; } } http://git-wip-us.apache.org/repos/asf/camel/blob/7153f3c3/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinClientResponseAdaptor.java ---------------------------------------------------------------------- diff --git a/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinClientResponseAdaptor.java b/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinClientResponseAdaptor.java index 296c021..8885ecd 100644 --- a/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinClientResponseAdaptor.java +++ b/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinClientResponseAdaptor.java @@ -16,30 +16,62 @@ */ package org.apache.camel.zipkin; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.List; import com.github.kristofa.brave.ClientResponseAdapter; import com.github.kristofa.brave.KeyValueAnnotation; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; +import org.apache.camel.util.MessageHelper; +import org.apache.camel.util.URISupport; public class ZipkinClientResponseAdaptor implements ClientResponseAdapter { + private final ZipkinEventNotifier eventNotifier; private final Exchange exchange; private final Endpoint endpoint; + private final String url; - public ZipkinClientResponseAdaptor(Exchange exchange, Endpoint endpoint) { + public ZipkinClientResponseAdaptor(ZipkinEventNotifier eventNotifier, Exchange exchange, Endpoint endpoint) { + this.eventNotifier = eventNotifier; this.exchange = exchange; this.endpoint = endpoint; + this.url = URISupport.sanitizeUri(endpoint.getEndpointUri()); } @Override public Collection<KeyValueAnnotation> responseAnnotations() { - if (exchange.getException() != null) { - return Collections.singletonList(KeyValueAnnotation.create("camel.failure", exchange.getException().getMessage())); - } else { - return Collections.emptyList(); + KeyValueAnnotation key1 = KeyValueAnnotation.create("camel.client.endpoint.url", url); + KeyValueAnnotation key2 = KeyValueAnnotation.create("camel.client.exchange.id", exchange.getExchangeId()); + KeyValueAnnotation key3 = KeyValueAnnotation.create("camel.client.exchange.pattern", exchange.getPattern().name()); + + KeyValueAnnotation key4 = null; + if (eventNotifier.isIncludeMessageBody()) { + String body = MessageHelper.extractBodyForLogging(exchange.hasOut() ? exchange.getOut() : exchange.getIn(), ""); + key4 = KeyValueAnnotation.create("camel.client.exchange.message.response.body", body); + } + + KeyValueAnnotation key5 = null; + // lets capture http response code for http based components + String responseCode = exchange.hasOut() ? exchange.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE, String.class) : exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, String.class); + if (responseCode != null) { + key5 = KeyValueAnnotation.create("camel.client.exchange.message.response.code", responseCode); + } + + List<KeyValueAnnotation> list = new ArrayList<>(); + list.add(key1); + list.add(key2); + list.add(key3); + if (key4 != null) { + list.add(key4); + } + if (key5 != null) { + list.add(key5); } + return list; } } http://git-wip-us.apache.org/repos/asf/camel/blob/7153f3c3/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 b8301e9..d06985a 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 @@ -31,6 +31,9 @@ import com.twitter.zipkin.gen.Span; import org.apache.camel.CamelContext; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; +import org.apache.camel.StatefulService; +import org.apache.camel.api.management.ManagedAttribute; +import org.apache.camel.api.management.ManagedResource; import org.apache.camel.management.event.ExchangeCompletedEvent; import org.apache.camel.management.event.ExchangeCreatedEvent; import org.apache.camel.management.event.ExchangeFailedEvent; @@ -58,12 +61,14 @@ import static org.apache.camel.builder.ExpressionBuilder.routeIdExpression; * <p/> * At least one mapping must be configured, you can use <tt>*</tt> to match all incoming and outgoing messages. */ -public class ZipkinEventNotifier extends EventNotifierSupport { +@ManagedResource(description = "Managing ZipkinEventNotifier") +public class ZipkinEventNotifier extends EventNotifierSupport implements StatefulService { private float rate = 1.0f; private SpanCollector spanCollector; private Map<String, String> serviceMappings = new HashMap<>(); private Map<String, Brave> braves = new HashMap<>(); + private boolean includeMessageBody; public ZipkinEventNotifier() { } @@ -123,6 +128,22 @@ public class ZipkinEventNotifier extends EventNotifierSupport { serviceMappings.put(pattern, serviceName); } + @ManagedAttribute(description = "Whether to include the Camel message body in the zipkin traces") + public boolean isIncludeMessageBody() { + return includeMessageBody; + } + + /** + * Whether to include the Camel message body in the zipkin traces. + * <p/> + * This is not recommended for production usage, or when having big payloads. You can limit the size by + * configuring the <a href="http://camel.apache.org/how-do-i-set-the-max-chars-when-debug-logging-messages-in-camel.html">max debug log size</a>. + */ + @ManagedAttribute(description = "Whether to include the Camel message body in the zipkin traces") + public void setIncludeMessageBody(boolean includeMessageBody) { + this.includeMessageBody = includeMessageBody; + } + @Override protected void doStart() throws Exception { super.doStart(); @@ -276,7 +297,7 @@ public class ZipkinEventNotifier extends EventNotifierSupport { private void clientRequest(Brave brave, String serviceName, ExchangeSendingEvent event) { ClientSpanThreadBinder binder = brave.clientSpanThreadBinder(); - brave.clientRequestInterceptor().handle(new ZipkinClientRequestAdapter(serviceName, event.getExchange(), event.getEndpoint())); + brave.clientRequestInterceptor().handle(new ZipkinClientRequestAdapter(this, serviceName, event.getExchange(), event.getEndpoint())); Span span = binder.getCurrentClientSpan(); String key = "CamelZipkinClientSpan-" + serviceName; @@ -292,7 +313,7 @@ public class ZipkinEventNotifier extends EventNotifierSupport { String key = "CamelZipkinClientSpan-" + serviceName; Span span = event.getExchange().getProperty(key, Span.class); binder.setCurrentSpan(span); - brave.clientResponseInterceptor().handle(new ZipkinClientResponseAdaptor(event.getExchange(), event.getEndpoint())); + brave.clientResponseInterceptor().handle(new ZipkinClientResponseAdaptor(this, event.getExchange(), event.getEndpoint())); binder.setCurrentSpan(null); if (log.isDebugEnabled()) { @@ -302,7 +323,7 @@ public class ZipkinEventNotifier extends EventNotifierSupport { private void serverRequest(Brave brave, String serviceName, ExchangeCreatedEvent event) { ServerSpanThreadBinder binder = brave.serverSpanThreadBinder(); - brave.serverRequestInterceptor().handle(new ZipkinServerRequestAdapter(event.getExchange())); + brave.serverRequestInterceptor().handle(new ZipkinServerRequestAdapter(this, event.getExchange())); ServerSpan span = binder.getCurrentServerSpan(); String key = "CamelZipkinServerSpan-" + serviceName; event.getExchange().setProperty(key, span); @@ -317,11 +338,11 @@ public class ZipkinEventNotifier extends EventNotifierSupport { String key = "CamelZipkinServerSpan-" + serviceName; ServerSpan span = event.getExchange().getProperty(key, ServerSpan.class); binder.setCurrentSpan(span); - brave.serverResponseInterceptor().handle(new ZipkinServerResponseAdapter(event.getExchange())); + brave.serverResponseInterceptor().handle(new ZipkinServerResponseAdapter(this, event.getExchange())); binder.setCurrentSpan(null); if (log.isDebugEnabled()) { - log.debug("serverResponse: service={}, spanId={} ", serviceName, span != null ? span.getSpan().getId() : "<null>"); + log.debug("serverResponse[service={}, spanId={}, status=exchangeCompleted]", serviceName, span != null ? span.getSpan().getId() : "<null>"); } } @@ -330,11 +351,11 @@ public class ZipkinEventNotifier extends EventNotifierSupport { String key = "CamelZipkinServerSpan-" + serviceName; ServerSpan span = event.getExchange().getProperty(key, ServerSpan.class); binder.setCurrentSpan(span); - brave.serverResponseInterceptor().handle(new ZipkinServerResponseAdapter(event.getExchange())); + brave.serverResponseInterceptor().handle(new ZipkinServerResponseAdapter(this, event.getExchange())); binder.setCurrentSpan(null); if (log.isDebugEnabled()) { - log.debug("serverResponse[service={}, spanId={}]", serviceName, span != null ? span.getSpan().getId() : "<null>"); + log.debug("serverResponse[service={}, spanId={}, status=exchangeFailed]", serviceName, span != null ? span.getSpan().getId() : "<null>"); } } http://git-wip-us.apache.org/repos/asf/camel/blob/7153f3c3/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinServerRequestAdapter.java ---------------------------------------------------------------------- diff --git a/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinServerRequestAdapter.java b/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinServerRequestAdapter.java index 59c6b4f..6dc89a2 100644 --- a/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinServerRequestAdapter.java +++ b/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinServerRequestAdapter.java @@ -16,8 +16,10 @@ */ package org.apache.camel.zipkin; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.List; import java.util.Locale; import com.github.kristofa.brave.KeyValueAnnotation; @@ -26,18 +28,21 @@ import com.github.kristofa.brave.SpanId; import com.github.kristofa.brave.TraceData; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; +import org.apache.camel.util.MessageHelper; import org.apache.camel.util.URISupport; import static org.apache.camel.zipkin.ZipkinHelper.getSpanId; public class ZipkinServerRequestAdapter implements ServerRequestAdapter { + private final ZipkinEventNotifier eventNotifier; private final Exchange exchange; private final Endpoint endpoint; private final String spanName; private final String url; - public ZipkinServerRequestAdapter(Exchange exchange) { + public ZipkinServerRequestAdapter(ZipkinEventNotifier eventNotifier, Exchange exchange) { + this.eventNotifier = eventNotifier; this.exchange = exchange; this.endpoint = exchange.getFromEndpoint(); this.spanName = URISupport.sanitizeUri(endpoint.getEndpointKey()).toLowerCase(Locale.US); @@ -64,13 +69,24 @@ public class ZipkinServerRequestAdapter implements ServerRequestAdapter { @Override public Collection<KeyValueAnnotation> requestAnnotations() { - String id = exchange.getExchangeId(); - String mep = exchange.getPattern().name(); - KeyValueAnnotation key1 = KeyValueAnnotation.create("camel.server.endpoint.url", url); - KeyValueAnnotation key2 = KeyValueAnnotation.create("camel.server.exchange.id", id); - KeyValueAnnotation key3 = KeyValueAnnotation.create("camel.server.exchange.pattern", mep); - return Arrays.asList(key1, key2, key3); + KeyValueAnnotation key2 = KeyValueAnnotation.create("camel.server.exchange.id", exchange.getExchangeId()); + KeyValueAnnotation key3 = KeyValueAnnotation.create("camel.server.exchange.pattern", exchange.getPattern().name()); + + KeyValueAnnotation key4 = null; + if (eventNotifier.isIncludeMessageBody()) { + String body = MessageHelper.extractBodyForLogging(exchange.hasOut() ? exchange.getOut() : exchange.getIn(), ""); + key4 = KeyValueAnnotation.create("camel.server.exchange.message.request.body", body); + } + + List<KeyValueAnnotation> list = new ArrayList<>(); + list.add(key1); + list.add(key2); + list.add(key3); + if (key4 != null) { + list.add(key4); + } + return list; } } http://git-wip-us.apache.org/repos/asf/camel/blob/7153f3c3/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinServerResponseAdapter.java ---------------------------------------------------------------------- diff --git a/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinServerResponseAdapter.java b/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinServerResponseAdapter.java index 0a7035c..3c33a12 100644 --- a/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinServerResponseAdapter.java +++ b/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinServerResponseAdapter.java @@ -16,30 +16,67 @@ */ package org.apache.camel.zipkin; +import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; +import java.util.List; import com.github.kristofa.brave.KeyValueAnnotation; import com.github.kristofa.brave.ServerResponseAdapter; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; +import org.apache.camel.util.MessageHelper; +import org.apache.camel.util.URISupport; public class ZipkinServerResponseAdapter implements ServerResponseAdapter { + private final ZipkinEventNotifier eventNotifier; private final Exchange exchange; private final Endpoint endpoint; + private final String url; - public ZipkinServerResponseAdapter(Exchange exchange) { + public ZipkinServerResponseAdapter(ZipkinEventNotifier eventNotifier, Exchange exchange) { + this.eventNotifier = eventNotifier; this.exchange = exchange; this.endpoint = exchange.getFromEndpoint(); + this.url = URISupport.sanitizeUri(endpoint.getEndpointUri()); } @Override public Collection<KeyValueAnnotation> responseAnnotations() { + String id = exchange.getExchangeId(); + String mep = exchange.getPattern().name(); + + KeyValueAnnotation key1 = KeyValueAnnotation.create("camel.server.endpoint.url", url); + KeyValueAnnotation key2 = KeyValueAnnotation.create("camel.server.exchange.id", id); + KeyValueAnnotation key3 = KeyValueAnnotation.create("camel.server.exchange.pattern", mep); + + KeyValueAnnotation key4 = null; if (exchange.getException() != null) { - return Collections.singletonList(KeyValueAnnotation.create("camel.server.failure", exchange.getException().getMessage())); - } else { - return Collections.emptyList(); + String message = exchange.getException().getMessage(); + key4 = KeyValueAnnotation.create("camel.server.exchange.failure", message); + } else if (eventNotifier.isIncludeMessageBody()) { + String body = MessageHelper.extractBodyForLogging(exchange.hasOut() ? exchange.getOut() : exchange.getIn(), ""); + key4 = KeyValueAnnotation.create("camel.server.exchange.message.response.body", body); + } + + KeyValueAnnotation key5 = null; + // lets capture http response code for http based components + String responseCode = exchange.hasOut() ? exchange.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE, String.class) : exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, String.class); + if (responseCode != null) { + key5 = KeyValueAnnotation.create("camel.server.exchange.message.response.code", responseCode); } + + List<KeyValueAnnotation> list = new ArrayList<>(); + list.add(key1); + list.add(key2); + list.add(key3); + if (key4 != null) { + list.add(key4); + } + if (key5 != null) { + list.add(key5); + } + return list; } + } http://git-wip-us.apache.org/repos/asf/camel/blob/7153f3c3/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinTwoRouteScribe.java ---------------------------------------------------------------------- diff --git a/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinTwoRouteScribe.java b/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinTwoRouteScribe.java index 7e72c17..2c59bbc 100644 --- a/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinTwoRouteScribe.java +++ b/components/camel-zipkin/src/test/java/org/apache/camel/zipkin/scribe/ZipkinTwoRouteScribe.java @@ -45,6 +45,8 @@ public class ZipkinTwoRouteScribe extends CamelTestSupport { // we have 2 routes as services zipkin.addServiceMapping("seda:cat", "cat"); zipkin.addServiceMapping("seda:dog", "dog"); + // capture message body as well + zipkin.setIncludeMessageBody(true); zipkin.setSpanCollector(new ScribeSpanCollector(ip, 9410)); context.getManagementStrategy().addEventNotifier(zipkin); @@ -53,7 +55,7 @@ public class ZipkinTwoRouteScribe extends CamelTestSupport { @Test public void testZipkinRoute() throws Exception { - template.requestBody("direct:start", "Hello Cat and Dog"); + template.requestBody("direct:start", "Camel say hello Cat"); } @Override @@ -66,11 +68,13 @@ public class ZipkinTwoRouteScribe extends CamelTestSupport { from("seda:cat").routeId("cat") .log("routing at ${routeId}") .delay(simple("${random(1000,2000)}")) + .setBody().constant("Cat says hello Dog") .to("seda:dog"); from("seda:dog").routeId("dog") .log("routing at ${routeId}") - .delay(simple("${random(0,500)}")); + .delay(simple("${random(0,500)}")) + .setBody().constant("Dog say hello Cat and Camel"); } }; } http://git-wip-us.apache.org/repos/asf/camel/blob/7153f3c3/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