diff --git a/instrumentation/micronaut-core-4.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRBiConsumerTokenWrapper.java b/instrumentation/micronaut-core-4.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRBiConsumerTokenWrapper.java new file mode 100644 index 0000000000..20ebbea92c --- /dev/null +++ b/instrumentation/micronaut-core-4.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRBiConsumerTokenWrapper.java @@ -0,0 +1,40 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package com.nr.agent.instrumentation.micronaut; + +import com.newrelic.agent.bridge.AgentBridge; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.Trace; + +import java.util.function.BiConsumer; + +public class NRBiConsumerTokenWrapper implements BiConsumer { + BiConsumer delegate = null; + private static boolean isTransformed = false; + + + public NRBiConsumerTokenWrapper(BiConsumer d) { + delegate = d; + if(!isTransformed) { + isTransformed = true; + AgentBridge.instrumentation.retransformUninstrumentedClass(getClass()); + } + } + + @Override + @Trace(dispatcher = true) + public void accept(R r, Throwable throwable) { + if(throwable != null) { + NewRelic.noticeError(throwable); + } + if(delegate != null) { + delegate.accept(r, throwable); + } + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/execution/CompletableFutureExecutionFlowImpl_Instrumentation.java b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/execution/CompletableFutureExecutionFlowImpl_Instrumentation.java deleted file mode 100644 index 7d9f76e69e..0000000000 --- a/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/execution/CompletableFutureExecutionFlowImpl_Instrumentation.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package io.micronaut.core.execution; - -import com.newrelic.api.agent.NewRelic; -import com.newrelic.api.agent.Token; -import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.weaver.MatchType; -import com.newrelic.api.agent.weaver.NewField; -import com.newrelic.api.agent.weaver.Weave; -import com.newrelic.api.agent.weaver.Weaver; -import com.nr.agent.instrumentation.micronaut.NRBiConsumerWrapper; - -import java.util.concurrent.CompletableFuture; -import java.util.function.BiConsumer; - -@Weave(originalName = "io.micronaut.core.execution.CompletableFutureExecutionFlowImpl", type = MatchType.ExactClass) -class CompletableFutureExecutionFlowImpl_Instrumentation { - @NewField - protected Token token = null; - - CompletableFutureExecutionFlowImpl_Instrumentation(CompletableFuture stage) { - Token t = NewRelic.getAgent().getTransaction().getToken(); - if (t != null) { - token = t; - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Trace(async = true) - public void onComplete(BiConsumer throwable) { - if (token != null) { - token.linkAndExpire(); - token = null; - throwable = new NRBiConsumerWrapper(throwable); - } - - Weaver.callOriginal(); - } -} \ No newline at end of file diff --git a/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/execution/DelayedExecutionFlowImpl_Instrumentation.java b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/execution/DelayedExecutionFlowImpl_Instrumentation.java deleted file mode 100644 index 0899e330f9..0000000000 --- a/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/execution/DelayedExecutionFlowImpl_Instrumentation.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package io.micronaut.core.execution; - -import com.newrelic.api.agent.NewRelic; -import com.newrelic.api.agent.Token; -import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.weaver.MatchType; -import com.newrelic.api.agent.weaver.NewField; -import com.newrelic.api.agent.weaver.Weave; -import com.newrelic.api.agent.weaver.Weaver; -import com.nr.agent.instrumentation.micronaut.NRBiConsumerWrapper; - -import java.util.function.BiConsumer; - -@Weave(originalName = "io.micronaut.core.execution.DelayedExecutionFlowImpl", type = MatchType.ExactClass) -class DelayedExecutionFlowImpl_Instrumentation { - - @NewField - protected Token token = null; - - DelayedExecutionFlowImpl_Instrumentation() { - Token t = NewRelic.getAgent().getTransaction().getToken(); - if (t != null) { - token = t; - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Trace(async = true) - public void onComplete(BiConsumer fn) { - if (token != null) { - token.linkAndExpire(); - token = null; - fn = new NRBiConsumerWrapper(fn); - } - - Weaver.callOriginal(); - } - - -} \ No newline at end of file diff --git a/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/execution/ExecutionFlow_Instrumentation.java b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/execution/ExecutionFlow_Instrumentation.java new file mode 100644 index 0000000000..e73131f194 --- /dev/null +++ b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/execution/ExecutionFlow_Instrumentation.java @@ -0,0 +1,20 @@ +package io.micronaut.core.execution; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.*; + +import java.util.function.BiConsumer; + +@Weave(originalName = "io.micronaut.core.execution.ExecutionFlow", type = MatchType.Interface) +public class ExecutionFlow_Instrumentation { + + @Trace + public ImperativeExecutionFlow tryComplete() { + return Weaver.callOriginal(); + } + + @Trace + public void onComplete(BiConsumer fn) { + Weaver.callOriginal(); + } +} diff --git a/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/execution/ImperativeExecutionFlowImpl_Instrumentation.java b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/execution/ImperativeExecutionFlowImpl_Instrumentation.java deleted file mode 100644 index 2dda07e37c..0000000000 --- a/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/execution/ImperativeExecutionFlowImpl_Instrumentation.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package io.micronaut.core.execution; - -import com.newrelic.api.agent.NewRelic; -import com.newrelic.api.agent.Token; -import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.weaver.MatchType; -import com.newrelic.api.agent.weaver.NewField; -import com.newrelic.api.agent.weaver.Weave; -import com.newrelic.api.agent.weaver.Weaver; -import com.nr.agent.instrumentation.micronaut.NRBiConsumerWrapper; - -import java.util.function.BiConsumer; - -@Weave(originalName = "io.micronaut.core.execution.ImperativeExecutionFlowImpl", type = MatchType.ExactClass) -class ImperativeExecutionFlowImpl_Instrumentation { - - @NewField - protected Token token = null; - - ImperativeExecutionFlowImpl_Instrumentation(T value, Throwable error) { - Token t = NewRelic.getAgent().getTransaction().getToken(); - if (t != null) { - token = t; - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Trace(async = true) - public void onComplete(BiConsumer fn) { - if (token != null) { - token.linkAndExpire(); - token = null; - fn = new NRBiConsumerWrapper(fn); - } - - Weaver.callOriginal(); - } -} \ No newline at end of file diff --git a/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/propagation/ThreadContext_Skip.java b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/propagation/ThreadContext_Skip.java new file mode 100644 index 0000000000..2506f49b23 --- /dev/null +++ b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/propagation/ThreadContext_Skip.java @@ -0,0 +1,11 @@ +package io.micronaut.core.propagation; + +import com.newrelic.api.agent.weaver.SkipIfPresent; + +/** + * Necessary to keep from instrumenting 4.3.0 and higher because instrumentation for 4.3.0 includes + * instrumentation for new functionality + */ +@SkipIfPresent(originalName = "io.micronaut.core.propagation.ThreadContext") +public class ThreadContext_Skip { +} diff --git a/instrumentation/micronaut-core-4.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRBiConsumerTokenWrapper.java b/instrumentation/micronaut-core-4.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRBiConsumerTokenWrapper.java new file mode 100644 index 0000000000..20ebbea92c --- /dev/null +++ b/instrumentation/micronaut-core-4.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRBiConsumerTokenWrapper.java @@ -0,0 +1,40 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package com.nr.agent.instrumentation.micronaut; + +import com.newrelic.agent.bridge.AgentBridge; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.Trace; + +import java.util.function.BiConsumer; + +public class NRBiConsumerTokenWrapper implements BiConsumer { + BiConsumer delegate = null; + private static boolean isTransformed = false; + + + public NRBiConsumerTokenWrapper(BiConsumer d) { + delegate = d; + if(!isTransformed) { + isTransformed = true; + AgentBridge.instrumentation.retransformUninstrumentedClass(getClass()); + } + } + + @Override + @Trace(dispatcher = true) + public void accept(R r, Throwable throwable) { + if(throwable != null) { + NewRelic.noticeError(throwable); + } + if(delegate != null) { + delegate.accept(r, throwable); + } + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/execution/CompletableFutureExecutionFlowImpl_Instrumentation.java b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/execution/CompletableFutureExecutionFlowImpl_Instrumentation.java deleted file mode 100644 index 6f52262699..0000000000 --- a/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/execution/CompletableFutureExecutionFlowImpl_Instrumentation.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package io.micronaut.core.execution; - -import com.newrelic.api.agent.NewRelic; -import com.newrelic.api.agent.Token; -import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.weaver.MatchType; -import com.newrelic.api.agent.weaver.NewField; -import com.newrelic.api.agent.weaver.Weave; -import com.newrelic.api.agent.weaver.Weaver; -import com.nr.agent.instrumentation.micronaut.NRBiConsumerWrapper; - -import java.util.concurrent.CompletionStage; -import java.util.function.BiConsumer; - -@Weave(originalName = "io.micronaut.core.execution.CompletableFutureExecutionFlowImpl", type = MatchType.ExactClass) -class CompletableFutureExecutionFlowImpl_Instrumentation { - @NewField - protected Token token = null; - - CompletableFutureExecutionFlowImpl_Instrumentation(CompletionStage stage) { - Token t = NewRelic.getAgent().getTransaction().getToken(); - if (t != null) { - token = t; - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Trace(async = true) - public void onComplete(BiConsumer throwable) { - if (token != null) { - token.linkAndExpire(); - token = null; - throwable = new NRBiConsumerWrapper<>(throwable); - } - - Weaver.callOriginal(); - } -} \ No newline at end of file diff --git a/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/execution/DelayedExecutionFlowImpl_Instrumentation.java b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/execution/DelayedExecutionFlowImpl_Instrumentation.java deleted file mode 100644 index 0899e330f9..0000000000 --- a/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/execution/DelayedExecutionFlowImpl_Instrumentation.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package io.micronaut.core.execution; - -import com.newrelic.api.agent.NewRelic; -import com.newrelic.api.agent.Token; -import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.weaver.MatchType; -import com.newrelic.api.agent.weaver.NewField; -import com.newrelic.api.agent.weaver.Weave; -import com.newrelic.api.agent.weaver.Weaver; -import com.nr.agent.instrumentation.micronaut.NRBiConsumerWrapper; - -import java.util.function.BiConsumer; - -@Weave(originalName = "io.micronaut.core.execution.DelayedExecutionFlowImpl", type = MatchType.ExactClass) -class DelayedExecutionFlowImpl_Instrumentation { - - @NewField - protected Token token = null; - - DelayedExecutionFlowImpl_Instrumentation() { - Token t = NewRelic.getAgent().getTransaction().getToken(); - if (t != null) { - token = t; - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Trace(async = true) - public void onComplete(BiConsumer fn) { - if (token != null) { - token.linkAndExpire(); - token = null; - fn = new NRBiConsumerWrapper(fn); - } - - Weaver.callOriginal(); - } - - -} \ No newline at end of file diff --git a/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/execution/ExecutionFlow_Instrumentation.java b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/execution/ExecutionFlow_Instrumentation.java new file mode 100644 index 0000000000..ee5049f4c0 --- /dev/null +++ b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/execution/ExecutionFlow_Instrumentation.java @@ -0,0 +1,30 @@ +package io.micronaut.core.execution; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.*; + +import java.util.function.BiConsumer; + +@Weave(originalName = "io.micronaut.core.execution.ExecutionFlow", type = MatchType.Interface) +public class ExecutionFlow_Instrumentation { + + @Trace + public ImperativeExecutionFlow tryComplete() { + return Weaver.callOriginal(); + } + + @Trace + public T tryCompleteValue() { + return Weaver.callOriginal(); + } + + @Trace + public Throwable tryCompleteError() { + return Weaver.callOriginal(); + } + + @Trace + public void onComplete(BiConsumer fn) { + Weaver.callOriginal(); + } +} diff --git a/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/execution/ImperativeExecutionFlowImpl_Instrumentation.java b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/execution/ImperativeExecutionFlowImpl_Instrumentation.java deleted file mode 100644 index 2dda07e37c..0000000000 --- a/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/execution/ImperativeExecutionFlowImpl_Instrumentation.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package io.micronaut.core.execution; - -import com.newrelic.api.agent.NewRelic; -import com.newrelic.api.agent.Token; -import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.weaver.MatchType; -import com.newrelic.api.agent.weaver.NewField; -import com.newrelic.api.agent.weaver.Weave; -import com.newrelic.api.agent.weaver.Weaver; -import com.nr.agent.instrumentation.micronaut.NRBiConsumerWrapper; - -import java.util.function.BiConsumer; - -@Weave(originalName = "io.micronaut.core.execution.ImperativeExecutionFlowImpl", type = MatchType.ExactClass) -class ImperativeExecutionFlowImpl_Instrumentation { - - @NewField - protected Token token = null; - - ImperativeExecutionFlowImpl_Instrumentation(T value, Throwable error) { - Token t = NewRelic.getAgent().getTransaction().getToken(); - if (t != null) { - token = t; - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Trace(async = true) - public void onComplete(BiConsumer fn) { - if (token != null) { - token.linkAndExpire(); - token = null; - fn = new NRBiConsumerWrapper(fn); - } - - Weaver.callOriginal(); - } -} \ No newline at end of file diff --git a/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/type/UnsafeExecutable_Instrumentation.java b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/type/UnsafeExecutable_Instrumentation.java index 1e2fc6d808..eadf96b616 100644 --- a/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/type/UnsafeExecutable_Instrumentation.java +++ b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/type/UnsafeExecutable_Instrumentation.java @@ -8,6 +8,7 @@ package io.micronaut.core.type; import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; @@ -15,6 +16,7 @@ @Weave(originalName = "io.micronaut.core.type.UnsafeExecutable", type = MatchType.Interface) public abstract class UnsafeExecutable_Instrumentation { + @Trace public R invokeUnsafe(T instance, Object... arguments) { NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "UnsafeExecutable", getClass().getSimpleName(),"invoke"); NewRelic.getAgent().getTracedMethod().addCustomAttribute("Instance", instance.getClass().getName()); diff --git a/instrumentation/micronaut-http-1.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/MicronautSubresourceInstrumentation.java b/instrumentation/micronaut-http-1.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/MicronautSubresourceInstrumentation.java index 578c003f34..e007a6091c 100644 --- a/instrumentation/micronaut-http-1.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/MicronautSubresourceInstrumentation.java +++ b/instrumentation/micronaut-http-1.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/MicronautSubresourceInstrumentation.java @@ -30,6 +30,9 @@ public class MicronautSubresourceInstrumentation { @WeaveIntoAllMethods @Trace private static void instrumentation() { + if(!NewRelic.getAgent().getTransaction().isWebTransaction()) { + NewRelic.getAgent().getTransaction().convertToWebTransaction(); + } Controller controller = Weaver.getClassAnnotation(Controller.class); if (controller != null) { String controllerValue = controller.value(); @@ -137,6 +140,8 @@ private static void instrumentation() { } StringBuilder sb = new StringBuilder(); + sb.append(methodName); + sb.append(" - "); if (controllerValue != null) { sb.append(controllerValue); @@ -146,9 +151,8 @@ private static void instrumentation() { if (value != null) { sb.append(value); } - - sb.append(" (").append(methodName).append(") "); - NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_HIGH, true, "MicronautController", sb.toString()); + String txnName = sb.toString().replace("//", "/"); + NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW , false, "MicronautController", txnName); } } } diff --git a/instrumentation/micronaut-http-1.3.0/src/main/java/io/micronaut/http/filter/ClientFilterChain_Instrumentation.java b/instrumentation/micronaut-http-1.3.0/src/main/java/io/micronaut/http/filter/ClientFilterChain_Instrumentation.java new file mode 100644 index 0000000000..b9ac5b8b0c --- /dev/null +++ b/instrumentation/micronaut-http-1.3.0/src/main/java/io/micronaut/http/filter/ClientFilterChain_Instrumentation.java @@ -0,0 +1,22 @@ +package io.micronaut.http.filter; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import io.micronaut.http.HttpResponse; +import io.micronaut.http.MutableHttpRequest; +import org.reactivestreams.Publisher; + +@Weave(originalName = "io.micronaut.http.filter.ClientFilterChain", type = MatchType.Interface) +public class ClientFilterChain_Instrumentation { + + @Trace + public Publisher> proceed(MutableHttpRequest request) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Micronaut","ClientFilterChain",getClass().getSimpleName(),"proceed"); + + return Weaver.callOriginal(); + } + +} diff --git a/instrumentation/micronaut-http-1.3.0/src/main/java/io/micronaut/http/filter/ServerFilterChain_Instrumentation.java b/instrumentation/micronaut-http-1.3.0/src/main/java/io/micronaut/http/filter/ServerFilterChain_Instrumentation.java new file mode 100644 index 0000000000..14e1aeb504 --- /dev/null +++ b/instrumentation/micronaut-http-1.3.0/src/main/java/io/micronaut/http/filter/ServerFilterChain_Instrumentation.java @@ -0,0 +1,21 @@ +package io.micronaut.http.filter; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import io.micronaut.http.HttpRequest; +import io.micronaut.http.MutableHttpResponse; +import org.reactivestreams.Publisher; + +@Weave(originalName = "io.micronaut.http.filter.ServerFilterChain", type = MatchType.Interface) +public class ServerFilterChain_Instrumentation { + + @Trace + public Publisher> proceed(HttpRequest request) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","ServerFilterChain", getClass().getSimpleName(),"proceed"); + return Weaver.callOriginal(); + } + +} diff --git a/instrumentation/micronaut-http-client-2.0.0/build.gradle b/instrumentation/micronaut-http-client-2.0.0/build.gradle index 0013132cc6..0029ec2998 100644 --- a/instrumentation/micronaut-http-client-2.0.0/build.gradle +++ b/instrumentation/micronaut-http-client-2.0.0/build.gradle @@ -12,7 +12,7 @@ jar { verifyInstrumentation { - passes('io.micronaut:micronaut-http-client:[2.0.0,3.0.0)') + passesOnly('io.micronaut:micronaut-http-client:[2.0.0,3.0.0)') excludeRegex 'io.micronaut:micronaut-http-client:.*(RC|M)[0-9]*$' } diff --git a/instrumentation/micronaut-http-client-2.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client/MicronautHttpInbound.java b/instrumentation/micronaut-http-client-2.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client/MicronautHttpInbound.java deleted file mode 100644 index 90e8656c8e..0000000000 --- a/instrumentation/micronaut-http-client-2.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client/MicronautHttpInbound.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package com.nr.agent.instrumentation.micronaut.http.client; - -import com.newrelic.api.agent.HeaderType; -import com.newrelic.api.agent.InboundHeaders; -import io.micronaut.http.HttpResponse; - -public class MicronautHttpInbound implements InboundHeaders { - - private final HttpResponse response; - - public MicronautHttpInbound(HttpResponse resp) { - response = resp; - } - - @Override - public HeaderType getHeaderType() { - return HeaderType.HTTP; - } - - @Override - public String getHeader(String name) { - if (response != null) { - return response.header(name); - } - return null; - } - -} diff --git a/instrumentation/micronaut-http-client-2.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client/MicronautHttpOutbound.java b/instrumentation/micronaut-http-client-2.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client/MicronautHttpOutbound.java deleted file mode 100644 index 7ef7d36d16..0000000000 --- a/instrumentation/micronaut-http-client-2.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client/MicronautHttpOutbound.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package com.nr.agent.instrumentation.micronaut.http.client; - -import com.newrelic.api.agent.HeaderType; -import com.newrelic.api.agent.OutboundHeaders; -import io.micronaut.http.HttpRequest; -import io.micronaut.http.MutableHttpRequest; - -public class MicronautHttpOutbound implements OutboundHeaders { - - private HttpRequest request = null; - - public MicronautHttpOutbound(HttpRequest req) { - request = req; - } - - @Override - public HeaderType getHeaderType() { - return HeaderType.HTTP; - } - - @Override - public void setHeader(String name, String value) { - if (request != null) { - if (request instanceof MutableHttpRequest) { - MutableHttpRequest mutable = (MutableHttpRequest) request; - mutable.header(name, value); - } - } - } - -} diff --git a/instrumentation/micronaut-http-client-2.0.0/src/main/java/io/micronaut/http/client/netty/DefaultHttpClient_Instrumentation.java b/instrumentation/micronaut-http-client-2.0.0/src/main/java/io/micronaut/http/client/netty/DefaultHttpClient_Instrumentation.java index 76fa498b6a..4de87c6485 100644 --- a/instrumentation/micronaut-http-client-2.0.0/src/main/java/io/micronaut/http/client/netty/DefaultHttpClient_Instrumentation.java +++ b/instrumentation/micronaut-http-client-2.0.0/src/main/java/io/micronaut/http/client/netty/DefaultHttpClient_Instrumentation.java @@ -15,7 +15,6 @@ import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import com.nr.agent.instrumentation.micronaut.http.client.MicronautHeaders; -import com.nr.agent.instrumentation.micronaut.http.client.MicronautHttpOutbound; import com.nr.agent.instrumentation.micronaut.http.client.ReactorListener; import com.nr.agent.instrumentation.micronaut.http.client.ResponseConsumer; import com.nr.agent.instrumentation.micronaut.http.client.Utils; @@ -35,8 +34,8 @@ public Flowable>> eventStream(io.micronaut.http.HttpRequ public Flowable> exchange(io.micronaut.http.HttpRequest request, Argument bodyType, Argument errorType) { - MicronautHttpOutbound wrapper = new MicronautHttpOutbound(request); - NewRelic.getAgent().getTracedMethod().addOutboundRequestHeaders(wrapper); + MicronautHeaders wrapper = new MicronautHeaders(request); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(wrapper); Flowable> result = Weaver.callOriginal(); HttpParameters params = HttpParameters.library("Micronaut") @@ -50,8 +49,8 @@ public Flowable> exchange(io.microna } public Flowable>> exchangeStream(io.micronaut.http.HttpRequest request) { - MicronautHttpOutbound wrapper = new MicronautHttpOutbound(request); - NewRelic.getAgent().getTracedMethod().addOutboundRequestHeaders(wrapper); + MicronautHeaders wrapper = new MicronautHeaders(request); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(wrapper); Flowable>> result = Weaver.callOriginal(); HttpParameters params = HttpParameters.library("Micronaut") diff --git a/instrumentation/micronaut-http-client-3.0.4/build.gradle b/instrumentation/micronaut-http-client-3.0.4/build.gradle index 9e6ab8cd89..56a6697a3b 100644 --- a/instrumentation/micronaut-http-client-3.0.4/build.gradle +++ b/instrumentation/micronaut-http-client-3.0.4/build.gradle @@ -13,7 +13,7 @@ jar { verifyInstrumentation { - passes('io.micronaut:micronaut-http-client:[3.1.0,)') { + passesOnly('io.micronaut:micronaut-http-client:[3.1.0,3.5.0)') { implementation("io.projectreactor:reactor-core:3.4.8") } excludeRegex 'io.micronaut:micronaut-http-client:.*(RC|M)[0-9]*$' diff --git a/instrumentation/micronaut-http-client-3.0.4/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/MicronautHttpInbound.java b/instrumentation/micronaut-http-client-3.0.4/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/MicronautHttpInbound.java deleted file mode 100644 index 15bba70575..0000000000 --- a/instrumentation/micronaut-http-client-3.0.4/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/MicronautHttpInbound.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package com.nr.agent.instrumentation.micronaut.http.client3; - -import com.newrelic.api.agent.HeaderType; -import com.newrelic.api.agent.InboundHeaders; -import io.micronaut.http.HttpResponse; - -public class MicronautHttpInbound implements InboundHeaders { - - private HttpResponse response; - - public MicronautHttpInbound(HttpResponse resp) { - response = resp; - } - - @Override - public HeaderType getHeaderType() { - return HeaderType.HTTP; - } - - @Override - public String getHeader(String name) { - if (response != null) { - return response.header(name); - } - return null; - } - -} \ No newline at end of file diff --git a/instrumentation/micronaut-http-client-3.0.4/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/MicronautHttpOutbound.java b/instrumentation/micronaut-http-client-3.0.4/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/MicronautHttpOutbound.java deleted file mode 100644 index 9392d1f93e..0000000000 --- a/instrumentation/micronaut-http-client-3.0.4/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/MicronautHttpOutbound.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package com.nr.agent.instrumentation.micronaut.http.client3; - -import com.newrelic.api.agent.HeaderType; -import com.newrelic.api.agent.OutboundHeaders; -import io.micronaut.http.HttpRequest; -import io.micronaut.http.MutableHttpRequest; - -public class MicronautHttpOutbound implements OutboundHeaders { - - private HttpRequest request = null; - - public MicronautHttpOutbound(HttpRequest req) { - request = req; - } - - @Override - public HeaderType getHeaderType() { - return HeaderType.HTTP; - } - - @Override - public void setHeader(String name, String value) { - if (request != null) { - if (request instanceof MutableHttpRequest) { - MutableHttpRequest mutable = (MutableHttpRequest) request; - mutable.header(name, value); - } - } - } - -} diff --git a/instrumentation/micronaut-http-client-3.0.4/src/main/java/io/micronaut/http/client/netty/DefaultHttpClient_Instrumentation.java b/instrumentation/micronaut-http-client-3.0.4/src/main/java/io/micronaut/http/client/netty/DefaultHttpClient_Instrumentation.java index ab78f31ebf..a0adb82f14 100644 --- a/instrumentation/micronaut-http-client-3.0.4/src/main/java/io/micronaut/http/client/netty/DefaultHttpClient_Instrumentation.java +++ b/instrumentation/micronaut-http-client-3.0.4/src/main/java/io/micronaut/http/client/netty/DefaultHttpClient_Instrumentation.java @@ -1,11 +1,10 @@ package io.micronaut.http.client.netty; +import com.newrelic.api.agent.*; +import com.newrelic.api.agent.weaver.NewField; +import io.netty.channel.ChannelHandlerContext; import org.reactivestreams.Publisher; -import com.newrelic.api.agent.HttpParameters; -import com.newrelic.api.agent.NewRelic; -import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.Transaction; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import com.newrelic.api.agent.weaver.MatchType; @@ -60,7 +59,7 @@ public Publisher> dataStream(io.micronaut.http.HttpRequest @Trace public Publisher> exchange(io.micronaut.http.HttpRequest request, Argument bodyType, - Argument errorType) { + Argument errorType) { MicronautHeaders headers = new MicronautHeaders(request); NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); @@ -174,4 +173,37 @@ public Publisher> proxy(io.micronaut.http.HttpRequest return result; } + @Weave(type = MatchType.BaseClass, originalName = "io.micronaut.http.client.netty.DefaultHttpClient$SimpleChannelInboundHandlerInstrumented") + static abstract class SimpleChannelInboundHandlerInstrumented_Instrumentation { + + @NewField + private Token token = null; + + SimpleChannelInboundHandlerInstrumented_Instrumentation() { + token = NewRelic.getAgent().getTransaction().getToken(); + } + + SimpleChannelInboundHandlerInstrumented_Instrumentation(boolean autoRelease) { + token = NewRelic.getAgent().getTransaction().getToken(); + } + + @Trace(async = true) + protected void channelReadInstrumented(ChannelHandlerContext ctx, I msg) { + if(token != null) { + token.linkAndExpire(); + token = null; + } + Weaver.callOriginal(); + } + + @Trace(async = true) + protected void channelRead0(ChannelHandlerContext ctx, I msg) { + if(token != null) { + token.linkAndExpire(); + token = null; + } + Weaver.callOriginal(); + } + } } + diff --git a/instrumentation/micronaut-http-client-3.5.0/build.gradle b/instrumentation/micronaut-http-client-3.5.0/build.gradle new file mode 100644 index 0000000000..5696ef6986 --- /dev/null +++ b/instrumentation/micronaut-http-client-3.5.0/build.gradle @@ -0,0 +1,25 @@ +dependencies { + implementation(project(":agent-bridge")) + implementation("io.micronaut:micronaut-http-client:3.5.0") + implementation("io.projectreactor:reactor-core:3.4.8") +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.micronaut-http-client-3.0.0', + 'Implementation-Title-Alias': 'micronaut-http-client' + } +} + +verifyInstrumentation { + + passesOnly('io.micronaut:micronaut-http-client:[3.5.0,4.0.0)') { + implementation("io.projectreactor:reactor-core:3.4.8") + } + excludeRegex 'io.micronaut:micronaut-http-client:.*(RC|M)[0-9]*$' +} + +site { + title 'Micronaut' + type 'Framework' +} \ No newline at end of file diff --git a/instrumentation/micronaut-http-client-3.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/MicronautHeaders.java b/instrumentation/micronaut-http-client-3.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/MicronautHeaders.java new file mode 100644 index 0000000000..0d369b6c10 --- /dev/null +++ b/instrumentation/micronaut-http-client-3.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/MicronautHeaders.java @@ -0,0 +1,101 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package com.nr.agent.instrumentation.micronaut.http.client3; + +import com.newrelic.api.agent.HeaderType; +import com.newrelic.api.agent.Headers; +import io.micronaut.http.HttpHeaders; +import io.micronaut.http.HttpRequest; +import io.micronaut.http.HttpResponse; +import io.micronaut.http.MutableHttpRequest; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class MicronautHeaders implements Headers { + + private HttpRequest request = null; + private HttpResponse response = null; + + public MicronautHeaders(HttpRequest req) { + this(req, null); + } + + public MicronautHeaders(HttpResponse resp) { + this(null, resp); + } + + public MicronautHeaders(HttpRequest req, HttpResponse resp) { + request = req; + response = resp; + } + + @Override + public HeaderType getHeaderType() { + return HeaderType.HTTP; + } + + @Override + public String getHeader(String name) { + if (response != null) { + return response.header(name); + } + return null; + } + + @Override + public Collection getHeaders(String name) { + List list = new ArrayList(); + String value = getHeader(name); + if (value != null && !value.isEmpty()) { + list.add(value); + } + return list; + } + + @Override + public void setHeader(String name, String value) { + if (request != null) { + if (request instanceof MutableHttpRequest) { + MutableHttpRequest mutable = (MutableHttpRequest) request; + mutable.header(name, value); + } + } + } + + @Override + public void addHeader(String name, String value) { + setHeader(name, value); + } + + @Override + public Collection getHeaderNames() { + List headerNames = new ArrayList(); + if (request != null) { + HttpHeaders headers = request.getHeaders(); + if (headers != null) { + headerNames.addAll(headers.names()); + } + } + if (response != null) { + HttpHeaders headers = response.getHeaders(); + if (headers != null) { + headerNames.addAll(headers.names()); + } + } + return headerNames; + } + + @Override + public boolean containsHeader(String name) { + Collection names = getHeaderNames(); + return names.contains(name); + } + +} \ No newline at end of file diff --git a/instrumentation/micronaut-http-client-3.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/ReactorListener.java b/instrumentation/micronaut-http-client-3.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/ReactorListener.java new file mode 100644 index 0000000000..216489c857 --- /dev/null +++ b/instrumentation/micronaut-http-client-3.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/ReactorListener.java @@ -0,0 +1,47 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package com.nr.agent.instrumentation.micronaut.http.client3; + +import java.util.function.Consumer; + +import org.reactivestreams.Subscription; + +import com.newrelic.api.agent.HttpParameters; +import com.newrelic.api.agent.Segment; +import com.newrelic.api.agent.Transaction; + +public class ReactorListener implements Runnable, Consumer { + + private Segment segment = null; + private Transaction txn = null; + private HttpParameters params = null; + + public ReactorListener(Transaction t, HttpParameters p) { + txn = t; + params = p; + } + + @Override + public void run() { + if (segment != null) { + segment.end(); + } + } + + @Override + public void accept(Subscription t) { + if (txn != null && segment == null) { + if (params != null) { + String proc = params.getProcedure(); + segment = txn.startSegment("MicronautClient/" + proc); + segment.reportAsExternal(params); + } + } + } + +} \ No newline at end of file diff --git a/instrumentation/micronaut-http-client-3.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/ResponseConsumer.java b/instrumentation/micronaut-http-client-3.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/ResponseConsumer.java new file mode 100644 index 0000000000..b4f31b539a --- /dev/null +++ b/instrumentation/micronaut-http-client-3.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/ResponseConsumer.java @@ -0,0 +1,33 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package com.nr.agent.instrumentation.micronaut.http.client3; + +import java.util.function.Consumer; + +import com.newrelic.api.agent.Transaction; +import com.newrelic.api.agent.TransportType; + +import io.micronaut.http.HttpResponse; + +public class ResponseConsumer implements Consumer> { + + private Transaction txn = null; + + public ResponseConsumer(Transaction t) { + txn = t; + } + + @Override + public void accept(HttpResponse response) { + if (txn != null && response != null) { + MicronautHeaders headers = new MicronautHeaders(response); + txn.acceptDistributedTraceHeaders(TransportType.HTTP, headers); + } + } + +} diff --git a/instrumentation/micronaut-http-client-3.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/Utils.java b/instrumentation/micronaut-http-client-3.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/Utils.java new file mode 100644 index 0000000000..10a99944b9 --- /dev/null +++ b/instrumentation/micronaut-http-client-3.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/http/client3/Utils.java @@ -0,0 +1,54 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package com.nr.agent.instrumentation.micronaut.http.client3; + +import com.newrelic.api.agent.NewRelic; +import io.micronaut.http.HttpRequest; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.logging.Level; + +public class Utils { + + public static boolean isFlux(Publisher pub) { + return (pub instanceof Flux); + } + + public static boolean isMono(Publisher pub) { + return (pub instanceof Mono); + } + + public static URI getRequestURI(HttpRequest request) { + InetSocketAddress serverAddress = request.getServerAddress(); + URI reqURI = request.getUri(); + + String scheme = reqURI != null ? reqURI.getScheme() : "http"; + String host = serverAddress.getHostName(); + int port = serverAddress.getPort(); + String path = request.getPath(); + + URI uri = null; + + try { + uri = new URI(scheme, null, host, port, path, null, null); + } catch (URISyntaxException e) { + NewRelic.getAgent().getLogger().log(Level.FINEST, e, "Error getting URI"); + } + + if (uri == null) { + uri = URI.create(scheme + "://UnknownHost"); + } + + return uri; + } +} diff --git a/instrumentation/micronaut-http-client-3.5.0/src/main/java/io/micronaut/http/client/netty/DefaultHttpClient_Instrumentation.java b/instrumentation/micronaut-http-client-3.5.0/src/main/java/io/micronaut/http/client/netty/DefaultHttpClient_Instrumentation.java new file mode 100644 index 0000000000..ab78f31ebf --- /dev/null +++ b/instrumentation/micronaut-http-client-3.5.0/src/main/java/io/micronaut/http/client/netty/DefaultHttpClient_Instrumentation.java @@ -0,0 +1,177 @@ +package io.micronaut.http.client.netty; + +import org.reactivestreams.Publisher; + +import com.newrelic.api.agent.HttpParameters; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.Transaction; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import com.newrelic.api.agent.weaver.MatchType; +import com.nr.agent.instrumentation.micronaut.http.client3.MicronautHeaders; +import com.nr.agent.instrumentation.micronaut.http.client3.ReactorListener; +import com.nr.agent.instrumentation.micronaut.http.client3.ResponseConsumer; +import com.nr.agent.instrumentation.micronaut.http.client3.Utils; + +import io.micronaut.core.io.buffer.ByteBuffer; +import io.micronaut.core.type.Argument; +import io.micronaut.http.MutableHttpResponse; +import io.micronaut.http.sse.Event; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Weave(originalName = "io.micronaut.http.client.netty.DefaultHttpClient", type = MatchType.ExactClass) +public abstract class DefaultHttpClient_Instrumentation { + + @Trace(dispatcher = true) + private Publisher>> eventStreamOrError(io.micronaut.http.HttpRequest request, Argument errorType) { + MicronautHeaders headers = new MicronautHeaders(request); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); + return Weaver.callOriginal(); + } + + @Trace + public Publisher> dataStream(io.micronaut.http.HttpRequest request) { + MicronautHeaders headers = new MicronautHeaders(request); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); + Publisher> result = Weaver.callOriginal(); + boolean isFlux = Utils.isFlux(result); + boolean isMono = Utils.isMono(result); + if (isFlux || isMono) { + HttpParameters params = HttpParameters.library("Micronaut") + .uri(Utils.getRequestURI(request)) + .procedure(request.getMethodName()) + .noInboundHeaders() + .build(); + Transaction txn = NewRelic.getAgent().getTransaction(); + ReactorListener listener = new ReactorListener(txn, params); + if (result instanceof Mono) { + Mono> mono = (Mono>) result; + result = mono.doOnSubscribe(listener).doOnCancel(listener).doOnTerminate(listener); + } else if (result instanceof Flux) { + Flux> flux = (Flux>) result; + result = flux.doOnSubscribe(listener).doOnCancel(listener).doOnTerminate(listener); + } + + } + return result; + } + + @Trace + public Publisher> exchange(io.micronaut.http.HttpRequest request, Argument bodyType, + Argument errorType) { + MicronautHeaders headers = new MicronautHeaders(request); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); + + Publisher> result = Weaver.callOriginal(); + boolean isFlux = Utils.isFlux(result); + boolean isMono = Utils.isMono(result); + if (isFlux || isMono) { + HttpParameters params = HttpParameters.library("Micronaut") + .uri(Utils.getRequestURI(request)) + .procedure(request.getMethodName()) + .noInboundHeaders() + .build(); + Transaction txn = NewRelic.getAgent().getTransaction(); + ReactorListener listener = new ReactorListener(txn, params); + ResponseConsumer respConsumer = new ResponseConsumer(txn); + if (result instanceof Mono) { + Mono> mono = (Mono>) result; + result = mono.doOnSubscribe(listener).doOnCancel(listener).doOnSuccess(respConsumer).doOnTerminate(listener); + } else if (result instanceof Flux) { + Flux> flux = (Flux>) result; + result = flux.doOnSubscribe(listener).doOnCancel(listener).doOnNext(respConsumer).doOnTerminate(listener); + } + + } + return result; + } + + @Trace + public Publisher>> exchangeStream(io.micronaut.http.HttpRequest request) { + MicronautHeaders headers = new MicronautHeaders(request); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); + + Publisher>> result = Weaver.callOriginal(); + boolean isFlux = Utils.isFlux(result); + boolean isMono = Utils.isMono(result); + if (isFlux || isMono) { + HttpParameters params = HttpParameters.library("Micronaut") + .uri(Utils.getRequestURI(request)) + .procedure(request.getMethodName()) + .noInboundHeaders() + .build(); + Transaction txn = NewRelic.getAgent().getTransaction(); + ReactorListener listener = new ReactorListener(txn, params); + ResponseConsumer respConsumer = new ResponseConsumer(txn); + if (result instanceof Mono) { + Mono>> mono = (Mono>>) result; + result = mono.doOnSubscribe(listener).doOnCancel(listener).doOnSuccess(respConsumer).doOnTerminate(listener); + } else if (result instanceof Flux) { + Flux>> flux = (Flux>>) result; + result = flux.doOnSubscribe(listener).doOnCancel(listener).doOnNext(respConsumer).doOnTerminate(listener); + } + + } + return result; + } + + @Trace(dispatcher = true) + public Publisher jsonStream(io.micronaut.http.HttpRequest request, Argument type, Argument errorType) { + MicronautHeaders headers = new MicronautHeaders(request); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); + Publisher result = Weaver.callOriginal(); + boolean isFlux = Utils.isFlux(result); + boolean isMono = Utils.isMono(result); + if (isFlux || isMono) { + HttpParameters params = HttpParameters.library("Micronaut") + .uri(Utils.getRequestURI(request)) + .procedure(request.getMethodName()) + .noInboundHeaders() + .build(); + Transaction txn = NewRelic.getAgent().getTransaction(); + ReactorListener listener = new ReactorListener(txn, params); + + if (isMono) { + Mono mono = (Mono) result; + result = mono.doOnSubscribe(listener).doOnTerminate(listener); + } else if (isFlux) { + Flux flux = (Flux) result; + result = flux.doOnSubscribe(listener).doOnTerminate(listener); + } + } + + return result; + } + + @Trace(dispatcher = true) + public Publisher> proxy(io.micronaut.http.HttpRequest request) { + MicronautHeaders headers = new MicronautHeaders(request); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); + + Publisher> result = Weaver.callOriginal(); + boolean isFlux = Utils.isFlux(result); + boolean isMono = Utils.isMono(result); + if (isFlux || isMono) { + HttpParameters params = HttpParameters.library("Micronaut") + .uri(Utils.getRequestURI(request)) + .procedure(request.getMethodName()) + .noInboundHeaders() + .build(); + Transaction txn = NewRelic.getAgent().getTransaction(); + ReactorListener listener = new ReactorListener(txn, params); + ResponseConsumer respConsumer = new ResponseConsumer(txn); + if (result instanceof Mono) { + Mono> mono = (Mono>) result; + result = mono.doOnSubscribe(listener).doOnCancel(listener).doOnSuccess(respConsumer).doOnTerminate(listener); + } else if (result instanceof Flux) { + Flux> flux = (Flux>) result; + result = flux.doOnSubscribe(listener).doOnCancel(listener).doOnNext(respConsumer).doOnTerminate(listener); + } + + } + return result; + } + +} diff --git a/instrumentation/micronaut-http-client-3.5.0/src/main/java/io/micronaut/http/client/netty/SimpleChannelInboundHandlerInstrumented_Instrumentation.java b/instrumentation/micronaut-http-client-3.5.0/src/main/java/io/micronaut/http/client/netty/SimpleChannelInboundHandlerInstrumented_Instrumentation.java new file mode 100644 index 0000000000..cc01644a3a --- /dev/null +++ b/instrumentation/micronaut-http-client-3.5.0/src/main/java/io/micronaut/http/client/netty/SimpleChannelInboundHandlerInstrumented_Instrumentation.java @@ -0,0 +1,45 @@ +package io.micronaut.http.client.netty; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.NewField; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import io.micronaut.scheduling.instrument.InvocationInstrumenter; +import io.netty.channel.ChannelHandlerContext; + +@Weave(type = MatchType.BaseClass, originalName = "io.micronaut.http.client.netty.SimpleChannelInboundHandlerInstrumented") +abstract class SimpleChannelInboundHandlerInstrumented_Instrumentation { + + @NewField + private Token token = null; + + SimpleChannelInboundHandlerInstrumented_Instrumentation(InvocationInstrumenter instrumenter) { + token = NewRelic.getAgent().getTransaction().getToken(); + } + + SimpleChannelInboundHandlerInstrumented_Instrumentation(InvocationInstrumenter instrumenter, boolean autoRelease) { + token = NewRelic.getAgent().getTransaction().getToken(); + } + + @Trace(async = true) + protected void channelReadInstrumented(ChannelHandlerContext ctx, I msg) { + if(token != null) { + token.linkAndExpire(); + token = null; + } + Weaver.callOriginal(); + } + + @Trace(async = true) + protected void channelRead0(ChannelHandlerContext ctx, I msg) { + if(token != null) { + token.linkAndExpire(); + token = null; + } + Weaver.callOriginal(); + } +} + diff --git a/instrumentation/micronaut-http-client-4.0.0/build.gradle b/instrumentation/micronaut-http-client-4.0.0/build.gradle new file mode 100644 index 0000000000..8fe548ae49 --- /dev/null +++ b/instrumentation/micronaut-http-client-4.0.0/build.gradle @@ -0,0 +1,30 @@ +dependencies { + implementation(project(":agent-bridge")) + implementation("io.micronaut:micronaut-http-client:4.0.0") + implementation("io.projectreactor:reactor-core:3.4.8") +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.micronaut-http-client-4.0.0', + 'Implementation-Title-Alias': 'micronaut-http-client' + } +} + +verifyInstrumentation { + + passesOnly 'io.micronaut:micronaut-http-client:[4.0.0,)' + excludeRegex '.*RC[0-9]' + excludeRegex '.*M[0-9]' +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +site { + title 'Micronaut' + type 'Framework' +} \ No newline at end of file diff --git a/instrumentation/micronaut-http-client-4.0.0/src/main/java/com/newrelic/instrumentation/micronaut/http/client4/MicronautHeaders.java b/instrumentation/micronaut-http-client-4.0.0/src/main/java/com/newrelic/instrumentation/micronaut/http/client4/MicronautHeaders.java new file mode 100644 index 0000000000..0ff810d83d --- /dev/null +++ b/instrumentation/micronaut-http-client-4.0.0/src/main/java/com/newrelic/instrumentation/micronaut/http/client4/MicronautHeaders.java @@ -0,0 +1,96 @@ +package com.newrelic.instrumentation.micronaut.http.client4; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import com.newrelic.api.agent.HeaderType; +import com.newrelic.api.agent.Headers; + +import io.micronaut.http.HttpHeaders; +import io.micronaut.http.HttpRequest; +import io.micronaut.http.HttpResponse; +import io.micronaut.http.MutableHttpRequest; + +public class MicronautHeaders implements Headers { + + private HttpRequest request = null; + private HttpResponse response = null; + + public MicronautHeaders(HttpRequest req) { + this(req,null); + } + + public MicronautHeaders(HttpResponse resp) { + this(null,resp); + } + + public MicronautHeaders(HttpRequest req,HttpResponse resp) { + request = req; + response = resp; + } + + + @Override + public HeaderType getHeaderType() { + return HeaderType.HTTP; + } + + @Override + public String getHeader(String name) { + if(response != null) { + return response.header(name); + } + return null; + } + + @Override + public Collection getHeaders(String name) { + List list = new ArrayList(); + String value = getHeader(name); + if(value != null && !value.isEmpty()) { + list.add(value); + } + return list; + } + + @Override + public void setHeader(String name, String value) { + if(request != null) { + if(request instanceof MutableHttpRequest) { + MutableHttpRequest mutable = (MutableHttpRequest)request; + mutable.header(name, value); + } + } + } + + @Override + public void addHeader(String name, String value) { + setHeader(name, value); + } + + @Override + public Collection getHeaderNames() { + List headerNames = new ArrayList(); + if(request != null) { + HttpHeaders headers = request.getHeaders(); + if(headers != null) { + headerNames.addAll(headers.names()); + } + } + if(response != null) { + HttpHeaders headers = response.getHeaders(); + if(headers != null) { + headerNames.addAll(headers.names()); + } + } + return headerNames; + } + + @Override + public boolean containsHeader(String name) { + Collection names = getHeaderNames(); + return names.contains(name); + } + +} diff --git a/instrumentation/micronaut-http-client-4.0.0/src/main/java/com/newrelic/instrumentation/micronaut/http/client4/ReactorListener.java b/instrumentation/micronaut-http-client-4.0.0/src/main/java/com/newrelic/instrumentation/micronaut/http/client4/ReactorListener.java new file mode 100644 index 0000000000..8429d31a3d --- /dev/null +++ b/instrumentation/micronaut-http-client-4.0.0/src/main/java/com/newrelic/instrumentation/micronaut/http/client4/ReactorListener.java @@ -0,0 +1,50 @@ +package com.newrelic.instrumentation.micronaut.http.client4; + +import java.util.function.Consumer; +import java.util.logging.Level; + +import org.reactivestreams.Subscription; + +import com.newrelic.api.agent.HttpParameters; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Segment; +import com.newrelic.api.agent.Transaction; + +public class ReactorListener implements Runnable, Consumer { + + private Segment segment = null; + private Transaction txn = null; + private HttpParameters params = null; + + public ReactorListener(Transaction t, HttpParameters p) { + txn = t; + params = p; + } + + @Override + public void run() { + try { + if(segment != null) { + segment.end(); + segment = null; + } + } catch (Exception e) { + NewRelic.getAgent().getLogger().log(Level.FINEST, e, "An error occurred while trying to end segment in {0}",getClass().getName()); + } + } + + + + @Override + public void accept(Subscription t) { + if(txn != null && segment == null) { + if(params != null) { + String proc = params.getProcedure(); + segment = txn.startSegment("MicronautClient/"+proc); + segment.reportAsExternal(params); + } + } + } + + +} diff --git a/instrumentation/micronaut-http-client-4.0.0/src/main/java/com/newrelic/instrumentation/micronaut/http/client4/ResponseConsumer.java b/instrumentation/micronaut-http-client-4.0.0/src/main/java/com/newrelic/instrumentation/micronaut/http/client4/ResponseConsumer.java new file mode 100644 index 0000000000..73710aae1c --- /dev/null +++ b/instrumentation/micronaut-http-client-4.0.0/src/main/java/com/newrelic/instrumentation/micronaut/http/client4/ResponseConsumer.java @@ -0,0 +1,26 @@ +package com.newrelic.instrumentation.micronaut.http.client4; + +import java.util.function.Consumer; + +import com.newrelic.api.agent.Transaction; +import com.newrelic.api.agent.TransportType; + +import io.micronaut.http.HttpResponse; + +public class ResponseConsumer implements Consumer> { + + private Transaction txn = null; + + public ResponseConsumer(Transaction t) { + txn = t; + } + + @Override + public void accept(HttpResponse response) { + if(txn != null && response != null) { + MicronautHeaders headers = new MicronautHeaders(response); + txn.acceptDistributedTraceHeaders(TransportType.HTTP, headers); + } + } + +} diff --git a/instrumentation/micronaut-http-client-4.0.0/src/main/java/com/newrelic/instrumentation/micronaut/http/client4/Utils.java b/instrumentation/micronaut-http-client-4.0.0/src/main/java/com/newrelic/instrumentation/micronaut/http/client4/Utils.java new file mode 100644 index 0000000000..c1a2a969be --- /dev/null +++ b/instrumentation/micronaut-http-client-4.0.0/src/main/java/com/newrelic/instrumentation/micronaut/http/client4/Utils.java @@ -0,0 +1,52 @@ +package com.newrelic.instrumentation.micronaut.http.client4; + +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.logging.Level; + +import io.micronaut.http.uri.UriBuilder; +import org.reactivestreams.Publisher; + +import com.newrelic.api.agent.NewRelic; + +import io.micronaut.http.HttpRequest; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public class Utils { + + + public static boolean isFlux(Publisher pub) { + return (pub instanceof Flux); + } + + public static boolean isMono(Publisher pub) { + return (pub instanceof Mono); + } + + public static URI getRequestURI(HttpRequest request) { + + InetSocketAddress serverAddress = request.getServerAddress(); + URI reqURI = request.getUri(); + + String schema = reqURI != null ? reqURI.getScheme() : null; + if(schema == null) schema = "http"; + String host = serverAddress.getHostName(); + int port = serverAddress.getPort(); + String path = "/"; //request.getPath(); + + URI uri = null; + + try { + uri = new URI(schema, null, host, port, path, null, null ); + } catch (URISyntaxException e) { + NewRelic.getAgent().getLogger().log(Level.FINEST, e, "Error getting URI"); + } + + if(uri == null) uri = URI.create(schema+"://UnknownHost"); + + + return uri; + } +} diff --git a/instrumentation/micronaut-http-client-4.0.0/src/main/java/io/micronaut/http/client/netty/DefaultHttpClient_Instrumentation.java b/instrumentation/micronaut-http-client-4.0.0/src/main/java/io/micronaut/http/client/netty/DefaultHttpClient_Instrumentation.java new file mode 100644 index 0000000000..fd652c4041 --- /dev/null +++ b/instrumentation/micronaut-http-client-4.0.0/src/main/java/io/micronaut/http/client/netty/DefaultHttpClient_Instrumentation.java @@ -0,0 +1,160 @@ +package io.micronaut.http.client.netty; + +import io.micronaut.http.uri.UriTemplate; +import org.reactivestreams.Publisher; + +import com.newrelic.api.agent.HttpParameters; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.Transaction; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import com.newrelic.instrumentation.micronaut.http.client4.MicronautHeaders; +import com.newrelic.instrumentation.micronaut.http.client4.ReactorListener; +import com.newrelic.instrumentation.micronaut.http.client4.ResponseConsumer; +import com.newrelic.instrumentation.micronaut.http.client4.Utils; + +import io.micronaut.core.io.buffer.ByteBuffer; +import io.micronaut.core.type.Argument; +import io.micronaut.http.MutableHttpResponse; +import io.micronaut.http.sse.Event; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.logging.Level; + +@Weave(originalName = "io.micronaut.http.client.netty.DefaultHttpClient") +public abstract class DefaultHttpClient_Instrumentation { + + @Trace(dispatcher = true) + private Publisher>> eventStreamOrError(io.micronaut.http.HttpRequest request, Argument errorType) { + MicronautHeaders headers = new MicronautHeaders(request); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); + return Weaver.callOriginal(); + } + + @Trace + public Publisher> dataStream(io.micronaut.http.HttpRequest request) { + MicronautHeaders headers = new MicronautHeaders(request); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); + Publisher> result = Weaver.callOriginal(); + boolean isFlux = Utils.isFlux(result); + boolean isMono = Utils.isMono(result); + if(isFlux || isMono) { + HttpParameters params = HttpParameters.library("Micronaut").uri(Utils.getRequestURI(request)).procedure(request.getMethodName()).noInboundHeaders().build(); + Transaction txn = NewRelic.getAgent().getTransaction(); + ReactorListener listener = new ReactorListener(txn, params); + if(result instanceof Mono) { + Mono> mono = (Mono>)result; + result = mono.doOnSubscribe(listener).doOnCancel(listener).doOnTerminate(listener); + } else if(result instanceof Flux) { + Flux> flux = (Flux>)result; + result = flux.doOnSubscribe(listener).doOnCancel(listener).doOnTerminate(listener); + } + + } + return result; + } + + @Trace + public Publisher> exchange(io.micronaut.http.HttpRequest request, Argument bodyType, Argument errorType) { + MicronautHeaders headers = new MicronautHeaders(request); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); + UriTemplate template = UriTemplate.of(request.getUri().toString()); + NewRelic.getAgent().getLogger().log(Level.FINE,"Found Client URITemplate {0}" , template.toString()); + + Publisher> result = Weaver.callOriginal(); + boolean isFlux = Utils.isFlux(result); + boolean isMono = Utils.isMono(result); + if(isFlux || isMono) { + HttpParameters params = HttpParameters.library("Micronaut").uri(Utils.getRequestURI(request)).procedure(request.getMethodName()).noInboundHeaders().build(); + Transaction txn = NewRelic.getAgent().getTransaction(); + ReactorListener listener = new ReactorListener(txn, params); + ResponseConsumer respConsumer = new ResponseConsumer(txn); + if(result instanceof Mono) { + Mono> mono = (Mono>)result; + result = mono.doOnSubscribe(listener).doOnCancel(listener).doOnSuccess(respConsumer).doOnTerminate(listener); + } else if(result instanceof Flux) { + Flux> flux = (Flux>)result; + result = flux.doOnSubscribe(listener).doOnCancel(listener).doOnNext(respConsumer).doOnTerminate(listener); + } + + } + return result; + } + + @Trace + public Publisher>> exchangeStream(io.micronaut.http.HttpRequest request) { + MicronautHeaders headers = new MicronautHeaders(request); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); + + Publisher>> result = Weaver.callOriginal(); + boolean isFlux = Utils.isFlux(result); + boolean isMono = Utils.isMono(result); + if(isFlux || isMono) { + HttpParameters params = HttpParameters.library("Micronaut").uri(Utils.getRequestURI(request)).procedure(request.getMethodName()).noInboundHeaders().build(); + Transaction txn = NewRelic.getAgent().getTransaction(); + ReactorListener listener = new ReactorListener(txn, params); + ResponseConsumer respConsumer = new ResponseConsumer(txn); + if(result instanceof Mono) { + Mono>> mono = (Mono>>)result; + result = mono.doOnSubscribe(listener).doOnCancel(listener).doOnSuccess(respConsumer).doOnTerminate(listener); + } else if(result instanceof Flux) { + Flux>> flux = (Flux>>)result; + result = flux.doOnSubscribe(listener).doOnCancel(listener).doOnNext(respConsumer).doOnTerminate(listener); + } + + } + return result; + } + + @Trace(dispatcher = true) + public Publisher jsonStream(io.micronaut.http.HttpRequest request, Argument type, Argument errorType) { + MicronautHeaders headers = new MicronautHeaders(request); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); + Publisher result = Weaver.callOriginal(); + boolean isFlux = Utils.isFlux(result); + boolean isMono = Utils.isMono(result); + if(isFlux || isMono) { + HttpParameters params = HttpParameters.library("Micronaut").uri(Utils.getRequestURI(request)).procedure(request.getMethodName()).noInboundHeaders().build(); + Transaction txn = NewRelic.getAgent().getTransaction(); + ReactorListener listener = new ReactorListener(txn, params); + + if(isMono) { + Mono mono = (Mono)result; + result = mono.doOnSubscribe(listener).doOnTerminate(listener); + } else if(isFlux) { + Flux flux = (Flux)result; + result = flux.doOnSubscribe(listener).doOnTerminate(listener); + } + } + + return result; + } + + @Trace(dispatcher = true) + public Publisher> proxy(io.micronaut.http.HttpRequest request) { + MicronautHeaders headers = new MicronautHeaders(request); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); + + Publisher> result = Weaver.callOriginal(); + boolean isFlux = Utils.isFlux(result); + boolean isMono = Utils.isMono(result); + if(isFlux || isMono) { + HttpParameters params = HttpParameters.library("Micronaut").uri(Utils.getRequestURI(request)).procedure(request.getMethodName()).noInboundHeaders().build(); + Transaction txn = NewRelic.getAgent().getTransaction(); + ReactorListener listener = new ReactorListener(txn, params); + ResponseConsumer respConsumer = new ResponseConsumer(txn); + if(result instanceof Mono) { + Mono> mono = (Mono>)result; + result = mono.doOnSubscribe(listener).doOnCancel(listener).doOnSuccess(respConsumer).doOnTerminate(listener); + } else if(result instanceof Flux) { + Flux> flux = (Flux>)result; + result = flux.doOnSubscribe(listener).doOnCancel(listener).doOnNext(respConsumer).doOnTerminate(listener); + } + + } + return result; + } + +} diff --git a/instrumentation/micronaut-http-client-4.0.0/src/main/java/io/micronaut/http/client/netty/SimpleChannelInboundHandlerInstrumented_Instrumentation.java b/instrumentation/micronaut-http-client-4.0.0/src/main/java/io/micronaut/http/client/netty/SimpleChannelInboundHandlerInstrumented_Instrumentation.java new file mode 100644 index 0000000000..2eb9fb6c2f --- /dev/null +++ b/instrumentation/micronaut-http-client-4.0.0/src/main/java/io/micronaut/http/client/netty/SimpleChannelInboundHandlerInstrumented_Instrumentation.java @@ -0,0 +1,45 @@ +package io.micronaut.http.client.netty; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.NewField; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import io.netty.channel.ChannelHandlerContext; + +@Weave(type = MatchType.BaseClass, originalName = "io.micronaut.http.client.netty.SimpleChannelInboundHandlerInstrumented") +abstract class SimpleChannelInboundHandlerInstrumented_Instrumentation { + + @NewField + private Token token = null; + + SimpleChannelInboundHandlerInstrumented_Instrumentation() { + token = NewRelic.getAgent().getTransaction().getToken(); + } + + SimpleChannelInboundHandlerInstrumented_Instrumentation(boolean autoRelease) { + token = NewRelic.getAgent().getTransaction().getToken(); + } + + @Trace(async = true) + protected void channelReadInstrumented(ChannelHandlerContext ctx, I msg) { + if(token != null) { + token.linkAndExpire(); + token = null; + } + Weaver.callOriginal(); + } + + @Trace(async = true) + protected void channelRead0(ChannelHandlerContext ctx, I msg) { + if(token != null) { + token.linkAndExpire(); + token = null; + } + Weaver.callOriginal(); + } +} + diff --git a/instrumentation/micronaut-http-server-netty-2.0.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-2.0.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java index 050e679896..a0fec927e6 100644 --- a/instrumentation/micronaut-http-server-netty-2.0.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-2.0.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java @@ -7,19 +7,16 @@ package io.micronaut.http.server.netty; -import java.net.URI; import java.util.List; import java.util.logging.Level; import com.newrelic.api.agent.NewRelic; -import com.newrelic.api.agent.TransactionNamePriority; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import com.nr.agent.instrumentation.micronaut.netty_2.Utils; import io.micronaut.http.HttpHeaders; -import io.micronaut.http.HttpMethod; import io.micronaut.http.annotation.Trace; import io.micronaut.web.router.RouteMatch; import io.netty.channel.ChannelHandlerContext; @@ -29,29 +26,13 @@ abstract class RoutingInBoundHandler_Instrumentation { @Trace protected void channelRead0(ChannelHandlerContext ctx, io.micronaut.http.HttpRequest request) { - if(request != null) { - StringBuffer sb = new StringBuffer(); - HttpMethod method = request.getMethod(); - if(method != null) { - sb.append(method.name()); - } else { - sb.append("UnknownMethod"); - } - sb.append(" - "); - URI uri = request.getUri(); - if(uri != null) { - sb.append(uri.toASCIIString()); - } else { - sb.append("UnknownURI"); - } - NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW, false, "Micronaut-Netty", sb.toString()); - } Weaver.callOriginal(); } @SuppressWarnings("unused") private void handleRouteMatch(RouteMatch route, NettyHttpRequest request, ChannelHandlerContext context, boolean skipOncePerRequest) { Utils.decorateWithRoute(route); + HttpHeaders headers = request.getHeaders(); if (headers != null) { for (String key : headers.names()) { diff --git a/instrumentation/micronaut-http-server-netty-3.0.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-3.0.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java index d0c3d117b7..3fde699f16 100644 --- a/instrumentation/micronaut-http-server-netty-3.0.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-3.0.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java @@ -7,16 +7,11 @@ package io.micronaut.http.server.netty; -import java.net.URI; - -import com.newrelic.api.agent.NewRelic; import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.TransactionNamePriority; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import io.micronaut.http.HttpMethod; import io.netty.channel.ChannelHandlerContext; @Weave(originalName = "io.micronaut.http.server.netty.RoutingInBoundHandler", type = MatchType.ExactClass) @@ -24,23 +19,6 @@ abstract class RoutingInBoundHandler_Instrumentation { @Trace(dispatcher = true) protected void channelRead0(ChannelHandlerContext ctx, io.micronaut.http.HttpRequest request) { - if(request != null) { - StringBuffer sb = new StringBuffer(); - HttpMethod method = request.getMethod(); - if(method != null) { - sb.append(method.name()); - } else { - sb.append("UnknownMethod"); - } - sb.append(" - "); - URI uri = request.getUri(); - if(uri != null) { - sb.append(uri.toASCIIString()); - } else { - sb.append("UnknownURI"); - } - NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW, false, "Micronaut-Netty", sb.toString()); - } Weaver.callOriginal(); } diff --git a/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_4/NettyExtendedRequest.java b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_4/NettyExtendedRequest.java new file mode 100644 index 0000000000..298f0af84e --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_4/NettyExtendedRequest.java @@ -0,0 +1,66 @@ +package com.nr.agent.instrumentation.micronaut.netty_4; + +import com.newrelic.api.agent.ExtendedRequest; +import com.newrelic.api.agent.HeaderType; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; + +import java.util.Enumeration; + +public class NettyExtendedRequest extends ExtendedRequest { + + private final HttpRequest request; + + public NettyExtendedRequest(HttpRequest request) { + this.request = request; + } + + @Override + public String getMethod() { + return request.method().name(); + } + + @Override + public String getRequestURI() { + return request.uri(); + } + + @Override + public String getRemoteUser() { + return ""; + } + + @Override + public Enumeration getParameterNames() { + return null; + } + + @Override + public String[] getParameterValues(String name) { + return null; + } + + @Override + public Object getAttribute(String name) { + return null; + } + + @Override + public String getCookieValue(String name) { + return ""; + } + + @Override + public HeaderType getHeaderType() { + return HeaderType.HTTP; + } + + @Override + public String getHeader(String name) { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.get(name); + } + return null; + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_4/NettyHeaders.java b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_4/NettyHeaders.java new file mode 100644 index 0000000000..1f422eb09e --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_4/NettyHeaders.java @@ -0,0 +1,67 @@ +package com.nr.agent.instrumentation.micronaut.netty_4; + +import com.newrelic.api.agent.HeaderType; +import com.newrelic.api.agent.Headers; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +public class NettyHeaders implements Headers { + + private final HttpRequest request; + + public NettyHeaders(HttpRequest request) { + this.request = request; + } + + @Override + public HeaderType getHeaderType() { + return HeaderType.HTTP; + } + + @Override + public String getHeader(String name) { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.get(name); + } + return null; + } + + @Override + public Collection getHeaders(String name) { + Set selectedHeaders = new HashSet<>(); + String header = getHeader(name); + if(header != null) { + selectedHeaders.add(header); + } + return selectedHeaders; + } + + @Override + public void setHeader(String name, String value) { + + } + + @Override + public void addHeader(String name, String value) { + + } + + @Override + public Collection getHeaderNames() { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.names(); + } + return new HashSet<>(); + } + + @Override + public boolean containsHeader(String name) { + return getHeaderNames().contains(name); + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_4/Utils.java b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_4/Utils.java deleted file mode 100644 index fb22aa2845..0000000000 --- a/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_4/Utils.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package com.nr.agent.instrumentation.micronaut.netty_4; - -import io.micronaut.web.router.RouteMatch; - -import java.util.Map; - -public class Utils { - - public static void decorateWithRoute(RouteMatch routeMatch) { - } - - public static void addAttribute(Map attributes, String key, Object value) { - if (attributes != null && key != null && !key.isEmpty() && value != null) { - attributes.put(key, value); - } - } -} diff --git a/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/NettyHttpRequest_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/NettyHttpRequest_Instrumentation.java new file mode 100644 index 0000000000..b1e297bc85 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/NettyHttpRequest_Instrumentation.java @@ -0,0 +1,13 @@ +package io.micronaut.http; + +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import io.netty.channel.ChannelHandlerContext_Instrumentation; + +@Weave(originalName = "io.micronaut.http.server.netty.NettyHttpRequest") +public class NettyHttpRequest_Instrumentation { + + public ChannelHandlerContext_Instrumentation getChannelHandlerContext() { + return Weaver.callOriginal(); + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java index f27b498c55..f734e3455a 100644 --- a/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java @@ -9,38 +9,38 @@ import com.newrelic.api.agent.NewRelic; import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.TransactionNamePriority; +import com.newrelic.api.agent.Transaction; +import com.newrelic.api.agent.TransportType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; +import com.nr.agent.instrumentation.micronaut.netty_4.NettyExtendedRequest; +import com.nr.agent.instrumentation.micronaut.netty_4.NettyHeaders; import io.micronaut.http.server.netty.handler.PipeliningServerHandler_Instrumentation; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpMethod; +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPipeline_Instrumentation; @Weave(originalName = "io.micronaut.http.server.netty.RoutingInBoundHandler", type = MatchType.ExactClass) public abstract class RoutingInBoundHandler_Instrumentation { - @Trace(dispatcher = true) - public void accept(ChannelHandlerContext ctx, io.netty.handler.codec.http.HttpRequest request, - PipeliningServerHandler_Instrumentation.OutboundAccess_Instrumentation outboundAccess) { - if(request != null) { - StringBuffer sb = new StringBuffer(); - HttpMethod method = request.method(); - if(method != null) { - sb.append(method.name()); - } else { - sb.append("UnknownMethod"); + @Trace(async = true) + public void accept(ChannelHandlerContext_Instrumentation ctx, io.netty.handler.codec.http.HttpRequest request, + PipeliningServerHandler_Instrumentation.OutboundAccess_Instrumentation outboundAccess) { + if(ctx != null) { + ChannelPipeline_Instrumentation pipeline = ctx.pipeline(); + if(pipeline != null) { + if(pipeline.micronautToken != null) { + pipeline.micronautToken.link(); + } } - sb.append(" - "); - String uri = request.uri(); - if(uri != null) { - sb.append(uri); - } else { - sb.append("UnknownURI"); - } - NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW, false, "Micronaut-Netty", sb.toString()); } + Transaction transaction = NewRelic.getAgent().getTransaction(); + if(!transaction.isWebTransaction()) { + transaction.convertToWebTransaction(); + } + transaction.setWebRequest(new NettyExtendedRequest(request)); + transaction.acceptDistributedTraceHeaders(TransportType.HTTP, new NettyHeaders(request)); Weaver.callOriginal(); } } diff --git a/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java index e7ad4e0cfe..5dce559b07 100644 --- a/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java @@ -7,27 +7,67 @@ package io.micronaut.http.server.netty.handler; -import com.newrelic.api.agent.NewRelic; -import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.*; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import io.netty.channel.ChannelHandlerContext; +import com.nr.agent.instrumentation.micronaut.netty_4.NettyExtendedRequest; +import com.nr.agent.instrumentation.micronaut.netty_4.NettyHeaders; +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPipeline_Instrumentation; +import io.netty.handler.codec.http.HttpRequest; -@Weave(originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler", type = MatchType.ExactClass) +@Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler") public abstract class PipeliningServerHandler_Instrumentation { - @Trace(dispatcher = true) - public void channelRead(ChannelHandlerContext ctx, Object msg) { + @Trace + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + ChannelPipeline_Instrumentation pipeline = ctx != null ? ctx.pipeline() : null; + if(pipeline != null) { + if(pipeline.micronautToken != null) { + pipeline.micronautToken.link(); + } else { + Token token = NewRelic.getAgent().getTransaction().getToken(); + if(token != null) { + if(token.isActive()) { + pipeline.micronautToken = token; + } else { + token.expire(); + token = null; + } + } + } + } + Weaver.callOriginal(); + } + + public void channelReadComplete(ChannelHandlerContext_Instrumentation ctx) { + ChannelPipeline_Instrumentation pipeline = ctx != null ? ctx.pipeline() : null; + if(pipeline != null) { + if(pipeline.micronautToken != null) { + pipeline.micronautToken.expire(); + pipeline.micronautToken = null; + } + } Weaver.callOriginal(); } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$MessageInboundHandler") private static class MessageInboundHandler_Instrumentation { - @Trace + @Trace(dispatcher = true) void read(Object message) { - NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "HTTP", "Netty", "InboundHander", "MessageInboundHandler", "read"); + NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "HTTP", "Netty", "InboundHandler", "MessageInboundHandler", "read"); + if(message instanceof HttpRequest) { + HttpRequest httpRequest = (HttpRequest) message; + NettyExtendedRequest nettyExtendedRequest = new NettyExtendedRequest(httpRequest); + NettyHeaders nettyHeaders = new NettyHeaders(httpRequest); + Transaction transaction = NewRelic.getAgent().getTransaction(); + transaction.acceptDistributedTraceHeaders(TransportType.HTTP, nettyHeaders); + transaction.setWebRequest(nettyExtendedRequest); + transaction.convertToWebTransaction(); + } + Weaver.callOriginal(); } @@ -47,7 +87,6 @@ void read(Object message) { } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$DroppingInboundHandler") - private static class DroppingInboundHandler_Instrumentation { @Trace @@ -59,7 +98,6 @@ void read(Object message) { } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$StreamingInboundHandler") - private static class StreamingInboundHandler_Instrumentation { @Trace @@ -70,21 +108,7 @@ void read(Object message) { } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$ChunkedOutboundHandler") - - private static class ChunkedOutboundHandler_Instrumentation { - - @Trace - void writeSome() { - NewRelic.getAgent() - .getTracedMethod() - .setMetricName("Micronaut", "HTTP", "Netty", "OutboundHander", "ChunkedOutboundHandler", "writeSome"); - Weaver.callOriginal(); - } - } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$ContinueOutboundHandler") - private static class ContinueOutboundHandler_Instrumentation { @Trace @@ -97,7 +121,6 @@ void writeSome() { } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$FullOutboundHandler") - private static class FullOutboundHandler_Instrumentation { @Trace @@ -108,7 +131,6 @@ void writeSome() { } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$StreamingOutboundHandler") - private static class StreamingOutboundHandler_Instrumentation { @Trace @@ -121,7 +143,6 @@ void writeSome() { } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$OutboundAccess") - public static class OutboundAccess_Instrumentation { } diff --git a/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java index 60978bd0ee..884ae450c2 100644 --- a/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java @@ -1,36 +1,35 @@ package io.micronaut.http.server.netty.handler; import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Token; import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.TransactionNamePriority; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpMethod; +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPipeline_Instrumentation; import io.netty.handler.codec.http.HttpRequest; @Weave(type = MatchType.Interface, originalName = "io.micronaut.http.server.netty.handler.RequestHandler") public abstract class RequestHandler_Instrumentation { @Trace - public void accept(ChannelHandlerContext ctx, HttpRequest request, PipeliningServerHandler.OutboundAccess outboundAccess) { - - if(request != null) { - String uri = request.uri(); - NewRelic.getAgent().getTracedMethod().addCustomAttribute("URI", uri != null ? uri : "null"); - HttpMethod method = request.method(); - String methodName = null; - if(method != null) { - methodName = method.name(); - } - NewRelic.getAgent().getTracedMethod().addCustomAttribute("Method", methodName != null ? methodName : "null"); - if(uri != null && methodName != null) { - NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW, false, "Micronaut-Netty", methodName + " - " + uri); + public void accept(ChannelHandlerContext_Instrumentation ctx, HttpRequest request, PipeliningServerHandler.OutboundAccess outboundAccess) { + if(ctx != null && ctx.pipeline() != null) { + ChannelPipeline_Instrumentation pipeline = ctx.pipeline(); + if(pipeline.micronautToken == null) { + Token token = NewRelic.getAgent().getTransaction().getToken(); + if(token != null) { + if(token.isActive()) { + pipeline.micronautToken = token; + } else { + token.expire(); + token = null; + } + } } } - Weaver.callOriginal(); } diff --git a/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketUpgradeHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketUpgradeHandler_Instrumentation.java deleted file mode 100644 index 38c9ae00ab..0000000000 --- a/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketUpgradeHandler_Instrumentation.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package io.micronaut.http.server.netty.websocket; - -import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.weaver.MatchType; -import com.newrelic.api.agent.weaver.Weave; -import com.newrelic.api.agent.weaver.Weaver; -import io.micronaut.http.server.netty.handler.PipeliningServerHandler_Instrumentation; -import io.netty.channel.ChannelHandlerContext; - -@Weave(originalName = "io.micronaut.http.server.netty.websocket.NettyServerWebSocketUpgradeHandler", type = MatchType.ExactClass) -public abstract class NettyServerWebSocketUpgradeHandler_Instrumentation { - - @Trace(dispatcher = true) - public void accept(ChannelHandlerContext ctx, io.netty.handler.codec.http.HttpRequest request, - PipeliningServerHandler_Instrumentation.OutboundAccess_Instrumentation outboundAccess) { - Weaver.callOriginal(); - } - -} diff --git a/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java new file mode 100644 index 0000000000..8ec28602b2 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java @@ -0,0 +1,10 @@ +package io.netty.channel; + +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; + +@Weave(type = MatchType.Interface, originalName = "io.netty.channel.ChannelHandlerContext") +public abstract class ChannelHandlerContext_Instrumentation { + + public abstract ChannelPipeline_Instrumentation pipeline(); +} diff --git a/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java new file mode 100644 index 0000000000..2127b44623 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java @@ -0,0 +1,31 @@ +package io.netty.channel; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(type = MatchType.Interface, originalName = "io.netty.channel.ChannelInboundHandler") +public abstract class ChannelInboundHandler_Instrumentation { + + @Trace(async = true, excludeFromTransactionTrace = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) throws Exception { + if(ctx.pipeline().micronautToken != null) { + ctx.pipeline().micronautToken.link(); + } else { + Token token = NewRelic.getAgent().getTransaction().getToken(); + if(token != null) { + if(token.isActive()) { + ctx.pipeline().micronautToken = token; + } else { + token.expire(); + token = null; + } + } + } + Weaver.callOriginal(); + } + +} diff --git a/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java new file mode 100644 index 0000000000..99fb24cdea --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.0.0/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java @@ -0,0 +1,14 @@ +package io.netty.channel; + +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.NewField; +import com.newrelic.api.agent.weaver.Weave; + +@Weave(type = MatchType.BaseClass, originalName = "io.netty.channel.ChannelPipeline") +public class ChannelPipeline_Instrumentation { + + @NewField + public Token micronautToken; + +} diff --git a/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_43/NettyExtendedRequest.java b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_43/NettyExtendedRequest.java new file mode 100644 index 0000000000..d5003c8961 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_43/NettyExtendedRequest.java @@ -0,0 +1,66 @@ +package com.nr.agent.instrumentation.micronaut.netty_43; + +import com.newrelic.api.agent.ExtendedRequest; +import com.newrelic.api.agent.HeaderType; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; + +import java.util.Enumeration; + +public class NettyExtendedRequest extends ExtendedRequest { + + private final HttpRequest request; + + public NettyExtendedRequest(HttpRequest request) { + this.request = request; + } + + @Override + public String getMethod() { + return request.method().name(); + } + + @Override + public String getRequestURI() { + return request.uri(); + } + + @Override + public String getRemoteUser() { + return ""; + } + + @Override + public Enumeration getParameterNames() { + return null; + } + + @Override + public String[] getParameterValues(String name) { + return null; + } + + @Override + public Object getAttribute(String name) { + return null; + } + + @Override + public String getCookieValue(String name) { + return ""; + } + + @Override + public HeaderType getHeaderType() { + return HeaderType.HTTP; + } + + @Override + public String getHeader(String name) { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.get(name); + } + return null; + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_43/NettyHeaders.java b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_43/NettyHeaders.java new file mode 100644 index 0000000000..b6dd59efa2 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_43/NettyHeaders.java @@ -0,0 +1,67 @@ +package com.nr.agent.instrumentation.micronaut.netty_43; + +import com.newrelic.api.agent.HeaderType; +import com.newrelic.api.agent.Headers; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +public class NettyHeaders implements Headers { + + private final HttpRequest request; + + public NettyHeaders(HttpRequest request) { + this.request = request; + } + + @Override + public HeaderType getHeaderType() { + return HeaderType.HTTP; + } + + @Override + public String getHeader(String name) { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.get(name); + } + return null; + } + + @Override + public Collection getHeaders(String name) { + Set selectedHeaders = new HashSet<>(); + String header = getHeader(name); + if(header != null) { + selectedHeaders.add(header); + } + return selectedHeaders; + } + + @Override + public void setHeader(String name, String value) { + + } + + @Override + public void addHeader(String name, String value) { + + } + + @Override + public Collection getHeaderNames() { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.names(); + } + return new HashSet<>(); + } + + @Override + public boolean containsHeader(String name) { + return getHeaderNames().contains(name); + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_43/Utils.java b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_43/Utils.java deleted file mode 100644 index 2e9a609223..0000000000 --- a/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_43/Utils.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package com.nr.agent.instrumentation.micronaut.netty_43; - -import java.util.Map; - -public class Utils { - - public static void addAttribute(Map attributes, String key, Object value) { - if (attributes != null && key != null && !key.isEmpty() && value != null) { - attributes.put(key, value); - } - } -} diff --git a/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/NettyHttpRequest_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/NettyHttpRequest_Instrumentation.java new file mode 100644 index 0000000000..b1e297bc85 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/NettyHttpRequest_Instrumentation.java @@ -0,0 +1,13 @@ +package io.micronaut.http; + +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import io.netty.channel.ChannelHandlerContext_Instrumentation; + +@Weave(originalName = "io.micronaut.http.server.netty.NettyHttpRequest") +public class NettyHttpRequest_Instrumentation { + + public ChannelHandlerContext_Instrumentation getChannelHandlerContext() { + return Weaver.callOriginal(); + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java index c124726962..c0da245162 100644 --- a/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java @@ -9,39 +9,39 @@ import com.newrelic.api.agent.NewRelic; import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.TransactionNamePriority; +import com.newrelic.api.agent.Transaction; +import com.newrelic.api.agent.TransportType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; + +import com.nr.agent.instrumentation.micronaut.netty_43.NettyExtendedRequest; +import com.nr.agent.instrumentation.micronaut.netty_43.NettyHeaders; import io.micronaut.http.server.netty.body.ByteBody; import io.micronaut.http.server.netty.handler.PipeliningServerHandler_Instrumentation; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpMethod; +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPipeline_Instrumentation; @Weave(originalName = "io.micronaut.http.server.netty.RoutingInBoundHandler", type = MatchType.ExactClass) - public abstract class RoutingInBoundHandler_Instrumentation { - @Trace(dispatcher = true) - public void accept(ChannelHandlerContext ctx, io.netty.handler.codec.http.HttpRequest request, ByteBody body, - PipeliningServerHandler_Instrumentation.OutboundAccess_Instrumentation outboundAccess) { - if(request != null) { - StringBuffer sb = new StringBuffer(); - HttpMethod method = request.method(); - if(method != null) { - sb.append(method.name()); - } else { - sb.append("UnknownMethod"); + @Trace(async = true) + public void accept(ChannelHandlerContext_Instrumentation ctx, io.netty.handler.codec.http.HttpRequest request, ByteBody body, + PipeliningServerHandler_Instrumentation.OutboundAccess_Instrumentation outboundAccess) { + if(ctx != null) { + ChannelPipeline_Instrumentation pipeline = ctx.pipeline(); + if(pipeline != null) { + if(pipeline.micronautToken != null) { + pipeline.micronautToken.link(); + } } - sb.append(" - "); - String uri = request.uri(); - if(uri != null) { - sb.append(uri); - } else { - sb.append("UnknownURI"); - } - NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW, false, "Micronaut-Netty", sb.toString()); } + Transaction transaction = NewRelic.getAgent().getTransaction(); + if(!transaction.isWebTransaction()) { + transaction.convertToWebTransaction(); + } + transaction.setWebRequest(new NettyExtendedRequest(request)); + transaction.acceptDistributedTraceHeaders(TransportType.HTTP, new NettyHeaders(request)); Weaver.callOriginal(); } } diff --git a/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java index b1476719ad..517b43cabc 100644 --- a/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java @@ -7,47 +7,73 @@ package io.micronaut.http.server.netty.handler; -import com.newrelic.api.agent.NewRelic; -import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.*; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import io.netty.channel.ChannelHandlerContext; +import com.nr.agent.instrumentation.micronaut.netty_43.NettyExtendedRequest; +import com.nr.agent.instrumentation.micronaut.netty_43.NettyHeaders; +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPipeline_Instrumentation; +import io.netty.handler.codec.http.HttpRequest; -@Weave(originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler", type = MatchType.ExactClass) +@Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler") public abstract class PipeliningServerHandler_Instrumentation { - @Trace(dispatcher = true) - public void channelRead(ChannelHandlerContext ctx, Object msg) { + @Trace + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + ChannelPipeline_Instrumentation pipeline = ctx != null ? ctx.pipeline() : null; + if(pipeline != null) { + if(pipeline.micronautToken != null) { + pipeline.micronautToken.link(); + } else { + Token token = NewRelic.getAgent().getTransaction().getToken(); + if(token != null) { + if(token.isActive()) { + pipeline.micronautToken = token; + } else { + token.expire(); + token = null; + } + } + } + } Weaver.callOriginal(); } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$MessageInboundHandler") - - private static class MessageInboundHandler_Instrumentation { - - @Trace - void read(Object message) { - NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "HTTP", "Netty", "InboundHander", "MessageInboundHandler", "read"); - Weaver.callOriginal(); + public void channelReadComplete(ChannelHandlerContext_Instrumentation ctx) { + ChannelPipeline_Instrumentation pipeline = ctx != null ? ctx.pipeline() : null; + if(pipeline != null) { + if(pipeline.micronautToken != null) { + pipeline.micronautToken.expire(); + pipeline.micronautToken = null; + } } - + Weaver.callOriginal(); } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$DecompressingInboundHandler") - - private static class DecompressingInboundHandler_Instrumentation { + @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$MessageInboundHandler") + private static class MessageInboundHandler_Instrumentation { - @Trace + @Trace(dispatcher = true) void read(Object message) { - NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "HTTP", "Netty", "InboundHander", "DecompressingInboundHandler", "read"); + NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "HTTP", "Netty", "InboundHandler", "MessageInboundHandler", "read"); + if(message instanceof HttpRequest) { + HttpRequest httpRequest = (HttpRequest) message; + NettyExtendedRequest nettyExtendedRequest = new NettyExtendedRequest(httpRequest); + NettyHeaders nettyHeaders = new NettyHeaders(httpRequest); + Transaction transaction = NewRelic.getAgent().getTransaction(); + transaction.acceptDistributedTraceHeaders(TransportType.HTTP, nettyHeaders); + transaction.setWebRequest(nettyExtendedRequest); + transaction.convertToWebTransaction(); + } + Weaver.callOriginal(); } } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$OptimisticBufferingInboundHandler") - private static class OptimisticBufferingInboundHandler_Instrumentation { @Trace @@ -61,7 +87,6 @@ void read(Object message) { } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$DroppingInboundHandler") - private static class DroppingInboundHandler_Instrumentation { @Trace @@ -73,7 +98,6 @@ void read(Object message) { } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$StreamingInboundHandler") - private static class StreamingInboundHandler_Instrumentation { @Trace @@ -84,21 +108,7 @@ void read(Object message) { } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$BlockingOutboundHandler") - - private static class BlockingOutboundHandler_Instrumentation { - - @Trace - void writeSome() { - NewRelic.getAgent() - .getTracedMethod() - .setMetricName("Micronaut", "HTTP", "Netty", "OutboundHander", "BlockingOutboundHandler", "writeSome"); - Weaver.callOriginal(); - } - } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$ContinueOutboundHandler") - private static class ContinueOutboundHandler_Instrumentation { @Trace @@ -111,7 +121,6 @@ void writeSome() { } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$FullOutboundHandler") - private static class FullOutboundHandler_Instrumentation { @Trace @@ -122,7 +131,6 @@ void writeSome() { } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$StreamingOutboundHandler") - private static class StreamingOutboundHandler_Instrumentation { @Trace @@ -135,7 +143,6 @@ void writeSome() { } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$OutboundAccess") - public static class OutboundAccess_Instrumentation { } diff --git a/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java index a5267d3e94..69fe119a1e 100644 --- a/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java @@ -1,37 +1,36 @@ package io.micronaut.http.server.netty.handler; import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Token; import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.TransactionNamePriority; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import io.micronaut.http.server.netty.body.ByteBody; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpMethod; +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPipeline_Instrumentation; import io.netty.handler.codec.http.HttpRequest; @Weave(type = MatchType.Interface, originalName = "io.micronaut.http.server.netty.handler.RequestHandler") public abstract class RequestHandler_Instrumentation { @Trace - public void accept(ChannelHandlerContext ctx, HttpRequest request, ByteBody body, PipeliningServerHandler.OutboundAccess outboundAccess) { - - if(request != null) { - String uri = request.uri(); - NewRelic.getAgent().getTracedMethod().addCustomAttribute("URI", uri != null ? uri : "null"); - HttpMethod method = request.method(); - String methodName = null; - if(method != null) { - methodName = method.name(); - } - NewRelic.getAgent().getTracedMethod().addCustomAttribute("Method", methodName != null ? methodName : "null"); - if(uri != null && methodName != null) { - NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW, false, "Micronaut-Netty", methodName + " - " + uri); + public void accept(ChannelHandlerContext_Instrumentation ctx, HttpRequest request, ByteBody body, PipeliningServerHandler.OutboundAccess outboundAccess) { + if(ctx != null && ctx.pipeline() != null) { + ChannelPipeline_Instrumentation pipeline = ctx.pipeline(); + if(pipeline.micronautToken == null) { + Token token = NewRelic.getAgent().getTransaction().getToken(); + if(token != null) { + if(token.isActive()) { + pipeline.micronautToken = token; + } else { + token.expire(); + token = null; + } + } } } - Weaver.callOriginal(); } diff --git a/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketUpgradeHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketUpgradeHandler_Instrumentation.java deleted file mode 100644 index 17b8842da4..0000000000 --- a/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketUpgradeHandler_Instrumentation.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package io.micronaut.http.server.netty.websocket; - -import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.weaver.MatchType; -import com.newrelic.api.agent.weaver.Weave; -import com.newrelic.api.agent.weaver.Weaver; -import io.micronaut.http.server.netty.body.ByteBody; -import io.micronaut.http.server.netty.handler.PipeliningServerHandler_Instrumentation; -import io.netty.channel.ChannelHandlerContext; - -@Weave(originalName = "io.micronaut.http.server.netty.websocket.NettyServerWebSocketUpgradeHandler", type = MatchType.ExactClass) -public abstract class NettyServerWebSocketUpgradeHandler_Instrumentation { - - @Trace(dispatcher = true) - public void accept(ChannelHandlerContext ctx, io.netty.handler.codec.http.HttpRequest request, ByteBody body, - PipeliningServerHandler_Instrumentation.OutboundAccess_Instrumentation outboundAccess) { - Weaver.callOriginal(); - } - -} diff --git a/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java new file mode 100644 index 0000000000..8ec28602b2 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java @@ -0,0 +1,10 @@ +package io.netty.channel; + +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; + +@Weave(type = MatchType.Interface, originalName = "io.netty.channel.ChannelHandlerContext") +public abstract class ChannelHandlerContext_Instrumentation { + + public abstract ChannelPipeline_Instrumentation pipeline(); +} diff --git a/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java new file mode 100644 index 0000000000..2127b44623 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java @@ -0,0 +1,31 @@ +package io.netty.channel; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(type = MatchType.Interface, originalName = "io.netty.channel.ChannelInboundHandler") +public abstract class ChannelInboundHandler_Instrumentation { + + @Trace(async = true, excludeFromTransactionTrace = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) throws Exception { + if(ctx.pipeline().micronautToken != null) { + ctx.pipeline().micronautToken.link(); + } else { + Token token = NewRelic.getAgent().getTransaction().getToken(); + if(token != null) { + if(token.isActive()) { + ctx.pipeline().micronautToken = token; + } else { + token.expire(); + token = null; + } + } + } + Weaver.callOriginal(); + } + +} diff --git a/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java new file mode 100644 index 0000000000..99fb24cdea --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.3.0/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java @@ -0,0 +1,14 @@ +package io.netty.channel; + +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.NewField; +import com.newrelic.api.agent.weaver.Weave; + +@Weave(type = MatchType.BaseClass, originalName = "io.netty.channel.ChannelPipeline") +public class ChannelPipeline_Instrumentation { + + @NewField + public Token micronautToken; + +} diff --git a/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_44/NettyExtendedRequest.java b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_44/NettyExtendedRequest.java new file mode 100644 index 0000000000..5c044afaab --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_44/NettyExtendedRequest.java @@ -0,0 +1,66 @@ +package com.nr.agent.instrumentation.micronaut.netty_44; + +import com.newrelic.api.agent.ExtendedRequest; +import com.newrelic.api.agent.HeaderType; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; + +import java.util.Enumeration; + +public class NettyExtendedRequest extends ExtendedRequest { + + private final HttpRequest request; + + public NettyExtendedRequest(HttpRequest request) { + this.request = request; + } + + @Override + public String getMethod() { + return request.method().name(); + } + + @Override + public String getRequestURI() { + return request.uri(); + } + + @Override + public String getRemoteUser() { + return ""; + } + + @Override + public Enumeration getParameterNames() { + return null; + } + + @Override + public String[] getParameterValues(String name) { + return null; + } + + @Override + public Object getAttribute(String name) { + return null; + } + + @Override + public String getCookieValue(String name) { + return ""; + } + + @Override + public HeaderType getHeaderType() { + return HeaderType.HTTP; + } + + @Override + public String getHeader(String name) { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.get(name); + } + return null; + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_44/NettyHeaders.java b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_44/NettyHeaders.java new file mode 100644 index 0000000000..ca5c0e0ee4 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_44/NettyHeaders.java @@ -0,0 +1,67 @@ +package com.nr.agent.instrumentation.micronaut.netty_44; + +import com.newrelic.api.agent.HeaderType; +import com.newrelic.api.agent.Headers; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +public class NettyHeaders implements Headers { + + private HttpRequest request; + + public NettyHeaders(HttpRequest request) { + this.request = request; + } + + @Override + public HeaderType getHeaderType() { + return HeaderType.HTTP; + } + + @Override + public String getHeader(String name) { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.get(name); + } + return null; + } + + @Override + public Collection getHeaders(String name) { + Set selectedHeaders = new HashSet<>(); + String header = getHeader(name); + if(header != null) { + selectedHeaders.add(header); + } + return selectedHeaders; + } + + @Override + public void setHeader(String name, String value) { + + } + + @Override + public void addHeader(String name, String value) { + + } + + @Override + public Collection getHeaderNames() { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.names(); + } + return new HashSet<>(); + } + + @Override + public boolean containsHeader(String name) { + return getHeaderNames().contains(name); + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_44/Utils.java b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_44/Utils.java deleted file mode 100644 index cdd944343a..0000000000 --- a/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_44/Utils.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package com.nr.agent.instrumentation.micronaut.netty_44; - -import java.util.Map; - -public class Utils { - - public static void addAttribute(Map attributes, String key, Object value) { - if (attributes != null && key != null && !key.isEmpty() && value != null) { - attributes.put(key, value); - } - } -} diff --git a/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/NettyHttpRequest_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/NettyHttpRequest_Instrumentation.java new file mode 100644 index 0000000000..b1e297bc85 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/NettyHttpRequest_Instrumentation.java @@ -0,0 +1,13 @@ +package io.micronaut.http; + +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import io.netty.channel.ChannelHandlerContext_Instrumentation; + +@Weave(originalName = "io.micronaut.http.server.netty.NettyHttpRequest") +public class NettyHttpRequest_Instrumentation { + + public ChannelHandlerContext_Instrumentation getChannelHandlerContext() { + return Weaver.callOriginal(); + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java index 457dc4bdfd..14dfca77ca 100644 --- a/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java @@ -9,39 +9,39 @@ import com.newrelic.api.agent.NewRelic; import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.TransactionNamePriority; +import com.newrelic.api.agent.Transaction; +import com.newrelic.api.agent.TransportType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; + +import com.nr.agent.instrumentation.micronaut.netty_44.NettyExtendedRequest; +import com.nr.agent.instrumentation.micronaut.netty_44.NettyHeaders; import io.micronaut.http.server.netty.body.ByteBody; import io.micronaut.http.server.netty.handler.OutboundAccess; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpMethod; +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPipeline_Instrumentation; @Weave(originalName = "io.micronaut.http.server.netty.RoutingInBoundHandler", type = MatchType.ExactClass) - public abstract class RoutingInBoundHandler_Instrumentation { - @Trace(dispatcher = true) - public void accept(ChannelHandlerContext ctx, io.netty.handler.codec.http.HttpRequest request, ByteBody body, - OutboundAccess outboundAccess) { - if(request != null) { - StringBuffer sb = new StringBuffer(); - HttpMethod method = request.method(); - if(method != null) { - sb.append(method.name()); - } else { - sb.append("UnknownMethod"); + @Trace(async = true) + public void accept(ChannelHandlerContext_Instrumentation ctx, io.netty.handler.codec.http.HttpRequest request, ByteBody body, + OutboundAccess outboundAccess) { + if(ctx != null) { + ChannelPipeline_Instrumentation pipeline = ctx.pipeline(); + if(pipeline != null) { + if(pipeline.micronautToken != null) { + pipeline.micronautToken.link(); + } } - sb.append(" - "); - String uri = request.uri(); - if(uri != null) { - sb.append(uri); - } else { - sb.append("UnknownURI"); - } - NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW, false, "Micronaut-Netty", sb.toString()); } + Transaction transaction = NewRelic.getAgent().getTransaction(); + if(!transaction.isWebTransaction()) { + transaction.convertToWebTransaction(); + } + transaction.setWebRequest(new NettyExtendedRequest(request)); + transaction.acceptDistributedTraceHeaders(TransportType.HTTP, new NettyHeaders(request)); Weaver.callOriginal(); } } diff --git a/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java index 7346aed489..f804d411e1 100644 --- a/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java @@ -7,47 +7,73 @@ package io.micronaut.http.server.netty.handler; -import com.newrelic.api.agent.NewRelic; -import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.*; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import io.netty.channel.ChannelHandlerContext; +import com.nr.agent.instrumentation.micronaut.netty_44.NettyExtendedRequest; +import com.nr.agent.instrumentation.micronaut.netty_44.NettyHeaders; +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPipeline_Instrumentation; +import io.netty.handler.codec.http.HttpRequest; -@Weave(originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler", type = MatchType.ExactClass) +@Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler") public abstract class PipeliningServerHandler_Instrumentation { - @Trace(dispatcher = true) - public void channelRead(ChannelHandlerContext ctx, Object msg) { + @Trace + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + ChannelPipeline_Instrumentation pipeline = ctx != null ? ctx.pipeline() : null; + if(pipeline != null) { + if(pipeline.micronautToken != null) { + pipeline.micronautToken.link(); + } else { + Token token = NewRelic.getAgent().getTransaction().getToken(); + if(token != null) { + if(token.isActive()) { + pipeline.micronautToken = token; + } else { + token.expire(); + token = null; + } + } + } + } Weaver.callOriginal(); } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$MessageInboundHandler") - - private static class MessageInboundHandler_Instrumentation { - - @Trace - void read(Object message) { - NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "HTTP", "Netty", "InboundHander", "MessageInboundHandler", "read"); - Weaver.callOriginal(); + public void channelReadComplete(ChannelHandlerContext_Instrumentation ctx) { + ChannelPipeline_Instrumentation pipeline = ctx != null ? ctx.pipeline() : null; + if(pipeline != null) { + if(pipeline.micronautToken != null) { + pipeline.micronautToken.expire(); + pipeline.micronautToken = null; + } } - + Weaver.callOriginal(); } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$DecompressingInboundHandler") - - private static class DecompressingInboundHandler_Instrumentation { + @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$MessageInboundHandler") + private static class MessageInboundHandler_Instrumentation { - @Trace + @Trace(dispatcher = true) void read(Object message) { - NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "HTTP", "Netty", "InboundHander", "DecompressingInboundHandler", "read"); + NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "HTTP", "Netty", "InboundHandler", "MessageInboundHandler", "read"); + if(message instanceof HttpRequest) { + HttpRequest httpRequest = (HttpRequest) message; + NettyExtendedRequest nettyExtendedRequest = new NettyExtendedRequest(httpRequest); + NettyHeaders nettyHeaders = new NettyHeaders(httpRequest); + Transaction transaction = NewRelic.getAgent().getTransaction(); + transaction.acceptDistributedTraceHeaders(TransportType.HTTP, nettyHeaders); + transaction.setWebRequest(nettyExtendedRequest); + transaction.convertToWebTransaction(); + } + Weaver.callOriginal(); } } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$OptimisticBufferingInboundHandler") - private static class OptimisticBufferingInboundHandler_Instrumentation { @Trace @@ -61,7 +87,6 @@ void read(Object message) { } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$DroppingInboundHandler") - private static class DroppingInboundHandler_Instrumentation { @Trace @@ -73,7 +98,6 @@ void read(Object message) { } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$StreamingInboundHandler") - private static class StreamingInboundHandler_Instrumentation { @Trace @@ -84,21 +108,7 @@ void read(Object message) { } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$BlockingOutboundHandler") - - private static class BlockingOutboundHandler_Instrumentation { - - @Trace - void writeSome() { - NewRelic.getAgent() - .getTracedMethod() - .setMetricName("Micronaut", "HTTP", "Netty", "OutboundHander", "BlockingOutboundHandler", "writeSome"); - Weaver.callOriginal(); - } - } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$ContinueOutboundHandler") - private static class ContinueOutboundHandler_Instrumentation { @Trace @@ -111,7 +121,6 @@ void writeSome() { } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$FullOutboundHandler") - private static class FullOutboundHandler_Instrumentation { @Trace @@ -122,7 +131,6 @@ void writeSome() { } @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$StreamingOutboundHandler") - private static class StreamingOutboundHandler_Instrumentation { @Trace @@ -134,10 +142,4 @@ void writeSome() { } } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$OutboundAccessImpl") - - public static class OutboundAccessImpl_Instrumentation { - - } - } diff --git a/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java index b2b197b219..e7e8b439d3 100644 --- a/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java @@ -1,37 +1,36 @@ package io.micronaut.http.server.netty.handler; import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Token; import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.TransactionNamePriority; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import io.micronaut.http.server.netty.body.ByteBody; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpMethod; +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPipeline_Instrumentation; import io.netty.handler.codec.http.HttpRequest; @Weave(type = MatchType.Interface, originalName = "io.micronaut.http.server.netty.handler.RequestHandler") public abstract class RequestHandler_Instrumentation { @Trace - public void accept(ChannelHandlerContext ctx, HttpRequest request, ByteBody body, OutboundAccess outboundAccess) { - - if(request != null) { - String uri = request.uri(); - NewRelic.getAgent().getTracedMethod().addCustomAttribute("URI", uri != null ? uri : "null"); - HttpMethod method = request.method(); - String methodName = null; - if(method != null) { - methodName = method.name(); - } - NewRelic.getAgent().getTracedMethod().addCustomAttribute("Method", methodName != null ? methodName : "null"); - if(uri != null && methodName != null) { - NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW, false, "Micronaut-Netty", methodName + " - " + uri); + public void accept(ChannelHandlerContext_Instrumentation ctx, HttpRequest request, ByteBody body, OutboundAccess outboundAccess) { + if(ctx != null && ctx.pipeline() != null) { + ChannelPipeline_Instrumentation pipeline = ctx.pipeline(); + if(pipeline.micronautToken == null) { + Token token = NewRelic.getAgent().getTransaction().getToken(); + if(token != null) { + if(token.isActive()) { + pipeline.micronautToken = token; + } else { + token.expire(); + token = null; + } + } } } - Weaver.callOriginal(); } diff --git a/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketUpgradeHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketUpgradeHandler_Instrumentation.java deleted file mode 100644 index fc096dff34..0000000000 --- a/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketUpgradeHandler_Instrumentation.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package io.micronaut.http.server.netty.websocket; - -import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.weaver.MatchType; -import com.newrelic.api.agent.weaver.Weave; -import com.newrelic.api.agent.weaver.Weaver; -import io.micronaut.http.server.netty.body.ByteBody; -import io.micronaut.http.server.netty.handler.OutboundAccess; -import io.netty.channel.ChannelHandlerContext; - -@Weave(originalName = "io.micronaut.http.server.netty.websocket.NettyServerWebSocketUpgradeHandler", type = MatchType.ExactClass) -public abstract class NettyServerWebSocketUpgradeHandler_Instrumentation { - - @Trace(dispatcher = true) - public void accept(ChannelHandlerContext ctx, io.netty.handler.codec.http.HttpRequest request, ByteBody body, - OutboundAccess outboundAccess) { - Weaver.callOriginal(); - } - -} diff --git a/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java new file mode 100644 index 0000000000..8ec28602b2 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java @@ -0,0 +1,10 @@ +package io.netty.channel; + +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; + +@Weave(type = MatchType.Interface, originalName = "io.netty.channel.ChannelHandlerContext") +public abstract class ChannelHandlerContext_Instrumentation { + + public abstract ChannelPipeline_Instrumentation pipeline(); +} diff --git a/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java new file mode 100644 index 0000000000..2127b44623 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java @@ -0,0 +1,31 @@ +package io.netty.channel; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(type = MatchType.Interface, originalName = "io.netty.channel.ChannelInboundHandler") +public abstract class ChannelInboundHandler_Instrumentation { + + @Trace(async = true, excludeFromTransactionTrace = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) throws Exception { + if(ctx.pipeline().micronautToken != null) { + ctx.pipeline().micronautToken.link(); + } else { + Token token = NewRelic.getAgent().getTransaction().getToken(); + if(token != null) { + if(token.isActive()) { + ctx.pipeline().micronautToken = token; + } else { + token.expire(); + token = null; + } + } + } + Weaver.callOriginal(); + } + +} diff --git a/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java new file mode 100644 index 0000000000..99fb24cdea --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.4.0/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java @@ -0,0 +1,14 @@ +package io.netty.channel; + +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.NewField; +import com.newrelic.api.agent.weaver.Weave; + +@Weave(type = MatchType.BaseClass, originalName = "io.netty.channel.ChannelPipeline") +public class ChannelPipeline_Instrumentation { + + @NewField + public Token micronautToken; + +} diff --git a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_45/NettyExtendedRequest.java b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_45/NettyExtendedRequest.java new file mode 100644 index 0000000000..49aab147a1 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_45/NettyExtendedRequest.java @@ -0,0 +1,66 @@ +package com.nr.agent.instrumentation.micronaut.netty_45; + +import com.newrelic.api.agent.ExtendedRequest; +import com.newrelic.api.agent.HeaderType; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; + +import java.util.Enumeration; + +public class NettyExtendedRequest extends ExtendedRequest { + + private final HttpRequest request; + + public NettyExtendedRequest(HttpRequest request) { + this.request = request; + } + + @Override + public String getMethod() { + return request.method().name(); + } + + @Override + public String getRequestURI() { + return request.uri(); + } + + @Override + public String getRemoteUser() { + return ""; + } + + @Override + public Enumeration getParameterNames() { + return null; + } + + @Override + public String[] getParameterValues(String name) { + return null; + } + + @Override + public Object getAttribute(String name) { + return null; + } + + @Override + public String getCookieValue(String name) { + return ""; + } + + @Override + public HeaderType getHeaderType() { + return HeaderType.HTTP; + } + + @Override + public String getHeader(String name) { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.get(name); + } + return null; + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_45/NettyHeaders.java b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_45/NettyHeaders.java new file mode 100644 index 0000000000..4ba90cd8bd --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_45/NettyHeaders.java @@ -0,0 +1,67 @@ +package com.nr.agent.instrumentation.micronaut.netty_45; + +import com.newrelic.api.agent.HeaderType; +import com.newrelic.api.agent.Headers; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +public class NettyHeaders implements Headers { + + private HttpRequest request; + + public NettyHeaders(HttpRequest request) { + this.request = request; + } + + @Override + public HeaderType getHeaderType() { + return HeaderType.HTTP; + } + + @Override + public String getHeader(String name) { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.get(name); + } + return null; + } + + @Override + public Collection getHeaders(String name) { + Set selectedHeaders = new HashSet<>(); + String header = getHeader(name); + if(header != null) { + selectedHeaders.add(header); + } + return selectedHeaders; + } + + @Override + public void setHeader(String name, String value) { + + } + + @Override + public void addHeader(String name, String value) { + + } + + @Override + public Collection getHeaderNames() { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.names(); + } + return new HashSet<>(); + } + + @Override + public boolean containsHeader(String name) { + return getHeaderNames().contains(name); + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_45/Utils.java b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_45/Utils.java deleted file mode 100644 index b0d63c521d..0000000000 --- a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_45/Utils.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package com.nr.agent.instrumentation.micronaut.netty_45; - -import io.micronaut.web.router.RouteMatch; - -import java.util.Map; - -public class Utils { - - public static void decorateWithRoute(RouteMatch routeMatch) { - - } - - public static void addAttribute(Map attributes, String key, Object value) { - if (attributes != null && key != null && !key.isEmpty() && value != null) { - attributes.put(key, value); - } - } -} diff --git a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/NettyHttpRequest_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/NettyHttpRequest_Instrumentation.java new file mode 100644 index 0000000000..b1e297bc85 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/NettyHttpRequest_Instrumentation.java @@ -0,0 +1,13 @@ +package io.micronaut.http; + +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import io.netty.channel.ChannelHandlerContext_Instrumentation; + +@Weave(originalName = "io.micronaut.http.server.netty.NettyHttpRequest") +public class NettyHttpRequest_Instrumentation { + + public ChannelHandlerContext_Instrumentation getChannelHandlerContext() { + return Weaver.callOriginal(); + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/reactive/execution/ReactorExecutionFlowImpl_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/reactive/execution/ReactorExecutionFlowImpl_Instrumentation.java index ab4b7142f1..63b0057779 100644 --- a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/reactive/execution/ReactorExecutionFlowImpl_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/reactive/execution/ReactorExecutionFlowImpl_Instrumentation.java @@ -19,7 +19,7 @@ import java.util.function.BiConsumer; -@Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.reactive.execution.ReactorExecutionFlowImpl") +@Weave(originalName = "io.micronaut.http.reactive.execution.ReactorExecutionFlowImpl", type = MatchType.ExactClass) abstract class ReactorExecutionFlowImpl_Instrumentation { @NewField diff --git a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/NettyHttpRequest_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/NettyHttpRequest_Instrumentation.java new file mode 100644 index 0000000000..de8d1afced --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/NettyHttpRequest_Instrumentation.java @@ -0,0 +1,13 @@ +package io.micronaut.http.server.netty; + +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import io.netty.channel.ChannelHandlerContext_Instrumentation; + +@Weave(originalName = "io.micronaut.http.server.netty.NettyHttpRequest") +public class NettyHttpRequest_Instrumentation { + + public ChannelHandlerContext_Instrumentation getChannelHandlerContext() { + return Weaver.callOriginal(); + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java index 7602e56d42..b7742f4a81 100644 --- a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java @@ -9,37 +9,39 @@ import com.newrelic.api.agent.NewRelic; import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.TransactionNamePriority; +import com.newrelic.api.agent.Transaction; +import com.newrelic.api.agent.TransportType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; + +import com.nr.agent.instrumentation.micronaut.netty_45.NettyExtendedRequest; +import com.nr.agent.instrumentation.micronaut.netty_45.NettyHeaders; import io.micronaut.http.body.CloseableByteBody; import io.micronaut.http.server.netty.handler.OutboundAccess; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpMethod; +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPipeline_Instrumentation; -@Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.RoutingInBoundHandler") +@Weave(originalName = "io.micronaut.http.server.netty.RoutingInBoundHandler", type = MatchType.ExactClass) public abstract class RoutingInBoundHandler_Instrumentation { - @Trace(dispatcher = true) - public void accept(ChannelHandlerContext ctx, io.netty.handler.codec.http.HttpRequest request, CloseableByteBody body, OutboundAccess outboundAccess) { - if(request != null) { - StringBuffer sb = new StringBuffer(); - HttpMethod method = request.method(); - if(method != null) { - sb.append(method.name()); - } else { - sb.append("UnknownMethod"); - } - sb.append(" - "); - String uri = request.uri(); - if(uri != null) { - sb.append(uri); - } else { - sb.append("UnknownURI"); + @Trace(async = true) + public void accept(ChannelHandlerContext_Instrumentation ctx, io.netty.handler.codec.http.HttpRequest request, CloseableByteBody body, + OutboundAccess outboundAccess) { + if(ctx != null) { + ChannelPipeline_Instrumentation pipeline = ctx.pipeline(); + if(pipeline != null) { + if(pipeline.micronautToken != null) { + pipeline.micronautToken.link(); + } } - NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW, false, "Micronaut-Netty", sb.toString()); } + Transaction transaction = NewRelic.getAgent().getTransaction(); + if(!transaction.isWebTransaction()) { + transaction.convertToWebTransaction(); + } + transaction.setWebRequest(new NettyExtendedRequest(request)); + transaction.acceptDistributedTraceHeaders(TransportType.HTTP, new NettyHeaders(request)); Weaver.callOriginal(); } } diff --git a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/body/NettyBodyAdapter_Skip.java b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/body/NettyBodyAdapter_Skip.java new file mode 100644 index 0000000000..3a1ebc5a8d --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/body/NettyBodyAdapter_Skip.java @@ -0,0 +1,7 @@ +package io.micronaut.http.server.netty.body; + +import com.newrelic.api.agent.weaver.SkipIfPresent; + +@SkipIfPresent(originalName = "io.micronaut.http.server.netty.body.NettyBodyAdapter") +public class NettyBodyAdapter_Skip { +} diff --git a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java index 7c45883331..ebf96ca592 100644 --- a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java @@ -7,38 +7,67 @@ package io.micronaut.http.server.netty.handler; -import com.newrelic.api.agent.NewRelic; -import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.*; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import io.netty.channel.ChannelHandlerContext; +import com.nr.agent.instrumentation.micronaut.netty_45.NettyExtendedRequest; +import com.nr.agent.instrumentation.micronaut.netty_45.NettyHeaders; +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPipeline_Instrumentation; +import io.netty.handler.codec.http.HttpRequest; @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler") public abstract class PipeliningServerHandler_Instrumentation { - @Trace(dispatcher = true) - public void channelRead(ChannelHandlerContext ctx, Object msg) { + @Trace + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + ChannelPipeline_Instrumentation pipeline = ctx != null ? ctx.pipeline() : null; + if(pipeline != null) { + if(pipeline.micronautToken != null) { + pipeline.micronautToken.link(); + } else { + Token token = NewRelic.getAgent().getTransaction().getToken(); + if(token != null) { + if(token.isActive()) { + pipeline.micronautToken = token; + } else { + token.expire(); + token = null; + } + } + } + } Weaver.callOriginal(); } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$MessageInboundHandler") - private static class MessageInboundHandler_Instrumentation { - - @Trace - void read(Object message) { - NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "HTTP", "Netty", "InboundHander", "MessageInboundHandler", "read"); - Weaver.callOriginal(); + public void channelReadComplete(ChannelHandlerContext_Instrumentation ctx) { + ChannelPipeline_Instrumentation pipeline = ctx != null ? ctx.pipeline() : null; + if(pipeline != null) { + if(pipeline.micronautToken != null) { + pipeline.micronautToken.expire(); + pipeline.micronautToken = null; + } } - + Weaver.callOriginal(); } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$DecompressingInboundHandler") - private static class DecompressingInboundHandler_Instrumentation { + @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$MessageInboundHandler") + private static class MessageInboundHandler_Instrumentation { - @Trace + @Trace(dispatcher = true) void read(Object message) { - NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "HTTP", "Netty", "InboundHander", "DecompressingInboundHandler", "read"); + NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "HTTP", "Netty", "InboundHandler", "MessageInboundHandler", "read"); + if(message instanceof HttpRequest) { + HttpRequest httpRequest = (HttpRequest) message; + NettyExtendedRequest nettyExtendedRequest = new NettyExtendedRequest(httpRequest); + NettyHeaders nettyHeaders = new NettyHeaders(httpRequest); + Transaction transaction = NewRelic.getAgent().getTransaction(); + transaction.acceptDistributedTraceHeaders(TransportType.HTTP, nettyHeaders); + transaction.setWebRequest(nettyExtendedRequest); + transaction.convertToWebTransaction(); + } + Weaver.callOriginal(); } @@ -79,18 +108,6 @@ void read(Object message) { } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$BlockingOutboundHandler") - private static class BlockingOutboundHandler_Instrumentation { - - @Trace - void writeSome() { - NewRelic.getAgent() - .getTracedMethod() - .setMetricName("Micronaut", "HTTP", "Netty", "OutboundHander", "BlockingOutboundHandler", "writeSome"); - Weaver.callOriginal(); - } - } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$ContinueOutboundHandler") private static class ContinueOutboundHandler_Instrumentation { @@ -125,9 +142,4 @@ void writeSome() { } } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$OutboundAccessImpl") - public static class OutboundAccessImpl_Instrumentation { - - } - } diff --git a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java index b266e71d3f..ead9c6ff2b 100644 --- a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java @@ -1,37 +1,36 @@ package io.micronaut.http.server.netty.handler; import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Token; import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.TransactionNamePriority; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import io.micronaut.http.body.CloseableByteBody; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpMethod; +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPipeline_Instrumentation; import io.netty.handler.codec.http.HttpRequest; @Weave(type = MatchType.Interface, originalName = "io.micronaut.http.server.netty.handler.RequestHandler") public abstract class RequestHandler_Instrumentation { @Trace - public void accept(ChannelHandlerContext ctx, HttpRequest request, CloseableByteBody body, OutboundAccess outboundAccess) { - - if(request != null) { - String uri = request.uri(); - NewRelic.getAgent().getTracedMethod().addCustomAttribute("URI", uri != null ? uri : "null"); - HttpMethod method = request.method(); - String methodName = null; - if(method != null) { - methodName = method.name(); - } - NewRelic.getAgent().getTracedMethod().addCustomAttribute("Method", methodName != null ? methodName : "null"); - if(uri != null && methodName != null) { - NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW, false, "Micronaut-Netty", methodName + " - " + uri); + public void accept(ChannelHandlerContext_Instrumentation ctx, HttpRequest request, CloseableByteBody body, OutboundAccess outboundAccess) { + if(ctx != null && ctx.pipeline() != null) { + ChannelPipeline_Instrumentation pipeline = ctx.pipeline(); + if(pipeline.micronautToken == null) { + Token token = NewRelic.getAgent().getTransaction().getToken(); + if(token != null) { + if(token.isActive()) { + pipeline.micronautToken = token; + } else { + token.expire(); + token = null; + } + } } } - Weaver.callOriginal(); } diff --git a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/handler/accesslog/element/ConnectionMetadata_Skip.java b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/handler/accesslog/element/ConnectionMetadata_Skip.java new file mode 100644 index 0000000000..b664e3094f --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/handler/accesslog/element/ConnectionMetadata_Skip.java @@ -0,0 +1,7 @@ +package io.micronaut.http.server.netty.handler.accesslog.element; + +import com.newrelic.api.agent.weaver.SkipIfPresent; + +@SkipIfPresent(originalName = "io.micronaut.http.server.netty.handler.accesslog.element.ConnectionMetadata") +public class ConnectionMetadata_Skip { +} diff --git a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketHandler_Instrumentation.java index 55fc63026d..4e094ea27c 100644 --- a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketHandler_Instrumentation.java @@ -13,7 +13,7 @@ import com.newrelic.api.agent.weaver.Weaver; import io.netty.channel.ChannelHandlerContext; -@Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.websocket.NettyServerWebSocketHandler") +@Weave(originalName = "io.micronaut.http.server.netty.websocket.NettyServerWebSocketHandler", type = MatchType.ExactClass) public abstract class NettyServerWebSocketHandler_Instrumentation { @Trace(dispatcher = true) diff --git a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketUpgradeHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketUpgradeHandler_Instrumentation.java deleted file mode 100644 index d3ad3631eb..0000000000 --- a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketUpgradeHandler_Instrumentation.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package io.micronaut.http.server.netty.websocket; - -import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.weaver.MatchType; -import com.newrelic.api.agent.weaver.Weave; -import com.newrelic.api.agent.weaver.Weaver; -import io.micronaut.http.body.CloseableByteBody; -import io.micronaut.http.server.netty.handler.OutboundAccess; -import io.netty.channel.ChannelHandlerContext; - -@Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.websocket.NettyServerWebSocketUpgradeHandler") -public abstract class NettyServerWebSocketUpgradeHandler_Instrumentation { - - @Trace(dispatcher = true) - public void accept(ChannelHandlerContext ctx, io.netty.handler.codec.http.HttpRequest request, CloseableByteBody body, OutboundAccess outboundAccess) { - Weaver.callOriginal(); - } - -} diff --git a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java new file mode 100644 index 0000000000..8ec28602b2 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java @@ -0,0 +1,10 @@ +package io.netty.channel; + +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; + +@Weave(type = MatchType.Interface, originalName = "io.netty.channel.ChannelHandlerContext") +public abstract class ChannelHandlerContext_Instrumentation { + + public abstract ChannelPipeline_Instrumentation pipeline(); +} diff --git a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java new file mode 100644 index 0000000000..2127b44623 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java @@ -0,0 +1,31 @@ +package io.netty.channel; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(type = MatchType.Interface, originalName = "io.netty.channel.ChannelInboundHandler") +public abstract class ChannelInboundHandler_Instrumentation { + + @Trace(async = true, excludeFromTransactionTrace = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) throws Exception { + if(ctx.pipeline().micronautToken != null) { + ctx.pipeline().micronautToken.link(); + } else { + Token token = NewRelic.getAgent().getTransaction().getToken(); + if(token != null) { + if(token.isActive()) { + ctx.pipeline().micronautToken = token; + } else { + token.expire(); + token = null; + } + } + } + Weaver.callOriginal(); + } + +} diff --git a/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java new file mode 100644 index 0000000000..99fb24cdea --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.5.0/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java @@ -0,0 +1,14 @@ +package io.netty.channel; + +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.NewField; +import com.newrelic.api.agent.weaver.Weave; + +@Weave(type = MatchType.BaseClass, originalName = "io.netty.channel.ChannelPipeline") +public class ChannelPipeline_Instrumentation { + + @NewField + public Token micronautToken; + +} diff --git a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_46/NettyExtendedRequest.java b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_46/NettyExtendedRequest.java new file mode 100644 index 0000000000..9879a2bc7b --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_46/NettyExtendedRequest.java @@ -0,0 +1,66 @@ +package com.nr.agent.instrumentation.micronaut.netty_46; + +import com.newrelic.api.agent.ExtendedRequest; +import com.newrelic.api.agent.HeaderType; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; + +import java.util.Enumeration; + +public class NettyExtendedRequest extends ExtendedRequest { + + private final HttpRequest request; + + public NettyExtendedRequest(HttpRequest request) { + this.request = request; + } + + @Override + public String getMethod() { + return request.method().name(); + } + + @Override + public String getRequestURI() { + return request.uri(); + } + + @Override + public String getRemoteUser() { + return ""; + } + + @Override + public Enumeration getParameterNames() { + return null; + } + + @Override + public String[] getParameterValues(String name) { + return null; + } + + @Override + public Object getAttribute(String name) { + return null; + } + + @Override + public String getCookieValue(String name) { + return ""; + } + + @Override + public HeaderType getHeaderType() { + return HeaderType.HTTP; + } + + @Override + public String getHeader(String name) { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.get(name); + } + return null; + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_46/NettyHeaders.java b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_46/NettyHeaders.java new file mode 100644 index 0000000000..4878bda6ed --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_46/NettyHeaders.java @@ -0,0 +1,68 @@ +package com.nr.agent.instrumentation.micronaut.netty_46; + +import com.newrelic.api.agent.HeaderType; +import com.newrelic.api.agent.Headers; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class NettyHeaders implements Headers { + + private HttpRequest request; + + public NettyHeaders(HttpRequest request) { + this.request = request; + } + + @Override + public HeaderType getHeaderType() { + return HeaderType.HTTP; + } + + @Override + public String getHeader(String name) { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.get(name); + } + return null; + } + + @Override + public Collection getHeaders(String name) { + Set selectedHeaders = new HashSet<>(); + String header = getHeader(name); + if(header != null) { + selectedHeaders.add(header); + } + return selectedHeaders; + } + + @Override + public void setHeader(String name, String value) { + + } + + @Override + public void addHeader(String name, String value) { + + } + + @Override + public Collection getHeaderNames() { + HttpHeaders headers = request.headers(); + if(headers != null) { + return headers.names(); + } + return new HashSet<>(); + } + + @Override + public boolean containsHeader(String name) { + return getHeaderNames().contains(name); + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_46/Utils.java b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_46/Utils.java deleted file mode 100644 index bfb27b3bde..0000000000 --- a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/com/nr/agent/instrumentation/micronaut/netty_46/Utils.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package com.nr.agent.instrumentation.micronaut.netty_46; - -import io.micronaut.web.router.RouteMatch; - -import java.util.Map; - -public class Utils { - - public static void decorateWithRoute(RouteMatch routeMatch) { - - } - - public static void addAttribute(Map attributes, String key, Object value) { - if (attributes != null && key != null && !key.isEmpty() && value != null) { - attributes.put(key, value); - } - } -} diff --git a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/NettyHttpRequest_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/NettyHttpRequest_Instrumentation.java new file mode 100644 index 0000000000..b1e297bc85 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/NettyHttpRequest_Instrumentation.java @@ -0,0 +1,13 @@ +package io.micronaut.http; + +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import io.netty.channel.ChannelHandlerContext_Instrumentation; + +@Weave(originalName = "io.micronaut.http.server.netty.NettyHttpRequest") +public class NettyHttpRequest_Instrumentation { + + public ChannelHandlerContext_Instrumentation getChannelHandlerContext() { + return Weaver.callOriginal(); + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/reactive/execution/ReactorExecutionFlowImpl_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/reactive/execution/ReactorExecutionFlowImpl_Instrumentation.java index 129fcdfb55..8b76c7b582 100644 --- a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/reactive/execution/ReactorExecutionFlowImpl_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/reactive/execution/ReactorExecutionFlowImpl_Instrumentation.java @@ -19,7 +19,7 @@ import java.util.function.BiConsumer; -@Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.reactive.execution.ReactorExecutionFlowImpl") +@Weave(originalName = "io.micronaut.http.reactive.execution.ReactorExecutionFlowImpl", type = MatchType.ExactClass) abstract class ReactorExecutionFlowImpl_Instrumentation { @NewField diff --git a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/NettyHttpRequest_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/NettyHttpRequest_Instrumentation.java new file mode 100644 index 0000000000..de8d1afced --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/NettyHttpRequest_Instrumentation.java @@ -0,0 +1,13 @@ +package io.micronaut.http.server.netty; + +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import io.netty.channel.ChannelHandlerContext_Instrumentation; + +@Weave(originalName = "io.micronaut.http.server.netty.NettyHttpRequest") +public class NettyHttpRequest_Instrumentation { + + public ChannelHandlerContext_Instrumentation getChannelHandlerContext() { + return Weaver.callOriginal(); + } +} diff --git a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java index 7602e56d42..c480c65c07 100644 --- a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/RoutingInBoundHandler_Instrumentation.java @@ -9,37 +9,39 @@ import com.newrelic.api.agent.NewRelic; import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.TransactionNamePriority; +import com.newrelic.api.agent.Transaction; +import com.newrelic.api.agent.TransportType; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; + +import com.nr.agent.instrumentation.micronaut.netty_46.NettyExtendedRequest; +import com.nr.agent.instrumentation.micronaut.netty_46.NettyHeaders; import io.micronaut.http.body.CloseableByteBody; import io.micronaut.http.server.netty.handler.OutboundAccess; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpMethod; +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPipeline_Instrumentation; -@Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.RoutingInBoundHandler") +@Weave(originalName = "io.micronaut.http.server.netty.RoutingInBoundHandler", type = MatchType.ExactClass) public abstract class RoutingInBoundHandler_Instrumentation { - @Trace(dispatcher = true) - public void accept(ChannelHandlerContext ctx, io.netty.handler.codec.http.HttpRequest request, CloseableByteBody body, OutboundAccess outboundAccess) { - if(request != null) { - StringBuffer sb = new StringBuffer(); - HttpMethod method = request.method(); - if(method != null) { - sb.append(method.name()); - } else { - sb.append("UnknownMethod"); - } - sb.append(" - "); - String uri = request.uri(); - if(uri != null) { - sb.append(uri); - } else { - sb.append("UnknownURI"); + @Trace(async = true) + public void accept(ChannelHandlerContext_Instrumentation ctx, io.netty.handler.codec.http.HttpRequest request, CloseableByteBody body, + OutboundAccess outboundAccess) { + if(ctx != null) { + ChannelPipeline_Instrumentation pipeline = ctx.pipeline(); + if(pipeline != null) { + if(pipeline.micronautToken != null) { + pipeline.micronautToken.link(); + } } - NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW, false, "Micronaut-Netty", sb.toString()); } + Transaction transaction = NewRelic.getAgent().getTransaction(); + if(!transaction.isWebTransaction()) { + transaction.convertToWebTransaction(); + } + transaction.setWebRequest(new NettyExtendedRequest(request)); + transaction.acceptDistributedTraceHeaders(TransportType.HTTP, new NettyHeaders(request)); Weaver.callOriginal(); } } diff --git a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java index 12ae43bc6c..d19453a12c 100644 --- a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler_Instrumentation.java @@ -7,38 +7,67 @@ package io.micronaut.http.server.netty.handler; -import com.newrelic.api.agent.NewRelic; -import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.*; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import io.netty.channel.ChannelHandlerContext; +import com.nr.agent.instrumentation.micronaut.netty_46.NettyExtendedRequest; +import com.nr.agent.instrumentation.micronaut.netty_46.NettyHeaders; +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPipeline_Instrumentation; +import io.netty.handler.codec.http.HttpRequest; @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler") public abstract class PipeliningServerHandler_Instrumentation { - @Trace(dispatcher = true) - public void channelRead(ChannelHandlerContext ctx, Object msg) { + @Trace(async = true) + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) { + ChannelPipeline_Instrumentation pipeline = ctx != null ? ctx.pipeline() : null; + if(pipeline != null) { + if(pipeline.micronautToken != null) { + pipeline.micronautToken.link(); + } else { + Token token = NewRelic.getAgent().getTransaction().getToken(); + if(token != null) { + if(token.isActive()) { + pipeline.micronautToken = token; + } else { + token.expire(); + token = null; + } + } + } + } Weaver.callOriginal(); } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$MessageInboundHandler") - private static class MessageInboundHandler_Instrumentation { - - @Trace - void read(Object message) { - NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "HTTP", "Netty", "InboundHander", "MessageInboundHandler", "read"); - Weaver.callOriginal(); + public void channelReadComplete(ChannelHandlerContext_Instrumentation ctx) { + ChannelPipeline_Instrumentation pipeline = ctx != null ? ctx.pipeline() : null; + if(pipeline != null) { + if(pipeline.micronautToken != null) { + pipeline.micronautToken.expire(); + pipeline.micronautToken = null; + } } - + Weaver.callOriginal(); } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$DecompressingInboundHandler") - private static class DecompressingInboundHandler_Instrumentation { + @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$MessageInboundHandler") + private static class MessageInboundHandler_Instrumentation { - @Trace + @Trace(dispatcher = true) void read(Object message) { - NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "HTTP", "Netty", "InboundHander", "DecompressingInboundHandler", "read"); + NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "HTTP", "Netty", "InboundHandler", "MessageInboundHandler", "read"); + if(message instanceof HttpRequest) { + HttpRequest httpRequest = (HttpRequest) message; + NettyExtendedRequest nettyExtendedRequest = new NettyExtendedRequest(httpRequest); + NettyHeaders nettyHeaders = new NettyHeaders(httpRequest); + Transaction transaction = NewRelic.getAgent().getTransaction(); + transaction.acceptDistributedTraceHeaders(TransportType.HTTP, nettyHeaders); + transaction.setWebRequest(nettyExtendedRequest); + transaction.convertToWebTransaction(); + } + Weaver.callOriginal(); } @@ -113,9 +142,4 @@ void writeSome() { } } - @Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.handler.PipeliningServerHandler$OutboundAccessImpl") - public static class OutboundAccessImpl_Instrumentation { - - } - } diff --git a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java index b266e71d3f..5b0a82324f 100644 --- a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/handler/RequestHandler_Instrumentation.java @@ -1,37 +1,38 @@ package io.micronaut.http.server.netty.handler; import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Token; import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.TransactionNamePriority; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; import io.micronaut.http.body.CloseableByteBody; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpMethod; +import io.netty.channel.ChannelHandlerContext_Instrumentation; +import io.netty.channel.ChannelPipeline_Instrumentation; import io.netty.handler.codec.http.HttpRequest; @Weave(type = MatchType.Interface, originalName = "io.micronaut.http.server.netty.handler.RequestHandler") public abstract class RequestHandler_Instrumentation { @Trace - public void accept(ChannelHandlerContext ctx, HttpRequest request, CloseableByteBody body, OutboundAccess outboundAccess) { - - if(request != null) { - String uri = request.uri(); - NewRelic.getAgent().getTracedMethod().addCustomAttribute("URI", uri != null ? uri : "null"); - HttpMethod method = request.method(); - String methodName = null; - if(method != null) { - methodName = method.name(); - } - NewRelic.getAgent().getTracedMethod().addCustomAttribute("Method", methodName != null ? methodName : "null"); - if(uri != null && methodName != null) { - NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW, false, "Micronaut-Netty", methodName + " - " + uri); + public void accept(ChannelHandlerContext_Instrumentation ctx, HttpRequest request, CloseableByteBody body, OutboundAccess outboundAccess) { + if(ctx != null && ctx.pipeline() != null) { + ChannelPipeline_Instrumentation pipeline = ctx.pipeline(); + if(pipeline.micronautToken == null) { + Token token = NewRelic.getAgent().getTransaction().getToken(); + if(token != null) { + if(token.isActive()) { + pipeline.micronautToken = token; + } else { + token.expire(); + token = null; + } + } + } else { + pipeline.micronautToken.link(); } } - Weaver.callOriginal(); } diff --git a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketHandler_Instrumentation.java index 55fc63026d..4e094ea27c 100644 --- a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketHandler_Instrumentation.java +++ b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketHandler_Instrumentation.java @@ -13,7 +13,7 @@ import com.newrelic.api.agent.weaver.Weaver; import io.netty.channel.ChannelHandlerContext; -@Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.websocket.NettyServerWebSocketHandler") +@Weave(originalName = "io.micronaut.http.server.netty.websocket.NettyServerWebSocketHandler", type = MatchType.ExactClass) public abstract class NettyServerWebSocketHandler_Instrumentation { @Trace(dispatcher = true) diff --git a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketUpgradeHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketUpgradeHandler_Instrumentation.java deleted file mode 100644 index d3ad3631eb..0000000000 --- a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/micronaut/http/server/netty/websocket/NettyServerWebSocketUpgradeHandler_Instrumentation.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * - * * Copyright 2025 New Relic Corporation. All rights reserved. - * * SPDX-License-Identifier: Apache-2.0 - * - */ - -package io.micronaut.http.server.netty.websocket; - -import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.weaver.MatchType; -import com.newrelic.api.agent.weaver.Weave; -import com.newrelic.api.agent.weaver.Weaver; -import io.micronaut.http.body.CloseableByteBody; -import io.micronaut.http.server.netty.handler.OutboundAccess; -import io.netty.channel.ChannelHandlerContext; - -@Weave(type = MatchType.ExactClass, originalName = "io.micronaut.http.server.netty.websocket.NettyServerWebSocketUpgradeHandler") -public abstract class NettyServerWebSocketUpgradeHandler_Instrumentation { - - @Trace(dispatcher = true) - public void accept(ChannelHandlerContext ctx, io.netty.handler.codec.http.HttpRequest request, CloseableByteBody body, OutboundAccess outboundAccess) { - Weaver.callOriginal(); - } - -} diff --git a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java new file mode 100644 index 0000000000..8ec28602b2 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/netty/channel/ChannelHandlerContext_Instrumentation.java @@ -0,0 +1,10 @@ +package io.netty.channel; + +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; + +@Weave(type = MatchType.Interface, originalName = "io.netty.channel.ChannelHandlerContext") +public abstract class ChannelHandlerContext_Instrumentation { + + public abstract ChannelPipeline_Instrumentation pipeline(); +} diff --git a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java new file mode 100644 index 0000000000..e88dd5b1c4 --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/netty/channel/ChannelInboundHandler_Instrumentation.java @@ -0,0 +1,20 @@ +package io.netty.channel; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(type = MatchType.Interface, originalName = "io.netty.channel.ChannelInboundHandler") +public abstract class ChannelInboundHandler_Instrumentation { + + public void channelRead(ChannelHandlerContext_Instrumentation ctx, Object msg) throws Exception { + if(ctx.pipeline().micronautToken != null) { + ctx.pipeline().micronautToken.link(); + } + Weaver.callOriginal(); + } + +} diff --git a/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java new file mode 100644 index 0000000000..99fb24cdea --- /dev/null +++ b/instrumentation/micronaut-http-server-netty-4.6.0/src/main/java/io/netty/channel/ChannelPipeline_Instrumentation.java @@ -0,0 +1,14 @@ +package io.netty.channel; + +import com.newrelic.api.agent.Token; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.NewField; +import com.newrelic.api.agent.weaver.Weave; + +@Weave(type = MatchType.BaseClass, originalName = "io.netty.channel.ChannelPipeline") +public class ChannelPipeline_Instrumentation { + + @NewField + public Token micronautToken; + +} diff --git a/instrumentation/micronaut-router-1.0.0/src/main/java/io/micronaut/web/router/AbstractRouteMatch_Instrumentation.java b/instrumentation/micronaut-router-1.0.0/src/main/java/io/micronaut/web/router/AbstractRouteMatch_Instrumentation.java new file mode 100644 index 0000000000..ddeb51ca8d --- /dev/null +++ b/instrumentation/micronaut-router-1.0.0/src/main/java/io/micronaut/web/router/AbstractRouteMatch_Instrumentation.java @@ -0,0 +1,28 @@ +package io.micronaut.web.router; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.TransactionNamePriority; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import io.micronaut.http.HttpMethod; + +import java.util.Map; + +@Weave(originalName = "io.micronaut.web.router.AbstractRouteMatch", type = MatchType.BaseClass) +abstract class AbstractRouteMatch_Instrumentation { + + @Trace + public R execute(Map argumentValues) { + NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "Netty", "RouteMatch", getClass().getSimpleName(), "execute"); + if(this instanceof DefaultUriRouteMatch_Instrumentation) { + HttpMethod method = ((DefaultUriRouteMatch_Instrumentation) this).getHttpMethod(); + String methodName = method.name(); + String uri = ((DefaultUriRouteMatch_Instrumentation) this).getUri(); + NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_HIGH, true, "RouteMatch", methodName + " -" + uri); + } + return Weaver.callOriginal(); + } + +} diff --git a/instrumentation/micronaut-router-1.0.0/src/main/java/io/micronaut/web/router/DefaultUriRouteMatch_Instrumentation.java b/instrumentation/micronaut-router-1.0.0/src/main/java/io/micronaut/web/router/DefaultUriRouteMatch_Instrumentation.java new file mode 100644 index 0000000000..41f57071e9 --- /dev/null +++ b/instrumentation/micronaut-router-1.0.0/src/main/java/io/micronaut/web/router/DefaultUriRouteMatch_Instrumentation.java @@ -0,0 +1,11 @@ +package io.micronaut.web.router; + +import com.newrelic.api.agent.weaver.Weave; +import io.micronaut.http.HttpMethod; + +@Weave(originalName = "io.micronaut.web.router.DefaultUriRouteMatch") +abstract class DefaultUriRouteMatch_Instrumentation extends AbstractRouteMatch_Instrumentation { + + public abstract String getUri(); + public abstract HttpMethod getHttpMethod(); +} diff --git a/instrumentation/micronaut-router-1.0.0/src/main/java/io/micronaut/web/router/RouteMatch_instrumentation.java b/instrumentation/micronaut-router-1.0.0/src/main/java/io/micronaut/web/router/RouteMatch_instrumentation.java deleted file mode 100644 index 7db78e39f0..0000000000 --- a/instrumentation/micronaut-router-1.0.0/src/main/java/io/micronaut/web/router/RouteMatch_instrumentation.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.micronaut.web.router; - -import java.util.Map; - -import com.newrelic.api.agent.NewRelic; -import com.newrelic.api.agent.Trace; -import com.newrelic.api.agent.weaver.MatchType; -import com.newrelic.api.agent.weaver.Weave; -import com.newrelic.api.agent.weaver.Weaver; - -@Weave(originalName = "io.micronaut.web.router.RouteMatch", type = MatchType.Interface) -public abstract class RouteMatch_instrumentation { - - @Trace - public R execute(Map argumentValues) { - NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "Netty", "RouteMatch", getClass().getSimpleName(), "execute"); - return Weaver.callOriginal(); - } -} diff --git a/instrumentation/micronaut-router-4.0.0/src/main/java/io/micronaut/web/router/RouteMatch_instrumentation.java b/instrumentation/micronaut-router-4.0.0/src/main/java/io/micronaut/web/router/RouteMatch_instrumentation.java index 0f6e76e10b..f8080d788f 100644 --- a/instrumentation/micronaut-router-4.0.0/src/main/java/io/micronaut/web/router/RouteMatch_instrumentation.java +++ b/instrumentation/micronaut-router-4.0.0/src/main/java/io/micronaut/web/router/RouteMatch_instrumentation.java @@ -2,16 +2,42 @@ import com.newrelic.api.agent.NewRelic; import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.Transaction; +import com.newrelic.api.agent.TransactionNamePriority; import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; +import io.micronaut.http.uri.UriMatchTemplate; @Weave(originalName = "io.micronaut.web.router.RouteMatch", type = MatchType.Interface) public abstract class RouteMatch_instrumentation { - @Trace + + public abstract RouteInfo getRouteInfo(); + + @Trace(dispatcher = true) public R execute() { + Transaction txn = NewRelic.getAgent().getTransaction(); + if(txn != null) { + if(!txn.isWebTransaction()) { + txn.convertToWebTransaction(); + } + } NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "Netty", "RouteMatch", getClass().getSimpleName(), "execute"); + RouteInfo routeInfo = getRouteInfo(); + if (routeInfo != null) { + if(routeInfo instanceof UriRouteInfo) { + UriRouteInfo uriRouteInfo = (UriRouteInfo) routeInfo; + String httpMethod = uriRouteInfo.getHttpMethodName(); + UriMatchTemplate uriTemplate = uriRouteInfo.getUriMatchTemplate(); + NewRelic.getAgent().getTracedMethod().addCustomAttribute("httpMethod", httpMethod); + if(uriTemplate != null) { + NewRelic.getAgent().getTracedMethod().addCustomAttribute("URITemplate", uriTemplate.toString()); + NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_HIGH,true,"RouteMatch", httpMethod + " - " + uriTemplate.toString()); + } + + } + } return Weaver.callOriginal(); } } diff --git a/settings.gradle b/settings.gradle index 78c7379b2f..61d80e6fae 100644 --- a/settings.gradle +++ b/settings.gradle @@ -290,6 +290,8 @@ include 'instrumentation:micronaut-http-server-netty-4.6.0' include 'instrumentation:micronaut-http-1.3.0' include 'instrumentation:micronaut-http-client-2.0.0' include 'instrumentation:micronaut-http-client-3.0.4' +include 'instrumentation:micronaut-http-client-3.5.0' +include 'instrumentation:micronaut-http-client-4.0.0' include 'instrumentation:micronaut-router-1.0.0' include 'instrumentation:micronaut-router-4.0.0' include 'instrumentation:mongodb-async-3.4'