Refactor `ServerSpanNaming` (in preparation for `http.route`) (#4852)
* Refactor ServerSpanNaming (in preparation for http.route) * fix tests * Add ServerSpanNaming to all HTTP server instrumentations * fix tests
This commit is contained in:
parent
331ce287d2
commit
a65e9633ba
|
@ -8,6 +8,7 @@ package io.opentelemetry.instrumentation.api.servlet;
|
|||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.ContextKey;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.ContextCustomizer;
|
||||
import io.opentelemetry.instrumentation.api.tracer.ServerSpan;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
@ -17,14 +18,13 @@ public final class ServerSpanNaming {
|
|||
private static final ContextKey<ServerSpanNaming> CONTEXT_KEY =
|
||||
ContextKey.named("opentelemetry-servlet-span-naming-key");
|
||||
|
||||
public static Context init(Context context, Source initialSource) {
|
||||
ServerSpanNaming serverSpanNaming = context.get(CONTEXT_KEY);
|
||||
if (serverSpanNaming != null) {
|
||||
// TODO (trask) does this ever happen?
|
||||
serverSpanNaming.updatedBySource = initialSource;
|
||||
return context;
|
||||
}
|
||||
return context.with(CONTEXT_KEY, new ServerSpanNaming(initialSource));
|
||||
public static <REQUEST> ContextCustomizer<REQUEST> get() {
|
||||
return (context, request, startAttributes) -> {
|
||||
if (context.get(CONTEXT_KEY) != null) {
|
||||
return context;
|
||||
}
|
||||
return context.with(CONTEXT_KEY, new ServerSpanNaming(Source.CONTAINER));
|
||||
};
|
||||
}
|
||||
|
||||
private volatile Source updatedBySource;
|
||||
|
@ -37,16 +37,15 @@ public final class ServerSpanNaming {
|
|||
}
|
||||
|
||||
/**
|
||||
* If there is a server span in the context, and {@link #init(Context, Source)} has been called to
|
||||
* populate a {@code ServerSpanName} into the context, then this method will update the server
|
||||
* span name using the provided {@link ServerSpanNameSupplier} if and only if the last {@link
|
||||
* Source} to update the span name using this method has strictly lower priority than the provided
|
||||
* {@link Source}, and the value returned from the {@link ServerSpanNameSupplier} is non-null.
|
||||
* If there is a server span in the context, and the context has been customized with a {@code
|
||||
* ServerSpanName}, then this method will update the server span name using the provided {@link
|
||||
* ServerSpanNameSupplier} if and only if the last {@link Source} to update the span name using
|
||||
* this method has strictly lower priority than the provided {@link Source}, and the value
|
||||
* returned from the {@link ServerSpanNameSupplier} is non-null.
|
||||
*
|
||||
* <p>If there is a server span in the context, and {@link #init(Context, Source)} has NOT been
|
||||
* called to populate a {@code ServerSpanName} into the context, then this method will update the
|
||||
* server span name using the provided {@link ServerSpanNameSupplier} if the value returned from
|
||||
* it is non-null.
|
||||
* <p>If there is a server span in the context, and the context has NOT been customized with a
|
||||
* {@code ServerSpanName}, then this method will update the server span name using the provided
|
||||
* {@link ServerSpanNameSupplier} if the value returned from it is non-null.
|
||||
*/
|
||||
public static <T> void updateServerSpanName(
|
||||
Context context, Source source, ServerSpanNameSupplier<T> serverSpanName, T arg1) {
|
||||
|
@ -54,17 +53,15 @@ public final class ServerSpanNaming {
|
|||
}
|
||||
|
||||
/**
|
||||
* If there is a server span in the context, and {@link #init(Context, Source)} has been called to
|
||||
* populate a {@code ServerSpanName} into the context, then this method will update the server
|
||||
* span name using the provided {@link ServerSpanNameTwoArgSupplier} if and only if the last
|
||||
* {@link Source} to update the span name using this method has strictly lower priority than the
|
||||
* provided {@link Source}, and the value returned from the {@link ServerSpanNameTwoArgSupplier}
|
||||
* is non-null.
|
||||
* If there is a server span in the context, and the context has been customized with a {@code
|
||||
* ServerSpanName}, then this method will update the server span name using the provided {@link
|
||||
* ServerSpanNameTwoArgSupplier} if and only if the last {@link Source} to update the span name
|
||||
* using this method has strictly lower priority than the provided {@link Source}, and the value
|
||||
* returned from the {@link ServerSpanNameTwoArgSupplier} is non-null.
|
||||
*
|
||||
* <p>If there is a server span in the context, and {@link #init(Context, Source)} has NOT been
|
||||
* called to populate a {@code ServerSpanName} into the context, then this method will update the
|
||||
* server span name using the provided {@link ServerSpanNameTwoArgSupplier} if the value returned
|
||||
* from it is non-null.
|
||||
* <p>If there is a server span in the context, and the context has NOT been customized with a
|
||||
* {@code ServerSpanName}, then this method will update the server span name using the provided
|
||||
* {@link ServerSpanNameTwoArgSupplier} if the value returned from it is non-null.
|
||||
*/
|
||||
public static <T, U> void updateServerSpanName(
|
||||
Context context,
|
||||
|
|
|
@ -11,6 +11,7 @@ import io.opentelemetry.api.GlobalOpenTelemetry;
|
|||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
||||
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
|
||||
import io.opentelemetry.javaagent.instrumentation.akkahttp.AkkaHttpUtil;
|
||||
|
||||
public class AkkaHttpServerSingletons {
|
||||
|
@ -28,6 +29,7 @@ public class AkkaHttpServerSingletons {
|
|||
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesExtractor))
|
||||
.addAttributesExtractor(httpAttributesExtractor)
|
||||
.addRequestMetrics(HttpServerMetrics.get())
|
||||
.addContextCustomizer(ServerSpanNaming.get())
|
||||
.newServerInstrumenter(AkkaHttpServerHeaders.INSTANCE);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
|
|||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
||||
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -135,7 +136,8 @@ public final class ArmeriaTracingBuilder {
|
|||
HttpSpanStatusExtractor.create(serverAttributesExtractor)))
|
||||
.addAttributesExtractor(new ArmeriaNetServerAttributesExtractor())
|
||||
.addAttributesExtractor(serverAttributesExtractor)
|
||||
.addRequestMetrics(HttpServerMetrics.get());
|
||||
.addRequestMetrics(HttpServerMetrics.get())
|
||||
.addContextCustomizer(ServerSpanNaming.get());
|
||||
|
||||
if (peerService != null) {
|
||||
clientInstrumenterBuilder.addAttributesExtractor(
|
||||
|
|
|
@ -32,10 +32,8 @@ public final class GrizzlySingletons {
|
|||
.addAttributesExtractor(netAttributesExtractor)
|
||||
.addRequestMetrics(HttpServerMetrics.get())
|
||||
.addContextCustomizer(
|
||||
(context, httpRequestPacket, startAttributes) -> {
|
||||
context = GrizzlyErrorHolder.init(context);
|
||||
return ServerSpanNaming.init(context, ServerSpanNaming.Source.CONTAINER);
|
||||
})
|
||||
(context, httpRequestPacket, startAttributes) -> GrizzlyErrorHolder.init(context))
|
||||
.addContextCustomizer(ServerSpanNaming.get())
|
||||
.newServerInstrumenter(HttpRequestHeadersGetter.INSTANCE);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.jetty.v11_0;
|
||||
|
||||
import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.CONTAINER;
|
||||
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
|
||||
import io.opentelemetry.javaagent.bootstrap.servlet.AppServerBridge;
|
||||
import io.opentelemetry.javaagent.instrumentation.jetty.common.JettyHelper;
|
||||
import io.opentelemetry.javaagent.instrumentation.servlet.ServletInstrumenterBuilder;
|
||||
|
@ -26,10 +23,7 @@ public final class Jetty11Singletons {
|
|||
INSTRUMENTER =
|
||||
ServletInstrumenterBuilder.<HttpServletRequest, HttpServletResponse>create()
|
||||
.addContextCustomizer(
|
||||
(context, request, attributes) -> {
|
||||
context = ServerSpanNaming.init(context, CONTAINER);
|
||||
return new AppServerBridge.Builder().init(context);
|
||||
})
|
||||
(context, request, attributes) -> new AppServerBridge.Builder().init(context))
|
||||
.build(INSTRUMENTATION_NAME, Servlet5Accessor.INSTANCE);
|
||||
|
||||
private static final JettyHelper<HttpServletRequest, HttpServletResponse> HELPER =
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.jetty.v8_0;
|
||||
|
||||
import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.CONTAINER;
|
||||
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
|
||||
import io.opentelemetry.javaagent.bootstrap.servlet.AppServerBridge;
|
||||
import io.opentelemetry.javaagent.instrumentation.jetty.common.JettyHelper;
|
||||
import io.opentelemetry.javaagent.instrumentation.servlet.ServletInstrumenterBuilder;
|
||||
|
@ -26,10 +23,7 @@ public final class Jetty8Singletons {
|
|||
INSTRUMENTER =
|
||||
ServletInstrumenterBuilder.<HttpServletRequest, HttpServletResponse>create()
|
||||
.addContextCustomizer(
|
||||
(context, request, attributes) -> {
|
||||
context = ServerSpanNaming.init(context, CONTAINER);
|
||||
return new AppServerBridge.Builder().init(context);
|
||||
})
|
||||
(context, request, attributes) -> new AppServerBridge.Builder().init(context))
|
||||
.build(INSTRUMENTATION_NAME, Servlet3Accessor.INSTANCE);
|
||||
|
||||
private static final JettyHelper<HttpServletRequest, HttpServletResponse> HELPER =
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.liberty.dispatcher;
|
||||
|
||||
import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.CONTAINER;
|
||||
|
||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
|
||||
|
@ -39,8 +37,7 @@ public final class LibertyDispatcherSingletons {
|
|||
.setSpanStatusExtractor(spanStatusExtractor)
|
||||
.addAttributesExtractor(httpAttributesExtractor)
|
||||
.addAttributesExtractor(netAttributesExtractor)
|
||||
.addContextCustomizer(
|
||||
(context, request, attributes) -> ServerSpanNaming.init(context, CONTAINER))
|
||||
.addContextCustomizer(ServerSpanNaming.get())
|
||||
.addRequestMetrics(HttpServerMetrics.get())
|
||||
.newServerInstrumenter(LibertyDispatcherRequestGetter.INSTANCE);
|
||||
}
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.liberty;
|
||||
|
||||
import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.CONTAINER;
|
||||
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
|
||||
import io.opentelemetry.javaagent.bootstrap.servlet.AppServerBridge;
|
||||
import io.opentelemetry.javaagent.instrumentation.servlet.ServletInstrumenterBuilder;
|
||||
import io.opentelemetry.javaagent.instrumentation.servlet.ServletRequestContext;
|
||||
|
@ -25,10 +22,8 @@ public final class LibertySingletons {
|
|||
INSTRUMENTER =
|
||||
ServletInstrumenterBuilder.<HttpServletRequest, HttpServletResponse>create()
|
||||
.addContextCustomizer(
|
||||
(context, request, attributes) -> {
|
||||
context = ServerSpanNaming.init(context, CONTAINER);
|
||||
return new AppServerBridge.Builder().recordException().init(context);
|
||||
})
|
||||
(context, request, attributes) ->
|
||||
new AppServerBridge.Builder().recordException().init(context))
|
||||
.build(INSTRUMENTATION_NAME, Servlet3Accessor.INSTANCE);
|
||||
|
||||
private static final LibertyHelper<HttpServletRequest, HttpServletResponse> HELPER =
|
||||
|
|
|
@ -10,6 +10,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
|||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
||||
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
|
||||
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyErrorHolder;
|
||||
import io.opentelemetry.javaagent.instrumentation.netty.v3_8.HttpRequestAndChannel;
|
||||
import org.jboss.netty.handler.codec.http.HttpResponse;
|
||||
|
@ -33,6 +34,7 @@ final class NettyServerSingletons {
|
|||
.addRequestMetrics(HttpServerMetrics.get())
|
||||
.addContextCustomizer(
|
||||
(context, requestAndChannel, startAttributes) -> NettyErrorHolder.init(context))
|
||||
.addContextCustomizer(ServerSpanNaming.get())
|
||||
.newServerInstrumenter(NettyHeadersGetter.INSTANCE);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,12 +31,8 @@ public final class NettyServerInstrumenterFactory {
|
|||
.addAttributesExtractor(httpAttributesExtractor)
|
||||
.addAttributesExtractor(new NettyNetServerAttributesExtractor())
|
||||
.addRequestMetrics(HttpServerMetrics.get())
|
||||
.addContextCustomizer(
|
||||
(context, request, attributes) -> {
|
||||
context = NettyErrorHolder.init(context);
|
||||
// netty is not exactly a "container", but it's the best match out of these
|
||||
return ServerSpanNaming.init(context, ServerSpanNaming.Source.CONTAINER);
|
||||
})
|
||||
.addContextCustomizer((context, request, attributes) -> NettyErrorHolder.init(context))
|
||||
.addContextCustomizer(ServerSpanNaming.get())
|
||||
.newServerInstrumenter(HttpRequestHeadersGetter.INSTANCE);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,12 +5,9 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.servlet.v2_2;
|
||||
|
||||
import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.SERVLET;
|
||||
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractor;
|
||||
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
|
||||
import io.opentelemetry.javaagent.instrumentation.servlet.ServletInstrumenterBuilder;
|
||||
import io.opentelemetry.javaagent.instrumentation.servlet.ServletRequestContext;
|
||||
import io.opentelemetry.javaagent.instrumentation.servlet.ServletResponseContext;
|
||||
|
@ -33,8 +30,6 @@ public final class Servlet2Singletons {
|
|||
ServletRequestContext<HttpServletRequest>, ServletResponseContext<HttpServletResponse>>
|
||||
instrumenter =
|
||||
ServletInstrumenterBuilder.<HttpServletRequest, HttpServletResponse>create()
|
||||
.addContextCustomizer(
|
||||
(context, request, attributes) -> ServerSpanNaming.init(context, SERVLET))
|
||||
.build(
|
||||
INSTRUMENTATION_NAME,
|
||||
Servlet2Accessor.INSTANCE,
|
||||
|
|
|
@ -9,7 +9,6 @@ import static io.opentelemetry.javaagent.instrumentation.servlet.v3_0.Servlet3Si
|
|||
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.instrumentation.api.tracer.ServerSpan;
|
||||
import io.opentelemetry.javaagent.bootstrap.servlet.AppServerBridge;
|
||||
import io.opentelemetry.javaagent.bootstrap.servlet.MappingResolver;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepth;
|
||||
|
@ -39,52 +38,41 @@ public class Servlet3Advice {
|
|||
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
|
||||
return;
|
||||
}
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||
|
||||
callDepth = CallDepth.forClass(AppServerBridge.getCallDepthKey());
|
||||
callDepth.getAndIncrement();
|
||||
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||
|
||||
Context currentContext = Java8BytecodeBridge.currentContext();
|
||||
Context attachedContext = helper().getServerContext(httpServletRequest);
|
||||
if (attachedContext != null && helper().needsRescoping(currentContext, attachedContext)) {
|
||||
MappingResolver mappingResolver = Servlet3Singletons.getMappingResolver(servletOrFilter);
|
||||
boolean servlet = servletOrFilter instanceof Servlet;
|
||||
attachedContext =
|
||||
helper().updateContext(attachedContext, httpServletRequest, mappingResolver, servlet);
|
||||
scope = attachedContext.makeCurrent();
|
||||
// We are inside nested servlet/filter/app-server span, don't create new span
|
||||
return;
|
||||
}
|
||||
|
||||
if (attachedContext != null || ServerSpan.fromContextOrNull(currentContext) != null) {
|
||||
// Update context with info from current request to ensure that server span gets the best
|
||||
// possible name.
|
||||
// In case server span was created by app server instrumentations calling updateContext
|
||||
// returns a new context that contains servlet context path that is used in other
|
||||
// instrumentations for naming server span.
|
||||
MappingResolver mappingResolver = Servlet3Singletons.getMappingResolver(servletOrFilter);
|
||||
boolean servlet = servletOrFilter instanceof Servlet;
|
||||
Context updatedContext =
|
||||
helper().updateContext(currentContext, httpServletRequest, mappingResolver, servlet);
|
||||
if (currentContext != updatedContext) {
|
||||
// updateContext updated context, need to re-scope
|
||||
scope = updatedContext.makeCurrent();
|
||||
}
|
||||
// We are inside nested servlet/filter/app-server span, don't create new span
|
||||
return;
|
||||
}
|
||||
Context contextToUpdate;
|
||||
|
||||
requestContext = new ServletRequestContext<>(httpServletRequest, servletOrFilter);
|
||||
if (attachedContext == null && helper().shouldStart(currentContext, requestContext)) {
|
||||
context = helper().start(currentContext, requestContext);
|
||||
helper().setAsyncListenerResponse(httpServletRequest, (HttpServletResponse) response);
|
||||
|
||||
if (!helper().shouldStart(currentContext, requestContext)) {
|
||||
return;
|
||||
contextToUpdate = context;
|
||||
} else if (attachedContext != null
|
||||
&& helper().needsRescoping(currentContext, attachedContext)) {
|
||||
// Given request already has a context associated with it.
|
||||
// see the needsRescoping() javadoc for more explanation
|
||||
contextToUpdate = attachedContext;
|
||||
} else {
|
||||
// We are inside nested servlet/filter/app-server span, don't create new span
|
||||
contextToUpdate = currentContext;
|
||||
}
|
||||
|
||||
context = helper().start(currentContext, requestContext);
|
||||
scope = context.makeCurrent();
|
||||
|
||||
helper().setAsyncListenerResponse(httpServletRequest, (HttpServletResponse) response);
|
||||
// Update context with info from current request to ensure that server span gets the best
|
||||
// possible name.
|
||||
// In case server span was created by app server instrumentations calling updateContext
|
||||
// returns a new context that contains servlet context path that is used in other
|
||||
// instrumentations for naming server span.
|
||||
MappingResolver mappingResolver = Servlet3Singletons.getMappingResolver(servletOrFilter);
|
||||
boolean servlet = servletOrFilter instanceof Servlet;
|
||||
contextToUpdate =
|
||||
helper().updateContext(contextToUpdate, httpServletRequest, mappingResolver, servlet);
|
||||
scope = contextToUpdate.makeCurrent();
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
|
|
|
@ -5,12 +5,8 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.servlet.v3_0;
|
||||
|
||||
import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.FILTER;
|
||||
import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.SERVLET;
|
||||
|
||||
import io.opentelemetry.instrumentation.api.field.VirtualField;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
|
||||
import io.opentelemetry.javaagent.bootstrap.servlet.MappingResolver;
|
||||
import io.opentelemetry.javaagent.instrumentation.servlet.ServletHelper;
|
||||
import io.opentelemetry.javaagent.instrumentation.servlet.ServletInstrumenterBuilder;
|
||||
|
@ -28,11 +24,6 @@ public final class Servlet3Singletons {
|
|||
ServletRequestContext<HttpServletRequest>, ServletResponseContext<HttpServletResponse>>
|
||||
INSTRUMENTER =
|
||||
ServletInstrumenterBuilder.<HttpServletRequest, HttpServletResponse>create()
|
||||
.setMappingResolverFunction(Servlet3Singletons::getMappingResolver)
|
||||
.addContextCustomizer(
|
||||
(context, request, attributes) ->
|
||||
ServerSpanNaming.init(
|
||||
context, request.servletOrFilter() instanceof Servlet ? SERVLET : FILTER))
|
||||
.build(INSTRUMENTATION_NAME, Servlet3Accessor.INSTANCE);
|
||||
|
||||
private static final ServletHelper<HttpServletRequest, HttpServletResponse> HELPER =
|
||||
|
@ -47,11 +38,6 @@ public final class Servlet3Singletons {
|
|||
return HELPER;
|
||||
}
|
||||
|
||||
private static MappingResolver getMappingResolver(
|
||||
ServletRequestContext<?> servletRequestContext) {
|
||||
return getMappingResolver(servletRequestContext.servletOrFilter());
|
||||
}
|
||||
|
||||
public static MappingResolver getMappingResolver(Object servletOrFilter) {
|
||||
MappingResolver.Factory factory = getMappingResolverFactory(servletOrFilter);
|
||||
if (factory != null) {
|
||||
|
|
|
@ -5,12 +5,8 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.servlet.v5_0;
|
||||
|
||||
import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.FILTER;
|
||||
import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.SERVLET;
|
||||
|
||||
import io.opentelemetry.instrumentation.api.field.VirtualField;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
|
||||
import io.opentelemetry.javaagent.bootstrap.servlet.MappingResolver;
|
||||
import io.opentelemetry.javaagent.instrumentation.servlet.ServletHelper;
|
||||
import io.opentelemetry.javaagent.instrumentation.servlet.ServletInstrumenterBuilder;
|
||||
|
@ -29,11 +25,6 @@ public final class Servlet5Singletons {
|
|||
ServletRequestContext<HttpServletRequest>, ServletResponseContext<HttpServletResponse>>
|
||||
INSTRUMENTER =
|
||||
ServletInstrumenterBuilder.<HttpServletRequest, HttpServletResponse>create()
|
||||
.setMappingResolverFunction(Servlet5Singletons::getMappingResolver)
|
||||
.addContextCustomizer(
|
||||
(context, request, attributes) ->
|
||||
ServerSpanNaming.init(
|
||||
context, request.servletOrFilter() instanceof Servlet ? SERVLET : FILTER))
|
||||
.build(INSTRUMENTATION_NAME, Servlet5Accessor.INSTANCE);
|
||||
|
||||
private static final ServletHelper<HttpServletRequest, HttpServletResponse> HELPER =
|
||||
|
@ -48,11 +39,6 @@ public final class Servlet5Singletons {
|
|||
return HELPER;
|
||||
}
|
||||
|
||||
private static MappingResolver getMappingResolver(
|
||||
ServletRequestContext<?> servletRequestContext) {
|
||||
return getMappingResolver(servletRequestContext.servletOrFilter());
|
||||
}
|
||||
|
||||
public static MappingResolver getMappingResolver(Object servletOrFilter) {
|
||||
MappingResolver.Factory factory = getMappingResolverFactory(servletOrFilter);
|
||||
if (factory != null) {
|
||||
|
|
|
@ -9,7 +9,6 @@ import static io.opentelemetry.javaagent.instrumentation.servlet.v5_0.Servlet5Si
|
|||
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.instrumentation.api.tracer.ServerSpan;
|
||||
import io.opentelemetry.javaagent.bootstrap.servlet.AppServerBridge;
|
||||
import io.opentelemetry.javaagent.bootstrap.servlet.MappingResolver;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.CallDepth;
|
||||
|
@ -40,52 +39,41 @@ public class JakartaServletServiceAdvice {
|
|||
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
|
||||
return;
|
||||
}
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||
|
||||
callDepth = CallDepth.forClass(AppServerBridge.getCallDepthKey());
|
||||
callDepth.getAndIncrement();
|
||||
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||
|
||||
Context currentContext = Java8BytecodeBridge.currentContext();
|
||||
Context attachedContext = helper().getServerContext(httpServletRequest);
|
||||
if (attachedContext != null && helper().needsRescoping(currentContext, attachedContext)) {
|
||||
MappingResolver mappingResolver = Servlet5Singletons.getMappingResolver(servletOrFilter);
|
||||
boolean servlet = servletOrFilter instanceof Servlet;
|
||||
attachedContext =
|
||||
helper().updateContext(attachedContext, httpServletRequest, mappingResolver, servlet);
|
||||
scope = attachedContext.makeCurrent();
|
||||
// We are inside nested servlet/filter/app-server span, don't create new span
|
||||
return;
|
||||
}
|
||||
|
||||
if (attachedContext != null || ServerSpan.fromContextOrNull(currentContext) != null) {
|
||||
// Update context with info from current request to ensure that server span gets the best
|
||||
// possible name.
|
||||
// In case server span was created by app server instrumentations calling updateContext
|
||||
// returns a new context that contains servlet context path that is used in other
|
||||
// instrumentations for naming server span.
|
||||
MappingResolver mappingResolver = Servlet5Singletons.getMappingResolver(servletOrFilter);
|
||||
boolean servlet = servletOrFilter instanceof Servlet;
|
||||
Context updatedContext =
|
||||
helper().updateContext(currentContext, httpServletRequest, mappingResolver, servlet);
|
||||
if (currentContext != updatedContext) {
|
||||
// updateContext updated context, need to re-scope
|
||||
scope = updatedContext.makeCurrent();
|
||||
}
|
||||
// We are inside nested servlet/filter/app-server span, don't create new span
|
||||
return;
|
||||
}
|
||||
Context contextToUpdate;
|
||||
|
||||
requestContext = new ServletRequestContext<>(httpServletRequest, servletOrFilter);
|
||||
if (attachedContext == null && helper().shouldStart(currentContext, requestContext)) {
|
||||
context = helper().start(currentContext, requestContext);
|
||||
helper().setAsyncListenerResponse(httpServletRequest, (HttpServletResponse) response);
|
||||
|
||||
if (!helper().shouldStart(currentContext, requestContext)) {
|
||||
return;
|
||||
contextToUpdate = context;
|
||||
} else if (attachedContext != null
|
||||
&& helper().needsRescoping(currentContext, attachedContext)) {
|
||||
// Given request already has a context associated with it.
|
||||
// see the needsRescoping() javadoc for more explanation
|
||||
contextToUpdate = attachedContext;
|
||||
} else {
|
||||
// We are inside nested servlet/filter/app-server span, don't create new span
|
||||
contextToUpdate = currentContext;
|
||||
}
|
||||
|
||||
context = helper().start(currentContext, requestContext);
|
||||
scope = context.makeCurrent();
|
||||
|
||||
helper().setAsyncListenerResponse(httpServletRequest, (HttpServletResponse) response);
|
||||
// Update context with info from current request to ensure that server span gets the best
|
||||
// possible name.
|
||||
// In case server span was created by app server instrumentations calling updateContext
|
||||
// returns a new context that contains servlet context path that is used in other
|
||||
// instrumentations for naming server span.
|
||||
MappingResolver mappingResolver = Servlet5Singletons.getMappingResolver(servletOrFilter);
|
||||
boolean servlet = servletOrFilter instanceof Servlet;
|
||||
contextToUpdate =
|
||||
helper().updateContext(contextToUpdate, httpServletRequest, mappingResolver, servlet);
|
||||
scope = contextToUpdate.makeCurrent();
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
|
|
|
@ -14,20 +14,16 @@ import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
|
|||
import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractor;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
||||
import io.opentelemetry.javaagent.bootstrap.servlet.MappingResolver;
|
||||
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public final class ServletInstrumenterBuilder<REQUEST, RESPONSE> {
|
||||
|
||||
private ServletInstrumenterBuilder() {}
|
||||
|
||||
@Nullable
|
||||
private Function<ServletRequestContext<REQUEST>, MappingResolver> mappingResolverFunction;
|
||||
|
||||
private final List<ContextCustomizer<? super ServletRequestContext<REQUEST>>> contextCustomizers =
|
||||
new ArrayList<>();
|
||||
|
||||
|
@ -35,12 +31,6 @@ public final class ServletInstrumenterBuilder<REQUEST, RESPONSE> {
|
|||
return new ServletInstrumenterBuilder<>();
|
||||
}
|
||||
|
||||
public ServletInstrumenterBuilder<REQUEST, RESPONSE> setMappingResolverFunction(
|
||||
Function<ServletRequestContext<REQUEST>, MappingResolver> mappingResolverFunction) {
|
||||
this.mappingResolverFunction = mappingResolverFunction;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServletInstrumenterBuilder<REQUEST, RESPONSE> addContextCustomizer(
|
||||
ContextCustomizer<? super ServletRequestContext<REQUEST>> contextCustomizer) {
|
||||
contextCustomizers.add(contextCustomizer);
|
||||
|
@ -72,7 +62,8 @@ public final class ServletInstrumenterBuilder<REQUEST, RESPONSE> {
|
|||
.addAttributesExtractor(httpAttributesExtractor)
|
||||
.addAttributesExtractor(netAttributesExtractor)
|
||||
.addAttributesExtractor(additionalAttributesExtractor)
|
||||
.addRequestMetrics(HttpServerMetrics.get());
|
||||
.addRequestMetrics(HttpServerMetrics.get())
|
||||
.addContextCustomizer(ServerSpanNaming.get());
|
||||
if (ServletRequestParametersExtractor.enabled()) {
|
||||
AttributesExtractor<ServletRequestContext<REQUEST>, ServletResponseContext<RESPONSE>>
|
||||
requestParametersExtractor = new ServletRequestParametersExtractor<>(accessor);
|
||||
|
@ -90,7 +81,7 @@ public final class ServletInstrumenterBuilder<REQUEST, RESPONSE> {
|
|||
HttpServerAttributesExtractor<ServletRequestContext<REQUEST>, ServletResponseContext<RESPONSE>>
|
||||
httpAttributesExtractor = new ServletHttpAttributesExtractor<>(accessor);
|
||||
SpanNameExtractor<ServletRequestContext<REQUEST>> spanNameExtractor =
|
||||
new ServletSpanNameExtractor<>(accessor, mappingResolverFunction);
|
||||
HttpSpanNameExtractor.create(httpAttributesExtractor);
|
||||
|
||||
return build(instrumentationName, accessor, spanNameExtractor, httpAttributesExtractor);
|
||||
}
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.servlet;
|
||||
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
|
||||
import io.opentelemetry.javaagent.bootstrap.servlet.MappingResolver;
|
||||
import java.util.function.Function;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ServletSpanNameExtractor<REQUEST, RESPONSE>
|
||||
implements SpanNameExtractor<ServletRequestContext<REQUEST>> {
|
||||
private final ServletAccessor<REQUEST, RESPONSE> accessor;
|
||||
|
||||
@Nullable
|
||||
private final Function<ServletRequestContext<REQUEST>, MappingResolver> mappingResolverFunction;
|
||||
|
||||
public ServletSpanNameExtractor(
|
||||
ServletAccessor<REQUEST, RESPONSE> accessor,
|
||||
@Nullable Function<ServletRequestContext<REQUEST>, MappingResolver> mappingResolverFunction) {
|
||||
this.accessor = accessor;
|
||||
this.mappingResolverFunction = mappingResolverFunction;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String route(ServletRequestContext<REQUEST> requestContext) {
|
||||
if (mappingResolverFunction == null) {
|
||||
return null;
|
||||
}
|
||||
MappingResolver mappingResolver = mappingResolverFunction.apply(requestContext);
|
||||
if (mappingResolver == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
REQUEST request = requestContext.request();
|
||||
String servletPath = accessor.getRequestServletPath(request);
|
||||
String pathInfo = accessor.getRequestPathInfo(request);
|
||||
String contextPath = accessor.getRequestContextPath(request);
|
||||
boolean hasContextPath =
|
||||
contextPath != null && !contextPath.isEmpty() && !contextPath.equals("/");
|
||||
|
||||
String route = mappingResolver.resolve(servletPath, pathInfo);
|
||||
if (route == null) {
|
||||
if (hasContextPath) {
|
||||
return contextPath + "/*";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// prepend context path
|
||||
return contextPath + route;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String extract(ServletRequestContext<REQUEST> requestContext) {
|
||||
String route = route(requestContext);
|
||||
if (route != null) {
|
||||
return route;
|
||||
}
|
||||
REQUEST request = requestContext.request();
|
||||
String method = accessor.getRequestMethod(request);
|
||||
if (method != null) {
|
||||
return "HTTP " + method;
|
||||
}
|
||||
return "HTTP request";
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.http.CapturedHttpHeader
|
|||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
||||
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -73,6 +74,7 @@ public final class SpringWebMvcTracingBuilder {
|
|||
.addAttributesExtractor(new SpringWebMvcNetAttributesExtractor())
|
||||
.addAttributesExtractors(additionalExtractors)
|
||||
.addRequestMetrics(HttpServerMetrics.get())
|
||||
.addContextCustomizer(ServerSpanNaming.get())
|
||||
.newServerInstrumenter(JavaxHttpServletRequestGetter.INSTANCE);
|
||||
|
||||
return new SpringWebMvcTracing(instrumenter);
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.tomcat.common;
|
||||
|
||||
import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.CONTAINER;
|
||||
|
||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
|
@ -50,15 +48,13 @@ public final class TomcatInstrumenterFactory {
|
|||
.addAttributesExtractor(httpAttributesExtractor)
|
||||
.addAttributesExtractor(netAttributesExtractor)
|
||||
.addAttributesExtractor(additionalAttributeExtractor)
|
||||
.addContextCustomizer(ServerSpanNaming.get())
|
||||
.addContextCustomizer(
|
||||
(context, request, attributes) -> {
|
||||
context = ServerSpanNaming.init(context, CONTAINER);
|
||||
|
||||
return new AppServerBridge.Builder()
|
||||
.captureServletAttributes()
|
||||
.recordException()
|
||||
.init(context);
|
||||
})
|
||||
(context, request, attributes) ->
|
||||
new AppServerBridge.Builder()
|
||||
.captureServletAttributes()
|
||||
.recordException()
|
||||
.init(context))
|
||||
.addRequestMetrics(HttpServerMetrics.get())
|
||||
.newServerInstrumenter(TomcatRequestGetter.INSTANCE);
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.undertow;
|
||||
|
||||
import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.CONTAINER;
|
||||
|
||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
|
||||
|
@ -42,9 +40,9 @@ public final class UndertowSingletons {
|
|||
.setSpanStatusExtractor(spanStatusExtractor)
|
||||
.addAttributesExtractor(httpAttributesExtractor)
|
||||
.addAttributesExtractor(netAttributesExtractor)
|
||||
.addContextCustomizer(ServerSpanNaming.get())
|
||||
.addContextCustomizer(
|
||||
(context, request, attributes) -> {
|
||||
context = ServerSpanNaming.init(context, CONTAINER);
|
||||
// span is ended when counter reaches 0, we start from 2 which accounts for the
|
||||
// handler that started the span and exchange completion listener
|
||||
context = UndertowActiveHandlers.init(context, 2);
|
||||
|
|
Loading…
Reference in New Issue