diff --git a/Mule-Core-4.7/build.gradle b/Mule-Core-4.7/build.gradle new file mode 100644 index 0000000..849a649 --- /dev/null +++ b/Mule-Core-4.7/build.gradle @@ -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.*' + +} diff --git a/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/HeaderUtils.java b/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/HeaderUtils.java new file mode 100644 index 0000000..982fd27 --- /dev/null +++ b/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/HeaderUtils.java @@ -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; + } + } + } + } +} diff --git a/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/NRBiConsumer.java b/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/NRBiConsumer.java new file mode 100644 index 0000000..0d3b6da --- /dev/null +++ b/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/NRBiConsumer.java @@ -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 implements BiConsumer { + + 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; + } + } + +} diff --git a/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/NRCoreUtils.java b/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/NRCoreUtils.java new file mode 100644 index 0000000..b3832ab --- /dev/null +++ b/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/NRCoreUtils.java @@ -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 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 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 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 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 attributes, String key, Object value) { + if(key != null && !key.isEmpty() && value != null) { + attributes.put(key, value); + } + } +} diff --git a/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/NREventConsumer.java b/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/NREventConsumer.java new file mode 100644 index 0000000..7e362a7 --- /dev/null +++ b/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/NREventConsumer.java @@ -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 { + + private static boolean isTransformed = false; + private static boolean startTransformed = false; + + private String name = null; + + private Consumer delegate = null; + + public NREventConsumer(String n, Consumer 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 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); + } + } + } +} diff --git a/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/NRFunction.java b/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/NRFunction.java new file mode 100644 index 0000000..a694693 --- /dev/null +++ b/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/NRFunction.java @@ -0,0 +1,18 @@ +package com.newrelic.mule.core; + +import java.util.function.Function; + +public class NRFunction implements Function { + + private Function actual = null; + + public NRFunction(Function a) { + actual = a; + } + + @Override + public R apply(T t) { + return actual.apply(t); + } + +} diff --git a/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/NRMuleHeaders.java b/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/NRMuleHeaders.java new file mode 100644 index 0000000..f177c86 --- /dev/null +++ b/Mule-Core-4.7/src/main/java/com/newrelic/mule/core/NRMuleHeaders.java @@ -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 headers = new HashMap(); + + @Override + public HeaderType getHeaderType() { + return HeaderType.MESSAGE; + } + + @Override + public String getHeader(String name) { + return headers.get(name); + } + + @Override + public Collection getHeaders(String name) { + String value = headers.get(name); + List list = new ArrayList(); + 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 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(); + } + +} diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/api/component/execution/CompletableCallback.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/api/component/execution/CompletableCallback.java new file mode 100644 index 0000000..a2875e6 --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/api/component/execution/CompletableCallback.java @@ -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 { + + @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(); + } + + +} diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/construct/Pipeline.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/construct/Pipeline.java new file mode 100644 index 0000000..6bd0571 --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/construct/Pipeline.java @@ -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(); + } +} diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/execution/ExecutionCallback.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/execution/ExecutionCallback.java new file mode 100644 index 0000000..dc68cb3 --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/execution/ExecutionCallback.java @@ -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 { + + @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(); + } +} diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/execution/ExecutionTemplate.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/execution/ExecutionTemplate.java new file mode 100644 index 0000000..aeedce8 --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/execution/ExecutionTemplate.java @@ -0,0 +1,22 @@ +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.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import com.newrelic.mule.core.NRMuleHeaders; + +@Weave(type=MatchType.Interface) +public abstract class ExecutionTemplate { + + @Trace(dispatcher=true) + public T execute(ExecutionCallback callback) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","ExecutionTemplate",getClass().getName()); + if(callback.headers == null) { + callback.headers = new NRMuleHeaders(); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(callback.headers); + } + return Weaver.callOriginal(); + } +} diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/processor/Processor.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/processor/Processor.java new file mode 100644 index 0000000..a2b0385 --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/processor/Processor.java @@ -0,0 +1,29 @@ +package org.mule.runtime.core.api.processor; + +import java.util.HashMap; +import java.util.Map; + +import org.mule.runtime.core.api.event.CoreEvent; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import com.newrelic.mule.core.NRCoreUtils; + +@Weave(type=MatchType.Interface) +public abstract class Processor { + + @Trace + public CoreEvent process(CoreEvent event) { + Map attributes = new HashMap(); + NRCoreUtils.recordCoreEvent("Input", event, attributes); + CoreEvent returnedEvent = Weaver.callOriginal(); + NRCoreUtils.recordCoreEvent("Returned", returnedEvent, attributes); + NewRelic.getAgent().getTracedMethod().addCustomAttributes(attributes); + + return returnedEvent; + } + +} diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/processor/Sink.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/processor/Sink.java new file mode 100644 index 0000000..eb792ed --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/processor/Sink.java @@ -0,0 +1,27 @@ +package org.mule.runtime.core.api.processor; + +import org.mule.runtime.core.api.construct.BackPressureReason; +import org.mule.runtime.core.api.event.CoreEvent; + +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(type=MatchType.Interface) +public abstract class Sink { + + @Trace(excludeFromTransactionTrace=true) + public BackPressureReason emit(CoreEvent event) { + BackPressureReason returned = Weaver.callOriginal(); + + return returned; + } + + @Trace(async=true,excludeFromTransactionTrace=true) + public void accept(final CoreEvent event) { + NewRelic.getAgent().getTracedMethod().setMetricName(new String[] {"Custom","Sink",getClass().getSimpleName(),"accept"}); + Weaver.callOriginal(); + } +} diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/retry/RetryCallback.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/retry/RetryCallback.java new file mode 100644 index 0000000..d61cc07 --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/retry/RetryCallback.java @@ -0,0 +1,17 @@ +package org.mule.runtime.core.api.retry; + +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(type=MatchType.Interface) +public abstract class RetryCallback { + + @Trace + public void doWork(RetryContext context) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","RetryCallback",getClass().getSimpleName(),"doWork"); + Weaver.callOriginal(); + } +} diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/retry/async/AsynchronousRetryTemplate.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/retry/async/AsynchronousRetryTemplate.java new file mode 100644 index 0000000..9119a68 --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/api/retry/async/AsynchronousRetryTemplate.java @@ -0,0 +1,20 @@ +package org.mule.runtime.core.api.retry.async; + +import java.util.concurrent.Executor; + +import org.mule.runtime.core.api.retry.RetryCallback; +import org.mule.runtime.core.api.retry.RetryContext; + +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave +public abstract class AsynchronousRetryTemplate { + + @Trace(dispatcher=true) + public RetryContext execute(RetryCallback callback, Executor workManager) { + + return Weaver.callOriginal(); + } +} diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/event/AbstractEventContext.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/event/AbstractEventContext.java new file mode 100644 index 0000000..1486ff4 --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/event/AbstractEventContext.java @@ -0,0 +1,140 @@ +package org.mule.runtime.core.internal.event; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +import org.mule.runtime.api.event.EventContext; +import org.mule.runtime.core.api.event.CoreEvent; +import org.mule.runtime.core.api.exception.FlowExceptionHandler; +import org.mule.runtime.core.privileged.event.BaseEventContext; +import org.reactivestreams.Publisher; + +import com.newrelic.api.agent.NewRelic; +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 +abstract class AbstractEventContext implements BaseEventContext { + + @NewField + public NRMuleHeaders headers = null; + + public AbstractEventContext() { + + } + + public AbstractEventContext(FlowExceptionHandler exceptionHandler, int depthLevel,Optional> externalCompletion) { + if(this instanceof DefaultEventContext) { + setHeaders(); + } + } + + public abstract Optional getParentContext(); + + void addChildContext(final BaseEventContext childContext) { + if(childContext != null && childContext instanceof AbstractEventContext) { + NRMuleHeaders childHeaders = MuleUtils.getHeaders(childContext); + if(childHeaders == null || childHeaders.isEmpty()) { + if(headers != null) { + if(headers.isEmpty()) { + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); + if(!headers.isEmpty()) { + MuleUtils.setHeaders(childContext,headers); + } + } + } + } + } + Weaver.callOriginal(); + } + + public void success() { + if(headers != null && !headers.isEmpty()) { + HeaderUtils.acceptHeaders(headers); + headers.clear(); + headers = null; + } + try { + Optional parent = getParentContext(); + if(parent != null && parent.isPresent()) { + expireParent(parent); + } + } catch (NullPointerException e) { + } + Weaver.callOriginal(); + } + + private void expireParent(Optional parent) { + if(parent != null && parent.isPresent()) { + BaseEventContext root = parent.get().getRootContext(); + if(root instanceof AbstractEventContext) { + ((AbstractEventContext)root).headers.clear(); + ((AbstractEventContext)root).headers = null; + } + } + } + + public void success(CoreEvent event) { + if(headers != null && !headers.isEmpty()) { + HeaderUtils.acceptHeaders(headers); + headers.clear(); + headers = null; + } else { + + EventContext ctx = event.getContext(); + if(AbstractEventContext.class.isInstance(ctx)) { + AbstractEventContext bctx = (AbstractEventContext)ctx; + if(headers != null && !headers.isEmpty()) { + HeaderUtils.acceptHeaders(headers); + headers.clear(); + headers = null; + } + try { + Optional parent = bctx.getParentContext(); + expireParent(parent); + } catch (NullPointerException e) { + } + } + } + try { + Optional parent = getParentContext(); + expireParent(parent); + } catch (NullPointerException e) { + } + Weaver.callOriginal(); + } + + public Publisher error(Throwable throwable) { + if(headers != null && !headers.isEmpty()) { + HeaderUtils.acceptHeaders(headers); + headers.clear(); + headers = null; + } + try { + Optional parent = getParentContext(); + expireParent(parent); + } catch (NullPointerException e) { + } + NewRelic.noticeError(throwable); + return Weaver.callOriginal(); + } + + private void setHeaders() { + if(headers == null) { + headers = MuleUtils.getHeaders(getRootContext()); + if(headers == null || headers.isEmpty()) { + try { + BaseEventContext root = getRootContext(); + if (root != null) { + MuleUtils.setHeaders(root); + } + } catch (NullPointerException e) { + } + } + } + } + +} \ No newline at end of file diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/event/DefaultEventBuilder.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/event/DefaultEventBuilder.java new file mode 100644 index 0000000..d0ddcde --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/event/DefaultEventBuilder.java @@ -0,0 +1,36 @@ +package org.mule.runtime.core.internal.event; + +import org.mule.runtime.api.component.location.ComponentLocation; +import org.mule.runtime.core.privileged.event.BaseEventContext; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import com.newrelic.mule.core.NRMuleHeaders; + +@Weave +public abstract class DefaultEventBuilder { + + public InternalEvent build() { + InternalEvent event = Weaver.callOriginal(); + + String corrId = event.getCorrelationId(); + + NewRelic.addCustomParameter("CorrelationId", corrId); + + BaseEventContext eventCtx = event.getContext(); + if(eventCtx != null) { + NRMuleHeaders headers = MuleUtils.getHeaders(event); + if(headers == null || headers.isEmpty()) { + MuleUtils.setHeaders(eventCtx); + } + ComponentLocation location = eventCtx.getOriginatingLocation(); + if(location != null) { + NewRelic.addCustomParameter("Location", location.getLocation()); + } + } + return event; + + } + +} \ No newline at end of file diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/event/DefaultEventContext.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/event/DefaultEventContext.java new file mode 100644 index 0000000..3488bd6 --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/event/DefaultEventContext.java @@ -0,0 +1,28 @@ +package org.mule.runtime.core.internal.event; + +import java.util.Optional; + +import org.mule.runtime.api.component.location.ComponentLocation; +import org.mule.runtime.api.event.EventContext; +import org.mule.runtime.core.api.exception.FlowExceptionHandler; +import org.mule.runtime.core.privileged.event.BaseEventContext; + +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave +public abstract class DefaultEventContext extends AbstractEventContext { + + public static BaseEventContext child(BaseEventContext parent, Optional componentLocation, FlowExceptionHandler exceptionHandler) { + + BaseEventContext ctx = (BaseEventContext)Weaver.callOriginal(); + AbstractEventContext actx = (AbstractEventContext)parent; + if (actx.headers != null) { + ((AbstractEventContext)ctx).headers = actx.headers; + } else { + MuleUtils.setHeaders((EventContext)parent); + MuleUtils.setHeaders((EventContext)ctx); + } + return ctx; + } +} diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/event/MuleUtils.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/event/MuleUtils.java new file mode 100644 index 0000000..e4743df --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/event/MuleUtils.java @@ -0,0 +1,62 @@ +package org.mule.runtime.core.internal.event; + +import org.mule.runtime.api.event.EventContext; +import org.mule.runtime.core.api.event.CoreEvent; +import org.mule.runtime.core.privileged.event.BaseEventContext; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.mule.core.NRMuleHeaders; + +public class MuleUtils { + + public static NRMuleHeaders getHeaders(CoreEvent event) { + EventContext context = event.getContext(); + if(context != null) { + return getHeaders(context); + } + + return null; + } + + + public static NRMuleHeaders getHeaders(EventContext context) { + if(AbstractEventContext.class.isInstance(context)) { + AbstractEventContext tmpEventCtx = (AbstractEventContext)context; + NRMuleHeaders headers = tmpEventCtx.headers; + if(headers != null) return headers; + BaseEventContext rootContext = tmpEventCtx.getRootContext(); + if(rootContext != tmpEventCtx) { + return getHeaders(rootContext); + } + } + + return null; + } + + public static void setHeaders(EventContext context) { + if(context instanceof AbstractEventContext) { + AbstractEventContext eventCtx = (AbstractEventContext)context; + if(eventCtx.headers == null) { + BaseEventContext rootContext = eventCtx.getRootContext(); + if(rootContext != eventCtx) { + setHeaders(rootContext); + } else { + eventCtx.headers = new NRMuleHeaders(); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(eventCtx.headers); + } + } else if(eventCtx.headers.isEmpty()) { + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(eventCtx.headers); + } + } + + } + + public static void setHeaders(EventContext context, NRMuleHeaders headers) { + if (context instanceof BaseEventContext) { + BaseEventContext rootContext = ((BaseEventContext)context).getRootContext(); + if (rootContext instanceof AbstractEventContext) { + ((AbstractEventContext) rootContext).headers = headers; + } + } + } +} diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/execution/ClassLoaderInjectorInvocationHandler.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/execution/ClassLoaderInjectorInvocationHandler.java new file mode 100644 index 0000000..b99945f --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/execution/ClassLoaderInjectorInvocationHandler.java @@ -0,0 +1,47 @@ +package org.mule.runtime.core.internal.execution; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave +public abstract class ClassLoaderInjectorInvocationHandler { + + private final Object delegate = Weaver.callOriginal(); + + @Trace + public Object invoke(Object proxy, Method method, Object[] args) { + List names = new ArrayList(); + names.add("Custom"); + names.add("ClassLoaderInjectorInvocationHandler"); + if(proxy != null) { + String tmp = proxy.getClass().getSimpleName(); + if(!tmp.startsWith("$")) { + names.add(proxy.getClass().getSimpleName()); + } + } + if(delegate != null) { + String tmp = delegate.getClass().getSimpleName(); + if(!tmp.startsWith("$")) { + names.add(delegate.getClass().getSimpleName()); + } + } + if(method != null) { + Class declaring = method.getDeclaringClass(); + if(declaring != null) { + names.add(declaring.getSimpleName()); + } + String methodName = method.getName(); + names.add(methodName); + } + String[] namesArray = new String[names.size()]; + names.toArray(namesArray); + NewRelic.getAgent().getTracedMethod().setMetricName(namesArray); + return Weaver.callOriginal(); + } +} diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/execution/ExecutionInterceptor.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/execution/ExecutionInterceptor.java new file mode 100644 index 0000000..740ecec --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/execution/ExecutionInterceptor.java @@ -0,0 +1,21 @@ +package org.mule.runtime.core.internal.execution; + +import org.mule.runtime.core.api.execution.ExecutionCallback; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import com.newrelic.mule.core.HeaderUtils; + +@Weave(type=MatchType.Interface) +public abstract class ExecutionInterceptor { + + @Trace + public T execute(ExecutionCallback callback, ExecutionContext executionContext) { + NewRelic.getAgent().getTracedMethod().setMetricName("Custom","ExecutionInterceptor",getClass().getName(),"execute"); + HeaderUtils.acceptHeaders(callback.headers); + return Weaver.callOriginal(); + } +} diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/execution/FlowProcessMediator.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/execution/FlowProcessMediator.java new file mode 100644 index 0000000..d2f8c4b --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/execution/FlowProcessMediator.java @@ -0,0 +1,40 @@ +package org.mule.runtime.core.internal.execution; + +import java.util.HashMap; +import java.util.Map; + +import org.mule.runtime.api.component.location.ComponentLocation; +import org.mule.runtime.core.api.construct.FlowConstruct; +import org.mule.runtime.core.api.source.MessageSource; +import org.mule.sdk.api.runtime.source.DistributedTraceContextManager; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.TracedMethod; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import com.newrelic.mule.core.NRCoreUtils; +import java.util.Optional; + +@Weave +public abstract class FlowProcessMediator { + + @Trace + public void process(FlowProcessTemplate template,MessageProcessContext messageProcessContext, Optional distributedTraceContextManager) { + Map attributes = new HashMap(); + FlowConstruct flowConstruct = messageProcessContext.getFlowConstruct(); + TracedMethod traced = NewRelic.getAgent().getTracedMethod(); + if(flowConstruct != null) { + NRCoreUtils.recordFlowConstruct(flowConstruct, attributes); + } + MessageSource msgSource = messageProcessContext.getMessageSource(); + if(msgSource != null) { + ComponentLocation location = msgSource.getLocation(); + if(location != null) { + traced.addCustomAttribute("MessageSource-Location", location.getLocation()); + } + } + traced.addCustomAttributes(attributes); + Weaver.callOriginal(); + } +} diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/execution/FlowProcessingTemplate.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/execution/FlowProcessingTemplate.java new file mode 100644 index 0000000..93dde4f --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/execution/FlowProcessingTemplate.java @@ -0,0 +1,79 @@ +package org.mule.runtime.core.internal.execution; + +import java.util.HashMap; +import java.util.Map; + +import org.mule.runtime.api.component.Component; +import org.mule.runtime.api.component.execution.CompletableCallback; +import org.mule.runtime.api.component.location.ComponentLocation; +import org.mule.runtime.core.api.event.CoreEvent; +import org.mule.runtime.core.internal.exception.MessagingException; +import org.reactivestreams.Publisher; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import com.newrelic.mule.core.NRCoreUtils; +import com.newrelic.mule.core.NRMuleHeaders; + +@Weave(type=MatchType.BaseClass) +public abstract class FlowProcessingTemplate { + + @Trace + public CoreEvent routeEvent(CoreEvent muleEvent) { + Map attributes = new HashMap(); + NRCoreUtils.recordCoreEvent("Input", muleEvent, attributes); + CoreEvent returnedEvent = Weaver.callOriginal(); + NRCoreUtils.recordCoreEvent("Returned", returnedEvent, attributes); + NewRelic.getAgent().getTracedMethod().addCustomAttributes(attributes); + + return returnedEvent; + } + + @Trace + public Publisher routeEventAsync(CoreEvent event) { + Map attributes = new HashMap(); + NRCoreUtils.recordCoreEvent("Input", event, attributes); + return Weaver.callOriginal(); + } + + @Trace + public void sendResponseToClient(CoreEvent response, Map parameters, CompletableCallback callback) { + Map attributes = new HashMap(); + NRCoreUtils.recordCoreEvent("Response", response, attributes); + NewRelic.getAgent().getTracedMethod().addCustomAttributes(attributes); + if(callback.headers == null || callback.headers.isEmpty()) { + callback.headers = new NRMuleHeaders(); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(callback.headers); + } + Weaver.callOriginal(); + } + + @Trace + public void sendFailureResponseToClient(MessagingException exception, Map parameters,CompletableCallback callback) { + CoreEvent event = exception.getEvent(); + Map attributes = new HashMap(); + NRCoreUtils.recordCoreEvent(null, event, attributes); + Component failing = exception.getFailingComponent(); + if (failing != null) { + ComponentLocation location = failing.getLocation(); + if(location != null) { + NRCoreUtils.recordValue(attributes,"FailingComponent", location.getLocation()); + } + } + NRCoreUtils.recordValue(attributes, "Handled", exception.handled()); + NewRelic.noticeError(exception, attributes); + if(callback.headers == null || callback.headers.isEmpty()) { + callback.headers = new NRMuleHeaders(); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(callback.headers); + } + Weaver.callOriginal(); + } + + @Trace + public Publisher routeEventAsync(Publisher eventPub) { + return Weaver.callOriginal(); + } +} \ No newline at end of file diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/execution/MuleMessageProcessingManager.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/execution/MuleMessageProcessingManager.java new file mode 100644 index 0000000..b887da6 --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/execution/MuleMessageProcessingManager.java @@ -0,0 +1,31 @@ +package org.mule.runtime.core.internal.execution; + +import java.util.HashMap; +import java.util.Map; + +import org.mule.runtime.core.api.construct.FlowConstruct; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.TracedMethod; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import com.newrelic.mule.core.NRCoreUtils; + +@Weave +public class MuleMessageProcessingManager { + + @Trace + public void processMessage(FlowProcessTemplate messageProcessTemplate, MessageProcessContext messageProcessContext) { + + FlowConstruct flow = messageProcessContext.getFlowConstruct(); + if(flow != null) { + Map attributes = new HashMap(); + NRCoreUtils.recordFlowConstruct(flow , attributes); + TracedMethod traced = NewRelic.getAgent().getTracedMethod(); + traced.addCustomAttributes(attributes); + traced.setMetricName(new String[] {"Custom","MuleMessageProcessingManager","processMessage",messageProcessContext.getFlowConstruct().getName()}); + } + Weaver.callOriginal(); + } +} diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/processor/strategy/AbstractProcessingStrategy.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/processor/strategy/AbstractProcessingStrategy.java new file mode 100644 index 0000000..d3fdd58 --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/processor/strategy/AbstractProcessingStrategy.java @@ -0,0 +1,33 @@ +package org.mule.runtime.core.internal.processor.strategy; + +import java.util.function.Consumer; + +import org.mule.runtime.core.api.event.CoreEvent; + +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import com.newrelic.mule.core.NREventConsumer; + +@Weave(type=MatchType.BaseClass) +public class AbstractProcessingStrategy { + + protected Consumer createDefaultOnEventConsumer() { + Consumer consumer = Weaver.callOriginal(); + if(NREventConsumer.class.isInstance(consumer)) { + return consumer; + } else { + NREventConsumer wrapper = new NREventConsumer("ProcessingStrategy-Create",consumer); + return wrapper; + } + } + + public void setOnEventConsumer(Consumer onEventConsumer) { + if(!NREventConsumer.class.isInstance(onEventConsumer)) { + NREventConsumer wrapper = new NREventConsumer("ProcessingStrategy-Create",onEventConsumer); + onEventConsumer = wrapper; + } + Weaver.callOriginal(); + } + +} \ No newline at end of file diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/retry/async/RetryWorker.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/retry/async/RetryWorker.java new file mode 100644 index 0000000..2492bdc --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/internal/retry/async/RetryWorker.java @@ -0,0 +1,34 @@ +package org.mule.runtime.core.internal.retry.async; + +import java.util.concurrent.Executor; + +import org.mule.runtime.api.util.concurrent.Latch; +import org.mule.runtime.core.api.retry.RetryCallback; +import org.mule.runtime.core.api.retry.policy.RetryPolicyTemplate; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +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 +public abstract class RetryWorker { + + @NewField + private NRMuleHeaders headers = null; + + public RetryWorker(RetryPolicyTemplate delegate, RetryCallback callback, Executor workManager, Latch startLatch) { + headers = new NRMuleHeaders(); + NewRelic.getAgent().getTransaction().insertDistributedTraceHeaders(headers); + } + + @Trace(dispatcher=true) + public void run() { + HeaderUtils.acceptHeaders(headers); + Weaver.callOriginal(); + } + +} \ No newline at end of file diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/privileged/processor/AbstractExecutableComponent.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/privileged/processor/AbstractExecutableComponent.java new file mode 100644 index 0000000..e1f9a7b --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/privileged/processor/AbstractExecutableComponent.java @@ -0,0 +1,54 @@ +package org.mule.runtime.core.privileged.processor; + +import java.util.concurrent.CompletableFuture; + +import org.mule.runtime.api.component.AbstractComponent; +import org.mule.runtime.api.component.execution.ExecutionResult; +import org.mule.runtime.api.component.execution.InputEvent; +import org.mule.runtime.api.component.location.ComponentLocation; +import org.mule.runtime.api.event.Event; +import org.mule.runtime.core.api.event.CoreEvent; +import org.mule.runtime.core.internal.event.MuleUtils; + +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import com.newrelic.mule.core.HeaderUtils; +import com.newrelic.mule.core.NRMuleHeaders; + +@Weave(type=MatchType.BaseClass) +public abstract class AbstractExecutableComponent extends AbstractComponent { + + @Trace(dispatcher=true) + public CompletableFuture execute(InputEvent paramInputEvent) { + CompletableFuture f = Weaver.callOriginal(); + ComponentLocation location = getLocation(); + if(location != null) { + String locationStr = location.getLocation(); + if(locationStr != null && !locationStr.isEmpty()) { + NewRelic.getAgent().getTracedMethod().setMetricName(new String[] {"Custom","AbstractExecutableComponent",getClass().getSimpleName(),"execute"}); + } + } + return f; + } + + @Trace(dispatcher=true) + public CompletableFuture execute(Event paramEvent) { + if(CoreEvent.class.isInstance(paramEvent)) { + NRMuleHeaders headers = MuleUtils.getHeaders((CoreEvent)paramEvent); + HeaderUtils.acceptHeaders(headers); + } + CompletableFuture f = Weaver.callOriginal(); + ComponentLocation location = getLocation(); + if(location != null) { + String locationStr = location.getLocation(); + if(locationStr != null && !locationStr.isEmpty()) { + NewRelic.getAgent().getTracedMethod().setMetricName(new String[] {"Custom","AbstractExecutableComponent",getClass().getSimpleName(),"execute"}); + } + } + return f; + } + +} diff --git a/Mule-Core-4.7/src/main/java/org/mule/runtime/core/privileged/processor/chain/AbstractMessageProcessorChain.java b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/privileged/processor/chain/AbstractMessageProcessorChain.java new file mode 100644 index 0000000..3b31f6e --- /dev/null +++ b/Mule-Core-4.7/src/main/java/org/mule/runtime/core/privileged/processor/chain/AbstractMessageProcessorChain.java @@ -0,0 +1,46 @@ +package org.mule.runtime.core.privileged.processor.chain; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.mule.runtime.core.api.event.CoreEvent; +import org.mule.runtime.core.api.exception.FlowExceptionHandler; +import org.mule.runtime.core.api.processor.Processor; +import org.mule.runtime.core.api.processor.strategy.ProcessingStrategy; + +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.NRCoreUtils; + +@Weave(type=MatchType.BaseClass) +class AbstractMessageProcessorChain { + + @NewField + protected String chainName = "Unknown"; + + AbstractMessageProcessorChain(String name,Optional processingStrategyOptional,List processors, FlowExceptionHandler messagingExceptionHandler) { + if(name != null && !name.isEmpty()) { + chainName = name; + } + } + + @Trace(dispatcher=true) + public CoreEvent process(final CoreEvent event) { + NewRelic.getAgent().getTracedMethod().setMetricName(new String[] {"Custom","MuleProcessorChain",getClass().getSimpleName(),"process",chainName}); + Map attributes = new HashMap(); + NRCoreUtils.recordCoreEvent("Input", event, attributes); + CoreEvent returnedEvent = Weaver.callOriginal(); + NRCoreUtils.recordCoreEvent("Returned", returnedEvent, attributes); + NRCoreUtils.recordValue(attributes, "ChainName", chainName); + NewRelic.getAgent().getTracedMethod().addCustomAttributes(attributes); + + return returnedEvent; + } + +}