Browse Source

Run context customizers before span start instead of after (#6634)

...so that they can have access to the parent span context, and so that
their additions to the context will be visible to span processors
Trask Stalnaker 2 years ago
parent
commit
586261d25a

+ 1 - 1
instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/ContextCustomizer.java

@@ -18,5 +18,5 @@ import io.opentelemetry.context.Context;
 public interface ContextCustomizer<REQUEST> {
 
   /** Allows to customize the operation {@link Context}. */
-  Context onStart(Context context, REQUEST request, Attributes startAttributes);
+  Context onStart(Context parentContext, REQUEST request, Attributes startAttributes);
 }

+ 12 - 9
instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/Instrumenter.java

@@ -160,10 +160,7 @@ public class Instrumenter<REQUEST, RESPONSE> {
   private Context doStart(Context parentContext, REQUEST request, @Nullable Instant startTime) {
     SpanKind spanKind = spanKindExtractor.extract(request);
     SpanBuilder spanBuilder =
-        tracer
-            .spanBuilder(spanNameExtractor.extract(request))
-            .setSpanKind(spanKind)
-            .setParent(parentContext);
+        tracer.spanBuilder(spanNameExtractor.extract(request)).setSpanKind(spanKind);
 
     if (startTime != null) {
       spanBuilder.setStartTimestamp(startTime);
@@ -181,22 +178,28 @@ public class Instrumenter<REQUEST, RESPONSE> {
 
     Context context = parentContext;
 
-    spanBuilder.setAllAttributes(attributes);
-    Span span = spanBuilder.startSpan();
-    context = context.with(span);
-
+    // context customizers run before span start, so that they can have access to the parent span
+    // context, and so that their additions to the context will be visible to span processors
     for (ContextCustomizer<? super REQUEST> contextCustomizer : contextCustomizers) {
       context = contextCustomizer.onStart(context, request, attributes);
     }
 
+    boolean localRoot = LocalRootSpan.isLocalRoot(context);
+
+    spanBuilder.setAllAttributes(attributes);
+    Span span = spanBuilder.setParent(context).startSpan();
+    context = context.with(span);
+
     if (!operationListeners.isEmpty()) {
+      // operation listeners run after span start, so that they have access to the current span
+      // for capturing exemplars
       long startNanos = getNanos(startTime);
       for (OperationListener operationListener : operationListeners) {
         context = operationListener.onStart(context, attributes, startNanos);
       }
     }
 
-    if (LocalRootSpan.isLocalRoot(parentContext)) {
+    if (localRoot) {
       context = LocalRootSpan.store(context, span);
     }