Skip to content

Commit

Permalink
Refactors ExtraFieldPlugin into a top-level type
Browse files Browse the repository at this point in the history
  • Loading branch information
Adrian Cole committed Aug 28, 2019
1 parent 1fd9107 commit 0266a4c
Show file tree
Hide file tree
Showing 10 changed files with 230 additions and 163 deletions.
15 changes: 7 additions & 8 deletions brave/src/main/java/brave/Tracing.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
import brave.internal.recorder.PendingSpans;
import brave.propagation.B3Propagation;
import brave.propagation.CurrentTraceContext;
import brave.propagation.ExtraFieldPlugin;
import brave.propagation.ExtraFieldPropagation;
import brave.propagation.ExtraFieldPropagation.Plugin;
import brave.propagation.Propagation;
import brave.propagation.TraceContext;
import brave.sampler.Sampler;
Expand Down Expand Up @@ -342,7 +342,7 @@ public Builder errorParser(ErrorParser errorParser) {
*
* @see #alwaysReportSpans()
* @see TraceContext#sampledLocal()
* @see ExtraFieldPropagation.FactoryBuilder#addPlugin(Plugin)
* @see ExtraFieldPropagation.FactoryBuilder#addPlugin(ExtraFieldPlugin)
*/
public Builder addFinishedSpanHandler(FinishedSpanHandler finishedSpanHandler) {
if (finishedSpanHandler == null) {
Expand Down Expand Up @@ -372,7 +372,7 @@ public Builder addFinishedSpanHandler(FinishedSpanHandler finishedSpanHandler) {
*
* @see #addFinishedSpanHandler(FinishedSpanHandler)
* @see TraceContext#sampledLocal()
* @see ExtraFieldPropagation.FactoryBuilder#addPlugin(Plugin)
* @see ExtraFieldPropagation.FactoryBuilder#addPlugin(ExtraFieldPlugin)
*/
public Builder alwaysReportSpans() {
this.alwaysReportSpans = true;
Expand Down Expand Up @@ -428,13 +428,12 @@ static final class Default extends Tracing {
builder.localServiceName, builder.localIp, builder.localPort, builder.alwaysReportSpans)
: FinishedSpanHandler.NOOP;

ArrayList<FinishedSpanHandler> finishedSpanHandlers = new ArrayList<>(builder.finishedSpanHandlers);
ArrayList<FinishedSpanHandler> finishedSpanHandlers =
new ArrayList<>(builder.finishedSpanHandlers);
// Register any extra field plugins as finished span handlers.
if (propagationFactory instanceof ExtraFieldPropagation.Factory) {
for (Plugin plugin : ((ExtraFieldPropagation.Factory) propagationFactory).plugins()) {
FinishedSpanHandler next = InternalPropagation.instance.finishedSpanHandler(plugin);
if (next != FinishedSpanHandler.NOOP) finishedSpanHandlers.add(next);
}
ExtraFieldPropagation.Factory extra = ((ExtraFieldPropagation.Factory) propagationFactory);
InternalPropagation.instance.extractFinishedSpanHandlers(extra, finishedSpanHandlers);
}

FinishedSpanHandler finishedSpanHandler =
Expand Down
4 changes: 3 additions & 1 deletion brave/src/main/java/brave/internal/InternalPropagation.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ public static int sampled(boolean sampled, int flags) {
return flags;
}

public abstract FinishedSpanHandler finishedSpanHandler(ExtraFieldPropagation.Plugin plugin);
/** Adds any finished span handlers used for extra fields into the given list. */
public abstract void extractFinishedSpanHandlers(
ExtraFieldPropagation.Factory factory, List<FinishedSpanHandler> out);

/**
* @param localRootId must be non-zero prior to instantiating {@link Span} or {@link ScopedSpan}
Expand Down
141 changes: 141 additions & 0 deletions brave/src/main/java/brave/propagation/ExtraFieldPlugin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Copyright 2013-2019 The OpenZipkin Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package brave.propagation;

import brave.Tracing;
import brave.handler.FinishedSpanHandler;
import brave.propagation.ExtraFieldPropagation.FieldUpdater;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/**
* Propagation plugins are self-contained and support advanced integration patterns such as metrics
* aggregation or sampling overlays.
*/
public abstract class ExtraFieldPlugin {
/**
* Returns a list of unique lower-case field names used by this plugin.
*
* <p>The value of this is only read when building {@link ExtraFieldPropagation} and during
* {@link #toString()}.
*/
protected abstract List<String> fieldNames();

/**
* This is called once during {@link TraceContext.Extractor#extract(Object)}, allowing you to
* decorate the primary trace state with secondary data from extra fields.
*
* <p>One use case is to override the sampling decision based on an alternate header. If the
* decision is intended to be permanent for the rest of the trace, use {@link
* TraceContextOrSamplingFlags.Builder#sampled(boolean)}, which affects the primary (usually B3)
* headers. Otherwise, you can set {@link TraceContextOrSamplingFlags.Builder#sampledLocal()} to
* make an overlaid decision.
*
* <p>If you are making an overlaid decision, you should either implement {@link
* #finishedSpanHandler()} here, or set {@link Tracing.Builder#alwaysReportSpans()} if your
* backend can tolerate inconsistent data.
*
* <p>The resulting field updater will called for each {@link #fieldNames() field name} in the
* order they were configured, not in the order headers were received.
*/
protected FieldUpdater extractFieldUpdater(TraceContextOrSamplingFlags.Builder builder) {
return FieldUpdater.NOOP;
}

/**
* This allows you to customize or prevent extra fields from going to the next host.
*
* <p>The resulting field updater will be called for each {@link #fieldNames() field name} in
* the order they were configured.
*/
protected FieldUpdater injectFieldUpdater(TraceContext context) {
return FieldUpdater.NOOP;
}

/** This allows you to set tags based on extra fields, most commonly for log correlation. */
// Intentionally protected to prevent accidental registration with Tracing.Builder
protected FinishedSpanHandler finishedSpanHandler() {
return FinishedSpanHandler.NOOP;
}

@Override public String toString() {
return getClass().getSimpleName() + "{" + fieldNames() + "}";
}

static final class Multiple extends ExtraFieldPlugin {
final ExtraFieldPlugin[] plugins; // Array ensures no iterators are created at runtime
final List<String> fieldNames;

Multiple(ExtraFieldPlugin[] plugins) {
this.plugins = plugins;
Set<String> fieldNames = new LinkedHashSet<>();
for (ExtraFieldPlugin plugin : plugins) fieldNames.addAll(plugin.fieldNames());
this.fieldNames = Collections.unmodifiableList(new ArrayList<>(fieldNames));
}

@Override protected List<String> fieldNames() {
return fieldNames;
}

@Override
protected FieldUpdater extractFieldUpdater(TraceContextOrSamplingFlags.Builder builder) {
FieldUpdater[] fieldUpdaters = fieldUpdatersArray();
for (int i = 0, length = plugins.length; i < length; i++) {
fieldUpdaters[i] = plugins[i].extractFieldUpdater(builder);
}
return compositeFieldUpdater(fieldUpdaters);
}

@Override protected FieldUpdater injectFieldUpdater(TraceContext context) {
FieldUpdater[] fieldUpdaters = fieldUpdatersArray();
for (int i = 0, length = plugins.length; i < length; i++) {
fieldUpdaters[i] = plugins[i].injectFieldUpdater(context);
}
return compositeFieldUpdater(fieldUpdaters);
}

@Override protected FinishedSpanHandler finishedSpanHandler() {
throw new AssertionError(); // expect special-casing as this is an internal class
}

@Override public String toString() {
return Arrays.toString(plugins);
}

static FieldUpdater compositeFieldUpdater(ExtraFieldPropagation.FieldUpdater[] fieldUpdaters) {
return (name, value) -> {
for (FieldUpdater fieldUpdater : fieldUpdaters) {
value = fieldUpdater.update(name, value);
}
return value;
};
}

@SuppressWarnings("ThreadLocalUsage") // intentional: instances may have different plugin counts
final ThreadLocal<Object[]> FIELD_UPDATERS = new ThreadLocal<>();

FieldUpdater[] fieldUpdatersArray() {
Object[] fieldUpdatersArray = FIELD_UPDATERS.get();
if (fieldUpdatersArray == null) {
fieldUpdatersArray = new FieldUpdater[plugins.length];
FIELD_UPDATERS.set(fieldUpdatersArray);
}
return (FieldUpdater[]) fieldUpdatersArray;
}
}
}
Loading

0 comments on commit 0266a4c

Please sign in to comment.