Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Netty: preserve caught exception in the context instead of calling end() #4413

Merged
merged 1 commit into from
Oct 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions instrumentation/netty/netty-3.8/javaagent/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ dependencies {
compileOnly("com.google.auto.value:auto-value-annotations")
annotationProcessor("com.google.auto.value:auto-value")

implementation(project(":instrumentation:netty:netty-common:javaagent"))

compileOnly("io.netty:netty:3.8.0.Final")

testLibrary("io.netty:netty:3.8.0.Final")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.instrumentation.netty.v3_8.server.NettyServerErrorHandler;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyErrorHolder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
Expand All @@ -39,7 +39,7 @@ public static class NotifyHandlerExceptionAdvice {
@Advice.OnMethodEnter
public static void onEnter(@Advice.Argument(1) Throwable throwable) {
if (throwable != null) {
NettyServerErrorHandler.onError(Java8BytecodeBridge.currentContext(), throwable);
NettyErrorHolder.set(Java8BytecodeBridge.currentContext(), throwable);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.field.VirtualField;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyErrorHolder;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.MessageEvent;
Expand All @@ -35,7 +36,7 @@ public void messageReceived(ChannelHandlerContext ctx, MessageEvent msg) {
requestAndContexts.context(),
requestAndContexts.request(),
(HttpResponse) msg.getMessage(),
null);
NettyErrorHolder.getOrDefault(requestAndContexts.context(), null));
requestContextsField.set(ctx.getChannel(), null);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
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;

Expand All @@ -35,6 +36,8 @@ final class NettyClientSingletons {
.addAttributesExtractor(
PeerServiceAttributesExtractor.create(netClientAttributesExtractor))
.addRequestMetrics(HttpClientMetrics.get())
.addContextCustomizer(
(context, requestAndChannel, startAttributes) -> NettyErrorHolder.init(context))
.newClientInstrumenter(new HttpRequestHeadersSetter());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.field.VirtualField;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyErrorHolder;
import io.opentelemetry.javaagent.instrumentation.netty.v3_8.HttpRequestAndChannel;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
Expand All @@ -35,12 +36,15 @@ public void writeRequested(ChannelHandlerContext ctx, MessageEvent msg) {
HttpRequestAndChannel request = requestAndContext.request();
HttpResponse response = (HttpResponse) msg.getMessage();

Throwable error = null;
try (Scope ignored = context.makeCurrent()) {
ctx.sendDownstream(msg);
instrumenter().end(context, request, response, null);
} catch (Throwable throwable) {
instrumenter().end(context, request, response, throwable);
throw throwable;
} catch (Throwable t) {
error = t;
throw t;
} finally {
error = NettyErrorHolder.getOrDefault(context, error);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it is a bit debatable whether we should use the exception that is in context or the one that happened here. Could be fine either way.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I don't have any strong preference on one over another - I guess it's fine either way.

instrumenter().end(context, request, response, error);
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
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.instrumentation.netty.common.NettyErrorHolder;
import io.opentelemetry.javaagent.instrumentation.netty.v3_8.HttpRequestAndChannel;
import org.jboss.netty.handler.codec.http.HttpResponse;

Expand All @@ -30,6 +31,8 @@ final class NettyServerSingletons {
.addAttributesExtractor(httpServerAttributesExtractor)
.addAttributesExtractor(new NettyNetServerAttributesExtractor())
.addRequestMetrics(HttpServerMetrics.get())
.addContextCustomizer(
(context, requestAndChannel, startAttributes) -> NettyErrorHolder.init(context))
.newServerInstrumenter(new NettyHeadersGetter());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ dependencies {
compileOnly("com.google.auto.value:auto-value-annotations")
annotationProcessor("com.google.auto.value:auto-value")

api(project(":instrumentation:netty:netty-common:javaagent"))

compileOnly("io.netty:netty-codec-http:4.0.0.Final")
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyCommonNetAttributesExtractor;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyErrorHolder;

public final class NettyServerInstrumenterFactory {

Expand All @@ -33,6 +34,7 @@ public static Instrumenter<HttpRequestAndChannel, HttpResponse> create(
.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);
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyErrorHandler;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyErrorHolder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
Expand Down Expand Up @@ -62,7 +62,7 @@ public static void onEnter(

Context serverContext = ctx.channel().attr(AttributeKeys.SERVER_CONTEXT).get();
if (serverContext != null) {
NettyErrorHandler.onError(serverContext, throwable);
NettyErrorHolder.set(serverContext, throwable);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyErrorHolder;
import io.opentelemetry.javaagent.instrumentation.netty.v4_0.AttributeKeys;
import javax.annotation.Nullable;

Expand All @@ -41,6 +42,7 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise prm) {
private static void end(Channel channel, HttpResponse response, @Nullable Throwable error) {
Context context = channel.attr(AttributeKeys.SERVER_CONTEXT).getAndRemove();
HttpRequestAndChannel request = channel.attr(AttributeKeys.SERVER_REQUEST).getAndRemove();
error = NettyErrorHolder.getOrDefault(context, error);
instrumenter().end(context, request, response, error);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyErrorHandler;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyErrorHolder;
import io.opentelemetry.javaagent.instrumentation.netty.v4_1.client.NettyClientSingletons;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
Expand Down Expand Up @@ -60,7 +60,7 @@ public static void onEnter(

Context serverContext = ctx.channel().attr(AttributeKeys.SERVER_CONTEXT).get();
if (serverContext != null) {
NettyErrorHandler.onError(serverContext, throwable);
NettyErrorHolder.set(serverContext, throwable);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.netty.v4_1.AttributeKeys;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyErrorHolder;
import javax.annotation.Nullable;

public class HttpServerResponseTracingHandler extends ChannelOutboundHandlerAdapter {
Expand Down Expand Up @@ -87,6 +88,7 @@ private static void end(
Channel channel, @Nullable HttpResponse response, @Nullable Throwable error) {
Context context = channel.attr(AttributeKeys.SERVER_CONTEXT).getAndRemove();
HttpRequestAndChannel request = channel.attr(NettyServerSingletons.HTTP_REQUEST).getAndRemove();
error = NettyErrorHolder.getOrDefault(context, error);
instrumenter().end(context, request, response, error);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
plugins {
id("otel.javaagent-instrumentation")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.netty.common;

import static io.opentelemetry.context.ContextKey.named;

import io.opentelemetry.context.Context;
import io.opentelemetry.context.ContextKey;
import io.opentelemetry.context.ImplicitContextKeyed;
import javax.annotation.Nullable;

public final class NettyErrorHolder implements ImplicitContextKeyed {

private static final ContextKey<NettyErrorHolder> KEY = named("opentelemetry-netty-error");

private volatile Throwable error;

private NettyErrorHolder() {}

public static Context init(Context context) {
if (context.get(KEY) != null) {
return context;
}
return context.with(new NettyErrorHolder());
}

public static void set(Context context, Throwable error) {
NettyErrorHolder holder = context.get(KEY);
if (holder != null) {
holder.error = error;
}
}

@Nullable
public static Throwable getOrDefault(Context context, @Nullable Throwable error) {
Throwable result = null;
NettyErrorHolder holder = context.get(KEY);
if (holder != null) {
result = holder.error;
}
return result == null ? error : result;
}

@Override
public Context storeInContext(Context context) {
return context.with(KEY, this);
}
}
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ include(":instrumentation:netty:netty-4.0:javaagent")
include(":instrumentation:netty:netty-4.1:library")
include(":instrumentation:netty:netty-4.1:javaagent")
include(":instrumentation:netty:netty-4-common:javaagent")
include(":instrumentation:netty:netty-common:javaagent")
include(":instrumentation:okhttp:okhttp-2.2:javaagent")
include(":instrumentation:okhttp:okhttp-3.0:javaagent")
include(":instrumentation:okhttp:okhttp-3.0:library")
Expand Down