Migrate Ratpack javaagent instrumentation to Instrumenter API (#4399)
This commit is contained in:
parent
888496413d
commit
22ea557c41
|
@ -11,6 +11,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.HttpRequestAndChannel;
|
||||
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyCommonNetAttributesExtractor;
|
||||
|
||||
|
@ -30,6 +31,11 @@ public final class NettyServerInstrumenterFactory {
|
|||
.addAttributesExtractor(httpAttributesExtractor)
|
||||
.addAttributesExtractor(new NettyCommonNetAttributesExtractor())
|
||||
.addRequestMetrics(HttpServerMetrics.get())
|
||||
.addContextCustomizer(
|
||||
(context, request, attributes) -> {
|
||||
// netty is not exactly a "container", but it's the best match out of these
|
||||
return ServerSpanNaming.init(context, ServerSpanNaming.Source.CONTAINER);
|
||||
})
|
||||
.newServerInstrumenter(new HttpRequestHeadersGetter());
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.ratpack;
|
||||
|
||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.ErrorCauseExtractor;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
|
||||
import ratpack.handling.Context;
|
||||
|
||||
public final class RatpackSingletons {
|
||||
|
||||
private static final Instrumenter<String, Void> INSTRUMENTER =
|
||||
Instrumenter.<String, Void>newBuilder(
|
||||
GlobalOpenTelemetry.get(), "io.opentelemetry.ratpack-1.4", s -> s)
|
||||
.newInstrumenter();
|
||||
|
||||
public static Instrumenter<String, Void> instrumenter() {
|
||||
return INSTRUMENTER;
|
||||
}
|
||||
|
||||
public static void updateSpanNames(io.opentelemetry.context.Context otelContext, Context ctx) {
|
||||
String matchedRoute = updateServerSpanName(otelContext, ctx);
|
||||
// update ratpack span name
|
||||
Span.fromContext(otelContext).updateName(matchedRoute);
|
||||
}
|
||||
|
||||
public static String updateServerSpanName(
|
||||
io.opentelemetry.context.Context otelContext, Context ctx) {
|
||||
String matchedRoute = ctx.getPathBinding().getDescription();
|
||||
if (matchedRoute == null || matchedRoute.isEmpty()) {
|
||||
matchedRoute = "/";
|
||||
} else if (!matchedRoute.startsWith("/")) {
|
||||
matchedRoute = "/" + matchedRoute;
|
||||
}
|
||||
|
||||
// update the netty server span name; FILTER is probably the best match for ratpack Handlers
|
||||
ServerSpanNaming.updateServerSpanName(
|
||||
otelContext, ServerSpanNaming.Source.FILTER, (context, name) -> name, matchedRoute);
|
||||
return matchedRoute;
|
||||
}
|
||||
|
||||
// copied from BaseTracer#onException()
|
||||
public static void onError(io.opentelemetry.context.Context context, Throwable error) {
|
||||
Span span = Span.fromContext(context);
|
||||
span.setStatus(StatusCode.ERROR);
|
||||
span.recordException(ErrorCauseExtractor.jdk().extractCause(error));
|
||||
}
|
||||
|
||||
private RatpackSingletons() {}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.ratpack;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
|
||||
import ratpack.handling.Context;
|
||||
|
||||
public class RatpackTracer extends BaseTracer {
|
||||
private static final RatpackTracer TRACER = new RatpackTracer();
|
||||
|
||||
public static RatpackTracer tracer() {
|
||||
return TRACER;
|
||||
}
|
||||
|
||||
public void onContext(io.opentelemetry.context.Context otelContext, Context ctx) {
|
||||
String description = ctx.getPathBinding().getDescription();
|
||||
if (description == null || description.isEmpty()) {
|
||||
description = "/";
|
||||
} else if (!description.startsWith("/")) {
|
||||
description = "/" + description;
|
||||
}
|
||||
|
||||
Span.fromContext(otelContext).updateName(description);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getInstrumentationName() {
|
||||
return "io.opentelemetry.ratpack-1.4";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Throwable unwrapThrowable(Throwable throwable) {
|
||||
if (throwable.getCause() != null && throwable instanceof Error) {
|
||||
throwable = throwable.getCause();
|
||||
}
|
||||
return super.unwrapThrowable(throwable);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,6 @@ package io.opentelemetry.javaagent.instrumentation.ratpack;
|
|||
|
||||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
|
||||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
|
||||
import static io.opentelemetry.javaagent.instrumentation.ratpack.RatpackTracer.tracer;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isAbstract;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.not;
|
||||
|
@ -51,7 +50,7 @@ public class ServerErrorHandlerInstrumentation implements TypeInstrumentation {
|
|||
Optional<io.opentelemetry.context.Context> otelContext =
|
||||
ctx.maybeGet(io.opentelemetry.context.Context.class);
|
||||
if (otelContext.isPresent()) {
|
||||
tracer().onException(otelContext.get(), throwable);
|
||||
RatpackSingletons.onError(otelContext.get(), throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
|
||||
package io.opentelemetry.javaagent.instrumentation.ratpack;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.ratpack.RatpackTracer.tracer;
|
||||
import static io.opentelemetry.javaagent.instrumentation.ratpack.RatpackSingletons.instrumenter;
|
||||
import static io.opentelemetry.javaagent.instrumentation.ratpack.RatpackSingletons.updateServerSpanName;
|
||||
import static io.opentelemetry.javaagent.instrumentation.ratpack.RatpackSingletons.updateSpanNames;
|
||||
|
||||
import io.netty.util.Attribute;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.instrumentation.netty.v4_1.AttributeKeys;
|
||||
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
|
||||
|
@ -16,6 +17,9 @@ import ratpack.handling.Context;
|
|||
import ratpack.handling.Handler;
|
||||
|
||||
public final class TracingHandler implements Handler {
|
||||
|
||||
private static final String INITIAL_SPAN_NAME = "ratpack.handler";
|
||||
|
||||
public static final Handler INSTANCE = new TracingHandler();
|
||||
|
||||
@Override
|
||||
|
@ -27,25 +31,28 @@ public final class TracingHandler implements Handler {
|
|||
// Must use context from channel, as executor instrumentation is not accurate - Ratpack
|
||||
// internally queues events and then drains them in batches, causing executor instrumentation to
|
||||
// attach the same context to a batch of events from different requests.
|
||||
io.opentelemetry.context.Context parentContext =
|
||||
io.opentelemetry.context.Context parentOtelContext =
|
||||
serverSpanContext != null ? serverSpanContext : Java8BytecodeBridge.currentContext();
|
||||
io.opentelemetry.context.Context callbackContext;
|
||||
|
||||
io.opentelemetry.context.Context ratpackContext =
|
||||
tracer().startSpan(parentContext, "ratpack.handler", SpanKind.INTERNAL);
|
||||
ctx.getExecution().add(ratpackContext);
|
||||
if (instrumenter().shouldStart(parentOtelContext, INITIAL_SPAN_NAME)) {
|
||||
io.opentelemetry.context.Context otelContext =
|
||||
instrumenter().start(parentOtelContext, INITIAL_SPAN_NAME);
|
||||
ctx.getExecution().add(otelContext);
|
||||
ctx.getResponse()
|
||||
.beforeSend(
|
||||
response -> {
|
||||
updateSpanNames(otelContext, ctx);
|
||||
instrumenter().end(otelContext, INITIAL_SPAN_NAME, null, null);
|
||||
});
|
||||
callbackContext = otelContext;
|
||||
} else {
|
||||
// just update the server span name
|
||||
ctx.getResponse().beforeSend(response -> updateServerSpanName(parentOtelContext, ctx));
|
||||
callbackContext = parentOtelContext;
|
||||
}
|
||||
|
||||
ctx.getResponse()
|
||||
.beforeSend(
|
||||
response -> {
|
||||
if (serverSpanContext != null) {
|
||||
// Rename the netty span name with the ratpack route.
|
||||
tracer().onContext(serverSpanContext, ctx);
|
||||
}
|
||||
tracer().onContext(ratpackContext, ctx);
|
||||
tracer().end(ratpackContext);
|
||||
});
|
||||
|
||||
try (Scope ignored = ratpackContext.makeCurrent()) {
|
||||
try (Scope ignored = callbackContext.makeCurrent()) {
|
||||
ctx.next();
|
||||
// exceptions are captured by ServerErrorHandlerInstrumentation
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue