Skip to content

Commit

Permalink
updated instrumentation to support Mule Core 4.7
Browse files Browse the repository at this point in the history
  • Loading branch information
dhilpipre committed Aug 28, 2024
1 parent cb2f4c7 commit 28e348d
Show file tree
Hide file tree
Showing 28 changed files with 1,151 additions and 0 deletions.
34 changes: 34 additions & 0 deletions Mule-Core-4.7/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

// Build.gradle generated for instrumentation module Mule-Core-4.5

apply plugin: 'java'


dependencies {
implementation 'org.mule.runtime:mule-core:4.7.0'
implementation group: 'com.google.guava', name: 'guava', version: '32.1.1-jre'

// New Relic Labs 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')
}

jar {
manifest {
attributes 'Implementation-Title': 'com.newrelic.instrumentation.labs.Mule-Core-4.5'
attributes 'Implementation-Vendor': 'New Relic Labs'
attributes 'Implementation-Vendor-Id': 'com.newrelic.labs'
attributes 'Implementation-Version': 1.0
}
}

verifyInstrumentation {
passes 'org.mule.runtime:mule-core:[4.7.0,)'
exclude 'org.mule.runtime:mule-core:4.8.0-20240422'
excludeRegex '.*MULE.*'
excludeRegex '.*rc.*'
excludeRegex '.*SNAPSHOT'
excludeRegex '.*4.5.0-202.*'

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.newrelic.mule.core;

import com.newrelic.agent.Transaction;
import com.newrelic.agent.tracing.SpanProxy;
import com.newrelic.api.agent.NewRelic;
import com.newrelic.api.agent.TransportType;

public class HeaderUtils {

public static void acceptHeaders(NRMuleHeaders headers) {
if(headers != null && !headers.isEmpty()) {
Transaction tx = Transaction.getTransaction(false);
if(tx != null) {
SpanProxy spanProxy = tx.getSpanProxy();
if(spanProxy.getOutboundDistributedTracePayload() == null) {
NewRelic.getAgent().getTransaction().acceptDistributedTraceHeaders(TransportType.Other, headers);
return;
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.newrelic.mule.core;

import java.util.function.BiConsumer;

import com.newrelic.agent.bridge.AgentBridge;
import com.newrelic.api.agent.NewRelic;
import com.newrelic.api.agent.Token;
import com.newrelic.api.agent.Trace;

public class NRBiConsumer<T,U> implements BiConsumer<T,U> {

private String name = null;
private Token token = null;

private static boolean isTransformed = false;

public NRBiConsumer(String n) {
name = n;
token = NewRelic.getAgent().getTransaction().getToken();
if(!isTransformed) {
AgentBridge.instrumentation.retransformUninstrumentedClass(getClass());
isTransformed = true;
}
}

@Override
@Trace(async=true)
public void accept(T t, U u) {
if(name != null && !name.isEmpty()) {
NewRelic.getAgent().getTracedMethod().setMetricName("Custom","CompletionHandler",name);
}
if(token != null) {
token.linkAndExpire();
token = null;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.newrelic.mule.core;

import java.util.Map;

import org.mule.runtime.api.component.location.ComponentLocation;
import org.mule.runtime.api.event.Event;
import org.mule.runtime.api.event.EventContext;
import org.mule.runtime.core.api.MuleContext;
import org.mule.runtime.core.api.construct.FlowConstruct;
import org.mule.runtime.core.api.event.CoreEvent;

@SuppressWarnings("deprecation")
public class NRCoreUtils {

public static void recordCoreEvent(String prefix, CoreEvent event, Map<String, Object> attributes) {
String prepend = prefix != null ? prefix + "-CoreEvent-" : "CoreEvent-";
recordValue(attributes, prepend+"CorrelationId", event.getCorrelationId());
EventContext eventContext = event.getContext();
if(eventContext != null) {
recordValue(attributes, prepend+"ID", eventContext.getId());
ComponentLocation origLoc = eventContext.getOriginatingLocation();
if(origLoc != null) {
recordValue(attributes, prepend+"OriginatingLocation", origLoc.getLocation());
}
}
}

public static void recordCoreEvent(String prefix, Event event, Map<String, Object> attributes) {
String prepend = prefix != null ? prefix + "-Event-" : "Event-";
recordValue(attributes, prepend+"CorrelationId", event.getCorrelationId());
EventContext eventContext = event.getContext();
if(eventContext != null) {
recordValue(attributes, prepend+"ID", eventContext.getId());
ComponentLocation origLoc = eventContext.getOriginatingLocation();
if(origLoc != null) {
recordValue(attributes, prepend+"OriginatingLocation", origLoc.getLocation());
}
}
}

public static void recordFlowConstruct(FlowConstruct flow, Map<String,Object> attributes) {
recordValue(attributes, "Flow-Name", flow.getName());
ComponentLocation location = flow.getLocation();
if(location != null) {
recordValue(attributes, "Flow-Location", location.getLocation());
}
recordMuleContext(flow.getMuleContext(), attributes);
recordValue(attributes,"Flow-ServerId",flow.getServerId());
recordValue(attributes,"Flow-UniqueId",flow.getUniqueIdString());
}

public static void recordMuleContext(MuleContext context, Map<String,Object> attributes) {
if (context != null) {
recordValue(attributes, "MuleContext-ClusterId", context.getClusterId());
recordValue(attributes, "MuleContext-Id", context.getId());
recordValue(attributes, "MuleContext-UniqueID", context.getUniqueIdString());
}
}

public static void recordValue(Map<String,Object> attributes, String key, Object value) {
if(key != null && !key.isEmpty() && value != null) {
attributes.put(key, value);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.newrelic.mule.core;

import java.util.function.Consumer;

import org.mule.runtime.core.api.event.CoreEvent;
import org.mule.runtime.core.internal.event.MuleUtils;

import com.newrelic.agent.bridge.AgentBridge;
import com.newrelic.api.agent.NewRelic;
import com.newrelic.api.agent.Token;
import com.newrelic.api.agent.Trace;


public class NREventConsumer implements Consumer<CoreEvent> {

private static boolean isTransformed = false;
private static boolean startTransformed = false;

private String name = null;

private Consumer<CoreEvent> delegate = null;

public NREventConsumer(String n, Consumer<CoreEvent> d) {
name = n;
delegate = d;
if(!isTransformed) {
isTransformed = true;
AgentBridge.instrumentation.retransformUninstrumentedClass(getClass());
}
}

public NREventConsumer() {
this(null,null);
}

@Override
public void accept(CoreEvent event) {
NRMuleHeaders headers = MuleUtils.getHeaders(event);
if(headers != null && !headers.isEmpty()) {
StartTransaction startTxn = new StartTransaction();
startTxn.start(delegate,event,headers);
} else {
if(delegate != null) {
delegate.accept(event);
}
}
}

private class StartTransaction {

protected StartTransaction() {
if(!startTransformed) {
startTransformed = true;
AgentBridge.instrumentation.retransformUninstrumentedClass(getClass());
}
}

@Trace(dispatcher = true)
protected void start(Consumer<CoreEvent> consumer, CoreEvent event,NRMuleHeaders headers) {
HeaderUtils.acceptHeaders(headers);
if(name != null) {
NewRelic.getAgent().getTracedMethod().setMetricName(new String[] {"Custom","EventConsumer",name});
}
if(consumer != null) {
consumer.accept(event);
}
}
}
}
18 changes: 18 additions & 0 deletions Mule-Core-4.7/src/main/java/com/newrelic/mule/core/NRFunction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.newrelic.mule.core;

import java.util.function.Function;

public class NRFunction<T,R> implements Function<T, R> {

private Function<T, R> actual = null;

public NRFunction(Function<T, R> a) {
actual = a;
}

@Override
public R apply(T t) {
return actual.apply(t);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.newrelic.mule.core;

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

import com.newrelic.api.agent.HeaderType;
import com.newrelic.api.agent.Headers;

public class NRMuleHeaders implements Headers {

private HashMap<String, String> headers = new HashMap<String, String>();

@Override
public HeaderType getHeaderType() {
return HeaderType.MESSAGE;
}

@Override
public String getHeader(String name) {
return headers.get(name);
}

@Override
public Collection<String> getHeaders(String name) {
String value = headers.get(name);
List<String> list = new ArrayList<String>();
if(value != null) {
list.add(value);
}
return list;
}

@Override
public void setHeader(String name, String value) {
headers.put(name, value);
}

@Override
public void addHeader(String name, String value) {
headers.put(name, value);
}

@Override
public Collection<String> getHeaderNames() {
return headers.keySet();
}

@Override
public boolean containsHeader(String name) {
return headers.containsKey(name);
}

public boolean isEmpty() {
return headers.isEmpty();
}

public void clear() {
headers.clear();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.mule.runtime.api.component.execution;

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.NewField;
import com.newrelic.api.agent.weaver.Weave;
import com.newrelic.api.agent.weaver.Weaver;
import com.newrelic.mule.core.HeaderUtils;
import com.newrelic.mule.core.NRMuleHeaders;

@Weave(type=MatchType.Interface)
public abstract class CompletableCallback<T> {

@NewField
public NRMuleHeaders headers = null;

@Trace
public void complete(T var1) {
HeaderUtils.acceptHeaders(headers);
headers = null;
Weaver.callOriginal();
}

@Trace
public void error(Throwable var1) {
NewRelic.noticeError(var1);
HeaderUtils.acceptHeaders(headers);
headers = null;
Weaver.callOriginal();
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.mule.runtime.core.api.construct;

import org.mule.runtime.core.api.processor.strategy.ProcessingStrategyFactory;

import com.newrelic.api.agent.Trace;
import com.newrelic.api.agent.weaver.MatchType;
import com.newrelic.api.agent.weaver.Weave;
import com.newrelic.api.agent.weaver.Weaver;

@Weave(type=MatchType.Interface)
public abstract class Pipeline {

@Trace
public ProcessingStrategyFactory getProcessingStrategyFactory() {
return Weaver.callOriginal();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.mule.runtime.core.api.execution;

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.NewField;
import com.newrelic.api.agent.weaver.Weave;
import com.newrelic.api.agent.weaver.Weaver;
import com.newrelic.mule.core.HeaderUtils;
import com.newrelic.mule.core.NRMuleHeaders;

@Weave(type=MatchType.Interface)
public abstract class ExecutionCallback<T> {

@NewField
public NRMuleHeaders headers;

@Trace(dispatcher=true)
public T process() {
HeaderUtils.acceptHeaders(headers);
headers = null;
NewRelic.getAgent().getTracedMethod().setMetricName("Custom","ExecutionCallback",getClass().getName());
return Weaver.callOriginal();
}
}
Loading

0 comments on commit 28e348d

Please sign in to comment.