[ 
https://issues.apache.org/jira/browse/CAMEL-19667?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17829595#comment-17829595
 ] 

Davin Taddeo edited comment on CAMEL-19667 at 3/21/24 2:59 PM:
---------------------------------------------------------------

Another workaround, in v4.4.0.  Going against the recommended operations was 
really the only way we were able to get things working.  You can use the 
`ActiveSpanManager` from the `camel-tracing` component to get the current span 
context and make it current. Looking at this [branch of my example 
app|https://github.com/tdarwin/camel-kafka-demo-tracing/tree/restore-exchange-span-context],
 we've got a couple examples of doing this

You can use ActiveSpanManager the way the camel-opentelemetry component does, 
to cast the processor's span as a camelSpan, then you can use that span with 
the makeCurrent function to get an AutoCloseable for your functions.



 
{code:java}
    from("kafka:pageviews?brokers=localhost:9092")
      .process(exchange -> {
        // We're not supposed to use ActiveSpanManager directly, but
        // camel-opentelemetry doesn't seem to provide a way to get the current 
span.
        OpenTelemetrySpanAdapter camelSpan = (OpenTelemetrySpanAdapter) 
ActiveSpanManager.getSpan(exchange);
        try (AutoCloseable scope = camelSpan.makeCurrent()) {
          // Custom processing logic
          modifyBody(exchange);
        }
      })
      .to("kafka:viewedpages?brokers=localhost:9092")
      .to("log:partone-done");
{code}
 


You could also just skip the OpenTelemetrySpanAdapter bit and just grab the 
AutoCloseable from the ActiveSpanManager class in camel-tracing. We were trying 
to do this without going to the option, since it says don't do it... But 
there's no way to get the context working an not do it that we can see, aside 
from the workaround from the OP to manually break down the kafka header to get 
the traceparent header and link into the trace that way.
{code:java}
    from("kafka:viewedpages?brokers=localhost:9092")
      .process(exchange -> {
        try (AutoCloseable scope = 
ActiveSpanManager.getSpan(exchange).makeCurrent()) {
          modifyBody(exchange);
        }
      })
      .to("kafka:processedviews?brokers=localhost:9092")
      .to("log:processedviews");{code}
[~davsclaus], If something could be added to camel-opentelemetry's 
OpenTelemetryTracer class, that would work like the getSpan method, that would 
at least make this easier, without having to dip into classes from the 
camel-tracing compoent. Assuming the camel-opentelemetry component itself can't 
be updated to just play nice with OTEL's @WithSpan decorators nicely on its 
own... This will at least get people a simpler method to get into current 
context where they _can_ then use the @WithSpan decorator later on.


was (Author: JIRAUSER304603):
Another workaround, in v4.4.0.  Going against the recommended operations was 
really the only way we were able to get things working.  You can use the 
`ActiveSpanManager` from the `camel-tracing` component to get the current span 
context and make it current.  Looking at this [branch of my example 
app|https://github.com/tdarwin/camel-kafka-demo-tracing/tree/restore-exchange-span-context],
 we've got a couple examples of doing this

You can use ActiveSpanManager the way the camel-opentelemetry component does, 
to cast the processor's span as a camelSpan, then you can use that span with 
the makeCurrent function to get an AutoCloseable for your functions.
```java
    from("kafka:pageviews?brokers=localhost:9092")
      .process(exchange -> {
        // We're not supposed to use ActiveSpanManager directly, but
        // camel-opentelemetry doesn't seem to provide a way to get the current 
span.
        OpenTelemetrySpanAdapter camelSpan = (OpenTelemetrySpanAdapter) 
ActiveSpanManager.getSpan(exchange);

        try (AutoCloseable scope = camelSpan.makeCurrent()) {
          // Custom processing logic
          modifyBody(exchange);
        }
      })
      .to("kafka:viewedpages?brokers=localhost:9092")
```

You could also just skip the OpenTelemetrySpanAdapter bit and just grab the 
AutoCloseable from the ActiveSpanManager class in camel-tracing. We were trying 
to do this without going to the option, since it says don't do it... But 
there's no way to get the context working an not do it that we can see, aside 
from the workaround from the OP to manually break down the kafka header to get 
the traceparent header and link into the trace that way.

```java
    from("kafka:viewedpages?brokers=localhost:9092")
      .process(exchange -> {
        try (AutoCloseable scope = 
ActiveSpanManager.getSpan(exchange).makeCurrent()) {
          modifyBody(exchange);
        }
      })
      .to("kafka:processedviews?brokers=localhost:9092")
      .to("log:processedviews");
```

[~davsclaus], If something could be added to camel-opentelemetry's 
OpenTelemetryTracer class, that would work like the getSpan method, that would 
at least make this easier, without having to dip into classes from the 
camel-tracing compoent.  Assuming the camel-opentelemetry component itself 
can't be updated to just play nice with OTEL's @WithSpan decorators nicely on 
its own...  This will at least get people a simpler method to get into current 
context where they _can_ then use the @WithSpan decorator later on.

> camel-tracing: Context is not propagated from exchange header to 
> OpenTelemetry Context
> --------------------------------------------------------------------------------------
>
>                 Key: CAMEL-19667
>                 URL: https://issues.apache.org/jira/browse/CAMEL-19667
>             Project: Camel
>          Issue Type: Improvement
>          Components: camel-opentelemetry, camel-tracing
>    Affects Versions: 3.20.5, 3.20.6, 3.21.0, 4.0-M3
>            Reporter: Roman Kvasnytskyi
>            Priority: Major
>              Labels: bug, opentelemetry, tracing
>             Fix For: 4.x
>
>         Attachments: screenshot-1.png
>
>
> I am using OpenTelemetry Agent for tracing along with 
> camel-opentelemetry-starter that configures OpenTelemetryTracer for Camel 
> aligned with camel-tracing. 
> I see my spans for Camel inside a single trace, but after control is passed 
> to the Processor process method next spans are disassociated from the trace 
> and are created in the separate trace.
> The tracing context does not seem to get propagated, and the resulting spans 
> end up being disassociated. For example:
> {code:java}
> from("timer:tick?period=5s)
>     .process("myProcessor");    
> {code}
> {code:java}
> public class MyProcessor implements Processor {
>     private final HttpClient someClient = new HttpClient();
>     @Override
>     public void process(Exchange exchange) {
>         // http client is instrumented and also produces spans
>         someClient.get('/example');
>     }
> }
> {code}
> This results in 2 spans. One for timer:tick & another for a client call. The 
> problem is that the parent span for client calls is not set, so they appear 
> as 2 distinct traces. 
> My exchange headers contain traceparent header with all data which should be 
> put inside the OpenTelemetry context, but they do not.
> I have come up with a workaround. The idea is trivial - get traceparent 
> header if it is present in exchange, parse trace metadata from it, create a 
> SpanContext object, and put it as a parent for the current OpenTelemetry 
> context.
> It looks like this:
> {code:java}
> public class TraceEnrichingProcessor implements Processor {
>     private final Processor delegate;
>     public TraceEnrichingProcessor(Processor delegate) {
>         this.delegate = delegate;
>     }
>     @Override
>     public void process(Exchange exchange) throws Exception {
>         // Get the existing traceparent header from the Exchange
>         String traceparent = exchange.getIn().getHeader("traceparent", 
> String.class);
>         if (traceparent != null && !traceparent.isEmpty()) {
>             // Extract the traceId, parentSpanId and sampleFlag
>             String[] parts = traceparent.split("-");
>             String traceId = parts[1];
>             String parentSpanId = parts[2];
>             boolean isSampled = parts[3].equals("01");
>             // Create the parent SpanContext
>             SpanContext parentContext = SpanContext.create(
>                 traceId,
>                 parentSpanId,
>                 isSampled ? TraceFlags.getSampled() : TraceFlags.getDefault(),
>                 TraceState.getDefault()
>             );
>             // Attach the parent SpanContext to the current Context
>             try (Scope scope = 
> Context.current().with(Span.wrap(parentContext)).makeCurrent()) {
>                 // Now, the current Context has the parent SpanContext 
> attached,
>                 // and any new spans created within this scope will use it as 
> their parent
>                 
>                 // Pass control to the delegate processor
>                 delegate.process(exchange);
>             }
>         } else {
>             // If no traceparent header is found, just delegate without 
> modifying the Context
>             delegate.process(exchange);
>         }
>     }
> } {code}
> Inside OpenTelemetry Agent, they dropped support of Camel 3.x+, because Camel 
> provides its module for tracing, and they will not help with it. 
> [Link|https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/4052]
> I wonder if that can be done inside Camel to propagate context from the 
> processor implicitly without manual propagation of context. 
> *UPD1:* I have verified that these behaviour is consistent across Camel 
> 3.20.5, 3.20.6, 3.21.0 and 4.0.0-RC1



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to