Solace does not recognise the JCSMP property "traceparent" from SAP's Advanced Event Mesh receiver adapter

Scenario: A SAP Cloud Integration iFlow uses SAP’s Advanced Event Mesh receiver adapter to publish event messages to a Solace event broker.

This adapter has the JCSMP property “traceparent” set to a valid traceparent value.

Solace event broker is configured to send trace data to Dynatrace, using a Distributed Tracing destination of type OTLP/HTTP.

Problem: When Solace generates trace OTEL records for Dynatrace, it generates its own trace-id value, for each span, and does not use the JCSMP property “traceparent”.

Questions:

  1. Is SAP’s AEM adapter capable of setting a JCSMP property that Solace would recognise?
  2. Is the JCSMP property name “traceparent” correct, in order for Solace to recognise it?

Kind regards

John Freeman

Hi John,

Thank you for the detailed description of your scenario. I work on the AEM adapter for SAP Integration Suite, so I can speak to exactly what’s happening here.

The short answer: the adapter can do what you need, but the property needs to be set in a different place than where you currently have it.

The AEM Receiver adapter has two separate property configuration areas that are easy to confuse:

  1. JCSMP Properties (on the Connection tab) – These are session/connection-level properties (e.g., GENERATE_SENDER_ID, CLIENT_CHANNEL_PROPERTIES.ReconnectRetries). They configure the underlying JCSMP
    session to the broker. Properties set here never end up on the published message – they only affect how the connection itself behaves.
  2. User Properties (on the Message Properties tab, under Additional Properties) – These are per-message key-value pairs that get carried inside the message’s SMF User Properties (SDTMap). This is exactly where the Solace broker’s distributed tracing feature looks for the W3C Trace Context.

Based on your description – “This adapter has the JCSMP property ‘traceparent’ set” – it sounds like you are setting traceparent in the JCSMP Properties on the Connection tab. If so, that value is being applied to the JCSMP session configuration and is never written onto the outgoing message. The broker therefore sees no trace context on the message and creates a new root span with its own trace-id, which is exactly the behavior you’re observing.

What to do instead:

Set the traceparent (and optionally tracestate) in the User Properties section under the Message Properties tab of the Receiver adapter:

  ┌─────────────┬───────────────────────────────────────────────────────────────┐                                                                                                                              
  │     Key     │                             Value                             │
  ├─────────────┼───────────────────────────────────────────────────────────────┤
  │ traceparent │ 00-<32-hex-char-trace-id>-<16-hex-char-span-id>-<trace-flags> │
  ├─────────────┼───────────────────────────────────────────────────────────────┤
  │ tracestate  │ (optional) vendor-specific key-value pairs                    │                                                                                                                              
  └─────────────┴───────────────────────────────────────────────────────────────┘   

The value must follow the Trace Context format exactly:

traceparent = 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01

Where:

  • 00 = version
  • 32 lowercase hex chars = trace-id
  • 16 lowercase hex chars = parent span-id
  • 01 = sampled (00 = not sampled)

When set in User Properties, the adapter writes these into the message’s SDTMap via XMLMessage.setProperties(). The Solace broker’s distributed tracing feature reads from this same location (this is the same mechanism used by the official solace-opentelemetry-jcsmp-integration library’s SolaceJCSMPTextMapSetter/SolaceJCSMPTextMapGetter). The broker should then use your provided trace-id when generating its OTEL spans for Dynatrace, linking them to your upstream trace.

Dynamic trace context propagation

If your iFlow receives an inbound HTTP request that already carries a traceparent header (e.g., from an upstream system with its own tracing), you can propagate it dynamically rather than hardcoding a value:

  1. Add traceparent to the iFlow’s Runtime Configuration > Allowed Header(s) allowlist
  2. In the Receiver adapter’s User Properties, set:
    • Key: traceparent
    • Value: ${header.traceparent}

This uses the adapter’s Camel expression support to dynamically resolve the value from the exchange header at runtime, so each message carries the correct trace context from its originating request.

To directly answer your three questions

  1. Is the AEM adapter capable of setting a property that the Solace broker would recognise for distributed tracing? – Yes, but it must be set via User Properties (Message Properties tab), not JCSMP Properties (Connection tab).
  2. Is the property name “traceparent” correct? – Yes, traceparent is the correct key name per the W3C Trace Context specification. The broker recognises this key when it appears in the message’s User Properties (SDTMap).
  3. Why does the broker generate its own trace-id? – Because the traceparent set in JCSMP Properties (Connection tab) is a session-level configuration and does not get placed onto the published message. The broker sees no trace context on the incoming message and therefore creates a new root span.

Important note

The AEM adapter does not natively generate or instrument traces itself – it has no built-in OpenTelemetry integration. However, it can pass through an existing trace context to the broker via User Properties, which is sufficient for your use case of continuing an existing trace through the broker to Dynatrace.

I hope that helps – please let us know if you run into any issues after moving the property to User Properties.

Regards,

Sunil

Thankyou Sunil for your extensive reply.

Let me reconfigure the adapter and see what happens.

Kind regards

John

Hello @Sunil-solace

I have a kind of similar situation, but already set the traceparent in the user properties under the message property section of the AEM reciever adapter.

For example my tracepartens looks like: 00-08e0df482dcf9f3d7707a4047ff4ad01-484a2e84d9f6a284-01

