diff --git a/instrumentation/micronaut-core-1.0.0/build.gradle b/instrumentation/micronaut-core-1.0.0/build.gradle new file mode 100644 index 0000000000..0709e3fb5c --- /dev/null +++ b/instrumentation/micronaut-core-1.0.0/build.gradle @@ -0,0 +1,19 @@ +dependencies { + implementation(project(":agent-bridge")) + implementation("io.micronaut:micronaut-core:2.4.0") +} + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.micronaut-core-1.0.0', + 'Implementation-Title-Alias': 'micronaut-core' } +} + +verifyInstrumentation { + passesOnly('io.micronaut:micronaut-core:[1.0.0,4.0.0)') + excludeRegex 'io.micronaut:micronaut-core:.*(RC|M)[0-9]*$' +} + +site { + title 'Micronaut' + type 'Framework' +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-1.0.0/src/main/java/io/micronaut/core/bind/BoundExecutable_Instrumentation.java b/instrumentation/micronaut-core-1.0.0/src/main/java/io/micronaut/core/bind/BoundExecutable_Instrumentation.java new file mode 100644 index 0000000000..5c293c44c0 --- /dev/null +++ b/instrumentation/micronaut-core-1.0.0/src/main/java/io/micronaut/core/bind/BoundExecutable_Instrumentation.java @@ -0,0 +1,27 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package io.micronaut.core.bind; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.TracedMethod; +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.core.bind.BoundExecutable", type = MatchType.Interface) +public abstract class BoundExecutable_Instrumentation { + + @Trace + public R invoke(T instance) { + TracedMethod traced = NewRelic.getAgent().getTracedMethod(); + traced.setMetricName("Micronaut", "BoundExecutable", getClass().getSimpleName(), "invoke"); + traced.addCustomAttribute("Instance", instance.getClass().getName()); + return Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-1.0.0/src/main/java/io/micronaut/core/type/Executable_Instrumentation.java b/instrumentation/micronaut-core-1.0.0/src/main/java/io/micronaut/core/type/Executable_Instrumentation.java new file mode 100644 index 0000000000..f77f10109f --- /dev/null +++ b/instrumentation/micronaut-core-1.0.0/src/main/java/io/micronaut/core/type/Executable_Instrumentation.java @@ -0,0 +1,27 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package io.micronaut.core.type; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.TracedMethod; +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.core.type.Executable", type = MatchType.Interface) +public abstract class Executable_Instrumentation { + + @Trace + public R invoke(T instance, Object... arguments) { + TracedMethod traced = NewRelic.getAgent().getTracedMethod(); + traced.setMetricName("Micronaut", "Executable", getClass().getSimpleName(), "invoke"); + traced.addCustomAttribute("Instance", instance.getClass().getName()); + return Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-1.0.0/src/main/java/io/micronaut/core/type/UnsafeExecutable_Skip.java b/instrumentation/micronaut-core-1.0.0/src/main/java/io/micronaut/core/type/UnsafeExecutable_Skip.java new file mode 100644 index 0000000000..42120b4a7b --- /dev/null +++ b/instrumentation/micronaut-core-1.0.0/src/main/java/io/micronaut/core/type/UnsafeExecutable_Skip.java @@ -0,0 +1,14 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package io.micronaut.core.type; + +import com.newrelic.api.agent.weaver.SkipIfPresent; + +@SkipIfPresent(originalName = "io.micronaut.core.type.UnsafeExecutable") +public class UnsafeExecutable_Skip { +} diff --git a/instrumentation/micronaut-core-4.0.0/build.gradle b/instrumentation/micronaut-core-4.0.0/build.gradle new file mode 100644 index 0000000000..0d27dbdb3d --- /dev/null +++ b/instrumentation/micronaut-core-4.0.0/build.gradle @@ -0,0 +1,32 @@ +dependencies { + implementation(project(":agent-bridge")) + implementation("io.micronaut:micronaut-core:4.0.0") +} + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.micronaut-core-4.0.0', + 'Implementation-Title-Alias': 'micronaut-core' } +} + +verifyInstrumentation { + passesOnly('io.micronaut:micronaut-core:[4.0.0,4.3.0)') + excludeRegex 'io.micronaut:micronaut-core:.*(RC|M)[0-9]*$' +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +test { + // These instrumentation tests only run on Java 17+ regardless of the -PtestN gradle property that is set. + onlyIf { + !project.hasProperty('test8') && !project.hasProperty('test11') + } +} + +site { + title 'Micronaut' + type 'Framework' +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-4.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRBiConsumerWrapper.java b/instrumentation/micronaut-core-4.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRBiConsumerWrapper.java new file mode 100644 index 0000000000..4c1145b8ee --- /dev/null +++ b/instrumentation/micronaut-core-4.0.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRBiConsumerWrapper.java @@ -0,0 +1,30 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package com.nr.agent.instrumentation.micronaut; + +import java.util.function.BiConsumer; + +import com.newrelic.api.agent.NewRelic; + +public class NRBiConsumerWrapper implements BiConsumer { + BiConsumer delegate = null; + + public NRBiConsumerWrapper(BiConsumer d) { + delegate = d; + } + + @Override + 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/beans/AbstractBeanMethod_Instrumentation.java b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/beans/AbstractBeanMethod_Instrumentation.java new file mode 100644 index 0000000000..9040aa357b --- /dev/null +++ b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/beans/AbstractBeanMethod_Instrumentation.java @@ -0,0 +1,26 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package io.micronaut.core.beans; + +import com.newrelic.api.agent.NewRelic; +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.core.beans.AbstractBeanMethod", type = MatchType.BaseClass) +public abstract class AbstractBeanMethod_Instrumentation { + + public abstract String getName(); + + protected T invokeInternal(B instance, Object... arguments) { + NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "AbstractBeanMethod", getClass().getSimpleName(), "invoke"); + NewRelic.getAgent().getTracedMethod().addCustomAttribute("Instance", instance.getClass().getName()); + NewRelic.getAgent().getTracedMethod().addCustomAttribute("Name", getName()); + return Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/bind/BoundExecutable_Instrumentation.java b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/bind/BoundExecutable_Instrumentation.java new file mode 100644 index 0000000000..299491286f --- /dev/null +++ b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/bind/BoundExecutable_Instrumentation.java @@ -0,0 +1,20 @@ +package io.micronaut.core.bind; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.TracedMethod; +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.core.bind.BoundExecutable", type = MatchType.Interface) +public abstract class BoundExecutable_Instrumentation { + + @Trace + public R invoke(T instance) { + TracedMethod traced = NewRelic.getAgent().getTracedMethod(); + traced.setMetricName("Micronaut", "BoundExecutable", getClass().getSimpleName(), "invoke"); + traced.addCustomAttribute("Instance", instance.getClass().getName()); + return Weaver.callOriginal(); + } +} \ 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 new file mode 100644 index 0000000000..7d9f76e69e --- /dev/null +++ b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/execution/CompletableFutureExecutionFlowImpl_Instrumentation.java @@ -0,0 +1,45 @@ +/* + * + * * 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 new file mode 100644 index 0000000000..0899e330f9 --- /dev/null +++ b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/execution/DelayedExecutionFlowImpl_Instrumentation.java @@ -0,0 +1,47 @@ +/* + * + * * 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/ImperativeExecutionFlowImpl_Instrumentation.java b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/execution/ImperativeExecutionFlowImpl_Instrumentation.java new file mode 100644 index 0000000000..2dda07e37c --- /dev/null +++ b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/execution/ImperativeExecutionFlowImpl_Instrumentation.java @@ -0,0 +1,45 @@ +/* + * + * * 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/type/Executable_Instrumentation.java b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/type/Executable_Instrumentation.java new file mode 100644 index 0000000000..f77f10109f --- /dev/null +++ b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/type/Executable_Instrumentation.java @@ -0,0 +1,27 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package io.micronaut.core.type; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.TracedMethod; +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.core.type.Executable", type = MatchType.Interface) +public abstract class Executable_Instrumentation { + + @Trace + public R invoke(T instance, Object... arguments) { + TracedMethod traced = NewRelic.getAgent().getTracedMethod(); + traced.setMetricName("Micronaut", "Executable", getClass().getSimpleName(), "invoke"); + traced.addCustomAttribute("Instance", instance.getClass().getName()); + return Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/type/UnsafeExecutable_Instrumentation.java b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/type/UnsafeExecutable_Instrumentation.java new file mode 100644 index 0000000000..1e2fc6d808 --- /dev/null +++ b/instrumentation/micronaut-core-4.0.0/src/main/java/io/micronaut/core/type/UnsafeExecutable_Instrumentation.java @@ -0,0 +1,23 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package io.micronaut.core.type; + +import com.newrelic.api.agent.NewRelic; +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.core.type.UnsafeExecutable", type = MatchType.Interface) +public abstract class UnsafeExecutable_Instrumentation { + + public R invokeUnsafe(T instance, Object... arguments) { + NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "UnsafeExecutable", getClass().getSimpleName(),"invoke"); + NewRelic.getAgent().getTracedMethod().addCustomAttribute("Instance", instance.getClass().getName()); + return Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-4.3.0/build.gradle b/instrumentation/micronaut-core-4.3.0/build.gradle new file mode 100644 index 0000000000..32c30f7eac --- /dev/null +++ b/instrumentation/micronaut-core-4.3.0/build.gradle @@ -0,0 +1,32 @@ +dependencies { + implementation(project(":agent-bridge")) + implementation("io.micronaut:micronaut-core:4.3.0") +} + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.micronaut-core-4.3.0', + 'Implementation-Title-Alias': 'micronaut-core' } +} + +verifyInstrumentation { + passesOnly('io.micronaut:micronaut-core:[4.3.0,)') + excludeRegex 'io.micronaut:micronaut-core:.*(RC|M)[0-9]*$' +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +test { + // These instrumentation tests only run on Java 17+ regardless of the -PtestN gradle property that is set. + onlyIf { + !project.hasProperty('test8') && !project.hasProperty('test11') + } +} + +site { + title 'Micronaut' + type 'Framework' +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-4.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRBiConsumerWrapper.java b/instrumentation/micronaut-core-4.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRBiConsumerWrapper.java new file mode 100644 index 0000000000..4c1145b8ee --- /dev/null +++ b/instrumentation/micronaut-core-4.3.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRBiConsumerWrapper.java @@ -0,0 +1,30 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package com.nr.agent.instrumentation.micronaut; + +import java.util.function.BiConsumer; + +import com.newrelic.api.agent.NewRelic; + +public class NRBiConsumerWrapper implements BiConsumer { + BiConsumer delegate = null; + + public NRBiConsumerWrapper(BiConsumer d) { + delegate = d; + } + + @Override + 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/annotation/Generated_Instrumentation.java b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/annotation/Generated_Instrumentation.java new file mode 100644 index 0000000000..a4620ebcf0 --- /dev/null +++ b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/annotation/Generated_Instrumentation.java @@ -0,0 +1,20 @@ +package io.micronaut.core.annotation; + +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.WeaveIntoAllMethods; +import com.newrelic.api.agent.weaver.WeaveWithAnnotation; + +@WeaveWithAnnotation(annotationClasses = {"io.micronaut.core.annotation.Generated"}, type = MatchType.Interface) +public abstract class Generated_Instrumentation { + + @WeaveWithAnnotation(annotationClasses = {"io.micronaut.core.annotation.Generated"}) + @WeaveIntoAllMethods + @Trace + private static void instrumentation() { + StackTraceElement[] traces = Thread.currentThread().getStackTrace(); + StackTraceElement firstElement = traces[1]; + NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "Generated", firstElement.getMethodName(), firstElement.getMethodName()); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/beans/AbstractBeanMethod_Instrumentation.java b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/beans/AbstractBeanMethod_Instrumentation.java new file mode 100644 index 0000000000..9040aa357b --- /dev/null +++ b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/beans/AbstractBeanMethod_Instrumentation.java @@ -0,0 +1,26 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package io.micronaut.core.beans; + +import com.newrelic.api.agent.NewRelic; +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.core.beans.AbstractBeanMethod", type = MatchType.BaseClass) +public abstract class AbstractBeanMethod_Instrumentation { + + public abstract String getName(); + + protected T invokeInternal(B instance, Object... arguments) { + NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "AbstractBeanMethod", getClass().getSimpleName(), "invoke"); + NewRelic.getAgent().getTracedMethod().addCustomAttribute("Instance", instance.getClass().getName()); + NewRelic.getAgent().getTracedMethod().addCustomAttribute("Name", getName()); + return Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/bind/BoundExecutable_Instrumentation.java b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/bind/BoundExecutable_Instrumentation.java new file mode 100644 index 0000000000..299491286f --- /dev/null +++ b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/bind/BoundExecutable_Instrumentation.java @@ -0,0 +1,20 @@ +package io.micronaut.core.bind; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.TracedMethod; +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.core.bind.BoundExecutable", type = MatchType.Interface) +public abstract class BoundExecutable_Instrumentation { + + @Trace + public R invoke(T instance) { + TracedMethod traced = NewRelic.getAgent().getTracedMethod(); + traced.setMetricName("Micronaut", "BoundExecutable", getClass().getSimpleName(), "invoke"); + traced.addCustomAttribute("Instance", instance.getClass().getName()); + return Weaver.callOriginal(); + } +} \ 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 new file mode 100644 index 0000000000..6f52262699 --- /dev/null +++ b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/execution/CompletableFutureExecutionFlowImpl_Instrumentation.java @@ -0,0 +1,45 @@ +/* + * + * * 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 new file mode 100644 index 0000000000..0899e330f9 --- /dev/null +++ b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/execution/DelayedExecutionFlowImpl_Instrumentation.java @@ -0,0 +1,47 @@ +/* + * + * * 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/ImperativeExecutionFlowImpl_Instrumentation.java b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/execution/ImperativeExecutionFlowImpl_Instrumentation.java new file mode 100644 index 0000000000..2dda07e37c --- /dev/null +++ b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/execution/ImperativeExecutionFlowImpl_Instrumentation.java @@ -0,0 +1,45 @@ +/* + * + * * 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/Executable_Instrumentation.java b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/type/Executable_Instrumentation.java new file mode 100644 index 0000000000..f77f10109f --- /dev/null +++ b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/type/Executable_Instrumentation.java @@ -0,0 +1,27 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package io.micronaut.core.type; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.TracedMethod; +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.core.type.Executable", type = MatchType.Interface) +public abstract class Executable_Instrumentation { + + @Trace + public R invoke(T instance, Object... arguments) { + TracedMethod traced = NewRelic.getAgent().getTracedMethod(); + traced.setMetricName("Micronaut", "Executable", getClass().getSimpleName(), "invoke"); + traced.addCustomAttribute("Instance", instance.getClass().getName()); + return 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 new file mode 100644 index 0000000000..1e2fc6d808 --- /dev/null +++ b/instrumentation/micronaut-core-4.3.0/src/main/java/io/micronaut/core/type/UnsafeExecutable_Instrumentation.java @@ -0,0 +1,23 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package io.micronaut.core.type; + +import com.newrelic.api.agent.NewRelic; +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.core.type.UnsafeExecutable", type = MatchType.Interface) +public abstract class UnsafeExecutable_Instrumentation { + + public R invokeUnsafe(T instance, Object... arguments) { + NewRelic.getAgent().getTracedMethod().setMetricName("Micronaut", "UnsafeExecutable", getClass().getSimpleName(),"invoke"); + NewRelic.getAgent().getTracedMethod().addCustomAttribute("Instance", instance.getClass().getName()); + return Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-reactive-2.4.0/build.gradle b/instrumentation/micronaut-core-reactive-2.4.0/build.gradle new file mode 100644 index 0000000000..65aa620383 --- /dev/null +++ b/instrumentation/micronaut-core-reactive-2.4.0/build.gradle @@ -0,0 +1,19 @@ +dependencies { + implementation(project(":agent-bridge")) + implementation("io.micronaut:micronaut-core-reactive:2.4.0") +} + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.micronaut-core-reactive-2.4.0', + 'Implementation-Title-Alias': 'micronaut-core-reactive' } +} + +verifyInstrumentation { + passesOnly('io.micronaut:micronaut-core-reactive:[2.4.0,3.2.0)') + excludeRegex 'io.micronaut:micronaut-core-reactive:.*(RC|M)[0-9]*$' +} + +site { + title 'Micronaut' + type 'Framework' +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRSubscriber.java b/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRSubscriber.java new file mode 100644 index 0000000000..17661f5fbe --- /dev/null +++ b/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRSubscriber.java @@ -0,0 +1,68 @@ +/* + * + * * 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 org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class NRSubscriber implements Subscriber { + private Subscriber delegate = null; + private Token token = null; + private static final AtomicBoolean isTransformed = new AtomicBoolean(false); + + public NRSubscriber(Subscriber d) { + delegate = d; + if(!isTransformed.getAndSet(true)) { + AgentBridge.instrumentation.retransformUninstrumentedClass(getClass()); + } + } + + @Override + public void onSubscribe(Subscription s) { + delegate.onSubscribe(s); + Token t = NewRelic.getAgent().getTransaction().getToken(); + if (t != null) { + token = t; + } + } + + @Override + @Trace(async = true) + public void onNext(T t) { + if (token != null) { + token.link(); + } + delegate.onNext(t); + } + + @Override + @Trace(async = true) + public void onError(Throwable t) { + NewRelic.noticeError(t); + if (token != null) { + token.linkAndExpire(); + token = null; + } + delegate.onError(t); + } + + @Override + @Trace(async = true) + public void onComplete() { + if (token != null) { + token.linkAndExpire(); + token = null; + } + delegate.onComplete(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/io/micronaut/core/async/publisher/AsyncSingleResultPublisher_Instrumentation.java b/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/io/micronaut/core/async/publisher/AsyncSingleResultPublisher_Instrumentation.java new file mode 100644 index 0000000000..68a5deacc9 --- /dev/null +++ b/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/io/micronaut/core/async/publisher/AsyncSingleResultPublisher_Instrumentation.java @@ -0,0 +1,27 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ +package io.micronaut.core.async.publisher; + +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.NRSubscriber; +import io.micronaut.core.async.subscriber.SingleThreadedBufferingSubscriber; +import org.reactivestreams.Subscriber; + +@Weave(originalName = "io.micronaut.core.async.publisher.AsyncSingleResultPublisher", type = MatchType.ExactClass) +public abstract class AsyncSingleResultPublisher_Instrumentation { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void subscribe(Subscriber subscriber) { + if (!(subscriber instanceof NRSubscriber) && !(subscriber instanceof CompletableFuturePublisher) && !(subscriber instanceof SingleThreadedBufferingSubscriber)) { + subscriber = new NRSubscriber(subscriber); + } + + Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/io/micronaut/core/async/publisher/CompletableFuturePublisher_Instrumentation.java b/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/io/micronaut/core/async/publisher/CompletableFuturePublisher_Instrumentation.java new file mode 100644 index 0000000000..46fb4cf180 --- /dev/null +++ b/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/io/micronaut/core/async/publisher/CompletableFuturePublisher_Instrumentation.java @@ -0,0 +1,26 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ +package io.micronaut.core.async.publisher; + +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.NRSubscriber; +import org.reactivestreams.Subscriber; + +@Weave(originalName = "io.micronaut.core.async.publisher.CompletableFuturePublisher", type = MatchType.ExactClass) +class CompletableFuturePublisher_Instrumentation { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void subscribe(Subscriber subscriber) { + if (!(subscriber instanceof NRSubscriber)) { + subscriber = new NRSubscriber(subscriber); + } + + Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/io/micronaut/core/async/publisher/SingleSubscriberPublisher_Instrumentation.java b/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/io/micronaut/core/async/publisher/SingleSubscriberPublisher_Instrumentation.java new file mode 100644 index 0000000000..2193d19314 --- /dev/null +++ b/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/io/micronaut/core/async/publisher/SingleSubscriberPublisher_Instrumentation.java @@ -0,0 +1,26 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ +package io.micronaut.core.async.publisher; + +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.NRSubscriber; +import org.reactivestreams.Subscriber; + +@Weave(originalName = "io.micronaut.core.async.publisher.SingleSubscriberPublisher", type = MatchType.BaseClass) +public abstract class SingleSubscriberPublisher_Instrumentation { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected void doSubscribe(Subscriber subscriber) { + if (!(subscriber instanceof NRSubscriber)) { + subscriber = new NRSubscriber(subscriber); + } + + Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/io/micronaut/core/async/subscriber/CompletionAwareSubscriber_Instrumentation.java b/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/io/micronaut/core/async/subscriber/CompletionAwareSubscriber_Instrumentation.java new file mode 100644 index 0000000000..fb072ba50f --- /dev/null +++ b/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/io/micronaut/core/async/subscriber/CompletionAwareSubscriber_Instrumentation.java @@ -0,0 +1,67 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ +package io.micronaut.core.async.subscriber; + +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 org.reactivestreams.Subscription; + +@Weave(originalName = "io.micronaut.core.async.subscriber.CompletionAwareSubscriber", type = MatchType.BaseClass) +public abstract class CompletionAwareSubscriber_Instrumentation { + @NewField + public Token token = null; + + public void onSubscribe(Subscription s) { + if (token == null) { + Token t = NewRelic.getAgent().getTransaction().getToken(); + if (t != null && t.isActive()) { + token = t; + } else if (t != null) { + t.expire(); + t = null; + } + } + + Weaver.callOriginal(); + } + + @Trace(async = true) + protected void doOnNext(T t) { + if (token != null) { + token.link(); + } + + Weaver.callOriginal(); + } + + @Trace(async = true) + protected void doOnComplete() { + if (token != null) { + token.linkAndExpire(); + token = null; + } + + Weaver.callOriginal(); + } + + @Trace(async = true) + protected void doOnError(Throwable throwable) { + NewRelic.noticeError(throwable); + + if (token != null) { + token.linkAndExpire(); + token = null; + } + + Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/io/micronaut/core/async/subscriber/SingleThreadedBufferingSubscriber_Instrumentation.java b/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/io/micronaut/core/async/subscriber/SingleThreadedBufferingSubscriber_Instrumentation.java new file mode 100644 index 0000000000..32e79f7c2f --- /dev/null +++ b/instrumentation/micronaut-core-reactive-2.4.0/src/main/java/io/micronaut/core/async/subscriber/SingleThreadedBufferingSubscriber_Instrumentation.java @@ -0,0 +1,66 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ +package io.micronaut.core.async.subscriber; + +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 org.reactivestreams.Subscription; + +@Weave(originalName = "io.micronaut.core.async.subscriber.SingleThreadedBufferingSubscriber", type = MatchType.BaseClass) +public abstract class SingleThreadedBufferingSubscriber_Instrumentation { + @NewField + public Token token = null; + + public void onSubscribe(Subscription subscription) { + if (token != null) { + Token t = NewRelic.getAgent().getTransaction().getToken(); + if (t != null && t.isActive()) { + token = t; + } else if (t != null) { + t.expire(); + t = null; + } + } + + Weaver.callOriginal(); + } + + @Trace(async = true) + protected void doOnNext(T message) { + if (token != null) { + token.link(); + } + + Weaver.callOriginal(); + } + + @Trace(async = true) + protected void doOnError(Throwable t) { + NewRelic.noticeError(t); + if (token != null) { + token.linkAndExpire(); + token = null; + } + + Weaver.callOriginal(); + } + + @Trace(async = true) + protected void doOnComplete() { + if (token != null) { + token.linkAndExpire(); + token = null; + } + + Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-reactive-3.2.0/build.gradle b/instrumentation/micronaut-core-reactive-3.2.0/build.gradle new file mode 100644 index 0000000000..f07d2c0933 --- /dev/null +++ b/instrumentation/micronaut-core-reactive-3.2.0/build.gradle @@ -0,0 +1,19 @@ +dependencies { + implementation(project(":agent-bridge")) + implementation("io.micronaut:micronaut-core-reactive:3.2.0") +} + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.micronaut-core-reactive-3.2.0', + 'Implementation-Title-Alias': 'micronaut-core-reactive' } +} + +verifyInstrumentation { + passesOnly('io.micronaut:micronaut-core-reactive:[3.2.0,)') + excludeRegex 'io.micronaut:micronaut-core-reactive:.*(RC|M)[0-9]*$' +} + +site { + title 'Micronaut' + type 'Framework' +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRSubscriber.java b/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRSubscriber.java new file mode 100644 index 0000000000..17661f5fbe --- /dev/null +++ b/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/com/nr/agent/instrumentation/micronaut/NRSubscriber.java @@ -0,0 +1,68 @@ +/* + * + * * 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 org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class NRSubscriber implements Subscriber { + private Subscriber delegate = null; + private Token token = null; + private static final AtomicBoolean isTransformed = new AtomicBoolean(false); + + public NRSubscriber(Subscriber d) { + delegate = d; + if(!isTransformed.getAndSet(true)) { + AgentBridge.instrumentation.retransformUninstrumentedClass(getClass()); + } + } + + @Override + public void onSubscribe(Subscription s) { + delegate.onSubscribe(s); + Token t = NewRelic.getAgent().getTransaction().getToken(); + if (t != null) { + token = t; + } + } + + @Override + @Trace(async = true) + public void onNext(T t) { + if (token != null) { + token.link(); + } + delegate.onNext(t); + } + + @Override + @Trace(async = true) + public void onError(Throwable t) { + NewRelic.noticeError(t); + if (token != null) { + token.linkAndExpire(); + token = null; + } + delegate.onError(t); + } + + @Override + @Trace(async = true) + public void onComplete() { + if (token != null) { + token.linkAndExpire(); + token = null; + } + delegate.onComplete(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/io/micronaut/core/async/publisher/AsyncSingleResultPublisher_Instrumentation.java b/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/io/micronaut/core/async/publisher/AsyncSingleResultPublisher_Instrumentation.java new file mode 100644 index 0000000000..68a5deacc9 --- /dev/null +++ b/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/io/micronaut/core/async/publisher/AsyncSingleResultPublisher_Instrumentation.java @@ -0,0 +1,27 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ +package io.micronaut.core.async.publisher; + +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.NRSubscriber; +import io.micronaut.core.async.subscriber.SingleThreadedBufferingSubscriber; +import org.reactivestreams.Subscriber; + +@Weave(originalName = "io.micronaut.core.async.publisher.AsyncSingleResultPublisher", type = MatchType.ExactClass) +public abstract class AsyncSingleResultPublisher_Instrumentation { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void subscribe(Subscriber subscriber) { + if (!(subscriber instanceof NRSubscriber) && !(subscriber instanceof CompletableFuturePublisher) && !(subscriber instanceof SingleThreadedBufferingSubscriber)) { + subscriber = new NRSubscriber(subscriber); + } + + Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/io/micronaut/core/async/publisher/CompletableFuturePublisher_Instrumentation.java b/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/io/micronaut/core/async/publisher/CompletableFuturePublisher_Instrumentation.java new file mode 100644 index 0000000000..6161de2781 --- /dev/null +++ b/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/io/micronaut/core/async/publisher/CompletableFuturePublisher_Instrumentation.java @@ -0,0 +1,26 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ +package io.micronaut.core.async.publisher; + +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.NRSubscriber; +import org.reactivestreams.Subscriber; + +@Weave(originalName = "io.micronaut.core.async.publisher.CompletableFuturePublisher", type = MatchType.ExactClass) +public class CompletableFuturePublisher_Instrumentation { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void subscribe(Subscriber subscriber) { + if (!(subscriber instanceof NRSubscriber)) { + subscriber = new NRSubscriber(subscriber); + } + + Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/io/micronaut/core/async/publisher/SingleSubscriberPublisher_Instrumentation.java b/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/io/micronaut/core/async/publisher/SingleSubscriberPublisher_Instrumentation.java new file mode 100644 index 0000000000..2193d19314 --- /dev/null +++ b/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/io/micronaut/core/async/publisher/SingleSubscriberPublisher_Instrumentation.java @@ -0,0 +1,26 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ +package io.micronaut.core.async.publisher; + +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.NRSubscriber; +import org.reactivestreams.Subscriber; + +@Weave(originalName = "io.micronaut.core.async.publisher.SingleSubscriberPublisher", type = MatchType.BaseClass) +public abstract class SingleSubscriberPublisher_Instrumentation { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected void doSubscribe(Subscriber subscriber) { + if (!(subscriber instanceof NRSubscriber)) { + subscriber = new NRSubscriber(subscriber); + } + + Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/io/micronaut/core/async/subscriber/CompletionAwareSubscriber_Instrumentation.java b/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/io/micronaut/core/async/subscriber/CompletionAwareSubscriber_Instrumentation.java new file mode 100644 index 0000000000..fb072ba50f --- /dev/null +++ b/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/io/micronaut/core/async/subscriber/CompletionAwareSubscriber_Instrumentation.java @@ -0,0 +1,67 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ +package io.micronaut.core.async.subscriber; + +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 org.reactivestreams.Subscription; + +@Weave(originalName = "io.micronaut.core.async.subscriber.CompletionAwareSubscriber", type = MatchType.BaseClass) +public abstract class CompletionAwareSubscriber_Instrumentation { + @NewField + public Token token = null; + + public void onSubscribe(Subscription s) { + if (token == null) { + Token t = NewRelic.getAgent().getTransaction().getToken(); + if (t != null && t.isActive()) { + token = t; + } else if (t != null) { + t.expire(); + t = null; + } + } + + Weaver.callOriginal(); + } + + @Trace(async = true) + protected void doOnNext(T t) { + if (token != null) { + token.link(); + } + + Weaver.callOriginal(); + } + + @Trace(async = true) + protected void doOnComplete() { + if (token != null) { + token.linkAndExpire(); + token = null; + } + + Weaver.callOriginal(); + } + + @Trace(async = true) + protected void doOnError(Throwable throwable) { + NewRelic.noticeError(throwable); + + if (token != null) { + token.linkAndExpire(); + token = null; + } + + Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/io/micronaut/core/async/subscriber/SingleThreadedBufferingSubscriber_Instrumentation.java b/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/io/micronaut/core/async/subscriber/SingleThreadedBufferingSubscriber_Instrumentation.java new file mode 100644 index 0000000000..32e79f7c2f --- /dev/null +++ b/instrumentation/micronaut-core-reactive-3.2.0/src/main/java/io/micronaut/core/async/subscriber/SingleThreadedBufferingSubscriber_Instrumentation.java @@ -0,0 +1,66 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ +package io.micronaut.core.async.subscriber; + +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 org.reactivestreams.Subscription; + +@Weave(originalName = "io.micronaut.core.async.subscriber.SingleThreadedBufferingSubscriber", type = MatchType.BaseClass) +public abstract class SingleThreadedBufferingSubscriber_Instrumentation { + @NewField + public Token token = null; + + public void onSubscribe(Subscription subscription) { + if (token != null) { + Token t = NewRelic.getAgent().getTransaction().getToken(); + if (t != null && t.isActive()) { + token = t; + } else if (t != null) { + t.expire(); + t = null; + } + } + + Weaver.callOriginal(); + } + + @Trace(async = true) + protected void doOnNext(T message) { + if (token != null) { + token.link(); + } + + Weaver.callOriginal(); + } + + @Trace(async = true) + protected void doOnError(Throwable t) { + NewRelic.noticeError(t); + if (token != null) { + token.linkAndExpire(); + token = null; + } + + Weaver.callOriginal(); + } + + @Trace(async = true) + protected void doOnComplete() { + if (token != null) { + token.linkAndExpire(); + token = null; + } + + Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-inject/build.gradle b/instrumentation/micronaut-inject/build.gradle new file mode 100644 index 0000000000..157c02b17c --- /dev/null +++ b/instrumentation/micronaut-inject/build.gradle @@ -0,0 +1,19 @@ +dependencies { + implementation(project(":agent-bridge")) + implementation("io.micronaut:micronaut-inject:1.0.0") +} + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.micronaut-inject', + 'Implementation-Title-Alias': 'micronaut-inject' } +} + +verifyInstrumentation { + passesOnly('io.micronaut:micronaut-inject:[1.0.0,)') + excludeRegex 'io.micronaut:micronaut-inject:.*(RC|M)[0-9]*$' +} + +site { + title 'Micronaut' + type 'Framework' +} \ No newline at end of file diff --git a/instrumentation/micronaut-inject/src/main/java/io/micronaut/context/AbstractExecutableMethod_Instrumentation.java b/instrumentation/micronaut-inject/src/main/java/io/micronaut/context/AbstractExecutableMethod_Instrumentation.java new file mode 100644 index 0000000000..ca664f67c6 --- /dev/null +++ b/instrumentation/micronaut-inject/src/main/java/io/micronaut/context/AbstractExecutableMethod_Instrumentation.java @@ -0,0 +1,34 @@ +/* + * + * * Copyright 2025 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package io.micronaut.context; + +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.context.AbstractExecutableMethod", type = MatchType.BaseClass) +public abstract class AbstractExecutableMethod_Instrumentation { + public abstract String getMethodName(); + public abstract Class getDeclaringType(); + + @Trace + public Object invoke(Object instance, Object... arguments) { + Class dType = getDeclaringType(); + String classname = "Unknown"; + if(dType != null) { + String tmp = dType.getSimpleName(); + if(tmp != null && !tmp.isEmpty()) { + classname = tmp; + } + } + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","Micronaut","ExecutableMethod",getClass().getSimpleName(),"invoke",classname,getMethodName()); + return Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/instrumentation/micronaut-inject/src/main/java/io/micronaut/inject/ExecutionHandle_Instrumentation.java b/instrumentation/micronaut-inject/src/main/java/io/micronaut/inject/ExecutionHandle_Instrumentation.java new file mode 100644 index 0000000000..4042aa1858 --- /dev/null +++ b/instrumentation/micronaut-inject/src/main/java/io/micronaut/inject/ExecutionHandle_Instrumentation.java @@ -0,0 +1,16 @@ +package io.micronaut.inject; + +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.inject.ExecutionHandle", type = MatchType.Interface) +public abstract class ExecutionHandle_Instrumentation { + public abstract Class getDeclaringType(); + + @Trace + public R invoke(Object... arguments) { + return Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 97ca3d24b5..368d1b7733 100644 --- a/settings.gradle +++ b/settings.gradle @@ -267,6 +267,12 @@ include 'instrumentation:lettuce-4.3' include 'instrumentation:lettuce-5.0' include 'instrumentation:lettuce-6.0' include 'instrumentation:logback-classic-1.2' +include 'instrumentation:micronaut-core-1.0.0' +include 'instrumentation:micronaut-core-4.0.0' +include 'instrumentation:micronaut-core-4.3.0' +include 'instrumentation:micronaut-inject' +include 'instrumentation:micronaut-core-reactive-2.4.0' +include 'instrumentation:micronaut-core-reactive-3.2.0' include 'instrumentation:mongodb-async-3.4' include 'instrumentation:mongodb-async-3.6' include 'instrumentation:mongodb-async-3.7' @@ -445,3 +451,4 @@ include 'instrumentation:wildfly-27' include 'instrumentation:wildfly-jmx-14' include 'instrumentation:zio' include 'instrumentation:zio-2' +