Pass around context more instead of span (HttpServerTracer) (#1810)

This commit is contained in:
Trask Stalnaker 2020-12-01 14:49:01 -08:00 committed by GitHub
parent 01b4345742
commit 0bd85d7b7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 131 additions and 174 deletions

View File

@ -12,7 +12,6 @@ import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.attributes.SemanticAttributes;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.context.propagation.TextMapPropagator;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
@ -35,17 +34,29 @@ public abstract class HttpServerTracer<REQUEST, RESPONSE, CONNECTION, STORAGE> e
super(tracer);
}
public Context startSpan(REQUEST request, CONNECTION connection, Method origin) {
public Context startSpan(REQUEST request, CONNECTION connection, STORAGE storage, Method origin) {
String spanName = spanNameForMethod(origin);
return startSpan(request, connection, spanName);
}
public Context startSpan(REQUEST request, CONNECTION connection, String spanName) {
return startSpan(request, connection, spanName, -1);
return startSpan(request, connection, storage, spanName);
}
public Context startSpan(
REQUEST request, CONNECTION connection, String spanName, long startTimestamp) {
REQUEST request, CONNECTION connection, STORAGE storage, String spanName) {
return startSpan(request, connection, storage, spanName, -1);
}
public Context startSpan(
REQUEST request,
CONNECTION connection,
@Nullable STORAGE storage,
String spanName,
long startTimestamp) {
// not checking if inside of nested SERVER span because of concerns about context leaking
// and so always starting with a clean context here
// also we can't conditionally start a span in this method, because the caller won't know
// whether to call end() or not on the Span in the returned Context
Context parentContext = extract(request, getGetter());
SpanBuilder builder = tracer.spanBuilder(spanName).setSpanKind(SERVER).setParent(parentContext);
@ -58,67 +69,51 @@ public abstract class HttpServerTracer<REQUEST, RESPONSE, CONNECTION, STORAGE> e
onRequest(span, request);
onConnectionAndRequest(span, connection, request);
return parentContext.with(span);
Context context = parentContext.with(CONTEXT_SERVER_SPAN_KEY, span).with(span);
attachServerContext(context, storage);
return context;
}
/**
* Creates new scoped context, based on the current context, with the given span.
*
* <p>Attaches new context to the request to avoid creating duplicate server spans.
*/
public Scope startScope(Span span, STORAGE storage) {
return startScope(span, storage, Context.current());
}
/**
* Creates new scoped context, based on the given context, with the given span.
*
* <p>Attaches new context to the request to avoid creating duplicate server spans.
*/
public Scope startScope(Span span, STORAGE storage, Context context) {
// TODO we could do this in one go, but TracingContextUtils.CONTEXT_SPAN_KEY is private
Context newContext = context.with(CONTEXT_SERVER_SPAN_KEY, span).with(span);
attachServerContext(newContext, storage);
return newContext.makeCurrent();
}
/**
* Convenience method. Delegates to {@link #end(Span, Object, long)}, passing {@code timestamp}
* Convenience method. Delegates to {@link #end(Context, Object, long)}, passing {@code timestamp}
* value of {@code -1}.
*/
// TODO should end methods remove SPAN attribute from request as well?
public void end(Span span, RESPONSE response) {
end(span, response, -1);
public void end(Context context, RESPONSE response) {
end(context, response, -1);
}
// TODO should end methods remove SPAN attribute from request as well?
public void end(Span span, RESPONSE response, long timestamp) {
public void end(Context context, RESPONSE response, long timestamp) {
Span span = Span.fromContext(context);
setStatus(span, responseStatus(response));
endSpan(span, timestamp);
}
/**
* Convenience method. Delegates to {@link #endExceptionally(Span, Throwable, Object)}, passing
* Convenience method. Delegates to {@link #endExceptionally(Context, Throwable, Object)}, passing
* {@code response} value of {@code null}.
*/
@Override
public void endExceptionally(Span span, Throwable throwable) {
endExceptionally(span, throwable, null);
public void endExceptionally(Context context, Throwable throwable) {
endExceptionally(context, throwable, null);
}
/**
* Convenience method. Delegates to {@link #endExceptionally(Span, Throwable, Object, long)},
* Convenience method. Delegates to {@link #endExceptionally(Context, Throwable, Object, long)},
* passing {@code timestamp} value of {@code -1}.
*/
public void endExceptionally(Span span, Throwable throwable, RESPONSE response) {
endExceptionally(span, throwable, response, -1);
public void endExceptionally(Context context, Throwable throwable, RESPONSE response) {
endExceptionally(context, throwable, response, -1);
}
/**
* If {@code response} is {@code null}, the {@code http.status_code} will be set to {@code 500}
* and the {@link Span} status will be set to {@link io.opentelemetry.api.trace.StatusCode#ERROR}.
*/
public void endExceptionally(Span span, Throwable throwable, RESPONSE response, long timestamp) {
public void endExceptionally(
Context context, Throwable throwable, RESPONSE response, long timestamp) {
Span span = Span.fromContext(context);
onError(span, unwrapThrowable(throwable));
if (response == null) {
setStatus(span, 500);

View File

@ -8,7 +8,6 @@ package io.opentelemetry.instrumentation.servlet;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.attributes.SemanticAttributes;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.context.propagation.TextMapPropagator.Getter;
import io.opentelemetry.instrumentation.api.servlet.ServletContextPath;
import io.opentelemetry.instrumentation.api.tracer.HttpServerTracer;
@ -26,19 +25,12 @@ public abstract class ServletHttpServerTracer<RESPONSE>
private static final Logger log = LoggerFactory.getLogger(ServletHttpServerTracer.class);
public Context startSpan(HttpServletRequest request) {
return startSpan(request, request, getSpanName(request));
}
@Override
public Scope startScope(Span span, HttpServletRequest request) {
Context context = Context.current();
// if we start returning Context from startSpan() then we can add ServletContextPath there
// (https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/1481)
Context context = startSpan(request, request, request, getSpanName(request));
String contextPath = request.getContextPath();
if (contextPath != null && !contextPath.isEmpty() && !contextPath.equals("/")) {
context = context.with(ServletContextPath.CONTEXT_KEY, contextPath);
}
return super.startScope(span, request, context);
return context;
}
@Override
@ -109,10 +101,10 @@ public abstract class ServletHttpServerTracer<RESPONSE>
return super.unwrapThrowable(result);
}
public void setPrincipal(Span span, HttpServletRequest request) {
public void setPrincipal(Context context, HttpServletRequest request) {
Principal principal = request.getUserPrincipal();
if (principal != null) {
span.setAttribute(SemanticAttributes.ENDUSER_ID, principal.getName());
Span.fromContext(context).setAttribute(SemanticAttributes.ENDUSER_ID, principal.getName());
}
}

View File

@ -14,10 +14,8 @@ import akka.http.scaladsl.model.HttpRequest;
import akka.http.scaladsl.model.HttpResponse;
import akka.stream.Materializer;
import com.google.auto.service.AutoService;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.HashMap;
@ -96,14 +94,13 @@ public class AkkaHttpServerInstrumentationModule extends InstrumentationModule {
@Override
public HttpResponse apply(HttpRequest request) {
Context ctx = tracer().startSpan(request, request, "akka.request");
Span span = Java8BytecodeBridge.spanFromContext(ctx);
try (Scope ignored = tracer().startScope(span, null)) {
Context ctx = tracer().startSpan(request, request, null, "akka.request");
try (Scope ignored = ctx.makeCurrent()) {
HttpResponse response = userHandler.apply(request);
tracer().end(span, response);
tracer().end(ctx, response);
return response;
} catch (Throwable t) {
tracer().endExceptionally(span, t);
tracer().endExceptionally(ctx, t);
throw t;
}
}
@ -122,29 +119,28 @@ public class AkkaHttpServerInstrumentationModule extends InstrumentationModule {
@Override
public Future<HttpResponse> apply(HttpRequest request) {
Context ctx = tracer().startSpan(request, request, "akka.request");
Span span = Java8BytecodeBridge.spanFromContext(ctx);
try (Scope ignored = tracer().startScope(span, null)) {
Context ctx = tracer().startSpan(request, request, null, "akka.request");
try (Scope ignored = ctx.makeCurrent()) {
return userHandler
.apply(request)
.transform(
new AbstractFunction1<HttpResponse, HttpResponse>() {
@Override
public HttpResponse apply(HttpResponse response) {
tracer().end(span, response);
tracer().end(ctx, response);
return response;
}
},
new AbstractFunction1<Throwable, Throwable>() {
@Override
public Throwable apply(Throwable t) {
tracer().endExceptionally(span, t);
tracer().endExceptionally(ctx, t);
return t;
}
},
executionContext);
} catch (Throwable t) {
tracer().endExceptionally(span, t);
tracer().endExceptionally(ctx, t);
throw t;
}
}

View File

@ -59,10 +59,9 @@ public class OpenTelemetryService extends SimpleDecoratingHttpService {
long requestStartTimeMicros =
ctx.log().ensureAvailable(RequestLogProperty.REQUEST_START_TIME).requestStartTimeMicros();
long requestStartTimeNanos = TimeUnit.MICROSECONDS.toNanos(requestStartTimeMicros);
Context context = serverTracer.startSpan(req, ctx, spanName, requestStartTimeNanos);
Span span = Span.fromContext(context);
Context context = serverTracer.startSpan(req, ctx, null, spanName, requestStartTimeNanos);
if (span.isRecording()) {
if (Span.fromContext(context).isRecording()) {
ctx.log()
.whenComplete()
.thenAccept(
@ -70,14 +69,14 @@ public class OpenTelemetryService extends SimpleDecoratingHttpService {
long requestEndTimeNanos = requestStartTimeNanos + log.responseDurationNanos();
if (log.responseCause() != null) {
serverTracer.endExceptionally(
span, log.responseCause(), log, requestEndTimeNanos);
context, log.responseCause(), log, requestEndTimeNanos);
} else {
serverTracer.end(span, log, requestEndTimeNanos);
serverTracer.end(context, log, requestEndTimeNanos);
}
});
}
try (Scope ignored = span.makeCurrent()) {
try (Scope ignored = context.makeCurrent()) {
return unwrap().serve(ctx, req);
}
}

View File

@ -7,9 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.grizzly;
import static io.opentelemetry.javaagent.instrumentation.grizzly.GrizzlyHttpServerTracer.tracer;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import java.lang.reflect.Method;
import net.bytebuddy.asm.Advice;
import org.glassfish.grizzly.filterchain.FilterChainContext;
@ -31,11 +29,9 @@ public class HttpCodecFilterAdvice {
return;
}
HttpRequestPacket httpRequest = (HttpRequestPacket) httpHeader;
Context extractedContext = tracer().startSpan(httpRequest, httpRequest, method);
Span span = Java8BytecodeBridge.spanFromContext(extractedContext);
// We don't actually want to attach new context to this thread, as actual request will continue
// on some other thread. But we do want to attach that new context to FilterChainContext
tracer().startScope(span, ctx).close();
// We don't want to attach the new context to this thread, as actual request will continue on
// some other thread where we will read and attach it via tracer().getServerContext(ctx).
tracer().startSpan(httpRequest, httpRequest, ctx, method);
}
}

View File

@ -7,9 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.grizzly;
import static io.opentelemetry.javaagent.instrumentation.grizzly.GrizzlyHttpServerTracer.tracer;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import java.lang.reflect.Method;
import net.bytebuddy.asm.Advice;
import org.glassfish.grizzly.filterchain.FilterChainContext;
@ -31,11 +29,9 @@ public class HttpCodecFilterOldAdvice {
return;
}
HttpRequestPacket httpRequest = (HttpRequestPacket) httpHeader;
Context extractedContext = tracer().startSpan(httpRequest, httpRequest, method);
Span span = Java8BytecodeBridge.spanFromContext(extractedContext);
// We don't actually want to attach new context to this thread, as actual request will continue
// on some other thread. But we do want to attach that new context to FilterChainContext
tracer().startScope(span, ctx).close();
// We don't want to attach the new context to this thread, as actual request will continue on
// some other thread where we will read and attach it via tracer().getServerContext(ctx).
tracer().startSpan(httpRequest, httpRequest, ctx, method);
}
}

View File

@ -7,7 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.grizzly;
import static io.opentelemetry.javaagent.instrumentation.grizzly.GrizzlyHttpServerTracer.tracer;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import net.bytebuddy.asm.Advice;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.http.HttpResponsePacket;
@ -16,9 +16,9 @@ public class HttpServerFilterAdvice {
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void onExit(
@Advice.Argument(0) FilterChainContext ctx, @Advice.Argument(2) HttpResponsePacket response) {
Span span = tracer().getServerSpan(ctx);
if (span != null) {
tracer().end(span, response);
Context context = tracer().getServerContext(ctx);
if (context != null) {
tracer().end(context, response);
}
}
}

View File

@ -7,10 +7,8 @@ package io.opentelemetry.javaagent.instrumentation.jetty;
import static io.opentelemetry.javaagent.instrumentation.jetty.JettyHttpServerTracer.tracer;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.instrumentation.servlet.v3_0.TagSettingAsyncListener;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicBoolean;
@ -25,7 +23,7 @@ public class JettyHandlerAdvice {
@Advice.Origin Method method,
@Advice.This Object source,
@Advice.Argument(value = 2, readOnly = false) HttpServletRequest request,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
Context attachedContext = tracer().getServerContext(request);
@ -34,9 +32,8 @@ public class JettyHandlerAdvice {
return;
}
Context ctx = tracer().startSpan(request, request, method);
span = Java8BytecodeBridge.spanFromContext(ctx);
scope = tracer().startScope(span, request);
context = tracer().startSpan(request, request, request, method);
scope = context.makeCurrent();
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
@ -44,22 +41,22 @@ public class JettyHandlerAdvice {
@Advice.Argument(2) HttpServletRequest request,
@Advice.Argument(3) HttpServletResponse response,
@Advice.Thrown Throwable throwable,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}
scope.close();
if (span == null) {
if (context == null) {
// an existing span was found
return;
}
tracer().setPrincipal(span, request);
tracer().setPrincipal(context, request);
if (throwable != null) {
tracer().endExceptionally(span, throwable, response);
tracer().endExceptionally(context, throwable, response);
return;
}
@ -68,7 +65,9 @@ public class JettyHandlerAdvice {
// In case of async servlets wait for the actual response to be ready
if (request.isAsyncStarted()) {
try {
request.getAsyncContext().addListener(new TagSettingAsyncListener(responseHandled, span));
request
.getAsyncContext()
.addListener(new TagSettingAsyncListener(responseHandled, context));
} catch (IllegalStateException e) {
// org.eclipse.jetty.server.Request may throw an exception here if request became
// finished after check above. We just ignore that exception and move on.
@ -77,7 +76,7 @@ public class JettyHandlerAdvice {
// Check again in case the request finished before adding the listener.
if (!request.isAsyncStarted() && responseHandled.compareAndSet(false, true)) {
tracer().end(span, response);
tracer().end(context, response);
}
}
}

View File

@ -7,11 +7,9 @@ package io.opentelemetry.javaagent.instrumentation.netty.v3_8.server;
import static io.opentelemetry.javaagent.instrumentation.netty.v3_8.server.NettyHttpServerTracer.tracer;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.instrumentation.netty.v3_8.ChannelTraceContext;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
@ -46,12 +44,13 @@ public class HttpServerRequestTracingHandler extends SimpleChannelUpstreamHandle
HttpRequest request = (HttpRequest) msg.getMessage();
Context context = tracer().startSpan(request, ctx.getChannel(), "netty.request");
Span span = Java8BytecodeBridge.spanFromContext(context);
try (Scope ignored = tracer().startScope(span, channelTraceContext)) {
Context context =
tracer().startSpan(request, ctx.getChannel(), channelTraceContext, "netty.request");
try (Scope ignored = context.makeCurrent()) {
ctx.sendUpstream(msg);
// the span is ended normally in HttpServerResponseTracingHandler
} catch (Throwable throwable) {
tracer().endExceptionally(span, throwable);
tracer().endExceptionally(context, throwable);
throw throwable;
}
}

View File

@ -7,7 +7,6 @@ package io.opentelemetry.javaagent.instrumentation.netty.v3_8.server;
import static io.opentelemetry.javaagent.instrumentation.netty.v3_8.server.NettyHttpServerTracer.tracer;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
@ -37,13 +36,12 @@ public class HttpServerResponseTracingHandler extends SimpleChannelDownstreamHan
return;
}
Span span = Span.fromContext(context);
try (Scope ignored = context.makeCurrent()) {
ctx.sendDownstream(msg);
} catch (Throwable throwable) {
tracer().endExceptionally(span, throwable);
tracer().endExceptionally(context, throwable);
throw throwable;
}
tracer().end(span, (HttpResponse) msg.getMessage());
tracer().end(context, (HttpResponse) msg.getMessage());
}
}

View File

@ -11,10 +11,8 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpRequest;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
public class HttpServerRequestTracingHandler extends ChannelInboundHandlerAdapter {
@ -34,12 +32,12 @@ public class HttpServerRequestTracingHandler extends ChannelInboundHandlerAdapte
return;
}
Context context = tracer().startSpan((HttpRequest) msg, channel, "netty.request");
Span span = Java8BytecodeBridge.spanFromContext(context);
try (Scope ignored = tracer().startScope(span, channel)) {
Context context = tracer().startSpan((HttpRequest) msg, channel, channel, "netty.request");
try (Scope ignored = context.makeCurrent()) {
ctx.fireChannelRead(msg);
// the span is ended normally in HttpServerResponseTracingHandler
} catch (Throwable throwable) {
tracer().endExceptionally(span, throwable);
tracer().endExceptionally(context, throwable);
throw throwable;
}
}

View File

@ -11,7 +11,6 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.HttpResponse;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
@ -25,13 +24,12 @@ public class HttpServerResponseTracingHandler extends ChannelOutboundHandlerAdap
return;
}
Span span = Span.fromContext(context);
try (Scope ignored = context.makeCurrent()) {
ctx.write(msg, prm);
} catch (Throwable throwable) {
tracer().endExceptionally(span, throwable);
tracer().endExceptionally(context, throwable);
throw throwable;
}
tracer().end(span, (HttpResponse) msg);
tracer().end(context, (HttpResponse) msg);
}
}

View File

@ -11,10 +11,8 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpRequest;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
public class HttpServerRequestTracingHandler extends ChannelInboundHandlerAdapter {
@ -34,12 +32,12 @@ public class HttpServerRequestTracingHandler extends ChannelInboundHandlerAdapte
return;
}
Context context = tracer().startSpan((HttpRequest) msg, channel, "netty.request");
Span span = Java8BytecodeBridge.spanFromContext(context);
try (Scope ignored = tracer().startScope(span, channel)) {
Context context = tracer().startSpan((HttpRequest) msg, channel, channel, "netty.request");
try (Scope ignored = context.makeCurrent()) {
ctx.fireChannelRead(msg);
// the span is ended normally in HttpServerResponseTracingHandler
} catch (Throwable throwable) {
tracer().endExceptionally(span, throwable);
tracer().endExceptionally(context, throwable);
throw throwable;
}
}

View File

@ -11,7 +11,6 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.HttpResponse;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
@ -25,13 +24,12 @@ public class HttpServerResponseTracingHandler extends ChannelOutboundHandlerAdap
return;
}
Span span = Span.fromContext(context);
try (Scope ignored = context.makeCurrent()) {
ctx.write(msg, prm);
} catch (Throwable throwable) {
tracer().endExceptionally(span, throwable);
tracer().endExceptionally(context, throwable);
throw throwable;
}
tracer().end(span, (HttpResponse) msg);
tracer().end(context, (HttpResponse) msg);
}
}

View File

@ -7,11 +7,9 @@ package io.opentelemetry.javaagent.instrumentation.servlet.v2_2;
import static io.opentelemetry.javaagent.instrumentation.servlet.v2_2.Servlet2HttpServerTracer.tracer;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
@ -24,7 +22,7 @@ public class Servlet2Advice {
public static void onEnter(
@Advice.Argument(0) ServletRequest request,
@Advice.Argument(value = 1, typing = Assigner.Typing.DYNAMIC) ServletResponse response,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
@ -37,9 +35,8 @@ public class Servlet2Advice {
return;
}
Context ctx = tracer().startSpan(httpServletRequest);
span = Java8BytecodeBridge.spanFromContext(ctx);
scope = tracer().startScope(span, httpServletRequest);
context = tracer().startSpan(httpServletRequest);
scope = context.makeCurrent();
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
@ -47,14 +44,14 @@ public class Servlet2Advice {
@Advice.Argument(0) ServletRequest request,
@Advice.Argument(1) ServletResponse response,
@Advice.Thrown Throwable throwable,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}
scope.close();
tracer().setPrincipal(span, (HttpServletRequest) request);
tracer().setPrincipal(context, (HttpServletRequest) request);
Integer responseStatus =
InstrumentationContext.get(ServletResponse.class, Integer.class).get(response);
@ -62,9 +59,9 @@ public class Servlet2Advice {
ResponseWithStatus responseWithStatus =
new ResponseWithStatus((HttpServletResponse) response, responseStatus);
if (throwable == null) {
tracer().end(span, responseWithStatus);
tracer().end(context, responseWithStatus);
} else {
tracer().endExceptionally(span, throwable, responseWithStatus);
tracer().endExceptionally(context, throwable, responseWithStatus);
}
}
}

View File

@ -7,10 +7,8 @@ package io.opentelemetry.javaagent.instrumentation.servlet.v3_0;
import static io.opentelemetry.javaagent.instrumentation.servlet.v3_0.Servlet3HttpServerTracer.tracer;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@ -24,7 +22,7 @@ public class Servlet3Advice {
public static void onEnter(
@Advice.Argument(value = 0, readOnly = false) ServletRequest request,
@Advice.Argument(value = 1, readOnly = false) ServletResponse response,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
return;
@ -42,9 +40,8 @@ public class Servlet3Advice {
return;
}
Context ctx = tracer().startSpan(httpServletRequest);
span = Java8BytecodeBridge.spanFromContext(ctx);
scope = tracer().startScope(span, httpServletRequest);
context = tracer().startSpan(httpServletRequest);
scope = context.makeCurrent();
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
@ -52,21 +49,21 @@ public class Servlet3Advice {
@Advice.Argument(0) ServletRequest request,
@Advice.Argument(1) ServletResponse response,
@Advice.Thrown Throwable throwable,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}
scope.close();
if (span == null) {
if (context == null) {
// an existing span was found
return;
}
tracer().setPrincipal(span, (HttpServletRequest) request);
tracer().setPrincipal(context, (HttpServletRequest) request);
if (throwable != null) {
tracer().endExceptionally(span, throwable, (HttpServletResponse) response);
tracer().endExceptionally(context, throwable, (HttpServletResponse) response);
return;
}
@ -75,7 +72,9 @@ public class Servlet3Advice {
// In case of async servlets wait for the actual response to be ready
if (request.isAsyncStarted()) {
try {
request.getAsyncContext().addListener(new TagSettingAsyncListener(responseHandled, span));
request
.getAsyncContext()
.addListener(new TagSettingAsyncListener(responseHandled, context));
} catch (IllegalStateException e) {
// org.eclipse.jetty.server.Request may throw an exception here if request became
// finished after check above. We just ignore that exception and move on.
@ -84,7 +83,7 @@ public class Servlet3Advice {
// Check again in case the request finished before adding the listener.
if (!request.isAsyncStarted() && responseHandled.compareAndSet(false, true)) {
tracer().end(span, (HttpServletResponse) response);
tracer().end(context, (HttpServletResponse) response);
}
}
}

View File

@ -37,24 +37,25 @@ public class Servlet3HttpServerTracer extends ServletHttpServerTracer<HttpServle
@Override
public void endExceptionally(
Span span, Throwable throwable, HttpServletResponse response, long timestamp) {
Context context, Throwable throwable, HttpServletResponse response, long timestamp) {
if (response.isCommitted()) {
super.endExceptionally(span, throwable, response, timestamp);
super.endExceptionally(context, throwable, response, timestamp);
} else {
// passing null response to super, in order to capture as 500 / INTERNAL, due to servlet spec
// https://javaee.github.io/servlet-spec/downloads/servlet-4.0/servlet-4_0_FINAL.pdf:
// "If a servlet generates an error that is not handled by the error page mechanism as
// described above, the container must ensure to send a response with status 500."
super.endExceptionally(span, throwable, null, timestamp);
super.endExceptionally(context, throwable, null, timestamp);
}
}
@Override
public void end(Span span, HttpServletResponse response, long timestamp) {
super.end(span, response, timestamp);
public void end(Context context, HttpServletResponse response, long timestamp) {
super.end(context, response, timestamp);
}
public void onTimeout(Span span, long timeout) {
public void onTimeout(Context context, long timeout) {
Span span = Span.fromContext(context);
span.setStatus(StatusCode.ERROR);
span.setAttribute("timeout", timeout);
span.end();

View File

@ -5,7 +5,7 @@
package io.opentelemetry.javaagent.instrumentation.servlet.v3_0;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
@ -16,24 +16,24 @@ public class TagSettingAsyncListener implements AsyncListener {
new Servlet3HttpServerTracer();
private final AtomicBoolean responseHandled;
private final Span span;
private final Context context;
public TagSettingAsyncListener(AtomicBoolean responseHandled, Span span) {
public TagSettingAsyncListener(AtomicBoolean responseHandled, Context context) {
this.responseHandled = responseHandled;
this.span = span;
this.context = context;
}
@Override
public void onComplete(AsyncEvent event) {
if (responseHandled.compareAndSet(false, true)) {
servletHttpServerTracer.end(span, (HttpServletResponse) event.getSuppliedResponse());
servletHttpServerTracer.end(context, (HttpServletResponse) event.getSuppliedResponse());
}
}
@Override
public void onTimeout(AsyncEvent event) {
if (responseHandled.compareAndSet(false, true)) {
servletHttpServerTracer.onTimeout(span, event.getAsyncContext().getTimeout());
servletHttpServerTracer.onTimeout(context, event.getAsyncContext().getTimeout());
}
}
@ -41,7 +41,7 @@ public class TagSettingAsyncListener implements AsyncListener {
public void onError(AsyncEvent event) {
if (responseHandled.compareAndSet(false, true)) {
servletHttpServerTracer.endExceptionally(
span, event.getThrowable(), (HttpServletResponse) event.getSuppliedResponse());
context, event.getThrowable(), (HttpServletResponse) event.getSuppliedResponse());
}
}

View File

@ -5,7 +5,6 @@
package io.opentelemetry.instrumentation.spring.webmvc;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
@ -31,13 +30,12 @@ public class WebMvcTracingFilter extends OncePerRequestFilter implements Ordered
public void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
Context ctx = tracer.startSpan(request, request, FILTER_CLASS + "." + FILTER_METHOD);
Span serverSpan = Span.fromContext(ctx);
try (Scope ignored = tracer.startScope(serverSpan, request)) {
Context ctx = tracer.startSpan(request, request, request, FILTER_CLASS + "." + FILTER_METHOD);
try (Scope ignored = ctx.makeCurrent()) {
filterChain.doFilter(request, response);
tracer.end(serverSpan, response);
tracer.end(ctx, response);
} catch (Throwable t) {
tracer.endExceptionally(serverSpan, t, response);
tracer.endExceptionally(ctx, t, response);
throw t;
}
}