For monitoring and tracing we use Datadog with an own subscription and connected the Datadog from the AEM with our own. I receive the traces in here, and I also can see the correct propagated user_properties, but the trace_id - which is set in the otel-segment - is not the same as from the user_properties I propagated.

Example from the trace view in Datadog:

"otel": {
"status_code": "Unset",
"trace_id": "fafa6551d637312d233c2909331cd9ad"
}...

Therefore I assume the broker still creates its own trace_id.

Am I missing something?

Thank you for you help in advance!

Jonas

Hi @Jonas

Good to hear that you’ve past the configuration step. The fact that you can see the expected user property propagated confirms the adapter side is doing its job.

The behavior you’re describing, though, points to a question that’s worth unpacking: where is the traceparent value coming from before the adapter sends it?

This matters because the AEM Receiver adapter is purely a passthrough for trace context — it does not generate or export any spans of its own. For end-to-end trace continuity to actually be visible in Datadog, three things need to line up:

  1. A real producer span must be exported to your Datadog tenant with trace-id X and span-id Y
  2. The traceparent user property on the message must be 00-X-Y-01 (or -00 if not sampled)
  3. The broker must extract that context and emit child spans with the same trace-id X, parent-span-id Y

If step 1 is missing — i.e., the traceparent value is hardcoded, generated inside a Groovy/script step, or forwarded from an upstream system that isn’t actually exporting spans to this Datadog tenant — then even a perfectly working broker would produce a trace tree that looks “orphaned” in Datadog (broker spans only, no producer parent).

Could you confirm a few things about the origin of the traceparent?

  1. Is the value 00-08e0df48…-01 coming from an actual instrumented producer — i.e., an OTel/Datadog SDK somewhere upstream that started a span and exported it to Datadog? Or is it hardcoded / generated inside the iFlow (e.g., in a script step) / forwarded from an inbound HTTP header?
  2. If you search Datadog directly for trace-id 08e0df482dcf9f3d7707a4047ff4ad01, do you find any span at all under that ID?
  3. If it’s coming from an upstream caller, is that caller exporting to the same Datadog tenant/subscription you’re viewing, with the same OTel collector path?

Without an actual exported parent span sitting in Datadog under that trace-id, broker continuity is effectively unverifiable from the UI — the broker may well be inheriting correctly, but you’ll never see the parent–child link because the parent doesn’t exist.

Regards,
Sunil

Hi @Sunil-solace

thank you for the quick response!

It’s a mix of all of them :grinning_face_with_smiling_eyes:

The one I tested with is a generated trace-Id within a groovy script. But this also creates a span body, which will be exported via a external micorservice to the http intake entpoint for traces from datadog. So, I would assume this is a “real” trace, because the cloud integration can also be a publisher (ex. timer-based processes). In case a sender is propagating headers to the iflow the script will reuse them and will calculate the span ids etc.

So, mappedn onto your list:

  1. half right
  2. the traceparent is set within the user property 00-X-Y-01 and is also read from the header (groovy script stores it there beforehand)
  3. I cannot see this correctly, whether the broker does this or not.

Now to your questions:

  1. Its generated within a groovy script, propagated to the broker. Afterwards the generated spans are exported to datadog.
  2. If I search for the trace_id I pasted here, I see the span and trace from the Broker. When I search for the trace-id i generated within my groovy script and exported this to datadog, I can search for this within the trace the broker created, but there under user proeprties. Aswell the trace/span from the cloud integration part from otel segment.
  3. The broker uses the inbuild one and the datadog is connected to our own one. The microservices export the traces/spans from ci directly to our datadog via http intake endpoint.

I hope this helps you? In case you have further questions, please reach out to me again!

Kind regards,

Jonas

Hi @Jonas @johnfreemanzespri

Thanks for the detailed follow-up — it let me validate what I’d said earlier with our internal teams and the Solace docs, and I need to refine one important point from my first reply.

I’d implied that setting traceparent in User Properties is effectively equivalent to what the official Solace OpenTelemetry Integration library does. That’s not quite accurate. Per the Distributed Tracing , the supported way to inject trace context into a Solace message is through the OpenTelemetry Integration APIs (SolaceJCSMPTextMapSetter and equivalents) or via auto-instrumentation. A plain user property named traceparent, set outside those integration libraries, is not a documented context-propagation path — the value travels with the message as application data, which is why you see it on the broker’s span, but the broker does not treat it as parent trace context and generates its own root trace instead. That matches exactly what you’re observing.

To be clear, setting traceparent in User Properties is still generally useful: any downstream consumer that supports OpenTelemetry can read it from the message and continue the trace based on that value. The Solace broker — as a downstream, it has its own mechanism for trace-context continuation that only works when the publisher officially supports OTel via the Solace Integration libraries. Since the AEM Receiver adapter does not currently have built-in OpenTelemetry integration, it can forward a traceparent user property faithfully, but that path isn’t equivalent to OTel-instrumented publishing — so trace continuity into the broker isn’t achievable today through the AEM Receiver on its own, and will only become possible once the adapter officially supports OTel.

Your producer instrumentation and Datadog export are fine — your producer span will remain valid and visible. Where end-to-end continuity through the broker is a hard requirement today, the supported path is publishing via a component that uses the Solace OpenTelemetry Integration library directly.

Apologies for the earlier ambiguity.

Regards,
Sunil

Hi Sunil, thankyou for the clarifying the propagation of the trace context within Solace. I will investigate how to use these APIs.

Kind regards

John