Remove deprecated SpanWithScope class (#1834)

This commit is contained in:
Mateusz Rzeszutek 2020-12-05 18:48:28 +01:00 committed by GitHub
parent ef02da9090
commit f520c2cd33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 451 additions and 428 deletions

View File

@ -18,8 +18,8 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import com.google.auto.service.AutoService;
import io.dropwizard.views.View;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
@ -65,27 +65,30 @@ public class DropwizardViewsInstrumentationModule extends InstrumentationModule
public static class RenderAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope onEnter(@Advice.Argument(0) View view) {
if (!Java8BytecodeBridge.currentSpan().getSpanContext().isValid()) {
return null;
public static void onEnter(
@Advice.Argument(0) View view,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
if (Java8BytecodeBridge.currentSpan().getSpanContext().isValid()) {
span = tracer().startSpan("Render " + view.getTemplateName());
scope = span.makeCurrent();
}
Span span = tracer().startSpan("Render " + view.getTemplateName());
return new SpanWithScope(span, span.makeCurrent());
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(
@Advice.Enter SpanWithScope spanWithScope, @Advice.Thrown Throwable throwable) {
if (spanWithScope == null) {
@Advice.Thrown Throwable throwable,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}
Span span = spanWithScope.getSpan();
scope.close();
if (throwable == null) {
tracer().end(span);
} else {
tracer().endExceptionally(span, throwable);
}
spanWithScope.closeScope();
}
}
}

View File

@ -22,8 +22,8 @@ import com.twitter.finatra.http.contexts.RouteInfo;
import com.twitter.util.Future;
import com.twitter.util.FutureEventListener;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
@ -71,60 +71,61 @@ public class FinatraInstrumentationModule extends InstrumentationModule {
public static class RouteAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope nameSpan(
public static void nameSpan(
@Advice.FieldValue("routeInfo") RouteInfo routeInfo,
@Advice.FieldValue("clazz") Class<?> clazz) {
@Advice.FieldValue("clazz") Class<?> clazz,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
Span serverSpan = BaseTracer.getCurrentServerSpan();
if (serverSpan != null) {
serverSpan.updateName(routeInfo.path());
}
Span span = tracer().startSpan(clazz);
return new SpanWithScope(span, span.makeCurrent());
span = tracer().startSpan(clazz);
scope = span.makeCurrent();
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void setupCallback(
@Advice.Enter SpanWithScope spanWithScope,
@Advice.Thrown Throwable throwable,
@Advice.Return Some<Future<Response>> responseOption) {
@Advice.Return Some<Future<Response>> responseOption,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
if (spanWithScope == null) {
if (scope == null) {
return;
}
Span span = spanWithScope.getSpan();
if (throwable != null) {
scope.close();
tracer().endExceptionally(span, throwable);
spanWithScope.closeScope();
return;
}
responseOption.get().addEventListener(new Listener(spanWithScope));
responseOption.get().addEventListener(new Listener(span, scope));
}
}
public static class Listener implements FutureEventListener<Response> {
private final SpanWithScope spanWithScope;
private final Span span;
private final Scope scope;
public Listener(SpanWithScope spanWithScope) {
this.spanWithScope = spanWithScope;
public Listener(Span span, Scope scope) {
this.span = span;
this.scope = scope;
}
@Override
public void onSuccess(Response response) {
Span span = spanWithScope.getSpan();
scope.close();
tracer().end(span);
spanWithScope.closeScope();
}
@Override
public void onFailure(Throwable cause) {
Span span = spanWithScope.getSpan();
scope.close();
tracer().endExceptionally(span, cause);
spanWithScope.closeScope();
}
}
}

View File

@ -13,9 +13,9 @@ import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
@ -48,24 +48,33 @@ public class CriteriaInstrumentation implements TypeInstrumentation {
public static class CriteriaMethodAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope startMethod(
@Advice.This Criteria criteria, @Advice.Origin("#m") String name) {
public static void startMethod(
@Advice.This Criteria criteria,
@Advice.Origin("#m") String name,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
ContextStore<Criteria, Context> contextStore =
InstrumentationContext.get(Criteria.class, Context.class);
return SessionMethodUtils.startScopeFrom(
contextStore, criteria, "Criteria." + name, null, true);
context = SessionMethodUtils.startSpanFrom(contextStore, criteria, "Criteria." + name, null);
if (context != null) {
scope = context.makeCurrent();
}
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void endMethod(
@Advice.Enter SpanWithScope spanWithScope,
@Advice.Thrown Throwable throwable,
@Advice.Return(typing = Assigner.Typing.DYNAMIC) Object entity,
@Advice.Origin("#m") String name) {
@Advice.Origin("#m") String name,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
SessionMethodUtils.closeScope(spanWithScope, throwable, "Criteria." + name, entity);
if (scope != null) {
SessionMethodUtils.end(context, throwable, "Criteria." + name, entity);
scope.close();
}
}
}
}

View File

@ -13,9 +13,9 @@ import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
@ -47,20 +47,30 @@ public class QueryInstrumentation implements TypeInstrumentation {
public static class QueryMethodAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope startMethod(@Advice.This Query query) {
public static void startMethod(
@Advice.This Query query,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
ContextStore<Query, Context> contextStore =
InstrumentationContext.get(Query.class, Context.class);
return SessionMethodUtils.startScopeFrom(
contextStore, query, query.getQueryString(), null, true);
context = SessionMethodUtils.startSpanFrom(contextStore, query, query.getQueryString(), null);
if (context != null) {
scope = context.makeCurrent();
}
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void endMethod(
@Advice.Enter SpanWithScope spanWithScope, @Advice.Thrown Throwable throwable) {
@Advice.Thrown Throwable throwable,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
SessionMethodUtils.closeScope(spanWithScope, throwable, null, null);
if (scope != null) {
SessionMethodUtils.end(context, throwable, null, null);
scope.close();
}
}
}
}

View File

@ -19,10 +19,11 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.HashMap;
@ -137,34 +138,53 @@ public class SessionInstrumentation implements TypeInstrumentation {
public static class SessionMethodAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope startMethod(
public static void startMethod(
@Advice.This Object session,
@Advice.Origin("#m") String name,
@Advice.Argument(0) Object entity) {
@Advice.Argument(0) Object entity,
@Advice.Local("otelContext") Context spanContext,
@Advice.Local("otelScope") Scope scope) {
boolean startSpan = !SCOPE_ONLY_METHODS.contains(name);
Context sessionContext = null;
if (session instanceof Session) {
ContextStore<Session, Context> contextStore =
InstrumentationContext.get(Session.class, Context.class);
return SessionMethodUtils.startScopeFrom(
contextStore, (Session) session, "Session." + name, entity, startSpan);
sessionContext = contextStore.get((Session) session);
} else if (session instanceof StatelessSession) {
ContextStore<StatelessSession, Context> contextStore =
InstrumentationContext.get(StatelessSession.class, Context.class);
return SessionMethodUtils.startScopeFrom(
contextStore, (StatelessSession) session, "Session." + name, entity, startSpan);
sessionContext = contextStore.get((StatelessSession) session);
}
if (sessionContext == null) {
return; // No state found. We aren't in a Session.
}
if (CallDepthThreadLocalMap.incrementCallDepth(SessionMethodUtils.class) > 0) {
return; // This method call is being traced already.
}
if (!SCOPE_ONLY_METHODS.contains(name)) {
Span span = tracer().startSpan(sessionContext, "Session." + name, entity);
spanContext = sessionContext.with(span);
scope = spanContext.makeCurrent();
} else {
scope = sessionContext.makeCurrent();
}
return null;
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void endMethod(
@Advice.Enter SpanWithScope spanWithScope,
@Advice.Thrown Throwable throwable,
@Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returned,
@Advice.Origin("#m") String name) {
@Advice.Origin("#m") String name,
@Advice.Local("otelContext") Context spanContext,
@Advice.Local("otelScope") Scope scope) {
SessionMethodUtils.closeScope(spanWithScope, throwable, "Session." + name, returned);
if (scope != null) {
scope.close();
SessionMethodUtils.end(spanContext, throwable, "Session." + name, returned);
}
}
}

View File

@ -13,9 +13,9 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
@ -47,20 +47,31 @@ public class TransactionInstrumentation implements TypeInstrumentation {
public static class TransactionCommitAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope startCommit(@Advice.This Transaction transaction) {
public static void startCommit(
@Advice.This Transaction transaction,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
ContextStore<Transaction, Context> contextStore =
InstrumentationContext.get(Transaction.class, Context.class);
return SessionMethodUtils.startScopeFrom(
contextStore, transaction, "Transaction.commit", null, true);
context =
SessionMethodUtils.startSpanFrom(contextStore, transaction, "Transaction.commit", null);
if (context != null) {
scope = context.makeCurrent();
}
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void endCommit(
@Advice.Enter SpanWithScope spanWithScope, @Advice.Thrown Throwable throwable) {
@Advice.Thrown Throwable throwable,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
SessionMethodUtils.closeScope(spanWithScope, throwable, null, null);
if (scope != null) {
SessionMethodUtils.end(context, throwable, null, null);
scope.close();
}
}
}
}

View File

@ -13,9 +13,9 @@ import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
@ -48,24 +48,33 @@ public class CriteriaInstrumentation implements TypeInstrumentation {
public static class CriteriaMethodAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope startMethod(
@Advice.This Criteria criteria, @Advice.Origin("#m") String name) {
public static void startMethod(
@Advice.This Criteria criteria,
@Advice.Origin("#m") String name,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
ContextStore<Criteria, Context> contextStore =
InstrumentationContext.get(Criteria.class, Context.class);
return SessionMethodUtils.startScopeFrom(
contextStore, criteria, "Criteria." + name, null, true);
context = SessionMethodUtils.startSpanFrom(contextStore, criteria, "Criteria." + name, null);
if (context != null) {
scope = context.makeCurrent();
}
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void endMethod(
@Advice.Enter SpanWithScope spanWithScope,
@Advice.Thrown Throwable throwable,
@Advice.Return(typing = Assigner.Typing.DYNAMIC) Object entity,
@Advice.Origin("#m") String name) {
@Advice.Origin("#m") String name,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
SessionMethodUtils.closeScope(spanWithScope, throwable, "Criteria." + name, entity);
if (scope != null) {
scope.close();
SessionMethodUtils.end(context, throwable, "Criteria." + name, entity);
}
}
}
}

View File

@ -13,9 +13,9 @@ import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
@ -47,20 +47,30 @@ public class QueryInstrumentation implements TypeInstrumentation {
public static class QueryMethodAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope startMethod(@Advice.This Query query) {
public static void startMethod(
@Advice.This Query query,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
ContextStore<Query, Context> contextStore =
InstrumentationContext.get(Query.class, Context.class);
return SessionMethodUtils.startScopeFrom(
contextStore, query, query.getQueryString(), null, true);
context = SessionMethodUtils.startSpanFrom(contextStore, query, query.getQueryString(), null);
if (context != null) {
scope = context.makeCurrent();
}
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void endMethod(
@Advice.Enter SpanWithScope spanWithScope, @Advice.Thrown Throwable throwable) {
@Advice.Thrown Throwable throwable,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
SessionMethodUtils.closeScope(spanWithScope, throwable, null, null);
if (scope != null) {
scope.close();
SessionMethodUtils.end(context, throwable, null, null);
}
}
}
}

View File

@ -19,10 +19,11 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.HashMap;
@ -126,26 +127,46 @@ public class SessionInstrumentation implements TypeInstrumentation {
public static class SessionMethodAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope startMethod(
public static void startMethod(
@Advice.This SharedSessionContract session,
@Advice.Origin("#m") String name,
@Advice.Argument(0) Object entity) {
@Advice.Argument(0) Object entity,
@Advice.Local("otelContext") Context spanContext,
@Advice.Local("otelScope") Scope scope) {
boolean startSpan = !SCOPE_ONLY_METHODS.contains(name);
ContextStore<SharedSessionContract, Context> contextStore =
InstrumentationContext.get(SharedSessionContract.class, Context.class);
return SessionMethodUtils.startScopeFrom(
contextStore, session, "Session." + name, entity, startSpan);
Context sessionContext = contextStore.get(session);
if (sessionContext == null) {
return; // No state found. We aren't in a Session.
}
if (CallDepthThreadLocalMap.incrementCallDepth(SessionMethodUtils.class) > 0) {
return; // This method call is being traced already.
}
if (!SCOPE_ONLY_METHODS.contains(name)) {
Span span = tracer().startSpan(sessionContext, "Session." + name, entity);
spanContext = sessionContext.with(span);
scope = spanContext.makeCurrent();
} else {
scope = sessionContext.makeCurrent();
}
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void endMethod(
@Advice.Enter SpanWithScope spanWithScope,
@Advice.Thrown Throwable throwable,
@Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returned,
@Advice.Origin("#m") String name) {
@Advice.Origin("#m") String name,
@Advice.Local("otelContext") Context spanContext,
@Advice.Local("otelScope") Scope scope) {
SessionMethodUtils.closeScope(spanWithScope, throwable, "Session." + name, returned);
if (scope != null) {
scope.close();
SessionMethodUtils.end(spanContext, throwable, "Session." + name, returned);
}
}
}

View File

@ -13,9 +13,9 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
@ -47,20 +47,31 @@ public class TransactionInstrumentation implements TypeInstrumentation {
public static class TransactionCommitAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope startCommit(@Advice.This Transaction transaction) {
public static void startCommit(
@Advice.This Transaction transaction,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
ContextStore<Transaction, Context> contextStore =
InstrumentationContext.get(Transaction.class, Context.class);
return SessionMethodUtils.startScopeFrom(
contextStore, transaction, "Transaction.commit", null, true);
context =
SessionMethodUtils.startSpanFrom(contextStore, transaction, "Transaction.commit", null);
if (context != null) {
scope = context.makeCurrent();
}
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void endCommit(
@Advice.Enter SpanWithScope spanWithScope, @Advice.Thrown Throwable throwable) {
@Advice.Thrown Throwable throwable,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
SessionMethodUtils.closeScope(spanWithScope, throwable, null, null);
if (scope != null) {
scope.close();
SessionMethodUtils.end(context, throwable, null, null);
}
}
}
}

View File

@ -12,9 +12,9 @@ import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.instrumentation.hibernate.SessionMethodUtils;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
@ -46,20 +46,33 @@ public class ProcedureCallInstrumentation implements TypeInstrumentation {
public static class ProcedureCallMethodAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope startMethod(
@Advice.This ProcedureCall call, @Advice.Origin("#m") String name) {
public static void startMethod(
@Advice.This ProcedureCall call,
@Advice.Origin("#m") String name,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
ContextStore<ProcedureCall, Context> contextStore =
InstrumentationContext.get(ProcedureCall.class, Context.class);
return SessionMethodUtils.startScopeFrom(
contextStore, call, "ProcedureCall." + name, call.getProcedureName(), true);
context =
SessionMethodUtils.startSpanFrom(
contextStore, call, "ProcedureCall." + name, call.getProcedureName());
if (context != null) {
scope = context.makeCurrent();
}
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void endMethod(
@Advice.Enter SpanWithScope spanWithScope, @Advice.Thrown Throwable throwable) {
SessionMethodUtils.closeScope(spanWithScope, throwable, null, null);
@Advice.Thrown Throwable throwable,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (scope != null) {
scope.close();
SessionMethodUtils.end(context, throwable, null, null);
}
}
}
}

View File

@ -11,24 +11,21 @@ import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.Nullable;
public class SessionMethodUtils {
public static final Set<String> SCOPE_ONLY_METHODS =
new HashSet<>(Arrays.asList("immediateLoad", "internalLoad"));
// Starts a scope as a child from a Span, where the Span is attached to the given spanKey using
// the given contextStore.
public static <TARGET, ENTITY> SpanWithScope startScopeFrom(
public static <TARGET, ENTITY> Context startSpanFrom(
ContextStore<TARGET, Context> contextStore,
TARGET spanKey,
String operationName,
ENTITY entity,
boolean createSpan) {
ENTITY entity) {
Context sessionContext = contextStore.get(spanKey);
if (sessionContext == null) {
@ -40,40 +37,31 @@ public class SessionMethodUtils {
return null; // This method call is being traced already.
}
if (createSpan) {
Span span = tracer().startSpan(sessionContext, operationName, entity);
return new SpanWithScope(span, sessionContext.with(span).makeCurrent());
} else {
return new SpanWithScope(null, sessionContext.makeCurrent());
}
Span span = tracer().startSpan(sessionContext, operationName, entity);
return sessionContext.with(span);
}
// Closes a Scope/Span, adding an error tag if the given Throwable is not null.
public static void closeScope(
SpanWithScope spanWithScope, Throwable throwable, String operationName, Object entity) {
public static void end(
@Nullable Context context, Throwable throwable, String operationName, Object entity) {
if (spanWithScope == null) {
// This method call was re-entrant. Do nothing, since it is being traced by the parent/first
// call.
return;
}
CallDepthThreadLocalMap.reset(SessionMethodUtils.class);
Span span = spanWithScope.getSpan();
if (span != null) {
if (operationName != null && entity != null) {
String entityName = tracer().entityName(entity);
if (entityName != null) {
span.updateName(operationName + " " + entityName);
}
}
if (throwable != null) {
tracer().endExceptionally(span, throwable);
} else {
tracer().end(span);
if (context == null) {
return;
}
Span span = Span.fromContext(context);
if (operationName != null && entity != null) {
String entityName = tracer().entityName(entity);
if (entityName != null) {
span.updateName(operationName + " " + entityName);
}
}
spanWithScope.closeScope();
if (throwable != null) {
tracer().endExceptionally(span, throwable);
} else {
tracer().end(span);
}
}
// Copies a span from the given Session ContextStore into the targetContextStore. Used to

View File

@ -17,8 +17,8 @@ import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.lang.reflect.Method;
import java.util.Map;
@ -63,31 +63,34 @@ public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation {
public static class JaxRsAnnotationsAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope nameSpan(@Advice.This Object target, @Advice.Origin Method method) {
public static void nameSpan(
@Advice.This Object target,
@Advice.Origin Method method,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
if (CallDepthThreadLocalMap.incrementCallDepth(Path.class) > 0) {
return null;
return;
}
Span span = tracer().startSpan(target.getClass(), method);
return new SpanWithScope(span, span.makeCurrent());
span = tracer().startSpan(target.getClass(), method);
scope = span.makeCurrent();
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(
@Advice.Enter SpanWithScope spanWithScope, @Advice.Thrown Throwable throwable) {
if (spanWithScope == null) {
@Advice.Thrown Throwable throwable,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}
CallDepthThreadLocalMap.reset(Path.class);
Span span = spanWithScope.getSpan();
scope.close();
if (throwable == null) {
tracer().end(span);
} else {
tracer().endExceptionally(span, throwable);
}
spanWithScope.closeScope();
}
}
}

View File

@ -6,7 +6,7 @@
package io.opentelemetry.javaagent.instrumentation.kafkaclients;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.context.Scope;
import java.util.Iterator;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.slf4j.Logger;
@ -24,7 +24,9 @@ public class TracingIterator implements Iterator<ConsumerRecord<?, ?>> {
* Note: this may potentially create problems if this iterator is used from different threads. But
* at the moment we cannot do much about this.
*/
private SpanWithScope currentSpanWithScope;
private Span currentSpan;
private Scope currentScope;
public TracingIterator(
Iterator<ConsumerRecord<?, ?>> delegateIterator, KafkaConsumerTracer tracer) {
@ -35,30 +37,21 @@ public class TracingIterator implements Iterator<ConsumerRecord<?, ?>> {
@Override
public boolean hasNext() {
if (currentSpanWithScope != null) {
tracer.end(currentSpanWithScope.getSpan());
currentSpanWithScope.closeScope();
currentSpanWithScope = null;
}
closeScopeAndEndSpan();
return delegateIterator.hasNext();
}
@Override
public ConsumerRecord<?, ?> next() {
if (currentSpanWithScope != null) {
// in case they didn't call hasNext()...
tracer.end(currentSpanWithScope.getSpan());
currentSpanWithScope.closeScope();
currentSpanWithScope = null;
}
// in case they didn't call hasNext()...
closeScopeAndEndSpan();
ConsumerRecord<?, ?> next = delegateIterator.next();
try {
if (next != null) {
Span span = tracer.startSpan(next);
currentSpanWithScope = new SpanWithScope(span, span.makeCurrent());
currentSpan = tracer.startSpan(next);
currentScope = currentSpan.makeCurrent();
}
} catch (Exception e) {
log.debug("Error during decoration", e);
@ -66,6 +59,15 @@ public class TracingIterator implements Iterator<ConsumerRecord<?, ?>> {
return next;
}
private void closeScopeAndEndSpan() {
if (currentScope != null) {
currentScope.close();
currentScope = null;
tracer.end(currentSpan);
currentSpan = null;
}
}
@Override
public void remove() {
delegateIterator.remove();

View File

@ -5,18 +5,25 @@
package io.opentelemetry.javaagent.instrumentation.kafkastreams;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
public class SpanScopeHolder {
public static final ThreadLocal<SpanScopeHolder> HOLDER = new ThreadLocal<>();
private SpanWithScope spanWithScope;
private Span span;
private Scope scope;
public SpanWithScope getSpanWithScope() {
return spanWithScope;
public void closeScope() {
scope.close();
}
public void setSpanWithScope(SpanWithScope spanWithScope) {
this.spanWithScope = spanWithScope;
public Span getSpan() {
return span;
}
public void set(Span span, Scope scope) {
this.span = span;
this.scope = scope;
}
}

View File

@ -14,7 +14,6 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.returns;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.asm.Advice;
@ -56,7 +55,7 @@ public class StreamTaskStartInstrumentation implements TypeInstrumentation {
Span span = tracer().startSpan(record);
holder.setSpanWithScope(new SpanWithScope(span, span.makeCurrent()));
holder.set(span, span.makeCurrent());
}
}
}

View File

@ -14,7 +14,6 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.asm.Advice;
@ -49,11 +48,9 @@ public class StreamTaskStopInstrumentation implements TypeInstrumentation {
public static void stopSpan(
@Advice.Enter SpanScopeHolder holder, @Advice.Thrown Throwable throwable) {
HOLDER.remove();
SpanWithScope spanWithScope = holder.getSpanWithScope();
if (spanWithScope != null) {
spanWithScope.closeScope();
Span span = spanWithScope.getSpan();
Span span = holder.getSpan();
if (span != null) {
holder.closeScope();
if (throwable != null) {
tracer().endExceptionally(span, throwable);

View File

@ -8,14 +8,13 @@ package io.opentelemetry.javaagent.instrumentation.lettuce.v4_0;
import static com.lambdaworks.redis.protocol.CommandKeyword.SEGFAULT;
import static com.lambdaworks.redis.protocol.CommandType.DEBUG;
import static com.lambdaworks.redis.protocol.CommandType.SHUTDOWN;
import static io.opentelemetry.javaagent.instrumentation.lettuce.v4_0.LettuceDatabaseClientTracer.tracer;
import com.lambdaworks.redis.RedisURI;
import com.lambdaworks.redis.protocol.AsyncCommand;
import com.lambdaworks.redis.protocol.CommandType;
import com.lambdaworks.redis.protocol.ProtocolKeyword;
import com.lambdaworks.redis.protocol.RedisCommand;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import java.util.EnumSet;
import java.util.Set;
import java.util.concurrent.CancellationException;
@ -24,52 +23,30 @@ public final class InstrumentationPoints {
private static final Set<CommandType> NON_INSTRUMENTING_COMMANDS = EnumSet.of(SHUTDOWN, DEBUG);
public static SpanWithScope beforeCommand(RedisCommand<?, ?, ?> command) {
Span span = LettuceDatabaseClientTracer.tracer().startSpan(null, command);
return new SpanWithScope(span, LettuceDatabaseClientTracer.tracer().startScope(span));
}
public static void afterCommand(
RedisCommand<?, ?, ?> command,
SpanWithScope spanWithScope,
Span span,
Throwable throwable,
AsyncCommand<?, ?, ?> asyncCommand) {
Span span = spanWithScope.getSpan();
if (throwable != null) {
LettuceDatabaseClientTracer.tracer().endExceptionally(span, throwable);
tracer().endExceptionally(span, throwable);
} else if (expectsResponse(command)) {
asyncCommand.handleAsync(
(value, ex) -> {
if (ex == null) {
LettuceDatabaseClientTracer.tracer().end(span);
tracer().end(span);
} else if (ex instanceof CancellationException) {
span.setAttribute("lettuce.command.cancelled", true);
LettuceDatabaseClientTracer.tracer().end(span);
tracer().end(span);
} else {
LettuceDatabaseClientTracer.tracer().endExceptionally(span, ex);
tracer().endExceptionally(span, ex);
}
return null;
});
} else {
// No response is expected, so we must finish the span now.
LettuceDatabaseClientTracer.tracer().end(span);
tracer().end(span);
}
spanWithScope.closeScope();
}
public static SpanWithScope beforeConnect(RedisURI redisUri) {
Span span = LettuceConnectionDatabaseClientTracer.tracer().startSpan(redisUri, "CONNECT");
return new SpanWithScope(span, LettuceConnectionDatabaseClientTracer.tracer().startScope(span));
}
public static void afterConnect(SpanWithScope spanWithScope, Throwable throwable) {
Span span = spanWithScope.getSpan();
if (throwable != null) {
LettuceConnectionDatabaseClientTracer.tracer().endExceptionally(span, throwable);
} else {
LettuceConnectionDatabaseClientTracer.tracer().end(span);
}
spanWithScope.closeScope();
}
/**

View File

@ -5,24 +5,33 @@
package io.opentelemetry.javaagent.instrumentation.lettuce.v4_0;
import static io.opentelemetry.javaagent.instrumentation.lettuce.v4_0.LettuceDatabaseClientTracer.tracer;
import com.lambdaworks.redis.protocol.AsyncCommand;
import com.lambdaworks.redis.protocol.RedisCommand;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import net.bytebuddy.asm.Advice;
public class LettuceAsyncCommandsAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope onEnter(@Advice.Argument(0) RedisCommand<?, ?, ?> command) {
return InstrumentationPoints.beforeCommand(command);
public static void onEnter(
@Advice.Argument(0) RedisCommand<?, ?, ?> command,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
span = tracer().startSpan(null, command);
scope = tracer().startScope(span);
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void onExit(
@Advice.Argument(0) RedisCommand<?, ?, ?> command,
@Advice.Enter SpanWithScope spanWithScope,
@Advice.Thrown Throwable throwable,
@Advice.Return AsyncCommand<?, ?, ?> asyncCommand) {
InstrumentationPoints.afterCommand(command, spanWithScope, throwable, asyncCommand);
@Advice.Return AsyncCommand<?, ?, ?> asyncCommand,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
scope.close();
InstrumentationPoints.afterCommand(command, span, throwable, asyncCommand);
}
}

View File

@ -5,19 +5,34 @@
package io.opentelemetry.javaagent.instrumentation.lettuce.v4_0;
import static io.opentelemetry.javaagent.instrumentation.lettuce.v4_0.LettuceConnectionDatabaseClientTracer.tracer;
import com.lambdaworks.redis.RedisURI;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import net.bytebuddy.asm.Advice;
public class RedisConnectionAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope onEnter(@Advice.Argument(1) RedisURI redisUri) {
return InstrumentationPoints.beforeConnect(redisUri);
public static void onEnter(
@Advice.Argument(1) RedisURI redisUri,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
span = tracer().startSpan(redisUri, "CONNECT");
scope = tracer().startScope(span);
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void onExit(@Advice.Enter SpanWithScope scope, @Advice.Thrown Throwable throwable) {
InstrumentationPoints.afterConnect(scope, throwable);
public static void onExit(
@Advice.Thrown Throwable throwable,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
scope.close();
if (throwable != null) {
tracer().endExceptionally(span, throwable);
} else {
tracer().end(span);
}
}
}

View File

@ -9,8 +9,8 @@ import static io.opentelemetry.javaagent.instrumentation.play.v2_3.PlayTracer.tr
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Span.Kind;
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import net.bytebuddy.asm.Advice;
import play.api.mvc.Action;
import play.api.mvc.Headers;
@ -20,30 +20,31 @@ import scala.concurrent.Future;
public class PlayAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope onEnter(@Advice.Argument(0) final Request<?> req) {
Span span = tracer().startSpan("play.request", Kind.INTERNAL);
return new SpanWithScope(span, span.makeCurrent());
public static void onEnter(
@Advice.Argument(0) final Request<?> req,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
span = tracer().startSpan("play.request", Kind.INTERNAL);
scope = span.makeCurrent();
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopTraceOnResponse(
@Advice.Enter SpanWithScope playControllerScope,
@Advice.This Object thisAction,
@Advice.Thrown Throwable throwable,
@Advice.Argument(0) Request<?> req,
@Advice.Return(readOnly = false) Future<Result> responseFuture) {
Span playControllerSpan = playControllerScope.getSpan();
@Advice.Return(readOnly = false) Future<Result> responseFuture,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
scope.close();
// span finished in RequestCompleteCallback
if (throwable == null) {
responseFuture.onComplete(
new RequestCompleteCallback(playControllerSpan),
((Action<?>) thisAction).executionContext());
new RequestCompleteCallback(span), ((Action<?>) thisAction).executionContext());
} else {
tracer().endExceptionally(playControllerSpan, throwable);
tracer().endExceptionally(span, throwable);
}
playControllerScope.closeScope();
// span finished in RequestCompleteCallback
// set the span name on the upstream akka/netty span
tracer().updateSpanName(BaseTracer.getCurrentServerSpan(), req);

View File

@ -9,8 +9,8 @@ import static io.opentelemetry.javaagent.instrumentation.play.v2_4.PlayTracer.tr
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Span.Kind;
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import net.bytebuddy.asm.Advice;
import play.api.mvc.Action;
import play.api.mvc.Headers;
@ -20,36 +20,36 @@ import scala.concurrent.Future;
public class PlayAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope onEnter(@Advice.Argument(0) Request<?> req) {
Span span = tracer().startSpan("play.request", Kind.INTERNAL);
return new SpanWithScope(span, span.makeCurrent());
public static void onEnter(
@Advice.Argument(0) Request<?> req,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
span = tracer().startSpan("play.request", Kind.INTERNAL);
scope = span.makeCurrent();
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopTraceOnResponse(
@Advice.Enter SpanWithScope playControllerScope,
@Advice.This Object thisAction,
@Advice.Thrown Throwable throwable,
@Advice.Argument(0) Request<?> req,
@Advice.Return(readOnly = false) Future<Result> responseFuture) {
Span playControllerSpan = playControllerScope.getSpan();
@Advice.Return(readOnly = false) Future<Result> responseFuture,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
// Call onRequest on return after tags are populated.
tracer().updateSpanName(playControllerSpan, req);
tracer().updateSpanName(span, req);
scope.close();
// span finished in RequestCompleteCallback
if (throwable == null) {
responseFuture.onComplete(
new RequestCompleteCallback(playControllerSpan),
((Action<?>) thisAction).executionContext());
new RequestCompleteCallback(span), ((Action<?>) thisAction).executionContext());
} else {
tracer().endExceptionally(playControllerSpan, throwable);
tracer().endExceptionally(span, throwable);
}
playControllerScope.closeScope();
// span finished in RequestCompleteCallback
Span rootSpan = BaseTracer.getCurrentServerSpan();
// set the span name on the upstream akka/netty span
tracer().updateSpanName(rootSpan, req);
tracer().updateSpanName(BaseTracer.getCurrentServerSpan(), req);
}
// Unused method for muzzle

View File

@ -9,8 +9,8 @@ import static io.opentelemetry.javaagent.instrumentation.play.v2_6.PlayTracer.tr
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Span.Kind;
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import net.bytebuddy.asm.Advice;
import play.api.mvc.Action;
import play.api.mvc.Request;
@ -19,36 +19,35 @@ import scala.concurrent.Future;
public class PlayAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope onEnter(@Advice.Argument(0) Request<?> req) {
Span span = tracer().startSpan("play.request", Kind.INTERNAL);
return new SpanWithScope(span, span.makeCurrent());
public static void onEnter(
@Advice.Argument(0) Request<?> req,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
span = tracer().startSpan("play.request", Kind.INTERNAL);
scope = span.makeCurrent();
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopTraceOnResponse(
@Advice.Enter SpanWithScope playControllerScope,
@Advice.This Object thisAction,
@Advice.Thrown Throwable throwable,
@Advice.Argument(0) Request<?> req,
@Advice.Return(readOnly = false) Future<Result> responseFuture) {
Span playControllerSpan = playControllerScope.getSpan();
@Advice.Return(readOnly = false) Future<Result> responseFuture,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
// Call onRequest on return after tags are populated.
tracer().updateSpanName(playControllerSpan, req);
tracer().updateSpanName(span, req);
scope.close();
// span finished in RequestCompleteCallback
if (throwable == null) {
responseFuture.onComplete(
new RequestCompleteCallback(playControllerSpan),
((Action<?>) thisAction).executionContext());
new RequestCompleteCallback(span), ((Action<?>) thisAction).executionContext());
} else {
tracer().endExceptionally(playControllerSpan, throwable);
tracer().endExceptionally(span, throwable);
}
playControllerScope.closeScope();
// span finished in RequestCompleteCallback
Span rootSpan = BaseTracer.getCurrentServerSpan();
// set the span name on the upstream akka/netty span
tracer().updateSpanName(rootSpan, req);
tracer().updateSpanName(BaseTracer.getCurrentServerSpan(), req);
}
}

View File

@ -9,9 +9,9 @@ import static io.opentelemetry.javaagent.instrumentation.spring.webflux.server.S
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.servlet.ServletContextPath;
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import net.bytebuddy.asm.Advice;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.HandlerMapping;
@ -21,10 +21,11 @@ import org.springframework.web.util.pattern.PathPattern;
public class HandlerAdapterAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope methodEnter(
@Advice.Argument(0) ServerWebExchange exchange, @Advice.Argument(1) Object handler) {
public static void methodEnter(
@Advice.Argument(0) ServerWebExchange exchange,
@Advice.Argument(1) Object handler,
@Advice.Local("otelScope") Scope scope) {
SpanWithScope spanWithScope = null;
Context context = exchange.getAttribute(AdviceUtils.CONTEXT_ATTRIBUTE);
if (handler != null && context != null) {
Span span = Span.fromContext(context);
@ -44,7 +45,7 @@ public class HandlerAdapterAdvice {
span.updateName(operationName);
span.setAttribute("spring-webflux.handler.type", handlerType);
spanWithScope = new SpanWithScope(span, context.makeCurrent());
scope = context.makeCurrent();
}
if (context != null) {
@ -56,20 +57,18 @@ public class HandlerAdapterAdvice {
ServletContextPath.prepend(Context.current(), bestPattern.toString()));
}
}
return spanWithScope;
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void methodExit(
@Advice.Argument(0) ServerWebExchange exchange,
@Advice.Enter SpanWithScope spanWithScope,
@Advice.Thrown Throwable throwable) {
@Advice.Thrown Throwable throwable,
@Advice.Local("otelScope") Scope scope) {
if (throwable != null) {
AdviceUtils.finishSpanIfPresent(exchange, throwable);
}
if (spanWithScope != null) {
spanWithScope.closeScope();
if (scope != null) {
scope.close();
// span finished in SpanFinishingSubscriber
}
}

View File

@ -14,8 +14,8 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.HashMap;
import java.util.List;
@ -84,21 +84,25 @@ public class DispatcherServletInstrumentation implements TypeInstrumentation {
public static class RenderAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope onEnter(@Advice.Argument(0) ModelAndView mv) {
Span span = tracer().startSpan(mv);
return new SpanWithScope(span, span.makeCurrent());
public static void onEnter(
@Advice.Argument(0) ModelAndView mv,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
span = tracer().startSpan(mv);
scope = span.makeCurrent();
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(
@Advice.Enter SpanWithScope spanWithScope, @Advice.Thrown Throwable throwable) {
Span span = spanWithScope.getSpan();
@Advice.Thrown Throwable throwable,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
scope.close();
if (throwable == null) {
tracer().end(span);
} else {
tracer().endExceptionally(span, throwable);
}
spanWithScope.closeScope();
}
}

View File

@ -18,9 +18,9 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
@ -54,35 +54,36 @@ public class HandlerAdapterInstrumentation implements TypeInstrumentation {
public static class ControllerAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope nameResourceAndStartSpan(
@Advice.Argument(0) HttpServletRequest request, @Advice.Argument(2) Object handler) {
public static void nameResourceAndStartSpan(
@Advice.Argument(0) HttpServletRequest request,
@Advice.Argument(2) Object handler,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
Context context = Java8BytecodeBridge.currentContext();
Span serverSpan = BaseTracer.getCurrentServerSpan(context);
if (serverSpan != null) {
// Name the parent span based on the matching pattern
tracer().onRequest(context, serverSpan, request);
// Now create a span for handler/controller execution.
Span span = tracer().startHandlerSpan(handler);
return new SpanWithScope(span, context.with(span).makeCurrent());
} else {
return null;
span = tracer().startHandlerSpan(handler);
scope = context.with(span).makeCurrent();
}
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(
@Advice.Enter SpanWithScope spanWithScope, @Advice.Thrown Throwable throwable) {
if (spanWithScope == null) {
@Advice.Thrown Throwable throwable,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}
Span span = spanWithScope.getSpan();
scope.close();
if (throwable == null) {
tracer().end(span);
} else {
tracer().endExceptionally(span, throwable);
}
spanWithScope.closeScope();
}
}
}

View File

@ -22,8 +22,8 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.twilio.Twilio;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.asm.Advice;
@ -75,52 +75,48 @@ public class TwilioAsyncInstrumentation implements TypeInstrumentation {
/** Method entry instrumentation. */
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope methodEnter(
@Advice.This Object that, @Advice.Origin("#m") String methodName) {
public static void methodEnter(
@Advice.This Object that,
@Advice.Origin("#m") String methodName,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
// Ensure that we only create a span for the top-level Twilio client method; except in the
// case of async operations where we want visibility into how long the task was delayed from
// starting. Our call depth checker does not span threads, so the async case is handled
// automatically for us.
int callDepth = CallDepthThreadLocalMap.incrementCallDepth(Twilio.class);
if (callDepth > 0) {
return null;
if (CallDepthThreadLocalMap.incrementCallDepth(Twilio.class) > 0) {
return;
}
// Don't automatically close the span with the scope if we're executing an async method
Span span = tracer().startSpan(that, methodName);
return new SpanWithScope(span, tracer().startScope(span));
span = tracer().startSpan(that, methodName);
scope = tracer().startScope(span);
}
/** Method exit instrumentation. */
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void methodExit(
@Advice.Enter SpanWithScope spanWithScope,
@Advice.Thrown Throwable throwable,
@Advice.Return ListenableFuture<?> response) {
if (spanWithScope == null) {
@Advice.Return ListenableFuture<?> response,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}
CallDepthThreadLocalMap.reset(Twilio.class);
// If we have a scope (i.e. we were the top-level Twilio SDK invocation),
try {
Span span = spanWithScope.getSpan();
if (throwable != null) {
// There was an synchronous error,
// which means we shouldn't wait for a callback to close the span.
tracer().endExceptionally(span, throwable);
} else {
// We're calling an async operation, we still need to finish the span when it's
// complete and report the results; set an appropriate callback
Futures.addCallback(
response, new SpanFinishingCallback<>(span), Twilio.getExecutorService());
}
} finally {
spanWithScope.closeScope();
// span finished in SpanFinishingCallback
// span finished in SpanFinishingCallback
scope.close();
if (throwable != null) {
// There was an synchronous error,
// which means we shouldn't wait for a callback to close the span.
tracer().endExceptionally(span, throwable);
} else {
// We're calling an async operation, we still need to finish the span when it's
// complete and report the results; set an appropriate callback
Futures.addCallback(
response, new SpanFinishingCallback<>(span), Twilio.getExecutorService());
}
}
}

View File

@ -17,8 +17,8 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
import com.twilio.Twilio;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.asm.Advice;
@ -71,45 +71,41 @@ public class TwilioSyncInstrumentation implements TypeInstrumentation {
/** Method entry instrumentation. */
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope methodEnter(
@Advice.This Object that, @Advice.Origin("#m") String methodName) {
public static void methodEnter(
@Advice.This Object that,
@Advice.Origin("#m") String methodName,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
// Ensure that we only create a span for the top-level Twilio client method; except in the
// case of async operations where we want visibility into how long the task was delayed from
// starting. Our call depth checker does not span threads, so the async case is handled
// automatically for us.
int callDepth = CallDepthThreadLocalMap.incrementCallDepth(Twilio.class);
if (callDepth > 0) {
return null;
if (CallDepthThreadLocalMap.incrementCallDepth(Twilio.class) > 0) {
return;
}
Span span = tracer().startSpan(that, methodName);
return new SpanWithScope(span, tracer().startScope(span));
span = tracer().startSpan(that, methodName);
scope = tracer().startScope(span);
}
/** Method exit instrumentation. */
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void methodExit(
@Advice.Enter SpanWithScope spanWithScope,
@Advice.Thrown Throwable throwable,
@Advice.Return Object response) {
if (spanWithScope == null) {
@Advice.Return Object response,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}
CallDepthThreadLocalMap.reset(Twilio.class);
// If we have a scope (i.e. we were the top-level Twilio SDK invocation),
try {
Span span = spanWithScope.getSpan();
if (throwable != null) {
tracer().endExceptionally(span, throwable);
} else {
tracer().end(span, response);
}
} finally {
spanWithScope.closeScope();
scope.close();
if (throwable != null) {
tracer().endExceptionally(span, throwable);
} else {
tracer().end(span, response);
}
}
}

View File

@ -1,88 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.api;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
/**
* This is deprecated.
*
* <p>Originally, we used {@code SpanWithScope} to pass the {@link Span} and {@link Scope} between
* {@code @Advice.OnMethodEnter} and {@code @Advice.OnMethodExit}, e.g.
*
* <pre>
* &#64;Advice.OnMethodEnter(...)
* public static SpanWithScope onEnter(...) {
* ...
* Span span = ...
* return new SpanWithScope(span, span.makeCurrent());
* }
*
* &#64;Advice.OnMethodExit(...)
* public static void stopSpan(
* ...
* &#64;Advice.Enter final SpanWithScope spanWithScope) {
* Span span = spanWithScope.getSpan();
* ...
* span.end();
* spanWithScope.closeScope();
* }
* </pre>
*
* <p>We are (slowly) migrating to a new pattern using `@Advice.Local`:
*
* <pre>
* &#64;Advice.OnMethodEnter(...)
* public static void onEnter(
* ...
* &#64;Advice.Local("otelSpan") Span span,
* &#64;Advice.Local("otelScope") Scope scope) {
* ...
* span = ...
* scope = ...
* }
*
* &#64;Advice.OnMethodExit
* public static void onExit(
* ...
* &#64;Advice.Local("otelSpan") Span span,
* &#64;Advice.Local("otelScope") Scope scope) {
* ...
* span.end();
* scope.close();
* }
* </pre>
*
* <p>This new pattern has the following benefits:
*
* <ul>
* <li>The new pattern is more efficient since it doesn't require instantiating the {@code
* SpanWithScope} holder object
* <li>The new pattern extends nicely in the common case where we also need to pass {@link
* CallDepth} between the methods
* </ul>
*
* @deprecated see above
*/
@Deprecated
public class SpanWithScope {
private final Span span;
private final Scope scope;
public SpanWithScope(Span span, Scope scope) {
this.span = span;
this.scope = scope;
}
public Span getSpan() {
return span;
}
public void closeScope() {
scope.close();
}
}