Refactored Twilio and Hibernate instrumentation (#81)
* Refactor of twilio (WIP) * Refactored hibernate instrumentation * Finished refactoring hibernate instrumentation * Minor changes * Minor change * Moved files after upstream restructuring * Fixed typo and Twilio test issues * Refactored hibernate tests * Fixed formatting * Moved span auto close functionality to SessionState
This commit is contained in:
parent
819ca7c256
commit
f53167063e
|
@ -62,7 +62,7 @@ public class QueryInstrumentation extends AbstractHibernateInstrumentation {
|
|||
SessionMethodUtils.startScopeFrom(
|
||||
contextStore, query, "hibernate.query." + name, null, true);
|
||||
if (state != null) {
|
||||
DECORATOR.onStatement(state.getMethodScope().span(), query.getQueryString());
|
||||
DECORATOR.onStatement(state.getMethodScope().getSpan(), query.getQueryString());
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.opentelemetry.auto.instrumentation.hibernate.core.v3_3;
|
||||
|
||||
import static io.opentelemetry.auto.instrumentation.api.AgentTracer.startSpan;
|
||||
import static io.opentelemetry.auto.instrumentation.hibernate.HibernateDecorator.DECORATOR;
|
||||
import static io.opentelemetry.auto.instrumentation.hibernate.HibernateDecorator.TRACER;
|
||||
import static io.opentelemetry.auto.tooling.ByteBuddyElementMatchers.safeHasSuperType;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
||||
|
@ -14,9 +14,9 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.auto.bootstrap.ContextStore;
|
||||
import io.opentelemetry.auto.bootstrap.InstrumentationContext;
|
||||
import io.opentelemetry.auto.instrumentation.api.AgentSpan;
|
||||
import io.opentelemetry.auto.instrumentation.hibernate.SessionState;
|
||||
import io.opentelemetry.auto.tooling.Instrumenter;
|
||||
import io.opentelemetry.trace.Span;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
@ -62,7 +62,7 @@ public class SessionFactoryInstrumentation extends AbstractHibernateInstrumentat
|
|||
@Advice.OnMethodExit(suppress = Throwable.class)
|
||||
public static void openSession(@Advice.Return final Object session) {
|
||||
|
||||
final AgentSpan span = startSpan("hibernate.session");
|
||||
final Span span = TRACER.spanBuilder("hibernate.session").startSpan();
|
||||
DECORATOR.afterStart(span);
|
||||
DECORATOR.onConnection(span, session);
|
||||
|
||||
|
|
|
@ -14,10 +14,10 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.auto.bootstrap.ContextStore;
|
||||
import io.opentelemetry.auto.bootstrap.InstrumentationContext;
|
||||
import io.opentelemetry.auto.instrumentation.api.AgentSpan;
|
||||
import io.opentelemetry.auto.instrumentation.hibernate.SessionMethodUtils;
|
||||
import io.opentelemetry.auto.instrumentation.hibernate.SessionState;
|
||||
import io.opentelemetry.auto.tooling.Instrumenter;
|
||||
import io.opentelemetry.trace.Span;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -130,13 +130,13 @@ public class SessionInstrumentation extends AbstractHibernateInstrumentation {
|
|||
return;
|
||||
}
|
||||
if (state.getMethodScope() != null) {
|
||||
state.getMethodScope().close();
|
||||
state.endScope();
|
||||
}
|
||||
|
||||
final AgentSpan span = state.getSessionSpan();
|
||||
final Span span = state.getSessionSpan();
|
||||
DECORATOR.onError(span, throwable);
|
||||
DECORATOR.beforeFinish(span);
|
||||
span.finish();
|
||||
span.end();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import io.opentelemetry.auto.api.MoreTags
|
||||
import io.opentelemetry.auto.api.SpanTypes
|
||||
import io.opentelemetry.auto.instrumentation.api.AgentScope
|
||||
import io.opentelemetry.auto.instrumentation.api.Tags
|
||||
import org.hibernate.LockMode
|
||||
import org.hibernate.MappingException
|
||||
|
@ -9,9 +8,6 @@ import org.hibernate.ReplicationMode
|
|||
import org.hibernate.Session
|
||||
import spock.lang.Shared
|
||||
|
||||
import static io.opentelemetry.auto.instrumentation.api.AgentTracer.activateSpan
|
||||
import static io.opentelemetry.auto.instrumentation.api.AgentTracer.startSpan
|
||||
|
||||
class SessionTest extends AbstractHibernateTest {
|
||||
|
||||
@Shared
|
||||
|
@ -518,7 +514,8 @@ class SessionTest extends AbstractHibernateTest {
|
|||
def "test hibernate overlapping Sessions"() {
|
||||
setup:
|
||||
|
||||
AgentScope scope = activateSpan(startSpan("overlapping Sessions"), true)
|
||||
def rootSpan = TEST_TRACER.spanBuilder("overlapping Sessions").startSpan()
|
||||
def scope = TEST_TRACER.withSpan(rootSpan)
|
||||
|
||||
def session1 = sessionFactory.openSession()
|
||||
session1.beginTransaction()
|
||||
|
@ -536,6 +533,7 @@ class SessionTest extends AbstractHibernateTest {
|
|||
session1.close()
|
||||
session3.close()
|
||||
|
||||
rootSpan.end()
|
||||
scope.close()
|
||||
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ public class QueryInstrumentation extends AbstractHibernateInstrumentation {
|
|||
SessionMethodUtils.startScopeFrom(
|
||||
contextStore, query, "hibernate.query." + name, null, true);
|
||||
if (state != null) {
|
||||
DECORATOR.onStatement(state.getMethodScope().span(), query.getQueryString());
|
||||
DECORATOR.onStatement(state.getMethodScope().getSpan(), query.getQueryString());
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.opentelemetry.auto.instrumentation.hibernate.core.v4_0;
|
||||
|
||||
import static io.opentelemetry.auto.instrumentation.api.AgentTracer.startSpan;
|
||||
import static io.opentelemetry.auto.instrumentation.hibernate.HibernateDecorator.DECORATOR;
|
||||
import static io.opentelemetry.auto.instrumentation.hibernate.HibernateDecorator.TRACER;
|
||||
import static io.opentelemetry.auto.tooling.ByteBuddyElementMatchers.safeHasSuperType;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
|
||||
|
@ -14,9 +14,9 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.auto.bootstrap.ContextStore;
|
||||
import io.opentelemetry.auto.bootstrap.InstrumentationContext;
|
||||
import io.opentelemetry.auto.instrumentation.api.AgentSpan;
|
||||
import io.opentelemetry.auto.instrumentation.hibernate.SessionState;
|
||||
import io.opentelemetry.auto.tooling.Instrumenter;
|
||||
import io.opentelemetry.trace.Span;
|
||||
import java.util.Map;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
|
@ -54,7 +54,7 @@ public class SessionFactoryInstrumentation extends AbstractHibernateInstrumentat
|
|||
@Advice.OnMethodExit(suppress = Throwable.class)
|
||||
public static void openSession(@Advice.Return final SharedSessionContract session) {
|
||||
|
||||
final AgentSpan span = startSpan("hibernate.session");
|
||||
final Span span = TRACER.spanBuilder("hibernate.session").startSpan();
|
||||
DECORATOR.afterStart(span);
|
||||
DECORATOR.onConnection(span, session);
|
||||
|
||||
|
|
|
@ -14,10 +14,10 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.auto.bootstrap.ContextStore;
|
||||
import io.opentelemetry.auto.bootstrap.InstrumentationContext;
|
||||
import io.opentelemetry.auto.instrumentation.api.AgentSpan;
|
||||
import io.opentelemetry.auto.instrumentation.hibernate.SessionMethodUtils;
|
||||
import io.opentelemetry.auto.instrumentation.hibernate.SessionState;
|
||||
import io.opentelemetry.auto.tooling.Instrumenter;
|
||||
import io.opentelemetry.trace.Span;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -117,13 +117,13 @@ public class SessionInstrumentation extends AbstractHibernateInstrumentation {
|
|||
return;
|
||||
}
|
||||
if (state.getMethodScope() != null) {
|
||||
state.getMethodScope().close();
|
||||
state.getMethodScope().getScope().close();
|
||||
}
|
||||
|
||||
final AgentSpan span = state.getSessionSpan();
|
||||
final Span span = state.getSessionSpan();
|
||||
DECORATOR.onError(span, throwable);
|
||||
DECORATOR.beforeFinish(span);
|
||||
span.finish();
|
||||
span.end();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import io.opentelemetry.auto.api.MoreTags
|
||||
import io.opentelemetry.auto.api.SpanTypes
|
||||
import io.opentelemetry.auto.instrumentation.api.AgentScope
|
||||
import io.opentelemetry.auto.instrumentation.api.Tags
|
||||
import org.hibernate.LockMode
|
||||
import org.hibernate.MappingException
|
||||
|
@ -9,9 +8,6 @@ import org.hibernate.ReplicationMode
|
|||
import org.hibernate.Session
|
||||
import spock.lang.Shared
|
||||
|
||||
import static io.opentelemetry.auto.instrumentation.api.AgentTracer.activateSpan
|
||||
import static io.opentelemetry.auto.instrumentation.api.AgentTracer.startSpan
|
||||
|
||||
class SessionTest extends AbstractHibernateTest {
|
||||
|
||||
@Shared
|
||||
|
@ -446,7 +442,8 @@ class SessionTest extends AbstractHibernateTest {
|
|||
def "test hibernate overlapping Sessions"() {
|
||||
setup:
|
||||
|
||||
AgentScope scope = activateSpan(startSpan("overlapping Sessions"), true)
|
||||
def rootSpan = TEST_TRACER.spanBuilder("overlapping Sessions").startSpan()
|
||||
def scope = TEST_TRACER.withSpan(rootSpan)
|
||||
|
||||
def session1 = sessionFactory.openSession()
|
||||
session1.beginTransaction()
|
||||
|
@ -464,6 +461,7 @@ class SessionTest extends AbstractHibernateTest {
|
|||
session1.close()
|
||||
session3.close()
|
||||
|
||||
rootSpan.end()
|
||||
scope.close()
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package io.opentelemetry.auto.instrumentation.hibernate;
|
||||
|
||||
import io.opentelemetry.OpenTelemetry;
|
||||
import io.opentelemetry.auto.api.SpanTypes;
|
||||
import io.opentelemetry.auto.decorator.OrmClientDecorator;
|
||||
import io.opentelemetry.trace.Tracer;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -9,6 +11,7 @@ import java.util.Set;
|
|||
|
||||
public class HibernateDecorator extends OrmClientDecorator {
|
||||
public static final HibernateDecorator DECORATOR = new HibernateDecorator();
|
||||
public static final Tracer TRACER = OpenTelemetry.getTracerFactory().get("io.opentelemetry.auto");
|
||||
|
||||
@Override
|
||||
protected String service() {
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
package io.opentelemetry.auto.instrumentation.hibernate;
|
||||
|
||||
import static io.opentelemetry.auto.instrumentation.api.AgentTracer.activateSpan;
|
||||
import static io.opentelemetry.auto.instrumentation.api.AgentTracer.startSpan;
|
||||
import static io.opentelemetry.auto.instrumentation.hibernate.HibernateDecorator.DECORATOR;
|
||||
import static io.opentelemetry.auto.instrumentation.hibernate.HibernateDecorator.TRACER;
|
||||
|
||||
import io.opentelemetry.auto.bootstrap.CallDepthThreadLocalMap;
|
||||
import io.opentelemetry.auto.bootstrap.ContextStore;
|
||||
import io.opentelemetry.auto.instrumentation.api.AgentScope;
|
||||
import io.opentelemetry.auto.instrumentation.api.AgentSpan;
|
||||
import io.opentelemetry.auto.instrumentation.api.SpanScopePair;
|
||||
import io.opentelemetry.trace.Span;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
@ -27,7 +26,6 @@ public class SessionMethodUtils {
|
|||
final boolean createSpan) {
|
||||
|
||||
final SessionState sessionState = contextStore.get(spanKey);
|
||||
|
||||
if (sessionState == null) {
|
||||
return null; // No state found. We aren't in a Session.
|
||||
}
|
||||
|
@ -37,18 +35,21 @@ public class SessionMethodUtils {
|
|||
return null; // This method call is being traced already.
|
||||
}
|
||||
|
||||
final AgentScope scope;
|
||||
final SpanScopePair spanAndScope;
|
||||
boolean endSpan = false;
|
||||
if (createSpan) {
|
||||
final AgentSpan span = startSpan(operationName, sessionState.getSessionSpan().context());
|
||||
final Span span =
|
||||
TRACER.spanBuilder(operationName).setParent(sessionState.getSessionSpan()).startSpan();
|
||||
DECORATOR.afterStart(span);
|
||||
DECORATOR.onOperation(span, entity);
|
||||
scope = activateSpan(span, true);
|
||||
spanAndScope = new SpanScopePair(span, TRACER.withSpan(span)); // Autoclose: true
|
||||
endSpan = true;
|
||||
} else {
|
||||
scope = activateSpan(sessionState.getSessionSpan(), false);
|
||||
final Span span = sessionState.getSessionSpan();
|
||||
spanAndScope = new SpanScopePair(span, TRACER.withSpan(span));
|
||||
sessionState.setHasChildSpan(false);
|
||||
}
|
||||
|
||||
sessionState.setMethodScope(scope);
|
||||
sessionState.setMethodScope(spanAndScope, endSpan);
|
||||
return sessionState;
|
||||
}
|
||||
|
||||
|
@ -63,19 +64,18 @@ public class SessionMethodUtils {
|
|||
}
|
||||
|
||||
CallDepthThreadLocalMap.reset(SessionMethodUtils.class);
|
||||
final AgentScope scope = sessionState.getMethodScope();
|
||||
final AgentSpan span = scope.span();
|
||||
final SpanScopePair spanAndScope = sessionState.getMethodScope();
|
||||
final Span span = spanAndScope.getSpan();
|
||||
if (span != null && sessionState.hasChildSpan) {
|
||||
DECORATOR.onError(span, throwable);
|
||||
if (entity != null) {
|
||||
DECORATOR.onOperation(span, entity);
|
||||
}
|
||||
DECORATOR.beforeFinish(span);
|
||||
span.finish();
|
||||
span.end();
|
||||
}
|
||||
|
||||
scope.close();
|
||||
sessionState.setMethodScope(null);
|
||||
sessionState.endScope();
|
||||
sessionState.setMethodScope(null, false);
|
||||
}
|
||||
|
||||
// Copies a span from the given Session ContextStore into the targetContextStore. Used to
|
||||
|
|
|
@ -1,13 +1,40 @@
|
|||
package io.opentelemetry.auto.instrumentation.hibernate;
|
||||
|
||||
import io.opentelemetry.auto.instrumentation.api.AgentScope;
|
||||
import io.opentelemetry.auto.instrumentation.api.AgentSpan;
|
||||
import lombok.Data;
|
||||
import io.opentelemetry.auto.instrumentation.api.SpanScopePair;
|
||||
import io.opentelemetry.trace.Span;
|
||||
import lombok.NonNull;
|
||||
|
||||
@Data
|
||||
public class SessionState {
|
||||
@NonNull public AgentSpan sessionSpan;
|
||||
public AgentScope methodScope;
|
||||
@NonNull public final Span sessionSpan;
|
||||
public SpanScopePair methodScope;
|
||||
private boolean endSpan;
|
||||
public boolean hasChildSpan = true;
|
||||
|
||||
public SessionState(@NonNull final Span sessionSpan) {
|
||||
this.sessionSpan = sessionSpan;
|
||||
}
|
||||
|
||||
public @NonNull Span getSessionSpan() {
|
||||
return sessionSpan;
|
||||
}
|
||||
|
||||
public SpanScopePair getMethodScope() {
|
||||
return methodScope;
|
||||
}
|
||||
|
||||
public void setMethodScope(final SpanScopePair methodScope, final boolean endSpan) {
|
||||
this.methodScope = methodScope;
|
||||
this.endSpan = endSpan;
|
||||
}
|
||||
|
||||
public void setHasChildSpan(final boolean hasChildSpan) {
|
||||
this.hasChildSpan = hasChildSpan;
|
||||
}
|
||||
|
||||
public void endScope() {
|
||||
if (endSpan) {
|
||||
methodScope.getSpan().end();
|
||||
}
|
||||
methodScope.getScope().close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package io.opentelemetry.auto.instrumentation.twilio;
|
||||
|
||||
import static io.opentelemetry.auto.instrumentation.api.AgentTracer.activateSpan;
|
||||
import static io.opentelemetry.auto.instrumentation.api.AgentTracer.startSpan;
|
||||
import static io.opentelemetry.auto.instrumentation.twilio.TwilioClientDecorator.DECORATE;
|
||||
import static io.opentelemetry.auto.instrumentation.twilio.TwilioClientDecorator.TRACER;
|
||||
import static io.opentelemetry.auto.tooling.ByteBuddyElementMatchers.safeHasSuperType;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isAbstract;
|
||||
|
@ -18,9 +17,9 @@ import com.google.common.util.concurrent.Futures;
|
|||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.twilio.Twilio;
|
||||
import io.opentelemetry.auto.bootstrap.CallDepthThreadLocalMap;
|
||||
import io.opentelemetry.auto.instrumentation.api.AgentScope;
|
||||
import io.opentelemetry.auto.instrumentation.api.AgentSpan;
|
||||
import io.opentelemetry.auto.instrumentation.api.SpanScopePair;
|
||||
import io.opentelemetry.auto.tooling.Instrumenter;
|
||||
import io.opentelemetry.trace.Span;
|
||||
import java.util.Map;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
|
@ -86,7 +85,7 @@ public class TwilioAsyncInstrumentation extends Instrumenter.Default {
|
|||
|
||||
/** Method entry instrumentation. */
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static AgentScope methodEnter(
|
||||
public static SpanScopePair methodEnter(
|
||||
@Advice.This final Object that, @Advice.Origin("#m") final String methodName) {
|
||||
|
||||
// Ensure that we only create a span for the top-level Twilio client method; except in the
|
||||
|
@ -99,32 +98,33 @@ public class TwilioAsyncInstrumentation extends Instrumenter.Default {
|
|||
}
|
||||
|
||||
// Don't automatically close the span with the scope if we're executing an async method
|
||||
final AgentSpan span = startSpan("twilio.sdk");
|
||||
final Span span = TRACER.spanBuilder("twilio.sdk").startSpan();
|
||||
|
||||
DECORATE.afterStart(span);
|
||||
DECORATE.onServiceExecution(span, that, methodName);
|
||||
|
||||
return activateSpan(span, false);
|
||||
return new SpanScopePair(span, TRACER.withSpan(span));
|
||||
}
|
||||
|
||||
/** Method exit instrumentation. */
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Enter final AgentScope scope,
|
||||
@Advice.Enter final SpanScopePair spanScopePair,
|
||||
@Advice.Thrown final Throwable throwable,
|
||||
@Advice.Return final ListenableFuture response) {
|
||||
if (scope == null) {
|
||||
if (spanScopePair == null) {
|
||||
return;
|
||||
}
|
||||
// If we have a scope (i.e. we were the top-level Twilio SDK invocation),
|
||||
try {
|
||||
final AgentSpan span = scope.span();
|
||||
final Span span = spanScopePair.getSpan();
|
||||
|
||||
if (throwable != null) {
|
||||
// There was an synchronous error,
|
||||
// which means we shouldn't wait for a callback to close the span.
|
||||
DECORATE.onError(span, throwable);
|
||||
DECORATE.beforeFinish(span);
|
||||
span.finish();
|
||||
span.end();
|
||||
} 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
|
||||
|
@ -132,7 +132,7 @@ public class TwilioAsyncInstrumentation extends Instrumenter.Default {
|
|||
response, new SpanFinishingCallback(span), Twilio.getExecutorService());
|
||||
}
|
||||
} finally {
|
||||
scope.close(); // won't finish the span.
|
||||
spanScopePair.getScope().close(); // won't finish the span.
|
||||
CallDepthThreadLocalMap.reset(Twilio.class); // reset call depth count
|
||||
}
|
||||
}
|
||||
|
@ -145,9 +145,9 @@ public class TwilioAsyncInstrumentation extends Instrumenter.Default {
|
|||
public static class SpanFinishingCallback implements FutureCallback {
|
||||
|
||||
/** Span that we should finish and annotate when the future is complete. */
|
||||
private final AgentSpan span;
|
||||
private final Span span;
|
||||
|
||||
public SpanFinishingCallback(final AgentSpan span) {
|
||||
public SpanFinishingCallback(final Span span) {
|
||||
this.span = span;
|
||||
}
|
||||
|
||||
|
@ -155,14 +155,14 @@ public class TwilioAsyncInstrumentation extends Instrumenter.Default {
|
|||
public void onSuccess(final Object result) {
|
||||
DECORATE.beforeFinish(span);
|
||||
DECORATE.onResult(span, result);
|
||||
span.finish();
|
||||
span.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Throwable t) {
|
||||
DECORATE.onError(span, t);
|
||||
DECORATE.beforeFinish(span);
|
||||
span.finish();
|
||||
span.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,12 @@ package io.opentelemetry.auto.instrumentation.twilio;
|
|||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.twilio.rest.api.v2010.account.Call;
|
||||
import com.twilio.rest.api.v2010.account.Message;
|
||||
import io.opentelemetry.OpenTelemetry;
|
||||
import io.opentelemetry.auto.api.MoreTags;
|
||||
import io.opentelemetry.auto.api.SpanTypes;
|
||||
import io.opentelemetry.auto.decorator.ClientDecorator;
|
||||
import io.opentelemetry.auto.instrumentation.api.AgentSpan;
|
||||
import io.opentelemetry.trace.Span;
|
||||
import io.opentelemetry.trace.Tracer;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -17,6 +19,9 @@ public class TwilioClientDecorator extends ClientDecorator {
|
|||
|
||||
public static final TwilioClientDecorator DECORATE = new TwilioClientDecorator();
|
||||
|
||||
public static final Tracer TRACER =
|
||||
OpenTelemetry.getTracerFactory().get("io.opentelemetry.auto.twilio");
|
||||
|
||||
static final String COMPONENT_NAME = "twilio-sdk";
|
||||
|
||||
@Override
|
||||
|
@ -40,8 +45,8 @@ public class TwilioClientDecorator extends ClientDecorator {
|
|||
}
|
||||
|
||||
/** Decorate trace based on service execution metadata. */
|
||||
public AgentSpan onServiceExecution(
|
||||
final AgentSpan span, final Object serviceExecutor, final String methodName) {
|
||||
public Span onServiceExecution(
|
||||
final Span span, final Object serviceExecutor, final String methodName) {
|
||||
|
||||
// Drop common package prefix (com.twilio.rest)
|
||||
final String simpleClassName =
|
||||
|
@ -53,7 +58,7 @@ public class TwilioClientDecorator extends ClientDecorator {
|
|||
}
|
||||
|
||||
/** Annotate the span with the results of the operation. */
|
||||
public AgentSpan onResult(final AgentSpan span, Object result) {
|
||||
public Span onResult(final Span span, Object result) {
|
||||
|
||||
// Unwrap ListenableFuture (if present)
|
||||
if (result instanceof ListenableFuture) {
|
||||
|
@ -84,7 +89,9 @@ public class TwilioClientDecorator extends ClientDecorator {
|
|||
final Call call = (Call) result;
|
||||
span.setAttribute("twilio.account", call.getAccountSid());
|
||||
span.setAttribute("twilio.sid", call.getSid());
|
||||
span.setAttribute("twilio.parentSid", call.getParentCallSid());
|
||||
if (call.getParentCallSid() != null) {
|
||||
span.setAttribute("twilio.parentSid", call.getParentCallSid());
|
||||
}
|
||||
if (call.getStatus() != null) {
|
||||
span.setAttribute("twilio.status", call.getStatus().toString());
|
||||
}
|
||||
|
@ -105,7 +112,7 @@ public class TwilioClientDecorator extends ClientDecorator {
|
|||
* required.
|
||||
*/
|
||||
private void setTagIfPresent(
|
||||
final AgentSpan span, final Object result, final String tag, final String getter) {
|
||||
final Span span, final Object result, final String tag, final String getter) {
|
||||
try {
|
||||
final Method method = result.getClass().getMethod(getter);
|
||||
final Object value = method.invoke(result);
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package io.opentelemetry.auto.instrumentation.twilio;
|
||||
|
||||
import static io.opentelemetry.auto.instrumentation.api.AgentTracer.activateSpan;
|
||||
import static io.opentelemetry.auto.instrumentation.api.AgentTracer.startSpan;
|
||||
import static io.opentelemetry.auto.instrumentation.twilio.TwilioClientDecorator.DECORATE;
|
||||
import static io.opentelemetry.auto.instrumentation.twilio.TwilioClientDecorator.TRACER;
|
||||
import static io.opentelemetry.auto.tooling.ByteBuddyElementMatchers.safeHasSuperType;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isAbstract;
|
||||
|
@ -14,9 +13,9 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
|
|||
import com.google.auto.service.AutoService;
|
||||
import com.twilio.Twilio;
|
||||
import io.opentelemetry.auto.bootstrap.CallDepthThreadLocalMap;
|
||||
import io.opentelemetry.auto.instrumentation.api.AgentScope;
|
||||
import io.opentelemetry.auto.instrumentation.api.AgentSpan;
|
||||
import io.opentelemetry.auto.instrumentation.api.SpanScopePair;
|
||||
import io.opentelemetry.auto.tooling.Instrumenter;
|
||||
import io.opentelemetry.trace.Span;
|
||||
import java.util.Map;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
|
@ -82,7 +81,7 @@ public class TwilioSyncInstrumentation extends Instrumenter.Default {
|
|||
|
||||
/** Method entry instrumentation. */
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static AgentScope methodEnter(
|
||||
public static SpanScopePair methodEnter(
|
||||
@Advice.This final Object that, @Advice.Origin("#m") final String methodName) {
|
||||
|
||||
// Ensure that we only create a span for the top-level Twilio client method; except in the
|
||||
|
@ -94,32 +93,33 @@ public class TwilioSyncInstrumentation extends Instrumenter.Default {
|
|||
return null;
|
||||
}
|
||||
|
||||
final AgentSpan span = startSpan("twilio.sdk");
|
||||
final Span span = TRACER.spanBuilder("twilio.sdk").startSpan();
|
||||
DECORATE.afterStart(span);
|
||||
DECORATE.onServiceExecution(span, that, methodName);
|
||||
|
||||
return activateSpan(span, true);
|
||||
return new SpanScopePair(span, TRACER.withSpan(span));
|
||||
}
|
||||
|
||||
/** Method exit instrumentation. */
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Enter final AgentScope scope,
|
||||
@Advice.Enter final SpanScopePair spanScopePair,
|
||||
@Advice.Thrown final Throwable throwable,
|
||||
@Advice.Return final Object response) {
|
||||
if (scope == null) {
|
||||
if (spanScopePair == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have a scope (i.e. we were the top-level Twilio SDK invocation),
|
||||
try {
|
||||
final AgentSpan span = scope.span();
|
||||
final Span span = spanScopePair.getSpan();
|
||||
|
||||
DECORATE.onResult(span, response);
|
||||
DECORATE.onError(span, throwable);
|
||||
DECORATE.beforeFinish(span);
|
||||
span.end();
|
||||
} finally {
|
||||
scope.close();
|
||||
spanScopePair.getScope().close();
|
||||
CallDepthThreadLocalMap.reset(Twilio.class); // reset call depth count
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,11 +24,7 @@ import org.apache.http.impl.client.HttpClientBuilder
|
|||
import java.util.concurrent.ExecutionException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
import static io.opentelemetry.auto.instrumentation.api.AgentTracer.activateSpan
|
||||
import static io.opentelemetry.auto.instrumentation.api.AgentTracer.startSpan
|
||||
|
||||
class TwilioClientTest extends AgentTestRunner {
|
||||
|
||||
final static String ACCOUNT_SID = "abc"
|
||||
final static String AUTH_TOKEN = "efg"
|
||||
|
||||
|
@ -113,16 +109,17 @@ class TwilioClientTest extends AgentTestRunner {
|
|||
|
||||
1 * twilioRestClient.request(_) >> new Response(new ByteArrayInputStream(MESSAGE_RESPONSE_BODY.getBytes()), 200)
|
||||
|
||||
def scope = activateSpan(startSpan("test"), true)
|
||||
def testSpan = TEST_TRACER.spanBuilder("test").startSpan()
|
||||
def testScope = TEST_TRACER.withSpan(testSpan)
|
||||
|
||||
Message message = Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"), // To number
|
||||
new PhoneNumber("+1 555 555 5215"), // From number
|
||||
"Hello world!" // SMS body
|
||||
).create(twilioRestClient)
|
||||
|
||||
scope.close()
|
||||
|
||||
testSpan.end()
|
||||
testScope.close()
|
||||
|
||||
expect:
|
||||
|
||||
message.body == "Hello, World!"
|
||||
|
@ -161,7 +158,8 @@ class TwilioClientTest extends AgentTestRunner {
|
|||
|
||||
1 * twilioRestClient.request(_) >> new Response(new ByteArrayInputStream(CALL_RESPONSE_BODY.getBytes()), 200)
|
||||
|
||||
def scope = activateSpan(startSpan("test"), true)
|
||||
def testSpan = TEST_TRACER.spanBuilder("test").startSpan()
|
||||
def testScope = TEST_TRACER.withSpan(testSpan)
|
||||
|
||||
Call call = Call.creator(
|
||||
new PhoneNumber("+15558881234"), // To number
|
||||
|
@ -171,7 +169,8 @@ class TwilioClientTest extends AgentTestRunner {
|
|||
new URI("http://twimlets.com/holdmusic?Bucket=com.twilio.music.ambient")
|
||||
).create(twilioRestClient)
|
||||
|
||||
scope.close()
|
||||
testSpan.end()
|
||||
testScope.close()
|
||||
|
||||
expect:
|
||||
|
||||
|
@ -235,7 +234,9 @@ class TwilioClientTest extends AgentTestRunner {
|
|||
.httpClient(networkHttpClient)
|
||||
.build()
|
||||
|
||||
def scope = activateSpan(startSpan("test"), true)
|
||||
|
||||
def testSpan = TEST_TRACER.spanBuilder("test").startSpan()
|
||||
def testScope = TEST_TRACER.withSpan(testSpan)
|
||||
|
||||
Message message = Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"), // To number
|
||||
|
@ -243,7 +244,8 @@ class TwilioClientTest extends AgentTestRunner {
|
|||
"Hello world!" // SMS body
|
||||
).create(realTwilioRestClient)
|
||||
|
||||
scope.close()
|
||||
testSpan.end()
|
||||
testScope.close()
|
||||
|
||||
expect:
|
||||
|
||||
|
@ -336,15 +338,16 @@ class TwilioClientTest extends AgentTestRunner {
|
|||
.httpClient(networkHttpClient)
|
||||
.build()
|
||||
|
||||
def scope = activateSpan(startSpan("test"), true)
|
||||
def testSpan = TEST_TRACER.spanBuilder("test").startSpan()
|
||||
def testScope = TEST_TRACER.withSpan(testSpan)
|
||||
|
||||
Message message = Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"), // To number
|
||||
new PhoneNumber("+1 555 555 5215"), // From number
|
||||
"Hello world!" // SMS body
|
||||
).create(realTwilioRestClient)
|
||||
|
||||
scope.close()
|
||||
testSpan.end()
|
||||
testScope.close()
|
||||
|
||||
expect:
|
||||
|
||||
|
@ -450,7 +453,8 @@ class TwilioClientTest extends AgentTestRunner {
|
|||
.httpClient(networkHttpClient)
|
||||
.build()
|
||||
|
||||
def scope = activateSpan(startSpan("test"), true)
|
||||
def testSpan = TEST_TRACER.spanBuilder("test").startSpan()
|
||||
def testScope = TEST_TRACER.withSpan(testSpan)
|
||||
|
||||
ListenableFuture<Message> future = Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"), // To number
|
||||
|
@ -464,7 +468,8 @@ class TwilioClientTest extends AgentTestRunner {
|
|||
} finally {
|
||||
// Give the future callback a chance to run
|
||||
Thread.sleep(1000)
|
||||
scope.close()
|
||||
testSpan.end()
|
||||
testScope.close()
|
||||
}
|
||||
|
||||
expect:
|
||||
|
@ -552,7 +557,8 @@ class TwilioClientTest extends AgentTestRunner {
|
|||
|
||||
1 * twilioRestClient.request(_) >> new Response(new ByteArrayInputStream(ERROR_RESPONSE_BODY.getBytes()), 500)
|
||||
|
||||
def scope = activateSpan(startSpan("test"), true)
|
||||
def testSpan = TEST_TRACER.spanBuilder("test").startSpan()
|
||||
def testScope = TEST_TRACER.withSpan(testSpan)
|
||||
|
||||
when:
|
||||
Message.creator(
|
||||
|
@ -564,7 +570,8 @@ class TwilioClientTest extends AgentTestRunner {
|
|||
then:
|
||||
thrown(ApiException)
|
||||
|
||||
scope.close()
|
||||
testSpan.end()
|
||||
testScope.close()
|
||||
|
||||
expect:
|
||||
|
||||
|
@ -639,7 +646,8 @@ class TwilioClientTest extends AgentTestRunner {
|
|||
|
||||
when:
|
||||
|
||||
def scope = activateSpan(startSpan("test"), true)
|
||||
def testSpan = TEST_TRACER.spanBuilder("test").startSpan()
|
||||
def testScope = TEST_TRACER.withSpan(testSpan)
|
||||
|
||||
ListenableFuture<Message> future = Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"), // To number
|
||||
|
@ -653,7 +661,8 @@ class TwilioClientTest extends AgentTestRunner {
|
|||
} finally {
|
||||
// Give the future callback a chance to run
|
||||
Thread.sleep(1000)
|
||||
scope.close()
|
||||
testSpan.end()
|
||||
testScope.close()
|
||||
}
|
||||
|
||||
then:
|
||||
|
@ -720,7 +729,8 @@ class TwilioClientTest extends AgentTestRunner {
|
|||
|
||||
1 * twilioRestClient.request(_) >> new Response(new ByteArrayInputStream(ERROR_RESPONSE_BODY.getBytes()), 500)
|
||||
|
||||
def scope = activateSpan(startSpan("test"), true)
|
||||
def testSpan = TEST_TRACER.spanBuilder("test").startSpan()
|
||||
def testScope = TEST_TRACER.withSpan(testSpan)
|
||||
|
||||
ListenableFuture<Message> future = Message.creator(
|
||||
new PhoneNumber("+1 555 720 5913"), // To number
|
||||
|
@ -736,7 +746,8 @@ class TwilioClientTest extends AgentTestRunner {
|
|||
|
||||
} finally {
|
||||
Thread.sleep(1000)
|
||||
scope.close()
|
||||
testSpan.end()
|
||||
testScope.close()
|
||||
}
|
||||
|
||||
then:
|
||||
|
|
Loading…
Reference in New Issue