|
1 | 1 | package datadog.trace.instrumentation.springmessaging; |
2 | 2 |
|
3 | 3 | import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; |
| 4 | +import static datadog.trace.api.datastreams.DataStreamsContext.create; |
| 5 | +import static datadog.trace.api.datastreams.DataStreamsTags.Direction.INBOUND; |
4 | 6 | import static datadog.trace.bootstrap.instrumentation.api.AgentPropagation.extractContextAndGetSpanContext; |
5 | | -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; |
6 | | -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; |
7 | | -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; |
| 7 | +import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.*; |
8 | 8 | import static datadog.trace.instrumentation.springmessaging.SpringMessageDecorator.DECORATE; |
9 | 9 | import static datadog.trace.instrumentation.springmessaging.SpringMessageDecorator.SPRING_INBOUND; |
10 | 10 | import static datadog.trace.instrumentation.springmessaging.SpringMessageExtractAdapter.GETTER; |
| 11 | +import static java.util.Collections.singletonMap; |
11 | 12 | import static net.bytebuddy.matcher.ElementMatchers.isMethod; |
12 | 13 | import static net.bytebuddy.matcher.ElementMatchers.takesArgument; |
13 | 14 |
|
14 | 15 | import com.google.auto.service.AutoService; |
15 | 16 | import datadog.trace.agent.tooling.Instrumenter; |
16 | 17 | import datadog.trace.agent.tooling.InstrumenterModule; |
| 18 | +import datadog.trace.api.datastreams.DataStreamsTags; |
| 19 | +import datadog.trace.bootstrap.InstrumentationContext; |
17 | 20 | import datadog.trace.bootstrap.instrumentation.api.AgentScope; |
18 | 21 | import datadog.trace.bootstrap.instrumentation.api.AgentSpan; |
19 | 22 | import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext; |
| 23 | +import datadog.trace.bootstrap.instrumentation.api.AgentTracer; |
| 24 | +import datadog.trace.bootstrap.instrumentation.java.concurrent.State; |
| 25 | +import java.util.Map; |
20 | 26 | import net.bytebuddy.asm.Advice; |
21 | 27 | import org.springframework.messaging.Message; |
22 | 28 | import org.springframework.messaging.handler.invocation.InvocableHandlerMethod; |
@@ -53,22 +59,88 @@ public String[] helperClassNames() { |
53 | 59 | }; |
54 | 60 | } |
55 | 61 |
|
| 62 | + @Override |
| 63 | + public Map<String, String> contextStore() { |
| 64 | + return singletonMap("org.springframework.messaging.Message", State.class.getName()); |
| 65 | + } |
| 66 | + |
56 | 67 | public static class HandleMessageAdvice { |
57 | 68 | @Advice.OnMethodEnter(suppress = Throwable.class) |
58 | 69 | public static AgentScope onEnter( |
59 | 70 | @Advice.This InvocableHandlerMethod thiz, @Advice.Argument(0) Message<?> message) { |
60 | 71 | AgentSpanContext parentContext; |
61 | 72 | AgentSpan parent = activeSpan(); |
| 73 | + |
| 74 | + // First try to get context from continuation (preferred method) |
| 75 | + State state = InstrumentationContext.get(Message.class, State.class).get(message); |
| 76 | + if (null != state) { |
| 77 | + System.out.println("[Spring] Found state in Spring message, attempting to activate continuation on thread: " + |
| 78 | + Thread.currentThread().getId()); |
| 79 | + AgentScope.Continuation continuation = state.getAndResetContinuation(); |
| 80 | + if (null != continuation) { |
| 81 | + try (AgentScope scope = continuation.activate()) { |
| 82 | + AgentSpan span = startSpan(SPRING_INBOUND); |
| 83 | + DECORATE.afterStart(span); |
| 84 | + span.setResourceName(DECORATE.spanNameForMethod(thiz.getMethod())); |
| 85 | + System.out.println("[Spring] Successfully activated continuation from Spring Message with span: " + |
| 86 | + span.getSpanId() + " on thread: " + Thread.currentThread().getId()); |
| 87 | + return activateSpan(span); |
| 88 | + } |
| 89 | + } else { |
| 90 | + System.out.println("[Spring] No continuation found in state on thread: " + Thread.currentThread().getId()); |
| 91 | + } |
| 92 | + } else { |
| 93 | + System.out.println("[Spring] No state found in Spring message 2, falling back to header extraction on thread: " + |
| 94 | + Thread.currentThread().getId()); |
| 95 | + } |
| 96 | + |
| 97 | + // Fallback to existing context or header extraction |
62 | 98 | if (null != parent) { |
63 | 99 | // prefer existing context, assume it was already extracted from this message |
64 | 100 | parentContext = parent.context(); |
| 101 | + System.out.println("[Spring] Using existing active span context on thread: " + Thread.currentThread().getId()); |
65 | 102 | } else { |
66 | 103 | // otherwise try to re-extract the message context to avoid disconnected trace |
67 | 104 | parentContext = extractContextAndGetSpanContext(message, GETTER); |
| 105 | + System.out.println("[Spring] Extracted context from message headers on thread: " + Thread.currentThread().getId()); |
68 | 106 | } |
| 107 | + |
69 | 108 | AgentSpan span = startSpan(SPRING_INBOUND, parentContext); |
70 | 109 | DECORATE.afterStart(span); |
71 | 110 | span.setResourceName(DECORATE.spanNameForMethod(thiz.getMethod())); |
| 111 | + |
| 112 | + // Extract SQS queue information - try different header patterns |
| 113 | + Object queueUrl = message.getHeaders().get("Sqs_QueueUrl"); |
| 114 | + Object queueName = message.getHeaders().get("Sqs_QueueName"); |
| 115 | + |
| 116 | + // If not found in Sqs_ prefixed headers, try aws. prefixed headers |
| 117 | + if (queueUrl == null) { |
| 118 | + queueUrl = message.getHeaders().get("aws.queue.url"); |
| 119 | + } |
| 120 | + if (queueName == null) { |
| 121 | + queueName = message.getHeaders().get("aws.queue.name"); |
| 122 | + } |
| 123 | + |
| 124 | + // If still not found, try to extract from QueueAttributes |
| 125 | + if (queueUrl == null || queueName == null) { |
| 126 | + Object queueAttributes = message.getHeaders().get("Sqs_QueueAttributes"); |
| 127 | + if (queueAttributes != null) { |
| 128 | + String attributesStr = queueAttributes.toString(); |
| 129 | + // Extract queue name from attributes if available |
| 130 | + if (queueName == null && attributesStr.contains("queueName=")) { |
| 131 | + queueName = attributesStr.substring(attributesStr.indexOf("queueName=") + 10).split(",")[0]; |
| 132 | + } |
| 133 | + } |
| 134 | + } |
| 135 | + |
| 136 | + // Add SQS queue tags to the span |
| 137 | + if (queueUrl != null) { |
| 138 | + span.setTag("aws.sqs.queue_url", queueUrl.toString()); |
| 139 | + } |
| 140 | + if (queueName != null) { |
| 141 | + span.setTag("aws.sqs.queue_name", queueName.toString()); |
| 142 | + } |
| 143 | + |
72 | 144 | return activateSpan(span); |
73 | 145 | } |
74 | 146 |
|
|
0 commit comments