Skip to content

Commit

Permalink
Merge pull request #22 from newrelic-experimental/camel-updates
Browse files Browse the repository at this point in the history
Camel updates
  • Loading branch information
dhilpipre committed Jan 25, 2024
2 parents feb45d3 + 815579d commit c0d1e3a
Show file tree
Hide file tree
Showing 58 changed files with 1,306 additions and 676 deletions.
1 change: 1 addition & 0 deletions camel-core-3.18/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ jar {
attributes 'Implementation-Vendor': 'New Relic Labs'
attributes 'Implementation-Vendor-Id': 'com.newrelic.labs'
attributes 'Implementation-Version': 1.0
attributes 'Agent-Class': 'com.newrelic.instrumentation.labs.apache.camel.processors.CamelCorePremain'
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.newrelic.instrumentation.labs.apache.camel.processors;

import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.logging.Level;

import com.newrelic.agent.deps.org.objectweb.asm.commons.Method;
import com.newrelic.agent.instrumentation.classmatchers.ClassAndMethodMatcher;
import com.newrelic.agent.instrumentation.classmatchers.OptimizedClassMatcher.Match;
import com.newrelic.agent.instrumentation.classmatchers.OptimizedClassMatcherBuilder;
import com.newrelic.agent.instrumentation.context.ClassMatchVisitorFactory;
import com.newrelic.agent.instrumentation.context.ContextClassTransformer;
import com.newrelic.agent.instrumentation.context.InstrumentationContext;
import com.newrelic.agent.instrumentation.methodmatchers.MethodMatcher;
import com.newrelic.agent.instrumentation.tracing.TraceDetailsBuilder;
import com.newrelic.api.agent.NewRelic;


public class CamelClassTransformer implements ContextClassTransformer {

private ClassMatchVisitorFactory matcher = null;

public ClassMatchVisitorFactory getMatcher() {
return matcher;
}

public CamelClassTransformer() {
matcher = OptimizedClassMatcherBuilder.newBuilder().addClassMethodMatcher(new ProcessorClassMethodMatcher()).build();
}

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer, InstrumentationContext context, Match match)
throws IllegalClassFormatException {
for (Method method : match.getMethods()) {
for (ClassAndMethodMatcher matcher : match.getClassMatches().keySet()) {
if (matcher.getMethodMatcher().matches(MethodMatcher.UNSPECIFIED_ACCESS, method.getName(),
method.getDescriptor(), match.getMethodAnnotations(method))) {
NewRelic.getAgent().getLogger().log(Level.FINE, "Instrumenting the Processor class {0} and method {1}",className,method.getName());
context.putTraceAnnotation(method, TraceDetailsBuilder.newBuilder().build());
}
}

}
return null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.newrelic.instrumentation.labs.apache.camel.processors;

import java.lang.instrument.Instrumentation;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;

import com.newrelic.agent.instrumentation.ClassTransformerService;
import com.newrelic.agent.instrumentation.context.InstrumentationContextManager;
import com.newrelic.agent.service.ServiceFactory;
import com.newrelic.api.agent.NewRelic;

public class CamelCorePremain {

private static ExecutorService executor = null;

public static void premain(String s, Instrumentation inst) {
initialize();
}

public static void initialize() {
ClassTransformerService classTransformerService = ServiceFactory.getClassTransformerService();
if(classTransformerService != null) {
InstrumentationContextManager contextMgr = classTransformerService.getContextManager();

if(contextMgr != null) {
CamelClassTransformer classTransformer = new CamelClassTransformer();
NewRelic.getAgent().getLogger().log(Level.FINE, "Constructed CamelClassTransformer: {0}, matcher: {1}", classTransformer, classTransformer.getMatcher());
contextMgr.addContextClassTransformer(classTransformer.getMatcher(), classTransformer);
} else {
NewRelic.getAgent().getLogger().log(Level.FINE, "Could not load matcher because ClassTransformerService is null");
startExecutor();
}
} else {
NewRelic.getAgent().getLogger().log(Level.FINE, "Could not load matcher because InstrumentationContextManager is null");
startExecutor();
}

}

private static void startExecutor() {
executor = Executors.newSingleThreadExecutor();
RunCheck runCheck = new RunCheck();
executor.submit(runCheck);
NewRelic.getAgent().getLogger().log(Level.FINE, "Submit RunCheck to executor");
}

private static void shutdownExecutor() {
if (executor != null) {
executor.shutdown();
NewRelic.getAgent().getLogger().log(Level.FINE, "CamelPremain executor has shut down");
}
}


private static class RunCheck implements Runnable {

@Override
public void run() {
boolean done = false;
while(!done) {
ClassTransformerService classTransformerService = ServiceFactory.getClassTransformerService();
if(classTransformerService != null) {
InstrumentationContextManager contextMgr = classTransformerService.getContextManager();

if(contextMgr != null) {
CamelClassTransformer classTransformer = new CamelClassTransformer();
NewRelic.getAgent().getLogger().log(Level.FINE, "Constructed CamelClassTransformer: {0}, matcher: {1}", classTransformer, classTransformer.getMatcher());
contextMgr.addContextClassTransformer(classTransformer.getMatcher(), classTransformer);
done = true;
}
} else {
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
}
}
}
shutdownExecutor();
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.newrelic.instrumentation.labs.apache.camel.processors;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import com.newrelic.agent.deps.org.objectweb.asm.ClassReader;
import com.newrelic.agent.instrumentation.classmatchers.ClassMatcher;

public class ExcludedClassMatcher extends ClassMatcher {

private static final List<String> excluded;

static {
excluded = new ArrayList<>();
excluded.add("com.nr.instrumentation.apache.camel.NRProcessorStart");
excluded.add("com.nr.instrumentation.apache.camel.NRAsyncProcessorStart");
excluded.add("com.nr.instrumentation.apache.camel.NRProcessorWrapper");
excluded.add("com.nr.instrumentation.apache.camel.NRAsyncProcessorWrapper");
excluded.add("org.apache.camel.impl.engine.SharedCamelInternalProcessor");
excluded.add("org.apache.camel.impl.engine.CamelInternalProcessor");
}

@Override
public boolean isMatch(ClassLoader loader, ClassReader cr) {

return !excluded.contains(cr.getClassName());
}

@Override
public boolean isMatch(Class<?> clazz) {
return !excluded.contains(clazz.getName());
}

@Override
public Collection<String> getClassNames() {

return Collections.emptyList();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.newrelic.instrumentation.labs.apache.camel.processors;

import java.util.Collection;

import com.newrelic.agent.deps.org.objectweb.asm.ClassReader;
import com.newrelic.agent.instrumentation.classmatchers.AndClassMatcher;
import com.newrelic.agent.instrumentation.classmatchers.ClassMatcher;
import com.newrelic.agent.instrumentation.classmatchers.InterfaceMatcher;

public class ProcessorClassMatcher extends ClassMatcher {

private AndClassMatcher matcher = null;
private static final String interfaceName = "org.apache.camel.Processor";

public ProcessorClassMatcher() {
ExcludedClassMatcher excluded = new ExcludedClassMatcher();
InterfaceMatcher interfaceMatcher = new InterfaceMatcher(interfaceName);
matcher = new AndClassMatcher(excluded,interfaceMatcher);
}

@Override
public boolean isMatch(ClassLoader loader, ClassReader cr) {
return matcher.isMatch(loader, cr);
}

@Override
public boolean isMatch(Class<?> clazz) {
return matcher.isMatch(clazz);
}

@Override
public Collection<String> getClassNames() {
return matcher.getClassNames();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.newrelic.instrumentation.labs.apache.camel.processors;

import com.newrelic.agent.instrumentation.classmatchers.ClassAndMethodMatcher;
import com.newrelic.agent.instrumentation.classmatchers.ClassMatcher;
import com.newrelic.agent.instrumentation.classmatchers.InterfaceMatcher;
import com.newrelic.agent.instrumentation.methodmatchers.MethodMatcher;
import com.newrelic.agent.instrumentation.methodmatchers.NameMethodMatcher;

public class ProcessorClassMethodMatcher implements ClassAndMethodMatcher {

private ProcessorClassMatcher classMatcher;
private NameMethodMatcher methodMatcher;
private static final String methodName = "process";

public ProcessorClassMethodMatcher() {
classMatcher = new ProcessorClassMatcher();
methodMatcher = new NameMethodMatcher(methodName);
}

@Override
public ClassMatcher getClassMatcher() {
return classMatcher;
}

@Override
public MethodMatcher getMethodMatcher() {
return methodMatcher;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@
import com.newrelic.api.agent.NewRelic;
import com.newrelic.api.agent.Trace;
import com.newrelic.api.agent.TransactionNamePriority;
import com.newrelic.api.agent.TransportType;
import com.newrelic.api.agent.weaver.Weave;
import com.newrelic.api.agent.weaver.Weaver;

@Weave(originalName="org.apache.camel.processor.aggregate.AggregateProcessor")
public abstract class AggregateProcessor_instrumentation {

@Trace(dispatcher = true)
@Trace
protected boolean doProcess(Exchange exchange, AsyncCallback callback) {
Map<String, Object> attributes = new HashMap<String, Object>();
Util.recordExchange(attributes, exchange);
Expand All @@ -26,19 +25,17 @@ protected boolean doProcess(Exchange exchange, AsyncCallback callback) {
NewRelic.getAgent().getTracedMethod().setMetricName(new String[] {"Custom","AggregateProcessor","doProcess",routeID});
NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW, false, "CamelProcessor", new String[] {"AggregateProcessor",routeID});
}
NewRelic.getAgent().getTransaction().acceptDistributedTraceHeaders(TransportType.Other, new CamelHeaders(exchange));
return Weaver.callOriginal();
}

@Trace(dispatcher=true)
@Trace
protected boolean doProcess(Exchange exchange, String key, AsyncCallback callback, boolean sync) {
String routeID = exchange != null ? exchange.getFromRouteId() : null;
if(routeID != null && !routeID.isEmpty()) {
NewRelic.addCustomParameter("From Route ID", routeID);
NewRelic.getAgent().getTracedMethod().setMetricName(new String[] {"Custom","AggregateProcessor","doProcess",routeID});
NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW, false, "CamelProcessor", new String[] {"AggregateProcessor",routeID});
}
NewRelic.getAgent().getTransaction().acceptDistributedTraceHeaders(TransportType.Other, new CamelHeaders(exchange));

return Weaver.callOriginal();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public String getHeader(String name) {
@Override
public Collection<String> getHeaderNames() {
Map<String, Object> props = exchange.getProperties();
Message msg = exchange.getMessage();
if(msg != null) {
Map<String, Object> msgHeaders = msg.getHeaders();
props.putAll(msgHeaders);
}

return props != null ? props.keySet() : Collections.emptyList();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package com.nr.instrumentation.apache.camel;

import java.util.HashMap;
import java.util.Map;

import org.apache.camel.AsyncCallback;
import org.apache.camel.Exchange;
import org.apache.camel.Message;

import com.newrelic.api.agent.NewRelic;
import com.newrelic.api.agent.Trace;
import com.newrelic.api.agent.TracedMethod;
import com.newrelic.api.agent.TransactionNamePriority;
import com.newrelic.api.agent.TransportType;
import com.newrelic.api.agent.weaver.MatchType;
import com.newrelic.api.agent.weaver.Weave;
Expand All @@ -20,19 +18,16 @@ public abstract class CamelInternalProcessor_instrumentation {

@Trace(dispatcher = true)
public boolean process(Exchange exchange, AsyncCallback callback) {
Map<String, Object> attributes = new HashMap<String, Object>();
HashMap<String, Object> attributes = new HashMap<>();
Util.recordExchange(attributes, exchange);
TracedMethod traced = NewRelic.getAgent().getTracedMethod();
if(exchange != null && exchange.getFromRouteId() != null) {
traced.setMetricName("Custom","CamelInternalProcessor","process",exchange.getFromRouteId());
NewRelic.getAgent().getTracedMethod().addCustomAttributes(attributes);
String routeId = exchange != null ? exchange.getFromRouteId() : null;
if(exchange != null) {
NewRelic.getAgent().getTransaction().acceptDistributedTraceHeaders(TransportType.Other, new CamelHeaders(exchange));
}
if(!attributes.isEmpty()) {
traced.addCustomAttributes(attributes);
if(routeId != null && !routeId.isEmpty()) {
NewRelic.getAgent().getTransaction().setTransactionName(TransactionNamePriority.FRAMEWORK_LOW, false, "CamelInternalProcessor", "Camel",getClass().getSimpleName(),routeId);
}
Message message = exchange.getMessage();


NewRelic.getAgent().getTransaction().acceptDistributedTraceHeaders(TransportType.Other, new CamelMessageHeaders(message));
return Weaver.callOriginal();
}
}
Loading

0 comments on commit c0d1e3a

Please sign in to comment.