From baa0439544dc909413b9fff56fa3c3f28847c547 Mon Sep 17 00:00:00 2001 From: Doug Hilpipre Date: Tue, 15 Oct 2024 11:32:07 -0500 Subject: [PATCH 01/10] initial --- .../com/newrelic/instrumentation/kotlin/coroutines/Utils.java | 4 ++-- .../kotlin/coroutines/tracing/SuspendClassTransformer.java | 3 ++- settings.gradle | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/Utils.java b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/Utils.java index da25bf9..2a991a4 100644 --- a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/Utils.java +++ b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/Utils.java @@ -13,13 +13,13 @@ public class Utils implements AgentConfigListener { public static final String CREATEMETHOD2 = "Continuation at kotlin.coroutines.intrinsics.IntrinsicsKt__IntrinsicsJvmKt$createCoroutineUnintercepted$$inlined$createCoroutineFromSuspendFunction$IntrinsicsKt__IntrinsicsJvmKt$3"; public static String sub = "createCoroutineFromSuspendFunction"; private static final String CONT_LOC = "Continuation at"; - + static { ServiceFactory.getConfigService().addIAgentConfigListener(INSTANCE); Config config = NewRelic.getAgent().getConfig(); SuspendIgnores.reset(config); } - + @Override public void configChanged(String appName, AgentConfig agentConfig) { SuspendIgnores.reset(agentConfig); diff --git a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendClassTransformer.java b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendClassTransformer.java index ee81be0..c5e9b41 100644 --- a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendClassTransformer.java +++ b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendClassTransformer.java @@ -54,7 +54,8 @@ public byte[] transform(ClassLoader loader, String className, Class classBein for(ClassAndMethodMatcher matcher : match.getClassMatches().keySet()) { if (matcher.getMethodMatcher().matches(MethodMatcher.UNSPECIFIED_ACCESS, method.getName(), method.getDescriptor(), match.getMethodAnnotations(method))) { - context.putTraceAnnotation(method, TraceDetailsBuilder.newBuilder().setTracerFactoryName(SuspendTracerFactory.TRACER_FACTORY_NAME).setDispatcher(true).setInstrumentationSourceName("CoroutinesCore").setInstrumentationType(InstrumentationType.TraceAnnotation).build()); + +// context.putTraceAnnotation(method, TraceDetailsBuilder.newBuilder().setTracerFactoryName(SuspendTracerFactory.TRACER_FACTORY_NAME).setDispatcher(true).setInstrumentationSourceName("CoroutinesCore").setInstrumentationType(InstrumentationType.TraceAnnotation).build()); } } diff --git a/settings.gradle b/settings.gradle index 0f268f4..42aa1a5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,3 +8,4 @@ include 'Kotlin-Coroutines_1.7' include 'Kotlin-Coroutines_1.9' include 'kroto-plus-coroutines' include 'Kotlin-Coroutines-Suspends' +include 'kotlin-suspends' From dfbe1cb102d152903a2e307cb46903b964145ca3 Mon Sep 17 00:00:00 2001 From: Doug Hilpipre Date: Fri, 17 Jan 2025 08:59:50 -0600 Subject: [PATCH 02/10] merged with suspend_fixes --- .../kotlin/coroutines/SuspendIgnores.java | 47 +++++++++++ .../kotlin/coroutines/Utils.java | 4 +- .../coroutines/tracing/CoroutinesPreMain.java | 84 +++++++++++++++++++ .../tracing/SuspendClassAndMethod.java | 27 ++++++ .../tracing/SuspendClassMatcher.java | 49 +++++++++++ .../tracing/SuspendClassTransformer.java | 3 +- .../tracing/SuspendMethodMatcher.java | 27 ++++++ .../tracing/SuspendTracerFactory.java | 25 ++++++ 8 files changed, 262 insertions(+), 4 deletions(-) create mode 100644 Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/SuspendIgnores.java create mode 100644 Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/CoroutinesPreMain.java create mode 100644 Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendClassAndMethod.java create mode 100644 Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendClassMatcher.java create mode 100644 Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendMethodMatcher.java create mode 100644 Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendTracerFactory.java diff --git a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/SuspendIgnores.java b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/SuspendIgnores.java new file mode 100644 index 0000000..712ce01 --- /dev/null +++ b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/SuspendIgnores.java @@ -0,0 +1,47 @@ +package com.newrelic.instrumentation.kotlin.coroutines; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; + +import com.newrelic.api.agent.Config; +import com.newrelic.api.agent.NewRelic; + +public class SuspendIgnores { + + private static final List ignoredSuspends = new ArrayList(); + private static final String SUSPENDSIGNORECONFIG = "Coroutines.ignores.suspends"; + + static { + Config config = NewRelic.getAgent().getConfig(); + String value = config.getValue(SUSPENDSIGNORECONFIG); + init(value); + + } + + private static void init(String value) { + if(value != null && !value.isEmpty()) { + String[] ignores = value.split(","); + for(String ignore : ignores) { + addIgnore(ignore); + } + } + } + + public static void reset(Config config) { + ignoredSuspends.clear(); + String value = config.getValue(SUSPENDSIGNORECONFIG); + init(value); + } + + public static void addIgnore(String s) { + if(!ignoredSuspends.contains(s)) { + ignoredSuspends.add(s); + NewRelic.getAgent().getLogger().log(Level.FINE, "Will ignore suspends named {0}", s); + } + } + + public static boolean ignoreSuspend(Object obj) { + return ignoredSuspends.contains(obj.toString()) || ignoredSuspends.contains(obj.getClass().getName()); + } +} diff --git a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/Utils.java b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/Utils.java index 2a991a4..da25bf9 100644 --- a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/Utils.java +++ b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/Utils.java @@ -13,13 +13,13 @@ public class Utils implements AgentConfigListener { public static final String CREATEMETHOD2 = "Continuation at kotlin.coroutines.intrinsics.IntrinsicsKt__IntrinsicsJvmKt$createCoroutineUnintercepted$$inlined$createCoroutineFromSuspendFunction$IntrinsicsKt__IntrinsicsJvmKt$3"; public static String sub = "createCoroutineFromSuspendFunction"; private static final String CONT_LOC = "Continuation at"; - + static { ServiceFactory.getConfigService().addIAgentConfigListener(INSTANCE); Config config = NewRelic.getAgent().getConfig(); SuspendIgnores.reset(config); } - + @Override public void configChanged(String appName, AgentConfig agentConfig) { SuspendIgnores.reset(agentConfig); diff --git a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/CoroutinesPreMain.java b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/CoroutinesPreMain.java new file mode 100644 index 0000000..e1dfd9a --- /dev/null +++ b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/CoroutinesPreMain.java @@ -0,0 +1,84 @@ +package com.newrelic.instrumentation.kotlin.coroutines.tracing; + +import java.lang.instrument.Instrumentation; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; + +import com.newrelic.agent.TracerService; +import com.newrelic.agent.core.CoreService; +import com.newrelic.agent.instrumentation.ClassTransformerService; +import com.newrelic.agent.instrumentation.context.ClassMatchVisitorFactory; +import com.newrelic.agent.instrumentation.context.InstrumentationContextManager; +import com.newrelic.agent.service.ServiceFactory; +import com.newrelic.api.agent.NewRelic; + +public class CoroutinesPreMain { + + private static int max_retries = 20; + private static ScheduledExecutorService executor = null; + + public static void premain(String args, Instrumentation inst) { + boolean b = setup(); + if(!b) { + executor = Executors.newSingleThreadScheduledExecutor(); + executor.schedule(new Setup(), 100L, TimeUnit.MILLISECONDS); + } + + } + + public static boolean setup() { + + TracerService tracerService = ServiceFactory.getTracerService(); + ClassTransformerService classTransformerService = ServiceFactory.getClassTransformerService(); + CoreService coreService = ServiceFactory.getCoreService(); + + if(tracerService != null && classTransformerService != null && coreService != null) { + tracerService.registerTracerFactory(SuspendTracerFactory.TRACER_FACTORY_NAME, new SuspendTracerFactory()); + InstrumentationContextManager contextMgr = classTransformerService.getContextManager(); + + if(contextMgr != null) { + SuspendClassTransformer suspendTransformer = new SuspendClassTransformer(contextMgr); + SuspendClassAndMethod suspendMatcher = new SuspendClassAndMethod(); + ClassMatchVisitorFactory suspendMatchVistor = suspendTransformer.addMatcher(suspendMatcher); + + Set factories = new HashSet<>(); + factories.add(suspendMatchVistor); + Class[] allLoadedClasses = coreService.getInstrumentation().getAllLoadedClasses(); + + classTransformerService.retransformMatchingClassesImmediately(allLoadedClasses, factories); + + return true; + } + } + + return false; + } + + private static class Setup implements Runnable { + + private static int count = 0; + + @Override + public void run() { + count++; + NewRelic.getAgent().getLogger().log(Level.FINE, "Call {0} to attempt setting up Suspend ClassTransformer",count); + boolean b = setup(); + + if(!b) { + if(count < max_retries) { + executor.schedule(this, 2L, TimeUnit.SECONDS); + } else { + NewRelic.getAgent().getLogger().log(Level.FINE, "Failed to initiate Suspend Client Transformer after {0} tries", max_retries); + executor.shutdownNow(); + } + } + + } + + } + +} diff --git a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendClassAndMethod.java b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendClassAndMethod.java new file mode 100644 index 0000000..bf392fd --- /dev/null +++ b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendClassAndMethod.java @@ -0,0 +1,27 @@ +package com.newrelic.instrumentation.kotlin.coroutines.tracing; + +import com.newrelic.agent.instrumentation.classmatchers.ClassAndMethodMatcher; +import com.newrelic.agent.instrumentation.classmatchers.ClassMatcher; +import com.newrelic.agent.instrumentation.methodmatchers.MethodMatcher; + +public class SuspendClassAndMethod implements ClassAndMethodMatcher { + + private ClassMatcher classMatcher; + private MethodMatcher methodMatcher; + + public SuspendClassAndMethod() { + classMatcher = new SuspendClassMatcher(); + methodMatcher = new SuspendMethodMatcher(); + } + + @Override + public ClassMatcher getClassMatcher() { + return classMatcher; + } + + @Override + public MethodMatcher getMethodMatcher() { + return methodMatcher; + } + +} diff --git a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendClassMatcher.java b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendClassMatcher.java new file mode 100644 index 0000000..b9093ac --- /dev/null +++ b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendClassMatcher.java @@ -0,0 +1,49 @@ +package com.newrelic.instrumentation.kotlin.coroutines.tracing; + +import java.util.ArrayList; +import java.util.Collection; + +import com.newrelic.agent.deps.org.objectweb.asm.ClassReader; +import com.newrelic.agent.instrumentation.classmatchers.ChildClassMatcher; +import com.newrelic.agent.instrumentation.classmatchers.ClassMatcher; +import com.newrelic.agent.instrumentation.classmatchers.ExactClassMatcher; +import com.newrelic.agent.instrumentation.classmatchers.NotMatcher; + +public class SuspendClassMatcher extends ClassMatcher { + + ChildClassMatcher matcher; + NotMatcher nrMatcher; + + public SuspendClassMatcher() { + matcher = new ChildClassMatcher("kotlin.coroutines.jvm.internal.BaseContinuationImpl",false); + nrMatcher = new NotMatcher(new ExactClassMatcher("com.newrelic.instrumentation.kotlin.coroutines.NRWrappedSuspend")); + } + + @Override + public boolean isMatch(ClassLoader loader, ClassReader cr) { + return matcher.isMatch(loader, cr) && nrMatcher.isMatch(loader, cr); + } + + @Override + public boolean isMatch(Class clazz) { + return matcher.isMatch(clazz) && nrMatcher.isMatch(clazz); + } + + @Override + public Collection getClassNames() { + Collection childClasses = matcher.getClassNames(); + Collection nrClasses = nrMatcher.getClassNames(); + if(childClasses == null && nrClasses == null) return null; + + ArrayList list = new ArrayList<>(); + if(childClasses != null) { + list.addAll(childClasses); + } + if(nrClasses != null) { + list.addAll(nrClasses); + } + + return list; + } + +} diff --git a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendClassTransformer.java b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendClassTransformer.java index c5e9b41..ee81be0 100644 --- a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendClassTransformer.java +++ b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendClassTransformer.java @@ -54,8 +54,7 @@ public byte[] transform(ClassLoader loader, String className, Class classBein for(ClassAndMethodMatcher matcher : match.getClassMatches().keySet()) { if (matcher.getMethodMatcher().matches(MethodMatcher.UNSPECIFIED_ACCESS, method.getName(), method.getDescriptor(), match.getMethodAnnotations(method))) { - -// context.putTraceAnnotation(method, TraceDetailsBuilder.newBuilder().setTracerFactoryName(SuspendTracerFactory.TRACER_FACTORY_NAME).setDispatcher(true).setInstrumentationSourceName("CoroutinesCore").setInstrumentationType(InstrumentationType.TraceAnnotation).build()); + context.putTraceAnnotation(method, TraceDetailsBuilder.newBuilder().setTracerFactoryName(SuspendTracerFactory.TRACER_FACTORY_NAME).setDispatcher(true).setInstrumentationSourceName("CoroutinesCore").setInstrumentationType(InstrumentationType.TraceAnnotation).build()); } } diff --git a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendMethodMatcher.java b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendMethodMatcher.java new file mode 100644 index 0000000..be48c40 --- /dev/null +++ b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendMethodMatcher.java @@ -0,0 +1,27 @@ +package com.newrelic.instrumentation.kotlin.coroutines.tracing; + +import java.util.Set; + +import com.newrelic.agent.deps.org.objectweb.asm.commons.Method; +import com.newrelic.agent.instrumentation.methodmatchers.MethodMatcher; +import com.newrelic.agent.instrumentation.methodmatchers.NameMethodMatcher; + +public class SuspendMethodMatcher implements MethodMatcher { + + NameMethodMatcher matcher = null; + + public SuspendMethodMatcher() { + matcher = new NameMethodMatcher("invokeSuspend"); + } + + @Override + public boolean matches(int access, String name, String desc, Set annotations) { + return matcher.matches(access, name, desc, annotations); + } + + @Override + public Method[] getExactMethods() { + return matcher.getExactMethods(); + } + +} diff --git a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendTracerFactory.java b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendTracerFactory.java new file mode 100644 index 0000000..570ad90 --- /dev/null +++ b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/tracing/SuspendTracerFactory.java @@ -0,0 +1,25 @@ +package com.newrelic.instrumentation.kotlin.coroutines.tracing; + +import com.newrelic.agent.Transaction; +import com.newrelic.agent.tracers.ClassMethodSignature; +import com.newrelic.agent.tracers.DefaultTracer; +import com.newrelic.agent.tracers.Tracer; +import com.newrelic.agent.tracers.TracerFactory; +import com.newrelic.agent.tracers.metricname.SimpleMetricNameFormat; +import com.newrelic.instrumentation.kotlin.coroutines.SuspendIgnores; +import com.newrelic.instrumentation.kotlin.coroutines.Utils; + +public class SuspendTracerFactory implements TracerFactory { + + protected static final String TRACER_FACTORY_NAME = "SUSPEND_TRACER_FACTORY"; + + @Override + public Tracer getTracer(Transaction transaction, ClassMethodSignature sig, Object object, Object[] args) { + + if(SuspendIgnores.ignoreSuspend(object)) { + return null; + } + return new DefaultTracer(transaction, sig, object, new SimpleMetricNameFormat("Custom/SuspendFunction/"+Utils.getSuspendString(object.toString(), object))); + } + +} From 521dffa5c29f9eda4a54afd1feb8d188915c13c9 Mon Sep 17 00:00:00 2001 From: Doug Hilpipre Date: Fri, 17 Jan 2025 10:47:22 -0600 Subject: [PATCH 03/10] added regex ignore capabilities --- Kotlin-Coroutines-Suspends/build.gradle | 32 +++++++++++++++++++ .../kotlin/coroutines/SuspendIgnores.java | 23 ++++++++++++- .../DispatchedTaskIgnores.java | 0 .../NRContinuationWrapper.java | 0 .../NRCoroutineToken.java | 0 .../NRFunction1Wrapper.java | 0 .../NRFunction2Wrapper.java | 0 .../NRRunnable.java | 0 .../Utils.java | 0 9 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 Kotlin-Coroutines-Suspends/build.gradle rename Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/{coroutines_17 => coroutines_19}/DispatchedTaskIgnores.java (100%) rename Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/{coroutines_17 => coroutines_19}/NRContinuationWrapper.java (100%) rename Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/{coroutines_17 => coroutines_19}/NRCoroutineToken.java (100%) rename Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/{coroutines_17 => coroutines_19}/NRFunction1Wrapper.java (100%) rename Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/{coroutines_17 => coroutines_19}/NRFunction2Wrapper.java (100%) rename Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/{coroutines_17 => coroutines_19}/NRRunnable.java (100%) rename Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/{coroutines_17 => coroutines_19}/Utils.java (100%) diff --git a/Kotlin-Coroutines-Suspends/build.gradle b/Kotlin-Coroutines-Suspends/build.gradle new file mode 100644 index 0000000..149b584 --- /dev/null +++ b/Kotlin-Coroutines-Suspends/build.gradle @@ -0,0 +1,32 @@ + +// Build.gradle generated for instrumentation module Kotlin-Coroutines-Core + +apply plugin: 'java' + +dependencies { + implementation group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.4.0' + + // New Relic Java Agent dependencies + implementation 'com.newrelic.agent.java:newrelic-agent:6.4.1' + implementation 'com.newrelic.agent.java:newrelic-api:6.4.1' + implementation fileTree(include: ['*.jar'], dir: '../libs') + implementation fileTree(include: ['*.jar'], dir: '../test-lib') +} + +jar { + manifest { + attributes 'Implementation-Title': 'com.newrelic.instrumentation.labs.Kotlin-Coroutines-Suspends' + attributes 'Implementation-Vendor': 'New Relic Labs' + attributes 'Implementation-Vendor-Id': 'com.newrelic.labs' + attributes 'Implementation-Version': 2.0 + attributes 'Agent-Class': 'com.newrelic.instrumentation.kotlin.coroutines.tracing.CoroutinesPreMain' + } +} + +verifyInstrumentation { + // Verifier plugin documentation: + // https://github.com/newrelic/newrelic-gradle-verify-instrumentation + // Example: + // passes 'javax.servlet:servlet-api:[2.2,2.5]' + // exclude 'javax.servlet:servlet-api:2.4.public_draft' +} \ No newline at end of file diff --git a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/SuspendIgnores.java b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/SuspendIgnores.java index 712ce01..54e5c04 100644 --- a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/SuspendIgnores.java +++ b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/SuspendIgnores.java @@ -3,6 +3,8 @@ import java.util.ArrayList; import java.util.List; import java.util.logging.Level; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import com.newrelic.api.agent.Config; import com.newrelic.api.agent.NewRelic; @@ -42,6 +44,25 @@ public static void addIgnore(String s) { } public static boolean ignoreSuspend(Object obj) { - return ignoredSuspends.contains(obj.toString()) || ignoredSuspends.contains(obj.getClass().getName()); + String objString = obj.toString(); + String className = obj.getClass().getName(); + NewRelic.getAgent().getLogger().log(Level.FINE, "Call to SuspendIgnores.ignoreSuspend, objString = {0}, className = {1}" , objString, className); + + if(ignoredSuspends.contains(objString) || ignoredSuspends.contains(className)) { + NewRelic.getAgent().getLogger().log(Level.FINE, "Matched classname or objString"); + return true; + } + + for(String s : ignoredSuspends) { + NewRelic.getAgent().getLogger().log(Level.FINE, "Comparing to regex {0}", s); + Pattern pattern = Pattern.compile(s); + Matcher matcher1 = pattern.matcher(objString); + Matcher matcher2 = pattern.matcher(className); + NewRelic.getAgent().getLogger().log(Level.FINE, matcher1.matches() ? "Matched objString" : matcher2.matches() ? "Matched Classname" : "not a match for object string or classname"); + if(matcher1.matches() || matcher2.matches()) return true; + } + + return false; +// return ignoredSuspends.contains(obj.toString()) || ignoredSuspends.contains(obj.getClass().getName()); } } diff --git a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_17/DispatchedTaskIgnores.java b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/DispatchedTaskIgnores.java similarity index 100% rename from Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_17/DispatchedTaskIgnores.java rename to Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/DispatchedTaskIgnores.java diff --git a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_17/NRContinuationWrapper.java b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRContinuationWrapper.java similarity index 100% rename from Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_17/NRContinuationWrapper.java rename to Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRContinuationWrapper.java diff --git a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_17/NRCoroutineToken.java b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRCoroutineToken.java similarity index 100% rename from Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_17/NRCoroutineToken.java rename to Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRCoroutineToken.java diff --git a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_17/NRFunction1Wrapper.java b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRFunction1Wrapper.java similarity index 100% rename from Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_17/NRFunction1Wrapper.java rename to Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRFunction1Wrapper.java diff --git a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_17/NRFunction2Wrapper.java b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRFunction2Wrapper.java similarity index 100% rename from Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_17/NRFunction2Wrapper.java rename to Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRFunction2Wrapper.java diff --git a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_17/NRRunnable.java b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRRunnable.java similarity index 100% rename from Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_17/NRRunnable.java rename to Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRRunnable.java diff --git a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_17/Utils.java b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/Utils.java similarity index 100% rename from Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_17/Utils.java rename to Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/Utils.java From 0fd0008e5fc5d28da7fbd915f9ce5264254cc5b0 Mon Sep 17 00:00:00 2001 From: Doug Hilpipre Date: Fri, 17 Jan 2025 10:48:00 -0600 Subject: [PATCH 04/10] added regex ignore capabilities --- Kotlin-Coroutines_1.7/build.gradle | 2 +- .../kotlin/coroutines_19/DispatchedTaskIgnores.java | 2 +- .../kotlin/coroutines_19/NRContinuationWrapper.java | 2 +- .../kotlin/coroutines_19/NRCoroutineToken.java | 2 +- .../kotlin/coroutines_19/NRFunction1Wrapper.java | 2 +- .../kotlin/coroutines_19/NRFunction2Wrapper.java | 2 +- .../instrumentation/kotlin/coroutines_19/NRRunnable.java | 2 +- .../instrumentation/kotlin/coroutines_19/Utils.java | 2 +- .../src/main/java/kotlin/coroutines/ContinuationKt.java | 4 ++-- .../main/java/kotlinx/coroutines/AbstractCoroutine.java | 4 ++-- .../src/main/java/kotlinx/coroutines/BuildersKt.java | 8 ++++---- .../main/java/kotlinx/coroutines/CoroutineDispatcher.java | 4 ++-- .../main/java/kotlinx/coroutines/DispatcherExecutor.java | 4 ++-- .../main/java/kotlinx/coroutines/EventLoopImplBase.java | 2 +- .../src/main/java/kotlinx/coroutines/YieldKt.java | 2 +- .../java/kotlinx/coroutines/intrinsics/CancellableKt.java | 8 ++++---- .../kotlinx/coroutines/intrinsics/UndispatchedKt.java | 6 +++--- 17 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Kotlin-Coroutines_1.7/build.gradle b/Kotlin-Coroutines_1.7/build.gradle index 83103c3..cac13f8 100644 --- a/Kotlin-Coroutines_1.7/build.gradle +++ b/Kotlin-Coroutines_1.7/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'java' -// targetCompatibility = JavaVersion.VERSION_1_9 +targetCompatibility = JavaVersion.VERSION_1_9 dependencies { implementation group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.7.3' diff --git a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/DispatchedTaskIgnores.java b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/DispatchedTaskIgnores.java index 5d239d3..25547fa 100644 --- a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/DispatchedTaskIgnores.java +++ b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/DispatchedTaskIgnores.java @@ -1,4 +1,4 @@ -package com.newrelic.instrumentation.kotlin.coroutines_17; +package com.newrelic.instrumentation.kotlin.coroutines_19; import java.util.ArrayList; import java.util.List; diff --git a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRContinuationWrapper.java b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRContinuationWrapper.java index 5a016fa..9773d3b 100644 --- a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRContinuationWrapper.java +++ b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRContinuationWrapper.java @@ -1,4 +1,4 @@ -package com.newrelic.instrumentation.kotlin.coroutines_17; +package com.newrelic.instrumentation.kotlin.coroutines_19; import com.newrelic.agent.bridge.AgentBridge; import com.newrelic.api.agent.NewRelic; diff --git a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRCoroutineToken.java b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRCoroutineToken.java index d6a63da..93dcdac 100644 --- a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRCoroutineToken.java +++ b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRCoroutineToken.java @@ -1,4 +1,4 @@ -package com.newrelic.instrumentation.kotlin.coroutines_17; +package com.newrelic.instrumentation.kotlin.coroutines_19; import com.newrelic.api.agent.Token; diff --git a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRFunction1Wrapper.java b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRFunction1Wrapper.java index 37bc3bc..f3f3038 100644 --- a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRFunction1Wrapper.java +++ b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRFunction1Wrapper.java @@ -1,4 +1,4 @@ -package com.newrelic.instrumentation.kotlin.coroutines_17; +package com.newrelic.instrumentation.kotlin.coroutines_19; import com.newrelic.agent.bridge.AgentBridge; diff --git a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRFunction2Wrapper.java b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRFunction2Wrapper.java index d81eb8e..fce671a 100644 --- a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRFunction2Wrapper.java +++ b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRFunction2Wrapper.java @@ -1,4 +1,4 @@ -package com.newrelic.instrumentation.kotlin.coroutines_17; +package com.newrelic.instrumentation.kotlin.coroutines_19; import com.newrelic.agent.bridge.AgentBridge; diff --git a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRRunnable.java b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRRunnable.java index 7d9cdb3..233dd62 100644 --- a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRRunnable.java +++ b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/NRRunnable.java @@ -1,4 +1,4 @@ -package com.newrelic.instrumentation.kotlin.coroutines_17; +package com.newrelic.instrumentation.kotlin.coroutines_19; import com.newrelic.agent.bridge.AgentBridge; import com.newrelic.api.agent.NewRelic; diff --git a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/Utils.java b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/Utils.java index 94850ff..2029f33 100644 --- a/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/Utils.java +++ b/Kotlin-Coroutines_1.9/src/main/java/com/newrelic/instrumentation/kotlin/coroutines_19/Utils.java @@ -1,4 +1,4 @@ -package com.newrelic.instrumentation.kotlin.coroutines_17; +package com.newrelic.instrumentation.kotlin.coroutines_19; import java.util.ArrayList; import java.util.List; diff --git a/Kotlin-Coroutines_1.9/src/main/java/kotlin/coroutines/ContinuationKt.java b/Kotlin-Coroutines_1.9/src/main/java/kotlin/coroutines/ContinuationKt.java index 1cf16ae..16b73ad 100644 --- a/Kotlin-Coroutines_1.9/src/main/java/kotlin/coroutines/ContinuationKt.java +++ b/Kotlin-Coroutines_1.9/src/main/java/kotlin/coroutines/ContinuationKt.java @@ -3,8 +3,8 @@ import com.newrelic.api.agent.Trace; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import com.newrelic.instrumentation.kotlin.coroutines_17.NRFunction1Wrapper; -import com.newrelic.instrumentation.kotlin.coroutines_17.NRFunction2Wrapper; +import com.newrelic.instrumentation.kotlin.coroutines_19.NRFunction1Wrapper; +import com.newrelic.instrumentation.kotlin.coroutines_19.NRFunction2Wrapper; import kotlin.jvm.functions.Function1; import kotlin.jvm.functions.Function2; diff --git a/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/AbstractCoroutine.java b/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/AbstractCoroutine.java index a600fe7..54c8e52 100644 --- a/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/AbstractCoroutine.java +++ b/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/AbstractCoroutine.java @@ -7,8 +7,8 @@ import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import com.newrelic.instrumentation.kotlin.coroutines_17.NRFunction2Wrapper; -import com.newrelic.instrumentation.kotlin.coroutines_17.Utils; +import com.newrelic.instrumentation.kotlin.coroutines_19.NRFunction2Wrapper; +import com.newrelic.instrumentation.kotlin.coroutines_19.Utils; import kotlin.coroutines.Continuation; import kotlin.coroutines.CoroutineContext; diff --git a/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/BuildersKt.java b/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/BuildersKt.java index 9f2ac41..e61df65 100644 --- a/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/BuildersKt.java +++ b/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/BuildersKt.java @@ -5,10 +5,10 @@ import com.newrelic.api.agent.Trace; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import com.newrelic.instrumentation.kotlin.coroutines_17.NRContinuationWrapper; -import com.newrelic.instrumentation.kotlin.coroutines_17.NRCoroutineToken; -import com.newrelic.instrumentation.kotlin.coroutines_17.NRFunction2Wrapper; -import com.newrelic.instrumentation.kotlin.coroutines_17.Utils; +import com.newrelic.instrumentation.kotlin.coroutines_19.NRContinuationWrapper; +import com.newrelic.instrumentation.kotlin.coroutines_19.NRCoroutineToken; +import com.newrelic.instrumentation.kotlin.coroutines_19.NRFunction2Wrapper; +import com.newrelic.instrumentation.kotlin.coroutines_19.Utils; import kotlin.Unit; import kotlin.coroutines.Continuation; diff --git a/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/CoroutineDispatcher.java b/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/CoroutineDispatcher.java index a28b871..8e0220f 100644 --- a/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/CoroutineDispatcher.java +++ b/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/CoroutineDispatcher.java @@ -3,8 +3,8 @@ import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import com.newrelic.instrumentation.kotlin.coroutines_17.NRRunnable; -import com.newrelic.instrumentation.kotlin.coroutines_17.Utils; +import com.newrelic.instrumentation.kotlin.coroutines_19.NRRunnable; +import com.newrelic.instrumentation.kotlin.coroutines_19.Utils; import kotlin.coroutines.CoroutineContext; diff --git a/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/DispatcherExecutor.java b/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/DispatcherExecutor.java index 034b646..939567d 100644 --- a/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/DispatcherExecutor.java +++ b/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/DispatcherExecutor.java @@ -5,8 +5,8 @@ import com.newrelic.api.agent.weaver.MatchType; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import com.newrelic.instrumentation.kotlin.coroutines_17.NRRunnable; -import com.newrelic.instrumentation.kotlin.coroutines_17.Utils; +import com.newrelic.instrumentation.kotlin.coroutines_19.NRRunnable; +import com.newrelic.instrumentation.kotlin.coroutines_19.Utils; @Weave(type = MatchType.BaseClass) abstract class DispatcherExecutor { diff --git a/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/EventLoopImplBase.java b/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/EventLoopImplBase.java index 3baf1dc..2847ecb 100644 --- a/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/EventLoopImplBase.java +++ b/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/EventLoopImplBase.java @@ -7,7 +7,7 @@ import com.newrelic.api.agent.weaver.NewField; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import com.newrelic.instrumentation.kotlin.coroutines_17.Utils; +import com.newrelic.instrumentation.kotlin.coroutines_19.Utils; @Weave public abstract class EventLoopImplBase { diff --git a/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/YieldKt.java b/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/YieldKt.java index 9f35049..4d4900a 100644 --- a/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/YieldKt.java +++ b/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/YieldKt.java @@ -4,7 +4,7 @@ import com.newrelic.api.agent.Trace; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import com.newrelic.instrumentation.kotlin.coroutines_17.Utils; +import com.newrelic.instrumentation.kotlin.coroutines_19.Utils; import kotlin.Unit; import kotlin.coroutines.Continuation; diff --git a/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/intrinsics/CancellableKt.java b/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/intrinsics/CancellableKt.java index b564669..23efac0 100644 --- a/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/intrinsics/CancellableKt.java +++ b/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/intrinsics/CancellableKt.java @@ -5,10 +5,10 @@ import com.newrelic.api.agent.TracedMethod; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import com.newrelic.instrumentation.kotlin.coroutines_17.NRContinuationWrapper; -import com.newrelic.instrumentation.kotlin.coroutines_17.NRFunction1Wrapper; -import com.newrelic.instrumentation.kotlin.coroutines_17.NRFunction2Wrapper; -import com.newrelic.instrumentation.kotlin.coroutines_17.Utils; +import com.newrelic.instrumentation.kotlin.coroutines_19.NRContinuationWrapper; +import com.newrelic.instrumentation.kotlin.coroutines_19.NRFunction1Wrapper; +import com.newrelic.instrumentation.kotlin.coroutines_19.NRFunction2Wrapper; +import com.newrelic.instrumentation.kotlin.coroutines_19.Utils; import kotlin.coroutines.Continuation; import kotlin.coroutines.jvm.internal.SuspendFunction; diff --git a/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/intrinsics/UndispatchedKt.java b/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/intrinsics/UndispatchedKt.java index af2928c..12977d0 100644 --- a/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/intrinsics/UndispatchedKt.java +++ b/Kotlin-Coroutines_1.9/src/main/java/kotlinx/coroutines/intrinsics/UndispatchedKt.java @@ -5,9 +5,9 @@ import com.newrelic.api.agent.TracedMethod; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import com.newrelic.instrumentation.kotlin.coroutines_17.NRContinuationWrapper; -import com.newrelic.instrumentation.kotlin.coroutines_17.NRFunction2Wrapper; -import com.newrelic.instrumentation.kotlin.coroutines_17.Utils; +import com.newrelic.instrumentation.kotlin.coroutines_19.NRContinuationWrapper; +import com.newrelic.instrumentation.kotlin.coroutines_19.NRFunction2Wrapper; +import com.newrelic.instrumentation.kotlin.coroutines_19.Utils; import kotlin.coroutines.Continuation; import kotlin.coroutines.jvm.internal.SuspendFunction; From 03d2ac36dd552b33f56843c3116097f96f5807cb Mon Sep 17 00:00:00 2001 From: Doug Hilpipre Date: Thu, 13 Mar 2025 12:14:24 -0500 Subject: [PATCH 05/10] added regular expression matching to suspend ignores --- .../kotlin/coroutines/SuspendIgnores.java | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/SuspendIgnores.java b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/SuspendIgnores.java index 54e5c04..47d3409 100644 --- a/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/SuspendIgnores.java +++ b/Kotlin-Coroutines-Suspends/src/main/java/com/newrelic/instrumentation/kotlin/coroutines/SuspendIgnores.java @@ -13,12 +13,14 @@ public class SuspendIgnores { private static final List ignoredSuspends = new ArrayList(); private static final String SUSPENDSIGNORECONFIG = "Coroutines.ignores.suspends"; + private static final List ignoredPackages = new ArrayList<>(); static { Config config = NewRelic.getAgent().getConfig(); String value = config.getValue(SUSPENDSIGNORECONFIG); init(value); - + ignoredPackages.add("kotlin.coroutines"); + ignoredPackages.add("kotlinx.coroutines"); } private static void init(String value) { @@ -45,24 +47,30 @@ public static void addIgnore(String s) { public static boolean ignoreSuspend(Object obj) { String objString = obj.toString(); - String className = obj.getClass().getName(); - NewRelic.getAgent().getLogger().log(Level.FINE, "Call to SuspendIgnores.ignoreSuspend, objString = {0}, className = {1}" , objString, className); + Class clazz = obj.getClass(); + String className = clazz.getName(); + String packageName = clazz.getPackage().getName(); + + for(String ignored : ignoredPackages) { + if(packageName.startsWith(ignored)) { + return true; + } + } + + boolean objStringMatch = ignoredSuspends.contains(objString); + boolean classNameMatch = ignoredSuspends.contains(className); - if(ignoredSuspends.contains(objString) || ignoredSuspends.contains(className)) { - NewRelic.getAgent().getLogger().log(Level.FINE, "Matched classname or objString"); + if(objStringMatch || classNameMatch) { return true; } for(String s : ignoredSuspends) { - NewRelic.getAgent().getLogger().log(Level.FINE, "Comparing to regex {0}", s); Pattern pattern = Pattern.compile(s); Matcher matcher1 = pattern.matcher(objString); Matcher matcher2 = pattern.matcher(className); - NewRelic.getAgent().getLogger().log(Level.FINE, matcher1.matches() ? "Matched objString" : matcher2.matches() ? "Matched Classname" : "not a match for object string or classname"); if(matcher1.matches() || matcher2.matches()) return true; } return false; -// return ignoredSuspends.contains(obj.toString()) || ignoredSuspends.contains(obj.getClass().getName()); } } From 0ad54441404a2e8e4dcd9231f1fabf8de04bc831 Mon Sep 17 00:00:00 2001 From: Doug Hilpipre Date: Thu, 13 Mar 2025 12:26:10 -0500 Subject: [PATCH 06/10] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index f07ed97..0ba3828 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,7 @@ Provides instrumentation for Kotlin Coroutines. In particular it will trace the coroutine from its start, suspend and resume. It does this across multilple threads. # Advisory -The current release is experiencing problems especially in the latest versions of the Java Agent. The problem is with the Kotlin-Coroutines-Suspend.jar which is used to track suspend methods. We are working on fixing the problem but if you are experiencing NullPointerExceptions or Inconsistent tracer errors in the Java Agent log, please remove Kotlin-Coroutines-Suspends.jar from the extensions directory and restart the application. -The current release has been modified and no longer contains Kotlin-Coroutines-Suspends.jar -We apologize for the inconvience. We will advise when we have fixed the problem. A new release will be generated when the problem is fixed. +Due to problems revolving around Suspend Functions in Kotlin Coroutines, a fix was required to the Java Agent to resolve these problems. The fix is available in the 8.19.0 version and later of the Java Agent. The instrumentation for Suspend Functions has been included again but does require that you use version 8.19.0 or later of the Java Agent. If you are unable to upgrade the agent, then remove the Kotlin-Coroutines-Suspends.jar from the extensions directory. ## Supported Versions From 1591f813024aa6f4719bfdbb1e5fe01db36ec753 Mon Sep 17 00:00:00 2001 From: Doug Hilpipre Date: Mon, 17 Mar 2025 10:18:46 -0500 Subject: [PATCH 07/10] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 0ba3828..927f3e9 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,10 @@ The following things are captured as part of the instrumentation Instrumentation of methods with high invocation rates can lead to CPU overhead especially if its average response time is very small (i.e. less than a few milliseconds). Therefore it is possible to configure the agent to ignore certain suspend methods, dispatched tasks and continuation resumeWiths. This configuation is done in the newrelic.yml file. +### Suspend Function Tracking + +The instrumentation will track suspend functions that are outside of those within the Kotlin Coroutine framework. This means that it will track suspend functions that are genrated in your code and in frameworks that use Coroutines. + ### Finding Coroutine Scopes to Ignore This is basically meant for Standalone Coroutines that you don't want to track for some reason such as it is a long running task that doesn't need to be tracked. Lazy Coroutines are a good example. If the agent encounters that scope it will stop tracing that transaction, hence if you disable a scope that is part of another transaction rather than just itself it will also disable that transaction. But the configuration is dynamic so you can remove to restore the transaction. To find the value to use for the Coroutine Scope to ignore go into the transaction trace and select the "Custom/Builders/launch" or "Custom/Builders/async" span. In the Attributes tab find CoroutineScope-Class for the value to use as shown below. image From 8f4bbb1fa74a06002aa03d240e743e1998942e1b Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 17 Mar 2025 15:23:02 +0000 Subject: [PATCH 08/10] Update Changelog for Release [skip ci] --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d9a98c..bc6f753 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## Version: [v1.0.6](https://github.com/newrelic/newrelic-java-kotlin-coroutines/releases/tag/v1.0.6) | Created: 2025-03-17 + + ## Version: [v1.0.5](https://github.com/newrelic/newrelic-java-kotlin-coroutines/releases/tag/v1.0.5) | Created: 2024-10-21 From 125c90aaca6e496edaf05fe42bd625dd2edf11cf Mon Sep 17 00:00:00 2001 From: Doug Hilpipre Date: Mon, 17 Mar 2025 11:02:19 -0500 Subject: [PATCH 09/10] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 927f3e9..4465915 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,8 @@ At minumum consider ignoring anything over 50K. Below each rate is the name of the metric, it has the form Custom/DispatchedTask/..., or Custom/WrappedSuspend/... or Custom/ContinuationWrapper/... depending on the query that was run. Collect a list of the remaining metric name (i.e. the ...). -### Configuring Methods to Ignore +### Configuring Methods to Ignore +The configuration supports using regular expression wildcards to ignore multiple items rather than having to list each one separately. For example, to ignore any suspend function in the class com.mycompany.mypackage.MyClass, use To configure methods to ignore, edit the newrelic.yml file in the New Relic Java Agent directory. 1. Find the following lines in newrelic.yml @@ -104,7 +105,7 @@ Note that these setting are dynamic, so typically the agent should pick up chang ### Configuring Scopes to Ignore Similar to configuring the method to ignore above except add a line scopes: to the configuration as shown: -image +image ## Building From 666cf362dff71fb34b34ad0e93d24a8dffe704c8 Mon Sep 17 00:00:00 2001 From: Doug Hilpipre Date: Mon, 17 Mar 2025 13:34:16 -0500 Subject: [PATCH 10/10] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4465915..94e4574 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,9 @@ At minumum consider ignoring anything over 50K. Below each rate is the name of the metric, it has the form Custom/DispatchedTask/..., or Custom/WrappedSuspend/... or Custom/ContinuationWrapper/... depending on the query that was run. Collect a list of the remaining metric name (i.e. the ...). ### Configuring Methods to Ignore -The configuration supports using regular expression wildcards to ignore multiple items rather than having to list each one separately. For example, to ignore any suspend function in the class com.mycompany.mypackage.MyClass, use +The configuration supports using regular expression wildcards to ignore multiple items rather than having to list each one separately. For example, to ignore any suspend function in the class com.mycompany.mypackage.MyClass, use com\.mycompany\.mypackage\.MyClass.* +Note that Java Regular Expressions as regular expressions so consult a cheat sheet for guidance. (e.g. https://quickref.me/regex.html) + To configure methods to ignore, edit the newrelic.yml file in the New Relic Java Agent directory. 1. Find the following lines in newrelic.yml