From 60aa4215f6a0edfa582da80ec1e808e400bac822 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 5 May 2023 12:44:55 +0300 Subject: [PATCH] Enable http pipelining test on Grizzly (#8411) --- .../FilterChainContextInstrumentation.java | 77 +++++++++++++++++++ .../grizzly/GrizzlyInstrumentationModule.java | 3 +- .../src/test/groovy/GrizzlyAsyncTest.groovy | 5 -- .../GrizzlyFilterchainServerTest.groovy | 5 -- .../src/test/groovy/GrizzlyTest.groovy | 5 -- 5 files changed, 79 insertions(+), 16 deletions(-) create mode 100644 instrumentation/grizzly-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grizzly/FilterChainContextInstrumentation.java diff --git a/instrumentation/grizzly-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grizzly/FilterChainContextInstrumentation.java b/instrumentation/grizzly-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grizzly/FilterChainContextInstrumentation.java new file mode 100644 index 0000000000..52f56c2cf2 --- /dev/null +++ b/instrumentation/grizzly-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grizzly/FilterChainContextInstrumentation.java @@ -0,0 +1,77 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.grizzly; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.bootstrap.CallDepth; +import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.glassfish.grizzly.filterchain.FilterChainContext; + +public class FilterChainContextInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("org.glassfish.grizzly.filterchain.FilterChainContext"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("resume").and(takesArguments(0)), + FilterChainContextInstrumentation.class.getName() + "$ResumeAdvice"); + transformer.applyAdviceToMethod( + named("write"), FilterChainContextInstrumentation.class.getName() + "$WriteAdvice"); + } + + @SuppressWarnings("unused") + public static class ResumeAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static Scope onEnter() { + return Java8BytecodeBridge.rootContext().makeCurrent(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void onExit(@Advice.Enter Scope scope) { + if (scope != null) { + scope.close(); + } + } + } + + @SuppressWarnings("unused") + public static class WriteAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter(@Advice.Local("otelCallDepth") CallDepth callDepth) { + callDepth = CallDepth.forClass(FilterChainContext.class); + callDepth.getAndIncrement(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void onExit( + @Advice.This FilterChainContext filterChainContext, + @Advice.Local("otelCallDepth") CallDepth callDepth) { + // When exiting the outermost call to write clear context & request from filter chain context. + // Write makes a copy of the current filter chain context and passes it on. In older versions + // new and old filter chain context share the attributes, but in newer versions the attributes + // are also copied. We need to remove the attributes here to ensure that the next request + // starts with clean state, failing to do so causes http pipelining test to fail with the + // latest deps. + if (callDepth.decrementAndGet() == 0) { + GrizzlyStateStorage.removeContext(filterChainContext); + GrizzlyStateStorage.removeRequest(filterChainContext); + } + } + } +} diff --git a/instrumentation/grizzly-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grizzly/GrizzlyInstrumentationModule.java b/instrumentation/grizzly-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grizzly/GrizzlyInstrumentationModule.java index 5400575596..a100805c78 100644 --- a/instrumentation/grizzly-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grizzly/GrizzlyInstrumentationModule.java +++ b/instrumentation/grizzly-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grizzly/GrizzlyInstrumentationModule.java @@ -25,6 +25,7 @@ public class GrizzlyInstrumentationModule extends InstrumentationModule { new FilterInstrumentation(), new HttpCodecFilterInstrumentation(), new HttpServerFilterInstrumentation(), - new HttpHandlerInstrumentation()); + new HttpHandlerInstrumentation(), + new FilterChainContextInstrumentation()); } } diff --git a/instrumentation/grizzly-2.0/javaagent/src/test/groovy/GrizzlyAsyncTest.groovy b/instrumentation/grizzly-2.0/javaagent/src/test/groovy/GrizzlyAsyncTest.groovy index 1d5e396ca8..7475f81a78 100644 --- a/instrumentation/grizzly-2.0/javaagent/src/test/groovy/GrizzlyAsyncTest.groovy +++ b/instrumentation/grizzly-2.0/javaagent/src/test/groovy/GrizzlyAsyncTest.groovy @@ -39,11 +39,6 @@ class GrizzlyAsyncTest extends GrizzlyTest { false } - @Override - boolean testHttpPipelining() { - false - } - @Override boolean verifyServerSpanEndTime() { // server spans are ended inside of the JAX-RS controller spans diff --git a/instrumentation/grizzly-2.0/javaagent/src/test/groovy/GrizzlyFilterchainServerTest.groovy b/instrumentation/grizzly-2.0/javaagent/src/test/groovy/GrizzlyFilterchainServerTest.groovy index ed72ef5e56..df603aef68 100644 --- a/instrumentation/grizzly-2.0/javaagent/src/test/groovy/GrizzlyFilterchainServerTest.groovy +++ b/instrumentation/grizzly-2.0/javaagent/src/test/groovy/GrizzlyFilterchainServerTest.groovy @@ -84,11 +84,6 @@ class GrizzlyFilterchainServerTest extends HttpServerTest implements false } - @Override - boolean testHttpPipelining() { - false - } - @Override boolean verifyServerSpanEndTime() { // server spans are ended inside of the controller spans diff --git a/instrumentation/grizzly-2.0/javaagent/src/test/groovy/GrizzlyTest.groovy b/instrumentation/grizzly-2.0/javaagent/src/test/groovy/GrizzlyTest.groovy index 90a34cc330..6b9d885f1c 100644 --- a/instrumentation/grizzly-2.0/javaagent/src/test/groovy/GrizzlyTest.groovy +++ b/instrumentation/grizzly-2.0/javaagent/src/test/groovy/GrizzlyTest.groovy @@ -68,11 +68,6 @@ class GrizzlyTest extends HttpServerTest implements AgentTestTrait { false } - @Override - boolean testHttpPipelining() { - false - } - static class SimpleExceptionMapper implements ExceptionMapper { @Override