Netty: don't expose tracing handler in handlers map (#10410)

This commit is contained in:
Lauri Tulmin 2024-02-06 08:43:46 +02:00 committed by GitHub
parent 86735748a1
commit d823ffed0b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 85 additions and 8 deletions

View File

@ -18,6 +18,8 @@ import io.netty.channel.ChannelPipeline;
import io.opentelemetry.instrumentation.api.util.VirtualField;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import java.util.Iterator;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@ -59,6 +61,9 @@ public abstract class AbstractNettyChannelPipelineInstrumentation implements Typ
.and(takesArgument(1, String.class))
.and(takesArguments(4)),
AbstractNettyChannelPipelineInstrumentation.class.getName() + "$AddAfterAdvice");
transformer.applyAdviceToMethod(
isMethod().and(named("toMap")).and(takesArguments(0)).and(returns(Map.class)),
AbstractNettyChannelPipelineInstrumentation.class.getName() + "$ToMapAdvice");
}
@SuppressWarnings("unused")
@ -194,4 +199,22 @@ public abstract class AbstractNettyChannelPipelineInstrumentation implements Typ
}
}
}
@SuppressWarnings("unused")
public static class ToMapAdvice {
@Advice.OnMethodExit(suppress = Throwable.class)
public static void wrapIterator(@Advice.Return Map<String, ChannelHandler> map) {
VirtualField<ChannelHandler, ChannelHandler> virtualField =
VirtualField.find(ChannelHandler.class, ChannelHandler.class);
for (Iterator<ChannelHandler> iterator = map.values().iterator(); iterator.hasNext(); ) {
ChannelHandler handler = iterator.next();
String handlerClassName = handler.getClass().getName();
if (handlerClassName.startsWith("io.opentelemetry.javaagent.instrumentation.netty.")
|| handlerClassName.startsWith("io.opentelemetry.instrumentation.netty.")) {
iterator.remove();
}
}
}
}
}

View File

@ -70,7 +70,7 @@ class ChannelPipelineTest extends AgentInstrumentationSpecification {
replaceMethod(channelPipeline, "test", noopHandler, "http", httpHandler)
then: "noop handler was removed; http and instrumentation handlers were added"
channelPipeline.size() == 2
channelPipeline.size() == 1
channelPipeline.first() == httpHandler
channelPipeline.last().getClass().getSimpleName() == "HttpClientTracingHandler"
@ -103,7 +103,7 @@ class ChannelPipelineTest extends AgentInstrumentationSpecification {
channelPipeline.addLast("http", httpHandler)
then: "add http and instrumentation handlers"
channelPipeline.size() == 2
channelPipeline.size() == 1
channelPipeline.first() == httpHandler
channelPipeline.last().getClass().getSimpleName() == "HttpClientTracingHandler"
@ -112,7 +112,7 @@ class ChannelPipelineTest extends AgentInstrumentationSpecification {
channelPipeline.addAfter("http", "noop", noopHandler)
then: "instrumentation handler is between with http and noop"
channelPipeline.size() == 3
channelPipeline.size() == 2
channelPipeline.first() == httpHandler
channelPipeline.last() == noopHandler
@ -120,7 +120,7 @@ class ChannelPipelineTest extends AgentInstrumentationSpecification {
channelPipeline.removeLast()
then: "http and instrumentation handlers will be remained"
channelPipeline.size() == 2
channelPipeline.size() == 1
channelPipeline.first() == httpHandler
channelPipeline.last().getClass().getSimpleName() == "HttpClientTracingHandler"
@ -133,6 +133,33 @@ class ChannelPipelineTest extends AgentInstrumentationSpecification {
removed == httpHandler
}
// regression test for https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/10377
def "our handler not in handlers map"() {
setup:
def channel = new EmbeddedChannel(new NoopChannelHandler())
def channelPipeline = new DefaultChannelPipeline(channel)
def handler = new HttpClientCodec()
when:
// no handlers
channelPipeline.first() == null
then:
// add handler
channelPipeline.addLast("http", handler)
channelPipeline.first() == handler
// our handler was also added
channelPipeline.last().getClass().simpleName == "HttpClientTracingHandler"
// our handler not counted
channelPipeline.size() == 1
// our handler is not in handlers map
channelPipeline.toMap().size() == 1
// our handler is not in handlers iterator
def list = []
channelPipeline.iterator().forEachRemaining {list.add(it) }
list.size() == 1
}
private static class NoopChannelHandler extends ChannelHandlerAdapter {
}
}

View File

@ -68,7 +68,7 @@ class ChannelPipelineTest extends AgentInstrumentationSpecification {
replaceMethod(channelPipeline, "test", noopHandler, "http", httpHandler)
then: "noop handler was removed; http and instrumentation handlers were added"
channelPipeline.size() == 2
channelPipeline.size() == 1
channelPipeline.first() == httpHandler
channelPipeline.last().getClass().simpleName == "HttpClientTracingHandler"
@ -101,7 +101,7 @@ class ChannelPipelineTest extends AgentInstrumentationSpecification {
channelPipeline.addLast("http", httpHandler)
then: "add http and instrumentation handlers"
channelPipeline.size() == 2
channelPipeline.size() == 1
channelPipeline.first() == httpHandler
channelPipeline.last().getClass().simpleName == "HttpClientTracingHandler"
@ -110,7 +110,7 @@ class ChannelPipelineTest extends AgentInstrumentationSpecification {
channelPipeline.addAfter("http", "noop", noopHandler)
then: "instrumentation handler is between with http and noop"
channelPipeline.size() == 3
channelPipeline.size() == 2
channelPipeline.first() == httpHandler
channelPipeline.last() == noopHandler
@ -118,7 +118,7 @@ class ChannelPipelineTest extends AgentInstrumentationSpecification {
channelPipeline.removeLast()
then: "http and instrumentation handlers will be remained"
channelPipeline.size() == 2
channelPipeline.size() == 1
channelPipeline.first() == httpHandler
channelPipeline.last().getClass().simpleName == "HttpClientTracingHandler"
@ -131,6 +131,33 @@ class ChannelPipelineTest extends AgentInstrumentationSpecification {
removed == httpHandler
}
// regression test for https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/10377
def "our handler not in handlers map"() {
setup:
def channel = new EmbeddedChannel()
def channelPipeline = new DefaultChannelPipeline(channel)
def handler = new HttpClientCodec()
when:
// no handlers
channelPipeline.first() == null
then:
// add handler
channelPipeline.addLast("http", handler)
channelPipeline.first() == handler
// our handler was also added
channelPipeline.last().getClass().simpleName == "HttpClientTracingHandler"
// our handler not counted
channelPipeline.size() == 1
// our handler is not in handlers map
channelPipeline.toMap().size() == 1
// our handler is not in handlers iterator
def list = []
channelPipeline.iterator().forEachRemaining {list.add(it) }
list.size() == 1
}
private static class NoopChannelHandler extends ChannelHandlerAdapter {
}
}