Skip to content

Commit

Permalink
fix: expression resolution on span name and tags (#225)
Browse files Browse the repository at this point in the history
  • Loading branch information
manikmagar authored Jan 7, 2025
1 parent e6f466d commit b711884
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.avioconsulting.mule.opentelemetry.api.store.TransactionStore;
import com.avioconsulting.mule.opentelemetry.api.traces.TraceComponent;
import com.avioconsulting.mule.opentelemetry.internal.processor.MuleNotificationProcessor;
import com.avioconsulting.mule.opentelemetry.internal.util.ComponentsUtil;
import org.mule.runtime.api.component.Component;
import org.mule.runtime.api.component.location.ComponentLocation;
import org.mule.runtime.api.component.location.ConfigurationComponentLocator;
Expand All @@ -24,6 +23,7 @@
import static com.avioconsulting.mule.opentelemetry.api.store.TransactionStore.*;
import static com.avioconsulting.mule.opentelemetry.internal.util.ComponentsUtil.*;
import static com.avioconsulting.mule.opentelemetry.internal.util.OpenTelemetryUtil.getEventTransactionId;
import static com.avioconsulting.mule.opentelemetry.internal.util.OpenTelemetryUtil.resolveExpressions;

/**
* Interceptor to set tracing context information in flow a variable
Expand Down Expand Up @@ -102,6 +102,8 @@ public void before(
}
LOGGER.trace("Creating Span in the interceptor for {} at {}",
location.getComponentIdentifier().getIdentifier(), location.getLocation());
resolveExpressions(traceComponent,
muleNotificationProcessor.getOpenTelemetryConnection().getExpressionManager(), event);
muleNotificationProcessor.getOpenTelemetryConnection().addProcessorSpan(traceComponent,
getLocationParent(location.getLocation()));
final String transactionId = getEventTransactionId(event);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import static com.avioconsulting.mule.opentelemetry.internal.util.ComponentsUtil.getTraceComponent;
import static com.avioconsulting.mule.opentelemetry.internal.util.ComponentsUtil.isFlowRef;
import static com.avioconsulting.mule.opentelemetry.internal.util.ComponentsUtil.resolveFlowName;
import static com.avioconsulting.mule.opentelemetry.internal.util.OpenTelemetryUtil.resolveExpressions;

/**
* Notification Processor bean. This is injected through registry-bootstrap into
Expand Down Expand Up @@ -180,6 +181,8 @@ private void processComponentStartSpan(EnrichedServerNotification notification)
.withStartTime(Instant.ofEpochMilli(notification.getTimestamp()))
.withEventContextId(notification.getEvent().getContext().getId())
.withComponentLocation(notification.getComponent().getLocation());
resolveExpressions(traceComponent, openTelemetryConnection.getExpressionManager(),
notification.getEvent());
openTelemetryConnection.addProcessorSpan(traceComponent,
ComponentsUtil.getLocationParent(notification.getComponent().getLocation().getLocation()));
processFlowRef(traceComponent, notification.getEvent());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package com.avioconsulting.mule.opentelemetry.internal.util;

import com.avioconsulting.mule.opentelemetry.api.traces.TraceComponent;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.AttributesBuilder;
import org.mule.runtime.api.event.Event;
import org.mule.runtime.api.event.EventContext;
import org.mule.runtime.api.metadata.TypedValue;
import org.mule.runtime.core.api.el.ExpressionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

public class OpenTelemetryUtil {

Expand Down Expand Up @@ -88,4 +93,39 @@ public static void addAttribute(String property, AttributesBuilder builder,
}
}

/**
* Resolves any expressions in the TraceComponent's spanName and tags using the
* provided ExpressionManager
* based on the given Event.
*
* @param traceComponent
* the TraceComponent containing spanName and tags to resolve
* @param expressionManager
* the ExpressionManager used to evaluate expressions
* @param event
* the Event used for context in expression evaluation
*/
public static void resolveExpressions(TraceComponent traceComponent, ExpressionManager expressionManager,
Event event) {
try {
if (expressionManager
.isExpression(traceComponent.getSpanName())) {
TypedValue<String> evaluatedSpanName = (TypedValue<String>) expressionManager
.evaluate(traceComponent.getSpanName(), event.asBindingContext());
if (evaluatedSpanName.getValue() != null) {
traceComponent.withSpanName(evaluatedSpanName.getValue());
}
}
List<Map.Entry<String, String>> expressionTags = traceComponent.getTags().entrySet().stream()
.filter(e -> expressionManager.isExpression(e.getValue())).collect(Collectors.toList());
for (Map.Entry<String, String> expressionTag : expressionTags) {
TypedValue<String> evaluate = (TypedValue<String>) expressionManager.evaluate(expressionTag.getValue(),
event.asBindingContext());
if (evaluate.getValue() != null) {
traceComponent.getTags().replace(expressionTag.getKey(), evaluate.getValue());
}
}
} catch (Exception ignored) {
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -321,4 +321,22 @@ public void testRequestSpanWithBasePath() throws Exception {
.containsExactly("/api/remote/invalid", "CLIENT");
}));
}

@Test
public void testHTTPSpanNames_withExpression() throws Exception {
Throwable throwable = catchThrowable(() -> flowRunner("flow-call-remote-with-expression")
.withVariable("resourcePath", "/expression/secrets")
.run());
await().untilAsserted(() -> assertThat(DelegatedLoggingSpanTestExporter.spanQueue)
.hasSize(2)
.element(0).as("Span for http:request flow")
.extracting("spanName", "spanKind")
.containsOnly("/expression/secrets", "CLIENT"));
DelegatedLoggingSpanTestExporter.Span client = getSpan("CLIENT", "/expression/secrets");
assertThat(client).isNotNull()
.extracting("attributes", as(InstanceOfAssertFactories.map(String.class, Object.class)))
.containsEntry("http.route", "/expression/secrets");

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.mule.runtime.api.interception.InterceptionAction;
import org.mule.runtime.api.interception.InterceptionEvent;
import org.mule.runtime.api.metadata.TypedValue;
import org.mule.runtime.core.api.el.ExpressionManager;

import java.util.Collections;
import java.util.Map;
Expand Down Expand Up @@ -239,8 +240,11 @@ public void verifyVariableResetOnTraceComponentNotFound() {
public void verifyVariableResetOnTraceComponentFound() {
OpenTelemetryConnection connection = mock(OpenTelemetryConnection.class);
TransactionStore transactionStore = mock(TransactionStore.class);
ExpressionManager expressionManager = mock(ExpressionManager.class);
when(expressionManager.isExpression(anyString())).thenReturn(false);
when(connection.getTransactionStore()).thenReturn(transactionStore);
when(transactionStore.transactionIdFor(any())).thenReturn("random-id");
when(connection.getExpressionManager()).thenReturn(expressionManager);

Map<String, String> traceparentMap = Collections.singletonMap("traceparent", "some-value");
ComponentLocation location = mock(ComponentLocation.class);
Expand Down
3 changes: 3 additions & 0 deletions src/test/resources/mule-opentelemetry-http.xml
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,7 @@ http://www.mulesoft.org/schema/mule/opentelemetry http://www.mulesoft.org/schema
<sub-flow name="sub-flow-call-remote-target" >
<http:request method="GET" doc:name="Request" config-ref="SELF_HTTP_Request_configuration" path="/test/remote/target"/>
</sub-flow>
<flow name="flow-call-remote-with-expression" >
<http:request method="GET" doc:name="Request" config-ref="SELF_HTTP_Request_configuration" path="#[vars.resourcePath]"/>
</flow>
</mule>

0 comments on commit b711884

Please sign in to comment.