Remove codec for inject/extract
In preparation for OT 0.32 support.
This commit is contained in:
parent
7a430647a0
commit
326577d7df
|
@ -2,9 +2,8 @@ package datadog.opentracing;
|
||||||
|
|
||||||
import datadog.opentracing.decorators.AbstractDecorator;
|
import datadog.opentracing.decorators.AbstractDecorator;
|
||||||
import datadog.opentracing.decorators.DDDecoratorsFactory;
|
import datadog.opentracing.decorators.DDDecoratorsFactory;
|
||||||
import datadog.opentracing.propagation.Codec;
|
import datadog.opentracing.propagation.DatadogHttpCodec;
|
||||||
import datadog.opentracing.propagation.ExtractedContext;
|
import datadog.opentracing.propagation.ExtractedContext;
|
||||||
import datadog.opentracing.propagation.HTTPCodec;
|
|
||||||
import datadog.opentracing.propagation.TagContext;
|
import datadog.opentracing.propagation.TagContext;
|
||||||
import datadog.opentracing.scopemanager.ContextualScopeManager;
|
import datadog.opentracing.scopemanager.ContextualScopeManager;
|
||||||
import datadog.opentracing.scopemanager.ScopeContext;
|
import datadog.opentracing.scopemanager.ScopeContext;
|
||||||
|
@ -24,6 +23,7 @@ import io.opentracing.ScopeManager;
|
||||||
import io.opentracing.Span;
|
import io.opentracing.Span;
|
||||||
import io.opentracing.SpanContext;
|
import io.opentracing.SpanContext;
|
||||||
import io.opentracing.propagation.Format;
|
import io.opentracing.propagation.Format;
|
||||||
|
import io.opentracing.propagation.TextMap;
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -84,7 +84,9 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
|
||||||
return Integer.compare(o1.priority(), o2.priority());
|
return Integer.compare(o1.priority(), o2.priority());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
private final CodecRegistry registry;
|
|
||||||
|
private final DatadogHttpCodec.Injector injector;
|
||||||
|
private final DatadogHttpCodec.Extractor extractor;
|
||||||
|
|
||||||
private final AtomicInteger traceCount;
|
private final AtomicInteger traceCount;
|
||||||
|
|
||||||
|
@ -238,9 +240,9 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
|
||||||
// The JVM is already shutting down.
|
// The JVM is already shutting down.
|
||||||
}
|
}
|
||||||
|
|
||||||
registry = new CodecRegistry();
|
injector = new DatadogHttpCodec.Injector();
|
||||||
registry.register(Format.Builtin.HTTP_HEADERS, new HTTPCodec(taggedHeaders));
|
extractor = new DatadogHttpCodec.Extractor(taggedHeaders);
|
||||||
registry.register(Format.Builtin.TEXT_MAP, new HTTPCodec(taggedHeaders));
|
|
||||||
if (this.writer instanceof DDAgentWriter) {
|
if (this.writer instanceof DDAgentWriter) {
|
||||||
final DDApi api = ((DDAgentWriter) this.writer).getApi();
|
final DDApi api = ((DDAgentWriter) this.writer).getApi();
|
||||||
traceCount = api.getTraceCounter();
|
traceCount = api.getTraceCounter();
|
||||||
|
@ -332,24 +334,21 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> void inject(final SpanContext spanContext, final Format<T> format, final T carrier) {
|
public <T> void inject(final SpanContext spanContext, final Format<T> format, final T carrier) {
|
||||||
|
if (!(carrier instanceof TextMap)) {
|
||||||
final Codec<T> codec = registry.get(format);
|
|
||||||
if (codec == null) {
|
|
||||||
log.debug("Unsupported format for propagation - {}", format.getClass().getName());
|
log.debug("Unsupported format for propagation - {}", format.getClass().getName());
|
||||||
} else {
|
} else {
|
||||||
codec.inject((DDSpanContext) spanContext, carrier);
|
injector.inject((DDSpanContext) spanContext, (TextMap) carrier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> SpanContext extract(final Format<T> format, final T carrier) {
|
public <T> SpanContext extract(final Format<T> format, final T carrier) {
|
||||||
final Codec<T> codec = registry.get(format);
|
if (!(carrier instanceof TextMap)) {
|
||||||
if (codec == null) {
|
|
||||||
log.debug("Unsupported format for propagation - {}", format.getClass().getName());
|
log.debug("Unsupported format for propagation - {}", format.getClass().getName());
|
||||||
} else {
|
|
||||||
return codec.extract(carrier);
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
|
} else {
|
||||||
|
return extractor.extract((TextMap) carrier);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -452,19 +451,6 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
|
||||||
return Config.get().getPartialFlushMinSpans();
|
return Config.get().getPartialFlushMinSpans();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class CodecRegistry {
|
|
||||||
|
|
||||||
private final Map<Format<?>, Codec<?>> codecs = new HashMap<>();
|
|
||||||
|
|
||||||
<T> Codec<T> get(final Format<T> format) {
|
|
||||||
return (Codec<T>) codecs.get(format);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> void register(final Format<T> format, final Codec<T> codec) {
|
|
||||||
codecs.put(format, codec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Spans are built using this builder */
|
/** Spans are built using this builder */
|
||||||
public class DDSpanBuilder implements SpanBuilder {
|
public class DDSpanBuilder implements SpanBuilder {
|
||||||
private final ScopeManager scopeManager;
|
private final ScopeManager scopeManager;
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 datadog.opentracing.propagation;
|
|
||||||
|
|
||||||
import datadog.opentracing.DDSpanContext;
|
|
||||||
import io.opentracing.SpanContext;
|
|
||||||
|
|
||||||
/** A codec is a simple object that can encode and decode a span context through a carrier */
|
|
||||||
public interface Codec<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize the span context using the provided carrier
|
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* @param carrier
|
|
||||||
*/
|
|
||||||
void inject(DDSpanContext context, T carrier);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a carrier, retrieve (rebuild) a span context. This context built will be use as the
|
|
||||||
* parent
|
|
||||||
*
|
|
||||||
* @param carrier
|
|
||||||
* @return the span context
|
|
||||||
*/
|
|
||||||
SpanContext extract(T carrier);
|
|
||||||
}
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
package datadog.opentracing.propagation;
|
||||||
|
|
||||||
|
import datadog.opentracing.DDSpanContext;
|
||||||
|
import datadog.trace.api.sampling.PrioritySampling;
|
||||||
|
import io.opentracing.SpanContext;
|
||||||
|
import io.opentracing.propagation.TextMap;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/** A codec designed for HTTP transport via headers */
|
||||||
|
@Slf4j
|
||||||
|
public class DatadogHttpCodec {
|
||||||
|
|
||||||
|
// uint 64 bits max value, 2^64 - 1
|
||||||
|
static final BigInteger BIG_INTEGER_UINT64_MAX =
|
||||||
|
new BigInteger("2").pow(64).subtract(BigInteger.ONE);
|
||||||
|
|
||||||
|
private static final String OT_BAGGAGE_PREFIX = "ot-baggage-";
|
||||||
|
private static final String TRACE_ID_KEY = "x-datadog-trace-id";
|
||||||
|
private static final String SPAN_ID_KEY = "x-datadog-parent-id";
|
||||||
|
private static final String SAMPLING_PRIORITY_KEY = "x-datadog-sampling-priority";
|
||||||
|
|
||||||
|
public static class Injector {
|
||||||
|
|
||||||
|
public void inject(final DDSpanContext context, final TextMap carrier) {
|
||||||
|
carrier.put(TRACE_ID_KEY, String.valueOf(context.getTraceId()));
|
||||||
|
carrier.put(SPAN_ID_KEY, String.valueOf(context.getSpanId()));
|
||||||
|
if (context.lockSamplingPriority()) {
|
||||||
|
carrier.put(SAMPLING_PRIORITY_KEY, String.valueOf(context.getSamplingPriority()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final Map.Entry<String, String> entry : context.baggageItems()) {
|
||||||
|
carrier.put(OT_BAGGAGE_PREFIX + entry.getKey(), encode(entry.getValue()));
|
||||||
|
}
|
||||||
|
log.debug("{} - Parent context injected", context.getTraceId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String encode(final String value) {
|
||||||
|
String encoded = value;
|
||||||
|
try {
|
||||||
|
encoded = URLEncoder.encode(value, "UTF-8");
|
||||||
|
} catch (final UnsupportedEncodingException e) {
|
||||||
|
log.info("Failed to encode value - {}", value);
|
||||||
|
}
|
||||||
|
return encoded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Extractor {
|
||||||
|
private final Map<String, String> taggedHeaders;
|
||||||
|
|
||||||
|
public Extractor(final Map<String, String> taggedHeaders) {
|
||||||
|
this.taggedHeaders = new HashMap<>();
|
||||||
|
for (final Map.Entry<String, String> mapping : taggedHeaders.entrySet()) {
|
||||||
|
this.taggedHeaders.put(mapping.getKey().trim().toLowerCase(), mapping.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpanContext extract(final TextMap carrier) {
|
||||||
|
|
||||||
|
Map<String, String> baggage = Collections.emptyMap();
|
||||||
|
Map<String, String> tags = Collections.emptyMap();
|
||||||
|
String traceId = "0";
|
||||||
|
String spanId = "0";
|
||||||
|
int samplingPriority = PrioritySampling.UNSET;
|
||||||
|
|
||||||
|
for (final Map.Entry<String, String> entry : carrier) {
|
||||||
|
final String key = entry.getKey().toLowerCase();
|
||||||
|
final String val = entry.getValue();
|
||||||
|
|
||||||
|
if (val == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TRACE_ID_KEY.equalsIgnoreCase(key)) {
|
||||||
|
traceId = validateUInt64BitsID(val);
|
||||||
|
} else if (SPAN_ID_KEY.equalsIgnoreCase(key)) {
|
||||||
|
spanId = validateUInt64BitsID(val);
|
||||||
|
} else if (key.startsWith(OT_BAGGAGE_PREFIX)) {
|
||||||
|
if (baggage.isEmpty()) {
|
||||||
|
baggage = new HashMap<>();
|
||||||
|
}
|
||||||
|
baggage.put(key.replace(OT_BAGGAGE_PREFIX, ""), decode(val));
|
||||||
|
} else if (SAMPLING_PRIORITY_KEY.equalsIgnoreCase(key)) {
|
||||||
|
samplingPriority = Integer.parseInt(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (taggedHeaders.containsKey(key)) {
|
||||||
|
if (tags.isEmpty()) {
|
||||||
|
tags = new HashMap<>();
|
||||||
|
}
|
||||||
|
tags.put(taggedHeaders.get(key), decode(val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpanContext context = null;
|
||||||
|
if (!"0".equals(traceId)) {
|
||||||
|
final ExtractedContext ctx =
|
||||||
|
new ExtractedContext(traceId, spanId, samplingPriority, baggage, tags);
|
||||||
|
ctx.lockSamplingPriority();
|
||||||
|
|
||||||
|
log.debug("{} - Parent context extracted", ctx.getTraceId());
|
||||||
|
context = ctx;
|
||||||
|
} else if (!tags.isEmpty()) {
|
||||||
|
context = new TagContext(tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String decode(final String value) {
|
||||||
|
String decoded = value;
|
||||||
|
try {
|
||||||
|
decoded = URLDecoder.decode(value, "UTF-8");
|
||||||
|
} catch (final UnsupportedEncodingException e) {
|
||||||
|
log.info("Failed to decode value - {}", value);
|
||||||
|
}
|
||||||
|
return decoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to validate an ID String to verify that it is an unsigned 64 bits number and is
|
||||||
|
* within range.
|
||||||
|
*
|
||||||
|
* @param val the String that contains the ID
|
||||||
|
* @return the ID in String format if it passes validations
|
||||||
|
* @throws IllegalArgumentException if val is not a number or if the number is out of range
|
||||||
|
*/
|
||||||
|
private String validateUInt64BitsID(final String val) throws IllegalArgumentException {
|
||||||
|
try {
|
||||||
|
final BigInteger validate = new BigInteger(val);
|
||||||
|
if (validate.compareTo(BigInteger.ZERO) == -1
|
||||||
|
|| validate.compareTo(BIG_INTEGER_UINT64_MAX) == 1) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"ID out of range, must be between 0 and 2^64-1, got: " + val);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
} catch (final NumberFormatException nfe) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Expecting a number for trace ID or span ID, but got: " + val, nfe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,147 +0,0 @@
|
||||||
package datadog.opentracing.propagation;
|
|
||||||
|
|
||||||
import datadog.opentracing.DDSpanContext;
|
|
||||||
import datadog.trace.api.sampling.PrioritySampling;
|
|
||||||
import io.opentracing.SpanContext;
|
|
||||||
import io.opentracing.propagation.TextMap;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
/** A codec designed for HTTP transport via headers */
|
|
||||||
@Slf4j
|
|
||||||
public class HTTPCodec implements Codec<TextMap> {
|
|
||||||
|
|
||||||
// uint 64 bits max value, 2^64 - 1
|
|
||||||
static final BigInteger BIG_INTEGER_UINT64_MAX =
|
|
||||||
new BigInteger("2").pow(64).subtract(BigInteger.ONE);
|
|
||||||
|
|
||||||
private static final String OT_BAGGAGE_PREFIX = "ot-baggage-";
|
|
||||||
private static final String TRACE_ID_KEY = "x-datadog-trace-id";
|
|
||||||
private static final String SPAN_ID_KEY = "x-datadog-parent-id";
|
|
||||||
private static final String SAMPLING_PRIORITY_KEY = "x-datadog-sampling-priority";
|
|
||||||
|
|
||||||
private final Map<String, String> taggedHeaders;
|
|
||||||
|
|
||||||
public HTTPCodec(final Map<String, String> taggedHeaders) {
|
|
||||||
this.taggedHeaders = new HashMap<>();
|
|
||||||
for (final Map.Entry<String, String> mapping : taggedHeaders.entrySet()) {
|
|
||||||
this.taggedHeaders.put(mapping.getKey().trim().toLowerCase(), mapping.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void inject(final DDSpanContext context, final TextMap carrier) {
|
|
||||||
carrier.put(TRACE_ID_KEY, String.valueOf(context.getTraceId()));
|
|
||||||
carrier.put(SPAN_ID_KEY, String.valueOf(context.getSpanId()));
|
|
||||||
if (context.lockSamplingPriority()) {
|
|
||||||
carrier.put(SAMPLING_PRIORITY_KEY, String.valueOf(context.getSamplingPriority()));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (final Map.Entry<String, String> entry : context.baggageItems()) {
|
|
||||||
carrier.put(OT_BAGGAGE_PREFIX + entry.getKey(), encode(entry.getValue()));
|
|
||||||
}
|
|
||||||
log.debug("{} - Parent context injected", context.getTraceId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SpanContext extract(final TextMap carrier) {
|
|
||||||
|
|
||||||
Map<String, String> baggage = Collections.emptyMap();
|
|
||||||
Map<String, String> tags = Collections.emptyMap();
|
|
||||||
String traceId = "0";
|
|
||||||
String spanId = "0";
|
|
||||||
int samplingPriority = PrioritySampling.UNSET;
|
|
||||||
|
|
||||||
for (final Map.Entry<String, String> entry : carrier) {
|
|
||||||
final String key = entry.getKey().toLowerCase();
|
|
||||||
final String val = entry.getValue();
|
|
||||||
|
|
||||||
if (val == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TRACE_ID_KEY.equalsIgnoreCase(key)) {
|
|
||||||
traceId = validateUInt64BitsID(val);
|
|
||||||
} else if (SPAN_ID_KEY.equalsIgnoreCase(key)) {
|
|
||||||
spanId = validateUInt64BitsID(val);
|
|
||||||
} else if (key.startsWith(OT_BAGGAGE_PREFIX)) {
|
|
||||||
if (baggage.isEmpty()) {
|
|
||||||
baggage = new HashMap<>();
|
|
||||||
}
|
|
||||||
baggage.put(key.replace(OT_BAGGAGE_PREFIX, ""), decode(val));
|
|
||||||
} else if (SAMPLING_PRIORITY_KEY.equalsIgnoreCase(key)) {
|
|
||||||
samplingPriority = Integer.parseInt(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (taggedHeaders.containsKey(key)) {
|
|
||||||
if (tags.isEmpty()) {
|
|
||||||
tags = new HashMap<>();
|
|
||||||
}
|
|
||||||
tags.put(taggedHeaders.get(key), decode(val));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SpanContext context = null;
|
|
||||||
if (!"0".equals(traceId)) {
|
|
||||||
final ExtractedContext ctx =
|
|
||||||
new ExtractedContext(traceId, spanId, samplingPriority, baggage, tags);
|
|
||||||
ctx.lockSamplingPriority();
|
|
||||||
|
|
||||||
log.debug("{} - Parent context extracted", ctx.getTraceId());
|
|
||||||
context = ctx;
|
|
||||||
} else if (!tags.isEmpty()) {
|
|
||||||
context = new TagContext(tags);
|
|
||||||
}
|
|
||||||
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String encode(final String value) {
|
|
||||||
String encoded = value;
|
|
||||||
try {
|
|
||||||
encoded = URLEncoder.encode(value, "UTF-8");
|
|
||||||
} catch (final UnsupportedEncodingException e) {
|
|
||||||
log.info("Failed to encode value - {}", value);
|
|
||||||
}
|
|
||||||
return encoded;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String decode(final String value) {
|
|
||||||
String decoded = value;
|
|
||||||
try {
|
|
||||||
decoded = URLDecoder.decode(value, "UTF-8");
|
|
||||||
} catch (final UnsupportedEncodingException e) {
|
|
||||||
log.info("Failed to decode value - {}", value);
|
|
||||||
}
|
|
||||||
return decoded;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method to validate an ID String to verify that it is an unsigned 64 bits number and is
|
|
||||||
* within range.
|
|
||||||
*
|
|
||||||
* @param val the String that contains the ID
|
|
||||||
* @return the ID in String format if it passes validations
|
|
||||||
* @throws IllegalArgumentException if val is not a number or if the number is out of range
|
|
||||||
*/
|
|
||||||
private String validateUInt64BitsID(final String val) throws IllegalArgumentException {
|
|
||||||
try {
|
|
||||||
final BigInteger validate = new BigInteger(val);
|
|
||||||
if (validate.compareTo(BigInteger.ZERO) == -1
|
|
||||||
|| validate.compareTo(BIG_INTEGER_UINT64_MAX) == 1) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"ID out of range, must be between 0 and 2^64-1, got: " + val);
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
} catch (final NumberFormatException nfe) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Expecting a number for trace ID or span ID, but got: " + val, nfe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,160 +1,18 @@
|
||||||
package datadog.opentracing.propagation
|
package datadog.opentracing.propagation
|
||||||
|
|
||||||
import datadog.opentracing.DDSpanContext
|
|
||||||
import datadog.opentracing.DDTracer
|
|
||||||
import datadog.opentracing.PendingTrace
|
|
||||||
import datadog.trace.api.sampling.PrioritySampling
|
import datadog.trace.api.sampling.PrioritySampling
|
||||||
import datadog.trace.common.writer.ListWriter
|
|
||||||
import io.opentracing.propagation.TextMapExtractAdapter
|
import io.opentracing.propagation.TextMapExtractAdapter
|
||||||
import io.opentracing.propagation.TextMapInjectAdapter
|
|
||||||
import spock.lang.Shared
|
|
||||||
import spock.lang.Specification
|
import spock.lang.Specification
|
||||||
|
|
||||||
import static datadog.opentracing.propagation.HTTPCodec.BIG_INTEGER_UINT64_MAX
|
import static datadog.opentracing.propagation.DatadogHttpCodec.BIG_INTEGER_UINT64_MAX
|
||||||
|
import static datadog.opentracing.propagation.DatadogHttpCodec.OT_BAGGAGE_PREFIX
|
||||||
|
import static datadog.opentracing.propagation.DatadogHttpCodec.SAMPLING_PRIORITY_KEY
|
||||||
|
import static datadog.opentracing.propagation.DatadogHttpCodec.SPAN_ID_KEY
|
||||||
|
import static datadog.opentracing.propagation.DatadogHttpCodec.TRACE_ID_KEY
|
||||||
|
|
||||||
class HTTPCodecTest extends Specification {
|
class DatadogHttpExtractorTest extends Specification {
|
||||||
@Shared
|
|
||||||
private static final String OT_BAGGAGE_PREFIX = "ot-baggage-"
|
|
||||||
@Shared
|
|
||||||
private static final String TRACE_ID_KEY = "x-datadog-trace-id"
|
|
||||||
@Shared
|
|
||||||
private static final String SPAN_ID_KEY = "x-datadog-parent-id"
|
|
||||||
@Shared
|
|
||||||
private static final String SAMPLING_PRIORITY_KEY = "x-datadog-sampling-priority"
|
|
||||||
|
|
||||||
HTTPCodec codec = new HTTPCodec(["SOME_HEADER": "some-tag"])
|
DatadogHttpCodec.Extractor extractor = new DatadogHttpCodec.Extractor(["SOME_HEADER": "some-tag"])
|
||||||
|
|
||||||
def "inject http headers"() {
|
|
||||||
setup:
|
|
||||||
def writer = new ListWriter()
|
|
||||||
def tracer = new DDTracer(writer)
|
|
||||||
final DDSpanContext mockedContext =
|
|
||||||
new DDSpanContext(
|
|
||||||
"1",
|
|
||||||
"2",
|
|
||||||
"0",
|
|
||||||
"fakeService",
|
|
||||||
"fakeOperation",
|
|
||||||
"fakeResource",
|
|
||||||
samplingPriority,
|
|
||||||
new HashMap<String, String>() {
|
|
||||||
{
|
|
||||||
put("k1", "v1")
|
|
||||||
put("k2", "v2")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
"fakeType",
|
|
||||||
null,
|
|
||||||
new PendingTrace(tracer, "1", [:]),
|
|
||||||
tracer)
|
|
||||||
|
|
||||||
final Map<String, String> carrier = new HashMap<>()
|
|
||||||
|
|
||||||
codec.inject(mockedContext, new TextMapInjectAdapter(carrier))
|
|
||||||
|
|
||||||
expect:
|
|
||||||
carrier.get(TRACE_ID_KEY) == "1"
|
|
||||||
carrier.get(SPAN_ID_KEY) == "2"
|
|
||||||
carrier.get(SAMPLING_PRIORITY_KEY) == (samplingPriority == PrioritySampling.UNSET ? null : String.valueOf(samplingPriority))
|
|
||||||
carrier.get(OT_BAGGAGE_PREFIX + "k1") == "v1"
|
|
||||||
carrier.get(OT_BAGGAGE_PREFIX + "k2") == "v2"
|
|
||||||
|
|
||||||
where:
|
|
||||||
samplingPriority | _
|
|
||||||
PrioritySampling.UNSET | _
|
|
||||||
PrioritySampling.SAMPLER_KEEP | _
|
|
||||||
}
|
|
||||||
|
|
||||||
def "inject http headers with larger than Java long IDs"() {
|
|
||||||
String largeTraceId = "9523372036854775807"
|
|
||||||
String largeSpanId = "15815582334751494918"
|
|
||||||
String largeParentId = "15815582334751494914"
|
|
||||||
setup:
|
|
||||||
def writer = new ListWriter()
|
|
||||||
def tracer = new DDTracer(writer)
|
|
||||||
final DDSpanContext mockedContext =
|
|
||||||
new DDSpanContext(
|
|
||||||
largeTraceId,
|
|
||||||
largeSpanId,
|
|
||||||
largeParentId,
|
|
||||||
"fakeService",
|
|
||||||
"fakeOperation",
|
|
||||||
"fakeResource",
|
|
||||||
samplingPriority,
|
|
||||||
new HashMap<String, String>() {
|
|
||||||
{
|
|
||||||
put("k1", "v1")
|
|
||||||
put("k2", "v2")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
"fakeType",
|
|
||||||
null,
|
|
||||||
new PendingTrace(tracer, largeTraceId, [:]),
|
|
||||||
tracer)
|
|
||||||
|
|
||||||
final Map<String, String> carrier = new HashMap<>()
|
|
||||||
|
|
||||||
codec.inject(mockedContext, new TextMapInjectAdapter(carrier))
|
|
||||||
|
|
||||||
expect:
|
|
||||||
carrier.get(TRACE_ID_KEY) == largeTraceId
|
|
||||||
carrier.get(SPAN_ID_KEY) == largeSpanId
|
|
||||||
carrier.get(SAMPLING_PRIORITY_KEY) == (samplingPriority == PrioritySampling.UNSET ? null : String.valueOf(samplingPriority))
|
|
||||||
carrier.get(OT_BAGGAGE_PREFIX + "k1") == "v1"
|
|
||||||
carrier.get(OT_BAGGAGE_PREFIX + "k2") == "v2"
|
|
||||||
|
|
||||||
where:
|
|
||||||
samplingPriority | _
|
|
||||||
PrioritySampling.UNSET | _
|
|
||||||
PrioritySampling.SAMPLER_KEEP | _
|
|
||||||
}
|
|
||||||
|
|
||||||
def "inject http headers with uint 64 max IDs"() {
|
|
||||||
String largeTraceId = "18446744073709551615"
|
|
||||||
String largeSpanId = "18446744073709551614"
|
|
||||||
String largeParentId = "18446744073709551613"
|
|
||||||
setup:
|
|
||||||
def writer = new ListWriter()
|
|
||||||
def tracer = new DDTracer(writer)
|
|
||||||
final DDSpanContext mockedContext =
|
|
||||||
new DDSpanContext(
|
|
||||||
largeTraceId,
|
|
||||||
largeSpanId,
|
|
||||||
largeParentId,
|
|
||||||
"fakeService",
|
|
||||||
"fakeOperation",
|
|
||||||
"fakeResource",
|
|
||||||
samplingPriority,
|
|
||||||
new HashMap<String, String>() {
|
|
||||||
{
|
|
||||||
put("k1", "v1")
|
|
||||||
put("k2", "v2")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
"fakeType",
|
|
||||||
null,
|
|
||||||
new PendingTrace(tracer, largeTraceId, [:]),
|
|
||||||
tracer)
|
|
||||||
|
|
||||||
final Map<String, String> carrier = new HashMap<>()
|
|
||||||
|
|
||||||
codec.inject(mockedContext, new TextMapInjectAdapter(carrier))
|
|
||||||
|
|
||||||
expect:
|
|
||||||
carrier.get(TRACE_ID_KEY) == largeTraceId
|
|
||||||
carrier.get(SPAN_ID_KEY) == largeSpanId
|
|
||||||
carrier.get(SAMPLING_PRIORITY_KEY) == (samplingPriority == PrioritySampling.UNSET ? null : String.valueOf(samplingPriority))
|
|
||||||
carrier.get(OT_BAGGAGE_PREFIX + "k1") == "v1"
|
|
||||||
carrier.get(OT_BAGGAGE_PREFIX + "k2") == "v2"
|
|
||||||
|
|
||||||
where:
|
|
||||||
samplingPriority | _
|
|
||||||
PrioritySampling.UNSET | _
|
|
||||||
PrioritySampling.SAMPLER_KEEP | _
|
|
||||||
}
|
|
||||||
|
|
||||||
def "extract http headers"() {
|
def "extract http headers"() {
|
||||||
setup:
|
setup:
|
||||||
|
@ -170,7 +28,7 @@ class HTTPCodecTest extends Specification {
|
||||||
actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority))
|
actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority))
|
||||||
}
|
}
|
||||||
|
|
||||||
final ExtractedContext context = codec.extract(new TextMapExtractAdapter(actual))
|
final ExtractedContext context = extractor.extract(new TextMapExtractAdapter(actual))
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
context.getTraceId() == "1"
|
context.getTraceId() == "1"
|
||||||
|
@ -192,7 +50,7 @@ class HTTPCodecTest extends Specification {
|
||||||
SOME_HEADER: "my-interesting-info",
|
SOME_HEADER: "my-interesting-info",
|
||||||
]
|
]
|
||||||
|
|
||||||
TagContext context = codec.extract(new TextMapExtractAdapter(actual))
|
TagContext context = extractor.extract(new TextMapExtractAdapter(actual))
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
!(context instanceof ExtractedContext)
|
!(context instanceof ExtractedContext)
|
||||||
|
@ -201,7 +59,7 @@ class HTTPCodecTest extends Specification {
|
||||||
|
|
||||||
def "extract empty headers returns null"() {
|
def "extract empty headers returns null"() {
|
||||||
expect:
|
expect:
|
||||||
codec.extract(new TextMapExtractAdapter(["ignored-header": "ignored-value"])) == null
|
extractor.extract(new TextMapExtractAdapter(["ignored-header": "ignored-value"])) == null
|
||||||
}
|
}
|
||||||
|
|
||||||
def "extract http headers with larger than Java long IDs"() {
|
def "extract http headers with larger than Java long IDs"() {
|
||||||
|
@ -220,7 +78,7 @@ class HTTPCodecTest extends Specification {
|
||||||
actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority))
|
actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority))
|
||||||
}
|
}
|
||||||
|
|
||||||
final ExtractedContext context = codec.extract(new TextMapExtractAdapter(actual))
|
final ExtractedContext context = extractor.extract(new TextMapExtractAdapter(actual))
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
context.getTraceId() == largeTraceId
|
context.getTraceId() == largeTraceId
|
||||||
|
@ -251,7 +109,7 @@ class HTTPCodecTest extends Specification {
|
||||||
actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority))
|
actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority))
|
||||||
}
|
}
|
||||||
|
|
||||||
final ExtractedContext context = codec.extract(new TextMapExtractAdapter(actual))
|
final ExtractedContext context = extractor.extract(new TextMapExtractAdapter(actual))
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
context.getTraceId() == BIG_INTEGER_UINT64_MAX.toString()
|
context.getTraceId() == BIG_INTEGER_UINT64_MAX.toString()
|
||||||
|
@ -282,7 +140,7 @@ class HTTPCodecTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
when:
|
when:
|
||||||
codec.extract(new TextMapExtractAdapter(actual))
|
extractor.extract(new TextMapExtractAdapter(actual))
|
||||||
|
|
||||||
then:
|
then:
|
||||||
def iae = thrown(IllegalArgumentException)
|
def iae = thrown(IllegalArgumentException)
|
||||||
|
@ -310,7 +168,7 @@ class HTTPCodecTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
when:
|
when:
|
||||||
codec.extract(new TextMapExtractAdapter(actual))
|
extractor.extract(new TextMapExtractAdapter(actual))
|
||||||
|
|
||||||
then:
|
then:
|
||||||
thrown(IllegalArgumentException)
|
thrown(IllegalArgumentException)
|
||||||
|
@ -336,7 +194,7 @@ class HTTPCodecTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
when:
|
when:
|
||||||
codec.extract(new TextMapExtractAdapter(actual))
|
extractor.extract(new TextMapExtractAdapter(actual))
|
||||||
|
|
||||||
then:
|
then:
|
||||||
thrown(IllegalArgumentException)
|
thrown(IllegalArgumentException)
|
|
@ -0,0 +1,151 @@
|
||||||
|
package datadog.opentracing.propagation
|
||||||
|
|
||||||
|
import datadog.opentracing.DDSpanContext
|
||||||
|
import datadog.opentracing.DDTracer
|
||||||
|
import datadog.opentracing.PendingTrace
|
||||||
|
import datadog.trace.api.sampling.PrioritySampling
|
||||||
|
import datadog.trace.common.writer.ListWriter
|
||||||
|
import io.opentracing.propagation.TextMapInjectAdapter
|
||||||
|
import spock.lang.Specification
|
||||||
|
|
||||||
|
import static datadog.opentracing.propagation.DatadogHttpCodec.OT_BAGGAGE_PREFIX
|
||||||
|
import static datadog.opentracing.propagation.DatadogHttpCodec.SAMPLING_PRIORITY_KEY
|
||||||
|
import static datadog.opentracing.propagation.DatadogHttpCodec.SPAN_ID_KEY
|
||||||
|
import static datadog.opentracing.propagation.DatadogHttpCodec.TRACE_ID_KEY
|
||||||
|
|
||||||
|
class DatadogHttpInjectorTest extends Specification {
|
||||||
|
|
||||||
|
DatadogHttpCodec.Injector injector = new DatadogHttpCodec.Injector()
|
||||||
|
|
||||||
|
def "inject http headers"() {
|
||||||
|
setup:
|
||||||
|
def writer = new ListWriter()
|
||||||
|
def tracer = new DDTracer(writer)
|
||||||
|
final DDSpanContext mockedContext =
|
||||||
|
new DDSpanContext(
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"0",
|
||||||
|
"fakeService",
|
||||||
|
"fakeOperation",
|
||||||
|
"fakeResource",
|
||||||
|
samplingPriority,
|
||||||
|
new HashMap<String, String>() {
|
||||||
|
{
|
||||||
|
put("k1", "v1")
|
||||||
|
put("k2", "v2")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
"fakeType",
|
||||||
|
null,
|
||||||
|
new PendingTrace(tracer, "1", [:]),
|
||||||
|
tracer)
|
||||||
|
|
||||||
|
final Map<String, String> carrier = new HashMap<>()
|
||||||
|
|
||||||
|
injector.inject(mockedContext, new TextMapInjectAdapter(carrier))
|
||||||
|
|
||||||
|
expect:
|
||||||
|
carrier.get(TRACE_ID_KEY) == "1"
|
||||||
|
carrier.get(SPAN_ID_KEY) == "2"
|
||||||
|
carrier.get(SAMPLING_PRIORITY_KEY) == (samplingPriority == PrioritySampling.UNSET ? null : String.valueOf(samplingPriority))
|
||||||
|
carrier.get(OT_BAGGAGE_PREFIX + "k1") == "v1"
|
||||||
|
carrier.get(OT_BAGGAGE_PREFIX + "k2") == "v2"
|
||||||
|
|
||||||
|
where:
|
||||||
|
samplingPriority | _
|
||||||
|
PrioritySampling.UNSET | _
|
||||||
|
PrioritySampling.SAMPLER_KEEP | _
|
||||||
|
}
|
||||||
|
|
||||||
|
def "inject http headers with larger than Java long IDs"() {
|
||||||
|
String largeTraceId = "9523372036854775807"
|
||||||
|
String largeSpanId = "15815582334751494918"
|
||||||
|
String largeParentId = "15815582334751494914"
|
||||||
|
setup:
|
||||||
|
def writer = new ListWriter()
|
||||||
|
def tracer = new DDTracer(writer)
|
||||||
|
final DDSpanContext mockedContext =
|
||||||
|
new DDSpanContext(
|
||||||
|
largeTraceId,
|
||||||
|
largeSpanId,
|
||||||
|
largeParentId,
|
||||||
|
"fakeService",
|
||||||
|
"fakeOperation",
|
||||||
|
"fakeResource",
|
||||||
|
samplingPriority,
|
||||||
|
new HashMap<String, String>() {
|
||||||
|
{
|
||||||
|
put("k1", "v1")
|
||||||
|
put("k2", "v2")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
"fakeType",
|
||||||
|
null,
|
||||||
|
new PendingTrace(tracer, largeTraceId, [:]),
|
||||||
|
tracer)
|
||||||
|
|
||||||
|
final Map<String, String> carrier = new HashMap<>()
|
||||||
|
|
||||||
|
injector.inject(mockedContext, new TextMapInjectAdapter(carrier))
|
||||||
|
|
||||||
|
expect:
|
||||||
|
carrier.get(TRACE_ID_KEY) == largeTraceId
|
||||||
|
carrier.get(SPAN_ID_KEY) == largeSpanId
|
||||||
|
carrier.get(SAMPLING_PRIORITY_KEY) == (samplingPriority == PrioritySampling.UNSET ? null : String.valueOf(samplingPriority))
|
||||||
|
carrier.get(OT_BAGGAGE_PREFIX + "k1") == "v1"
|
||||||
|
carrier.get(OT_BAGGAGE_PREFIX + "k2") == "v2"
|
||||||
|
|
||||||
|
where:
|
||||||
|
samplingPriority | _
|
||||||
|
PrioritySampling.UNSET | _
|
||||||
|
PrioritySampling.SAMPLER_KEEP | _
|
||||||
|
}
|
||||||
|
|
||||||
|
def "inject http headers with uint 64 max IDs"() {
|
||||||
|
String largeTraceId = "18446744073709551615"
|
||||||
|
String largeSpanId = "18446744073709551614"
|
||||||
|
String largeParentId = "18446744073709551613"
|
||||||
|
setup:
|
||||||
|
def writer = new ListWriter()
|
||||||
|
def tracer = new DDTracer(writer)
|
||||||
|
final DDSpanContext mockedContext =
|
||||||
|
new DDSpanContext(
|
||||||
|
largeTraceId,
|
||||||
|
largeSpanId,
|
||||||
|
largeParentId,
|
||||||
|
"fakeService",
|
||||||
|
"fakeOperation",
|
||||||
|
"fakeResource",
|
||||||
|
samplingPriority,
|
||||||
|
new HashMap<String, String>() {
|
||||||
|
{
|
||||||
|
put("k1", "v1")
|
||||||
|
put("k2", "v2")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
"fakeType",
|
||||||
|
null,
|
||||||
|
new PendingTrace(tracer, largeTraceId, [:]),
|
||||||
|
tracer)
|
||||||
|
|
||||||
|
final Map<String, String> carrier = new HashMap<>()
|
||||||
|
|
||||||
|
injector.inject(mockedContext, new TextMapInjectAdapter(carrier))
|
||||||
|
|
||||||
|
expect:
|
||||||
|
carrier.get(TRACE_ID_KEY) == largeTraceId
|
||||||
|
carrier.get(SPAN_ID_KEY) == largeSpanId
|
||||||
|
carrier.get(SAMPLING_PRIORITY_KEY) == (samplingPriority == PrioritySampling.UNSET ? null : String.valueOf(samplingPriority))
|
||||||
|
carrier.get(OT_BAGGAGE_PREFIX + "k1") == "v1"
|
||||||
|
carrier.get(OT_BAGGAGE_PREFIX + "k2") == "v2"
|
||||||
|
|
||||||
|
where:
|
||||||
|
samplingPriority | _
|
||||||
|
PrioritySampling.UNSET | _
|
||||||
|
PrioritySampling.SAMPLER_KEEP | _
|
||||||
|
}
|
||||||
|
}
|
|
@ -78,7 +78,7 @@ class DDTracerTest extends Specification {
|
||||||
when:
|
when:
|
||||||
def config = new Config()
|
def config = new Config()
|
||||||
def tracer = new DDTracer(config)
|
def tracer = new DDTracer(config)
|
||||||
def taggedHeaders = tracer.registry.codecs.values().first().taggedHeaders
|
def taggedHeaders = tracer.extractor.taggedHeaders
|
||||||
|
|
||||||
then:
|
then:
|
||||||
tracer.defaultSpanTags == map
|
tracer.defaultSpanTags == map
|
||||||
|
|
Loading…
Reference in New Issue