1911 b3 propagator debug flag (#2038)
CHANGELOG: Added support for propagating the B3 debug flag * b3 propagator supports inject/extract of debug flag * rename context key * Update extensions/trace-propagators/src/main/java/io/opentelemetry/extension/trace/propagation/B3Propagator.java Co-authored-by: Anuraag Agrawal <anuraaga@gmail.com> * changes as per code review comments * added constants for b3propagator debug propagation * tidy up * changed b3 propagator to store a boolean in context Co-authored-by: Anuraag Agrawal <anuraaga@gmail.com>
This commit is contained in:
parent
c177dacdbb
commit
d4583db62f
|
|
@ -6,6 +6,7 @@
|
|||
package io.opentelemetry.extension.trace.propagation;
|
||||
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.ContextKey;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
|
@ -49,12 +50,17 @@ public class B3Propagator implements TextMapPropagator {
|
|||
static final String TRACE_ID_HEADER = "X-B3-TraceId";
|
||||
static final String SPAN_ID_HEADER = "X-B3-SpanId";
|
||||
static final String SAMPLED_HEADER = "X-B3-Sampled";
|
||||
static final String DEBUG_HEADER = "X-B3-Flags";
|
||||
static final String COMBINED_HEADER = "b3";
|
||||
static final String COMBINED_HEADER_DELIMITER = "-";
|
||||
static final ContextKey<Boolean> DEBUG_CONTEXT_KEY = ContextKey.named("b3-debug");
|
||||
static final String MULTI_HEADER_DEBUG = "1";
|
||||
static final String SINGLE_HEADER_DEBUG = "d";
|
||||
|
||||
static final char COMBINED_HEADER_DELIMITER_CHAR = '-';
|
||||
static final char IS_SAMPLED = '1';
|
||||
static final char NOT_SAMPLED = '0';
|
||||
static final char DEBUG_SAMPLED = 'd';
|
||||
|
||||
private static final List<String> FIELDS =
|
||||
Collections.unmodifiableList(
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@
|
|||
|
||||
package io.opentelemetry.extension.trace.propagation;
|
||||
|
||||
import static io.opentelemetry.extension.trace.propagation.B3Propagator.DEBUG_HEADER;
|
||||
import static io.opentelemetry.extension.trace.propagation.B3Propagator.SAMPLED_HEADER;
|
||||
import static io.opentelemetry.extension.trace.propagation.B3Propagator.SPAN_ID_HEADER;
|
||||
import static io.opentelemetry.extension.trace.propagation.B3Propagator.TRACE_ID_HEADER;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanContext;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||
import java.util.Objects;
|
||||
|
|
@ -28,33 +28,37 @@ final class B3PropagatorExtractorMultipleHeaders implements B3PropagatorExtracto
|
|||
Context context, C carrier, TextMapPropagator.Getter<C> getter) {
|
||||
Objects.requireNonNull(carrier, "carrier");
|
||||
Objects.requireNonNull(getter, "getter");
|
||||
SpanContext spanContext = getSpanContextFromMultipleHeaders(carrier, getter);
|
||||
if (!spanContext.isValid()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(context.with(Span.wrap(spanContext)));
|
||||
return extractSpanContextFromMultipleHeaders(context, carrier, getter);
|
||||
}
|
||||
|
||||
private static <C> SpanContext getSpanContextFromMultipleHeaders(
|
||||
C carrier, TextMapPropagator.Getter<C> getter) {
|
||||
private static <C> Optional<Context> extractSpanContextFromMultipleHeaders(
|
||||
Context context, C carrier, TextMapPropagator.Getter<C> getter) {
|
||||
String traceId = getter.get(carrier, TRACE_ID_HEADER);
|
||||
if (StringUtils.isNullOrEmpty(traceId)) {
|
||||
return SpanContext.getInvalid();
|
||||
return Optional.empty();
|
||||
}
|
||||
if (!Common.isTraceIdValid(traceId)) {
|
||||
logger.fine(
|
||||
"Invalid TraceId in B3 header: " + traceId + "'. Returning INVALID span context.");
|
||||
return SpanContext.getInvalid();
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String spanId = getter.get(carrier, SPAN_ID_HEADER);
|
||||
if (!Common.isSpanIdValid(spanId)) {
|
||||
logger.fine("Invalid SpanId in B3 header: " + spanId + "'. Returning INVALID span context.");
|
||||
return SpanContext.getInvalid();
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// if debug flag is set, then set sampled flag, and also set B3 debug to true in the context
|
||||
// for onward use by B3 injector
|
||||
if (B3Propagator.MULTI_HEADER_DEBUG.equals(getter.get(carrier, DEBUG_HEADER))) {
|
||||
return Optional.of(
|
||||
context
|
||||
.with(B3Propagator.DEBUG_CONTEXT_KEY, true)
|
||||
.with(Span.wrap(Common.buildSpanContext(traceId, spanId, Common.TRUE_INT))));
|
||||
}
|
||||
|
||||
String sampled = getter.get(carrier, SAMPLED_HEADER);
|
||||
return Common.buildSpanContext(traceId, spanId, sampled);
|
||||
return Optional.of(context.with(Span.wrap(Common.buildSpanContext(traceId, spanId, sampled))));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import static io.opentelemetry.extension.trace.propagation.B3Propagator.COMBINED
|
|||
import static io.opentelemetry.extension.trace.propagation.B3Propagator.COMBINED_HEADER_DELIMITER;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanContext;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||
import java.util.Objects;
|
||||
|
|
@ -27,20 +26,15 @@ final class B3PropagatorExtractorSingleHeader implements B3PropagatorExtractor {
|
|||
Context context, C carrier, TextMapPropagator.Getter<C> getter) {
|
||||
Objects.requireNonNull(carrier, "carrier");
|
||||
Objects.requireNonNull(getter, "getter");
|
||||
SpanContext spanContext = getSpanContextFromSingleHeader(carrier, getter);
|
||||
if (!spanContext.isValid()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(context.with(Span.wrap(spanContext)));
|
||||
return extractSpanContextFromSingleHeader(context, carrier, getter);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StringSplitter")
|
||||
private static <C> SpanContext getSpanContextFromSingleHeader(
|
||||
C carrier, TextMapPropagator.Getter<C> getter) {
|
||||
private static <C> Optional<Context> extractSpanContextFromSingleHeader(
|
||||
Context context, C carrier, TextMapPropagator.Getter<C> getter) {
|
||||
String value = getter.get(carrier, COMBINED_HEADER);
|
||||
if (StringUtils.isNullOrEmpty(value)) {
|
||||
return SpanContext.getInvalid();
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// must have between 2 and 4 hyphen delimited parts:
|
||||
|
|
@ -50,25 +44,34 @@ final class B3PropagatorExtractorSingleHeader implements B3PropagatorExtractor {
|
|||
if (parts.length < 2 || parts.length > 4) {
|
||||
logger.fine(
|
||||
"Invalid combined header '" + COMBINED_HEADER + ". Returning INVALID span context.");
|
||||
return SpanContext.getInvalid();
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String traceId = parts[0];
|
||||
if (!Common.isTraceIdValid(traceId)) {
|
||||
logger.fine(
|
||||
"Invalid TraceId in B3 header: " + COMBINED_HEADER + ". Returning INVALID span context.");
|
||||
return SpanContext.getInvalid();
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String spanId = parts[1];
|
||||
if (!Common.isSpanIdValid(spanId)) {
|
||||
logger.fine(
|
||||
"Invalid SpanId in B3 header: " + COMBINED_HEADER + ". Returning INVALID span context.");
|
||||
return SpanContext.getInvalid();
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String sampled = parts.length >= 3 ? parts[2] : null;
|
||||
|
||||
return Common.buildSpanContext(traceId, spanId, sampled);
|
||||
// if sampled is marked as 'd'ebug, then set sampled flag, and also set B3 debug to true in
|
||||
// the context for onward use by the B3 injector
|
||||
if (B3Propagator.SINGLE_HEADER_DEBUG.equals(sampled)) {
|
||||
return Optional.of(
|
||||
context
|
||||
.with(B3Propagator.DEBUG_CONTEXT_KEY, true)
|
||||
.with(Span.wrap(Common.buildSpanContext(traceId, spanId, Common.TRUE_INT))));
|
||||
}
|
||||
|
||||
return Optional.of(context.with(Span.wrap(Common.buildSpanContext(traceId, spanId, sampled))));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,11 @@ final class B3PropagatorInjectorMultipleHeaders implements B3PropagatorInjector
|
|||
|
||||
String sampled = spanContext.isSampled() ? Common.TRUE_INT : Common.FALSE_INT;
|
||||
|
||||
if (Boolean.TRUE.equals(context.get(B3Propagator.DEBUG_CONTEXT_KEY))) {
|
||||
setter.set(carrier, B3Propagator.DEBUG_HEADER, Common.TRUE_INT);
|
||||
sampled = Common.TRUE_INT;
|
||||
}
|
||||
|
||||
setter.set(carrier, B3Propagator.TRACE_ID_HEADER, spanContext.getTraceIdAsHexString());
|
||||
setter.set(carrier, B3Propagator.SPAN_ID_HEADER, spanContext.getSpanIdAsHexString());
|
||||
setter.set(carrier, B3Propagator.SAMPLED_HEADER, sampled);
|
||||
|
|
|
|||
|
|
@ -44,8 +44,12 @@ final class B3PropagatorInjectorSingleHeader implements B3PropagatorInjector {
|
|||
System.arraycopy(spanId.toCharArray(), 0, chars, SPAN_ID_OFFSET, SpanId.getHexLength());
|
||||
|
||||
chars[SAMPLED_FLAG_OFFSET - 1] = B3Propagator.COMBINED_HEADER_DELIMITER_CHAR;
|
||||
chars[SAMPLED_FLAG_OFFSET] =
|
||||
spanContext.isSampled() ? B3Propagator.IS_SAMPLED : B3Propagator.NOT_SAMPLED;
|
||||
if (Boolean.TRUE.equals(context.get(B3Propagator.DEBUG_CONTEXT_KEY))) {
|
||||
chars[SAMPLED_FLAG_OFFSET] = B3Propagator.DEBUG_SAMPLED;
|
||||
} else {
|
||||
chars[SAMPLED_FLAG_OFFSET] =
|
||||
spanContext.isSampled() ? B3Propagator.IS_SAMPLED : B3Propagator.NOT_SAMPLED;
|
||||
}
|
||||
setter.set(carrier, B3Propagator.COMBINED_HEADER, new String(chars));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@
|
|||
|
||||
package io.opentelemetry.extension.trace.propagation;
|
||||
|
||||
import static io.opentelemetry.extension.trace.propagation.B3Propagator.DEBUG_CONTEXT_KEY;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanContext;
|
||||
|
|
@ -599,4 +601,96 @@ class B3PropagatorTest {
|
|||
assertThat(getSpanContext(b3Propagator.extract(Context.current(), emptyHeaders, getter)))
|
||||
.isEqualTo(SpanContext.getInvalid());
|
||||
}
|
||||
|
||||
@Test
|
||||
void extract_DebugContext_SingleHeader() {
|
||||
Map<String, String> carrier = new LinkedHashMap<>();
|
||||
carrier.put(B3Propagator.COMBINED_HEADER, TRACE_ID + "-" + SPAN_ID + "-" + "d");
|
||||
|
||||
Context context = b3Propagator.extract(Context.current(), carrier, getter);
|
||||
assertThat(getSpanContext(context))
|
||||
.isEqualTo(
|
||||
SpanContext.createFromRemoteParent(
|
||||
TRACE_ID, SPAN_ID, SAMPLED_TRACE_OPTIONS, TRACE_STATE_DEFAULT));
|
||||
assertTrue(context.get(DEBUG_CONTEXT_KEY));
|
||||
}
|
||||
|
||||
@Test
|
||||
void extract_DebugContext_MultipleHeaders() {
|
||||
Map<String, String> carrier = new LinkedHashMap<>();
|
||||
carrier.put(B3Propagator.TRACE_ID_HEADER, TRACE_ID);
|
||||
carrier.put(B3Propagator.SPAN_ID_HEADER, SPAN_ID);
|
||||
carrier.put(B3Propagator.DEBUG_HEADER, Common.TRUE_INT);
|
||||
|
||||
Context context = b3Propagator.extract(Context.current(), carrier, getter);
|
||||
assertThat(getSpanContext(context))
|
||||
.isEqualTo(
|
||||
SpanContext.createFromRemoteParent(
|
||||
TRACE_ID, SPAN_ID, SAMPLED_TRACE_OPTIONS, TRACE_STATE_DEFAULT));
|
||||
assertTrue(context.get(DEBUG_CONTEXT_KEY));
|
||||
}
|
||||
|
||||
@Test
|
||||
void extract_DebugContext_SampledFalseDebugTrue_MultipleHeaders() {
|
||||
Map<String, String> carrier = new LinkedHashMap<>();
|
||||
carrier.put(B3Propagator.TRACE_ID_HEADER, TRACE_ID);
|
||||
carrier.put(B3Propagator.SPAN_ID_HEADER, SPAN_ID);
|
||||
carrier.put(B3Propagator.SAMPLED_HEADER, Common.FALSE_INT);
|
||||
carrier.put(B3Propagator.DEBUG_HEADER, Common.TRUE_INT);
|
||||
|
||||
Context context = b3Propagator.extract(Context.current(), carrier, getter);
|
||||
assertThat(getSpanContext(context))
|
||||
.isEqualTo(
|
||||
SpanContext.createFromRemoteParent(
|
||||
TRACE_ID, SPAN_ID, SAMPLED_TRACE_OPTIONS, TRACE_STATE_DEFAULT));
|
||||
assertTrue(context.get(DEBUG_CONTEXT_KEY));
|
||||
}
|
||||
|
||||
@Test
|
||||
void extract_DebugContext_SampledTrueDebugTrue_MultipleHeaders() {
|
||||
Map<String, String> carrier = new LinkedHashMap<>();
|
||||
carrier.put(B3Propagator.TRACE_ID_HEADER, TRACE_ID);
|
||||
carrier.put(B3Propagator.SPAN_ID_HEADER, SPAN_ID);
|
||||
carrier.put(B3Propagator.SAMPLED_HEADER, Common.TRUE_INT);
|
||||
carrier.put(B3Propagator.DEBUG_HEADER, Common.TRUE_INT);
|
||||
|
||||
Context context = b3Propagator.extract(Context.current(), carrier, getter);
|
||||
assertThat(getSpanContext(context))
|
||||
.isEqualTo(
|
||||
SpanContext.createFromRemoteParent(
|
||||
TRACE_ID, SPAN_ID, SAMPLED_TRACE_OPTIONS, TRACE_STATE_DEFAULT));
|
||||
assertTrue(context.get(DEBUG_CONTEXT_KEY));
|
||||
}
|
||||
|
||||
@Test
|
||||
void inject_DebugContext_MultipleHeaders() {
|
||||
Map<String, String> carrier = new LinkedHashMap<>();
|
||||
Context context = Context.current().with(DEBUG_CONTEXT_KEY, true);
|
||||
b3Propagator.inject(
|
||||
withSpanContext(
|
||||
SpanContext.create(TRACE_ID, SPAN_ID, SAMPLED_TRACE_OPTIONS, TRACE_STATE_DEFAULT),
|
||||
context),
|
||||
carrier,
|
||||
setter);
|
||||
assertThat(carrier).containsEntry(B3Propagator.TRACE_ID_HEADER, TRACE_ID);
|
||||
assertThat(carrier).containsEntry(B3Propagator.SPAN_ID_HEADER, SPAN_ID);
|
||||
assertThat(carrier).containsEntry(B3Propagator.SAMPLED_HEADER, Common.TRUE_INT);
|
||||
assertThat(carrier).containsEntry(B3Propagator.DEBUG_HEADER, Common.TRUE_INT);
|
||||
}
|
||||
|
||||
@Test
|
||||
void inject_DebugContext_SingleHeader() {
|
||||
Map<String, String> carrier = new LinkedHashMap<>();
|
||||
Context context = Context.current().with(DEBUG_CONTEXT_KEY, true);
|
||||
b3PropagatorSingleHeader.inject(
|
||||
withSpanContext(
|
||||
SpanContext.create(TRACE_ID, SPAN_ID, SAMPLED_TRACE_OPTIONS, TRACE_STATE_DEFAULT),
|
||||
context),
|
||||
carrier,
|
||||
setter);
|
||||
assertThat(carrier)
|
||||
.containsEntry(
|
||||
B3Propagator.COMBINED_HEADER,
|
||||
TRACE_ID + "-" + SPAN_ID + "-" + B3Propagator.SINGLE_HEADER_DEBUG);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue