Skip to content
This repository has been archived by the owner on Jul 1, 2022. It is now read-only.

Add baggage to B3 codec #438

Merged
merged 3 commits into from
Jun 6, 2018
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion jaeger-core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ The `config` objects lazily builds and configures Jaeger Tracer. Multiple calls
Jaeger tracer can also work in the environment where B3 propagation is used. This is mostly related
to systems instrumented with Zipkin. Once you register `B3TextMapCodec`, Jaeger can join traces
started by other Zipkin instrumented applications. This includes reading headers
like "X-B3-TraceId".
like "X-B3-TraceId". Jaeger B3 implementation automatically propagates baggage and by default it
uses `baggage-` prefix.

Example configuration:
```java
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
package io.jaegertracing.propagation;

import io.jaegertracing.SpanContext;
import io.jaegertracing.Tracer;
import io.jaegertracing.baggage.BaggageRestrictionManager;
import io.opentracing.propagation.TextMap;
import java.util.HashMap;
import java.util.Map;

/**
Expand All @@ -34,17 +37,34 @@
*
* <p>
* See <a href="http://zipkin.io/pages/instrumenting.html">Instrumenting a Library</a>
*
* Note that this codec automatically propagates baggage
* (with {@value io.jaegertracing.propagation.B3TextMapCodec#BAGGAGE_NAME} prefix).
* Baggage whitelisting can be configured in {@link BaggageRestrictionManager} and then
* passed to {@link Tracer.Builder#baggageRestrictionManager}
*/
public class B3TextMapCodec implements Codec<TextMap> {
protected static final String TRACE_ID_NAME = "X-B3-TraceId";
protected static final String SPAN_ID_NAME = "X-B3-SpanId";
protected static final String PARENT_SPAN_ID_NAME = "X-B3-ParentSpanId";
protected static final String SAMPLED_NAME = "X-B3-Sampled";
protected static final String FLAGS_NAME = "X-B3-Flags";
protected static final String BAGGAGE_NAME = "baggage-";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/NAME/PREFIX?

// NOTE: uber's flags aren't the same as B3/Finagle ones
protected static final byte SAMPLED_FLAG = 1;
protected static final byte DEBUG_FLAG = 2;

private static final PrefixedKeys keys = new PrefixedKeys();
private final String baggageName;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto call it prefix instead?


public B3TextMapCodec() {
this(new Builder());
}

private B3TextMapCodec(Builder builder) {
this.baggageName = builder.baggagePrefix;
}

@Override
public void inject(SpanContext spanContext, TextMap carrier) {
carrier.put(TRACE_ID_NAME, HexCodec.toLowerHex(spanContext.getTraceId()));
Expand All @@ -56,6 +76,9 @@ public void inject(SpanContext spanContext, TextMap carrier) {
if (spanContext.isDebug()) {
carrier.put(FLAGS_NAME, "1");
}
for (Map.Entry<String, String> entry : spanContext.baggageItems()) {
carrier.put(keys.prefixedKey(entry.getKey(), baggageName), entry.getValue());
}
}

@Override
Expand All @@ -64,6 +87,7 @@ public SpanContext extract(TextMap carrier) {
Long spanId = null;
Long parentId = 0L; // Conventionally, parent id == 0 means the root span
byte flags = 0;
Map<String, String> baggage = null;
for (Map.Entry<String, String> entry : carrier) {
if (entry.getKey().equalsIgnoreCase(SAMPLED_NAME)) {
String value = entry.getValue();
Expand All @@ -80,12 +104,37 @@ public SpanContext extract(TextMap carrier) {
if (entry.getValue().equals("1")) {
flags |= DEBUG_FLAG;
}
} else if (entry.getKey().startsWith(BAGGAGE_NAME)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be this.baggageName?

if (baggage == null) {
baggage = new HashMap<String, String>();
}
baggage.put(keys.unprefixedKey(entry.getKey(), BAGGAGE_NAME), entry.getValue());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

}
}

if (null != traceId && null != parentId && null != spanId) {
return new SpanContext(traceId, spanId, parentId, flags);
SpanContext spanContext = new SpanContext(traceId, spanId, parentId, flags);
if (baggage != null) {
spanContext = spanContext.withBaggage(baggage);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is an interesting use case, what if only baggage is propagated without the rest of the trace context?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the moment it's an invalid span context - null

}
return spanContext;
}
return null;
}

public static class Builder {
private String baggagePrefix = BAGGAGE_NAME;

/**
* Specify baggage prefix. The default is {@value B3TextMapCodec#BAGGAGE_NAME}
*/
public Builder withBaggagePrefix(String baggagePrefix) {
this.baggagePrefix = baggagePrefix;
return this;
}

public B3TextMapCodec build() {
return new B3TextMapCodec(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,19 @@
package io.jaegertracing.propagation;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import io.jaegertracing.SpanContext;
import io.opentracing.propagation.TextMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.junit.Test;

/**
Expand All @@ -48,6 +53,8 @@ public void downgrades128BitTraceIdToLower64Bits() throws Exception {
textMap.put(B3TextMapCodec.PARENT_SPAN_ID_NAME, "0");
textMap.put(B3TextMapCodec.SAMPLED_NAME, "1");
textMap.put(B3TextMapCodec.FLAGS_NAME, "1");
textMap.put(B3TextMapCodec.BAGGAGE_NAME + "foo", "bar");
textMap.put("random-foo", "bar");

SpanContext context = b3Codec.extract(textMap);

Expand All @@ -56,6 +63,41 @@ public void downgrades128BitTraceIdToLower64Bits() throws Exception {
assertEquals(HexCodec.lowerHexToUnsignedLong(lower64Bits).longValue(), context.getSpanId());
assertEquals(0, context.getParentId());
assertEquals(B3TextMapCodec.SAMPLED_FLAG | B3TextMapCodec.DEBUG_FLAG, context.getFlags());
assertEquals(1, ((Set)context.baggageItems()).size());
assertEquals("bar", context.getBaggageItem("foo"));
}

@Test
public void testDefault() {
B3TextMapCodec b3Codec = new B3TextMapCodec.Builder()
.build();

DelegatingTextMap entries = new DelegatingTextMap();
SpanContext spanContext = new SpanContext(1, 2, 3, (byte)0)
.withBaggageItem("foo", "bar");

b3Codec.inject(spanContext, entries);
assertEquals(5, entries.delegate.size());
assertNotNull(entries.delegate.get(B3TextMapCodec.TRACE_ID_NAME));
assertNotNull(entries.delegate.get(B3TextMapCodec.SPAN_ID_NAME));
assertNotNull(entries.delegate.get(B3TextMapCodec.PARENT_SPAN_ID_NAME));
assertNotNull(entries.delegate.get(B3TextMapCodec.SAMPLED_NAME));
assertEquals("bar", entries.delegate.get("baggage-foo"));
}

@Test
public void testChangeBaggagePrefix() {
B3TextMapCodec b3Codec = new B3TextMapCodec.Builder()
.withBaggagePrefix("foo")
.build();

DelegatingTextMap entries = new DelegatingTextMap();
SpanContext spanContext = new SpanContext(1, 2, 3, (byte)0)
.withBaggageItem("foo", "bar");

b3Codec.inject(spanContext, entries);
assertEquals(5, entries.delegate.size());
assertEquals("bar", entries.delegate.get("foofoo"));
}

@Test
Expand Down