Skip to content

Commit

Permalink
Onto latest brave
Browse files Browse the repository at this point in the history
  • Loading branch information
Adrian Cole committed May 8, 2020
1 parent 58b4a06 commit 733a586
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 368 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*/
package brave.propagation.w3c;

import brave.internal.HexCodec;
import brave.internal.codec.HexCodec;
import brave.propagation.Propagation;
import brave.propagation.TraceContext;
import brave.propagation.TraceContext.Extractor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,26 @@
import brave.propagation.TraceContextOrSamplingFlags;

import static brave.propagation.B3SingleFormat.parseB3SingleFormat;
import static brave.propagation.w3c.TraceContextPropagation.TRACEPARENT;
import static brave.propagation.w3c.TraceContextPropagation.TRACESTATE;

// TODO: this class has no useful tests wrt traceparent yet
final class TraceContextExtractor<R, K> implements Extractor<R> {
static final TraceContextOrSamplingFlags EXTRACTED_EMPTY =
TraceContextOrSamplingFlags.EMPTY.toBuilder().addExtra(Tracestate.EMPTY).build();
final class TraceContextExtractor<R> implements Extractor<R> {
final Getter<R, String> getter;
final TraceContextPropagation propagation;

final Getter<R, K> getter;
final K traceparentKey, tracestateKey;
final TracestateFormat tracestateFormat;
final B3SingleFormatHandler handler = new B3SingleFormatHandler();

TraceContextExtractor(TraceContextPropagation<K> propagation, Getter<R, K> getter) {
TraceContextExtractor(TraceContextPropagation propagation, Getter<R, String> getter) {
this.getter = getter;
this.traceparentKey = propagation.traceparent;
this.tracestateKey = propagation.tracestate;
this.tracestateFormat = new TracestateFormat(propagation.tracestateKey);
this.propagation = propagation;
}

@Override public TraceContextOrSamplingFlags extract(R request) {
if (request == null) throw new NullPointerException("request == null");
String traceparentString = getter.get(request, traceparentKey);
if (traceparentString == null) return EXTRACTED_EMPTY;
String traceparentString = getter.get(request, TRACEPARENT);
if (traceparentString == null) return TraceContextOrSamplingFlags.EMPTY;

// TODO: add link that says tracestate itself is optional
String tracestateString = getter.get(request, tracestateKey);
String tracestateString = getter.get(request, TRACESTATE);
if (tracestateString == null) {
// NOTE: we may not want to pay attention to the sampled flag. Since it conflates
// not-yet-sampled with sampled=false, implementations that always set flags to -00 would
Expand All @@ -54,29 +49,19 @@ final class TraceContextExtractor<R, K> implements Extractor<R> {
// read the tracestate header. Trusting the span ID (traceparent calls the span ID parent-id)
// could result in a headless trace.
TraceContext maybeUpstream = TraceparentFormat.parseTraceparentFormat(traceparentString);
return TraceContextOrSamplingFlags.newBuilder(maybeUpstream)
.addExtra(Tracestate.EMPTY) // marker for outbound propagation
.build();
}

Tracestate tracestate = tracestateFormat.parseAndReturnOtherEntries(tracestateString, handler);

TraceContext context = handler.context;
if (context == null) {
if (tracestate == Tracestate.EMPTY) return EXTRACTED_EMPTY;
return EXTRACTED_EMPTY.toBuilder().addExtra(tracestate).build();
return TraceContextOrSamplingFlags.create(maybeUpstream);
}
return TraceContextOrSamplingFlags.newBuilder(context).addExtra(tracestate).build();
}

static final class B3SingleFormatHandler implements TracestateFormat.Handler {
TraceContext context;

@Override
public boolean onThisEntry(CharSequence tracestate, int beginIndex, int endIndex) {
TraceContextOrSamplingFlags extracted = parseB3SingleFormat(tracestate, beginIndex, endIndex);
if (extracted != null) context = extracted.context();
return context != null;
Tracestate tracestate = propagation.tracestateFactory.create();
TraceContextOrSamplingFlags extracted = null;
if (TracestateFormat.INSTANCE.parseInto(tracestateString, tracestate)) {
String b3 = tracestate.get(propagation.tracestateKey);
if (b3 != null) {
tracestate.put(propagation.tracestateKey, null);
extracted = parseB3SingleFormat(b3);
}
}
if (extracted == null) extracted = TraceContextOrSamplingFlags.EMPTY;
return extracted.toBuilder().addExtra(tracestate).build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,28 @@
*/
package brave.propagation.w3c;

import brave.propagation.B3SingleFormat;
import brave.propagation.Propagation.Setter;
import brave.propagation.TraceContext;
import brave.propagation.TraceContext.Injector;

import static brave.propagation.B3SingleFormat.writeB3SingleFormat;
import static brave.propagation.w3c.TraceContextPropagation.TRACEPARENT;
import static brave.propagation.w3c.TraceContextPropagation.TRACESTATE;
import static brave.propagation.w3c.TraceparentFormat.writeTraceparentFormat;

final class TraceContextInjector<R, K> implements Injector<R> {
final TracestateFormat tracestateFormat;
final Setter<R, K> setter;
final K traceparentKey, tracestateKey;
final class TraceContextInjector<R> implements Injector<R> {
final Setter<R, String> setter;
final String tracestateKey;

TraceContextInjector(TraceContextPropagation<K> propagation, Setter<R, K> setter) {
this.tracestateFormat = new TracestateFormat(propagation.tracestateKey);
this.traceparentKey = propagation.traceparent;
this.tracestateKey = propagation.tracestate;
TraceContextInjector(TraceContextPropagation propagation, Setter<R, String> setter) {
this.setter = setter;
this.tracestateKey = propagation.tracestateKey;
}

@Override public void inject(TraceContext traceContext, R request) {

setter.put(request, traceparentKey, writeTraceparentFormat(traceContext));

CharSequence otherState = null;
for (int i = 0, length = traceContext.extra().size(); i < length; i++) {
Object next = traceContext.extra().get(i);
if (next instanceof Tracestate) {
otherState = ((Tracestate) next).otherEntries;
break;
}
}

String tracestate = tracestateFormat.write(writeB3SingleFormat(traceContext), otherState);
setter.put(request, tracestateKey, tracestate);
@Override public void inject(TraceContext context, R request) {
setter.put(request, TRACEPARENT, writeTraceparentFormat(context));
Tracestate tracestate = context.findExtra(Tracestate.class);
tracestate.put(tracestateKey, B3SingleFormat.writeB3SingleFormat(context));
setter.put(request, TRACESTATE, tracestate.stateString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,30 @@
*/
package brave.propagation.w3c;

import brave.internal.propagation.StringPropagationAdapter;
import brave.propagation.Propagation;
import brave.propagation.TraceContext;
import brave.propagation.TraceContext.Extractor;
import brave.propagation.TraceContext.Injector;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public final class TraceContextPropagation<K> implements Propagation<K> {
public static Factory newFactory() {
return new FactoryBuilder().build();
import static java.util.Arrays.asList;

public final class TraceContextPropagation extends Propagation.Factory
implements Propagation<String> {
static final String TRACEPARENT = "traceparent", TRACESTATE = "tracestate";

public static Propagation.Factory create() {
return new Builder().build();
}

public static FactoryBuilder newFactoryBuilder() {
return new FactoryBuilder();
public static Builder newBuilder() {
return new Builder();
}

public static final class FactoryBuilder {
public static final class Builder {
static final TracestateFormat THROWING_VALIDATOR = new TracestateFormat(true);
String tracestateKey = "b3";

/**
Expand All @@ -38,60 +45,56 @@ public static final class FactoryBuilder {
* @throws IllegalArgumentException if the key doesn't conform to ABNF rules defined by the
* <href="https://www.w3.org/TR/trace-context-1/#key">trace-context specification</href>.
*/
public FactoryBuilder tracestateKey(String key) {
public Builder tracestateKey(String key) {
if (key == null) throw new NullPointerException("key == null");
TracestateFormat.validateKey(key, true);
THROWING_VALIDATOR.validateKey(key, 0, key.length());
this.tracestateKey = key;
return this;
}

public Factory build() {
return new Factory(this);
public Propagation.Factory build() {
return new TraceContextPropagation(this);
}

FactoryBuilder() {
Builder() {
}
}

static final class Factory extends Propagation.Factory {
final String tracestateKey;
final String tracestateKey;
final Tracestate.Factory tracestateFactory;
final List<String> keys = Collections.unmodifiableList(asList(TRACEPARENT, TRACESTATE));

Factory(FactoryBuilder builder) {
this.tracestateKey = builder.tracestateKey;
}
TraceContextPropagation(Builder builder) {
this.tracestateKey = builder.tracestateKey;
this.tracestateFactory = Tracestate.newFactory(tracestateKey);
}

@Override public <K> Propagation<K> create(KeyFactory<K> keyFactory) {
return new TraceContextPropagation<>(keyFactory, tracestateKey);
}
@Override public List<String> keys() {
return keys;
}

@Override public TraceContext decorate(TraceContext context) {
// TODO: almost certain we will need to decorate as not all contexts will start with an
// incoming request (ex schedule or client-originated traces)
return super.decorate(context);
}
@Override public boolean requires128BitTraceId() {
return true;
}

final String tracestateKey;
final K traceparent, tracestate;
final List<K> keys;

TraceContextPropagation(KeyFactory<K> keyFactory, String tracestateKey) {
this.tracestateKey = tracestateKey;
this.traceparent = keyFactory.create("traceparent");
this.tracestate = keyFactory.create("tracestate");
this.keys = Arrays.asList(traceparent, tracestate);
@Override public TraceContext decorate(TraceContext context) {
return tracestateFactory.decorate(context);
}

@Override public List<K> keys() {
return keys;
@Override public Propagation<String> get() {
return this;
}

@Override public <K> Propagation<K> create(KeyFactory<K> keyFactory) {
return StringPropagationAdapter.create(this, keyFactory);
}

@Override public <R> Injector<R> injector(Setter<R, K> setter) {
@Override public <R> Injector<R> injector(Setter<R, String> setter) {
if (setter == null) throw new NullPointerException("setter == null");
return new TraceContextInjector<>(this, setter);
}

@Override public <R> Extractor<R> extractor(Getter<R, K> getter) {
@Override public <R> Extractor<R> extractor(Getter<R, String> getter) {
if (getter == null) throw new NullPointerException("getter == null");
return new TraceContextExtractor<>(this, getter);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import brave.propagation.TraceContext;
import java.nio.ByteBuffer;

import static brave.internal.HexCodec.writeHexLong;
import static brave.internal.codec.HexCodec.writeHexLong;

/** Implements https://w3c.github.io/trace-context/#traceparent-header */
// TODO: this uses the internal Platform class as it defers access to the logger and makes JUL less
Expand Down
64 changes: 41 additions & 23 deletions propagation/w3c/src/main/java/brave/propagation/w3c/Tracestate.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,38 +13,56 @@
*/
package brave.propagation.w3c;

import brave.internal.Nullable;
import brave.internal.extra.MapExtra;
import brave.internal.extra.MapExtraFactory;

/**
* This only contains other entries. The entry for the current trace is only written during
* injection.
*/
final class Tracestate { // hidden intentionally
static final Tracestate EMPTY = new Tracestate("");
final class Tracestate extends MapExtra<String, String, Tracestate, Tracestate.Factory> {
static Factory newFactory(String tracestateKey) {
// max is total initial + dynamic
return new FactoryBuilder().addInitialKey(tracestateKey).maxDynamicEntries(31).build();
}

static final class FactoryBuilder extends
MapExtraFactory.Builder<String, String, Tracestate, Factory, FactoryBuilder> {
@Override protected Factory build() {
return new Factory(this);
}
}

// TODO: this will change
final String otherEntries;
static final class Factory extends MapExtraFactory<String, String, Tracestate, Factory> {
Factory(FactoryBuilder builder) {
super(builder);
}

static Tracestate create(@Nullable CharSequence otherEntries) {
if (otherEntries == null || otherEntries.length() == 0) return EMPTY;
return new Tracestate(otherEntries.toString());
@Override protected Tracestate create() {
return new Tracestate(this);
}
}

private Tracestate(String otherEntries) {
this.otherEntries = otherEntries;
Tracestate(Factory factory) {
super(factory);
}

@Override public String toString() {
return "tracestate: " + otherEntries;
@Override protected String get(String key) {
return super.get(key);
}

@Override public final boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Tracestate)) return false;
return otherEntries.equals(((Tracestate) o).otherEntries);
@Override protected String stateString() {
Object[] array = (Object[]) state;
// TODO: SHOULD on 512 char limit https://w3c.github.io/trace-context/#tracestate-limits
StringBuilder result = new StringBuilder();
boolean empty = true;
for (int i = 0; i < array.length; i += 2) {
String key = (String) array[i], value = (String) array[i + 1];
if (value == null) continue;
if (!empty) result.append(',');
result.append(key).append('=').append(value);
empty = false;
}
return result.toString();
}

@Override public final int hashCode() {
return otherEntries.hashCode();
@Override protected boolean put(String key, String value) {
return super.put(key, value);
}
}
}
Loading

0 comments on commit 733a586

Please sign in to comment.