Adding cross boundaries extractor/injector
ADD
src/main/java/com/datadoghq/trace/Codec.java
+/*
+ * Copyright (c) 2016, Uber Technologies, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.datadoghq.trace;
+
+
+import com.datadoghq.trace.impl.DDSpanContext;
+
+public interface Codec<T> {
+
+ void inject(DDSpanContext context, T carrier);
+
+ DDSpanContext extract(T carrier);
+}

MODIFY
src/main/java/com/datadoghq/trace/impl/DDTracer.java
src/main/java/com/datadoghq/trace/impl/DDTracer.java
package com.datadoghq.trace.impl;
+import com.datadoghq.trace.Codec;
import com.datadoghq.trace.Sampler;
import com.datadoghq.trace.Writer;
+import com.datadoghq.trace.propagation.impl.HTTPCodec;
import com.datadoghq.trace.writer.impl.LoggingWritter;
import io.opentracing.Span;
import io.opentracing.SpanContext;
import io.opentracing.propagation.Format;
+import io.opentracing.propagation.TextMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -27,6 +30,8 @@ public class DDTracer implements io.opentracing.Tracer {
private final static Logger logger = LoggerFactory.getLogger(DDTracer.class);
+ private final CodecRegistry registry;
+ private HTTPCodec codec = new HTTPCodec();
/**
* Default constructor, trace/spans are logged, no trace/span dropped
@@ -38,20 +43,33 @@ public class DDTracer implements io.opentracing.Tracer {
public DDTracer(Writer writer, Sampler sampler) {
this.writer = writer;
this.sampler = sampler;
+ registry = new CodecRegistry();
+ registry.register(Format.Builtin.HTTP_HEADERS, new HTTPCodec());
}
public DDSpanBuilder buildSpan(String operationName) {
return new DDSpanBuilder(operationName);
}
- public <C> void inject(SpanContext spanContext, Format<C> format, C c) {
- //FIXME Implement it ASAP
- logger.warn("Method `inject` not implemented yet");
+
+ public <T> void inject(SpanContext spanContext, Format<T> format, T carrier) {
+
+ Codec<T> codec = registry.get(format);
+ if (codec == null) {
+ logger.warn("Unsupported format for propagation - {}", format.getClass().getName());
+ } else {
+ codec.inject((DDSpanContext) spanContext, carrier);
}
+ }
+
+ public <T> SpanContext extract(Format<T> format, T carrier) {
- public <C> SpanContext extract(Format<C> format, C c) {
- //FIXME Implement it ASAP
- logger.warn("Method `inject` not implemented yet");
+ Codec<T> codec = registry.get(format);
+ if (codec == null) {
+ logger.warn("Unsupported format for propagation - {}", format.getClass().getName());
+ } else {
+ return codec.extract(carrier);
+ }
return null;
}
@@ -233,6 +251,20 @@ public class DDTracer implements io.opentracing.Tracer {
}
+ private static class CodecRegistry {
+
+ private final Map<Format<?>, Codec<?>> codecs = new HashMap<Format<?>, Codec<?>>();
+
+ <T> Codec<T> get(Format<T> format) {
+ return (Codec<T>) codecs.get(format);
+ }
+
+ public <T> void register(Format<T> format, Codec<T> codec) {
+ codecs.put(format, codec);
+ }
+
+ }
+
@Override
public String toString() {
return "DDTracer{" +

ADD
src/main/java/com/datadoghq/trace/propagation/impl/HTTPCodec.java
+package com.datadoghq.trace.propagation.impl;
+
+import com.datadoghq.trace.Codec;
+import com.datadoghq.trace.impl.DDSpanContext;
+import io.opentracing.propagation.TextMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class HTTPCodec implements Codec<TextMap> {
+
+ private static final String OT_PREFIX = "ot-tracer-";
+ private static final String OT_BAGGAGE_PREFIX = "ot-baggage-";
+ private static final String TRACE_ID_KEY = OT_PREFIX + "traceid";
+ private static final String SPAN_ID_KEY = OT_PREFIX + "spanid";
+
+ private static final Logger logger = LoggerFactory.getLogger(HTTPCodec.class);
+
+ @Override
+ public void inject(DDSpanContext context, TextMap carrier) {
+
+ carrier.put(TRACE_ID_KEY, String.valueOf(context.getTraceId()));
+ carrier.put(SPAN_ID_KEY, String.valueOf(context.getSpanId()));
+
+ for (Map.Entry<String, String> entry : context.baggageItems()) {
+ carrier.put(OT_BAGGAGE_PREFIX + entry.getKey(), encode(entry.getValue()));
+ }
+ }
+
+
+
+ @Override
+ public DDSpanContext extract(TextMap carrier) {
+
+ Map<String, String> baggage = Collections.emptyMap();
+ Long traceId = 0L;
+ Long spanId = 0L;
+
+ for (Map.Entry<String, String> entry : carrier) {
+
+ if (entry.getKey().equals(TRACE_ID_KEY)) {
+ traceId = Long.parseLong(entry.getValue());
+ } else if (entry.getKey().equals(SPAN_ID_KEY)) {
+ spanId = Long.parseLong(entry.getValue());
+ } else if (entry.getKey().startsWith(OT_BAGGAGE_PREFIX)) {
+ if (baggage.isEmpty()) {
+ baggage = new HashMap<String, String>();
+ }
+ baggage.put(entry.getKey(), decode(entry.getValue()));
+ }
+ }
+ DDSpanContext context = null;
+ if (traceId != 0L) {
+
+ context = new DDSpanContext(
+ traceId,
+ spanId,
+ 0L,
+ null,
+ null,
+ null,
+ baggage,
+ false,
+ null,
+ null,
+ null,
+ null);
+
+ logger.debug("{} - Parent context extracted", context);
+
+ }
+
+ return context;
+ }
+
+
+ private String encode(String value) {
+ String encoded = value;
+ try {
+ encoded = URLEncoder.encode(value, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ logger.info("Failed to encode value - {}", value);
+ }
+ return encoded;
+ }
+
+ private String decode(String value) {
+ String decoded = value;
+ try {
+ decoded = URLDecoder.decode(value, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ logger.info("Failed to decode value - {}", value);
+ }
+ return decoded;
+ }
+
+}

Adding cross boundaries extractor/injector