This is an automated email from the ASF dual-hosted git repository.

pcongiusti pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new b176cf9a4fb2 feat(components): telemetry tracing info in headers
b176cf9a4fb2 is described below

commit b176cf9a4fb28ff61f63aa24952936934e511238
Author: Pasquale Congiusti <[email protected]>
AuthorDate: Tue Oct 21 12:47:11 2025 +0200

    feat(components): telemetry tracing info in headers
    
    This feature will simplify the exposure of the generated traces information 
giving a consisten solution across any Camel telemetry component.
    
    Closes CAMEL-22478
---
 .../MicrometerObservabilityTracerConfigurer.java   |  6 ++
 .../src/main/docs/micrometer-observability.adoc    |  7 ++
 .../MicrometerObservabilityTracer.java             |  6 +-
 .../micrometer/observability/HeadersTraceTest.java | 70 +++++++++++++++++++
 .../OpenTelemetryTracerConfigurer.java             |  6 ++
 .../src/main/docs/opentelemetry2.adoc              |  8 +++
 .../camel/opentelemetry2/OpenTelemetryTracer.java  |  6 +-
 .../camel/opentelemetry2/MDCHeadersTraceTest.java  | 78 +++++++++++++++++++++
 .../telemetrydev/TelemetryDevTracerConfigurer.java |  6 ++
 .../src/main/docs/telemetry-dev.adoc               | 13 ++--
 .../camel/telemetrydev/TelemetryDevTracer.java     |  7 +-
 .../camel/telemetrydev/MDCHeadersTraceTest.java    | 76 +++++++++++++++++++++
 .../camel-telemetry/src/main/docs/telemetry.adoc   |  9 ++-
 .../camel/telemetry/SpanLifecycleManager.java      |  2 +-
 .../java/org/apache/camel/telemetry/Tracer.java    | 15 +++-
 .../apache/camel/telemetry/HeadersTraceTest.java   | 79 ++++++++++++++++++++++
 .../apache/camel/telemetry/mock/MockTracer.java    |  7 +-
 proposals/tracing.adoc                             | 10 +--
 18 files changed, 394 insertions(+), 17 deletions(-)

diff --git 
a/components/camel-micrometer-observability/src/generated/java/org/apache/camel/micrometer/observability/MicrometerObservabilityTracerConfigurer.java
 
b/components/camel-micrometer-observability/src/generated/java/org/apache/camel/micrometer/observability/MicrometerObservabilityTracerConfigurer.java
index b8aba43c8641..81a5e30fb4b1 100644
--- 
a/components/camel-micrometer-observability/src/generated/java/org/apache/camel/micrometer/observability/MicrometerObservabilityTracerConfigurer.java
+++ 
b/components/camel-micrometer-observability/src/generated/java/org/apache/camel/micrometer/observability/MicrometerObservabilityTracerConfigurer.java
@@ -32,6 +32,8 @@ public class MicrometerObservabilityTracerConfigurer extends 
org.apache.camel.su
         case "propagator": target.setPropagator(property(camelContext, 
io.micrometer.tracing.propagation.Propagator.class, value)); return true;
         case "spanlifecyclemanager":
         case "spanLifecycleManager": 
target.setSpanLifecycleManager(property(camelContext, 
org.apache.camel.telemetry.SpanLifecycleManager.class, value)); return true;
+        case "traceheadersinclusion":
+        case "traceHeadersInclusion": 
target.setTraceHeadersInclusion(property(camelContext, boolean.class, value)); 
return true;
         case "traceprocessors":
         case "traceProcessors": 
target.setTraceProcessors(property(camelContext, boolean.class, value)); return 
true;
         case "tracer": target.setTracer(property(camelContext, 
io.micrometer.tracing.Tracer.class, value)); return true;
@@ -51,6 +53,8 @@ public class MicrometerObservabilityTracerConfigurer extends 
org.apache.camel.su
         case "propagator": return 
io.micrometer.tracing.propagation.Propagator.class;
         case "spanlifecyclemanager":
         case "spanLifecycleManager": return 
org.apache.camel.telemetry.SpanLifecycleManager.class;
+        case "traceheadersinclusion":
+        case "traceHeadersInclusion": return boolean.class;
         case "traceprocessors":
         case "traceProcessors": return boolean.class;
         case "tracer": return io.micrometer.tracing.Tracer.class;
@@ -71,6 +75,8 @@ public class MicrometerObservabilityTracerConfigurer extends 
org.apache.camel.su
         case "propagator": return target.getPropagator();
         case "spanlifecyclemanager":
         case "spanLifecycleManager": return target.getSpanLifecycleManager();
+        case "traceheadersinclusion":
+        case "traceHeadersInclusion": return target.isTraceHeadersInclusion();
         case "traceprocessors":
         case "traceProcessors": return target.isTraceProcessors();
         case "tracer": return target.getTracer();
diff --git 
a/components/camel-micrometer-observability/src/main/docs/micrometer-observability.adoc
 
b/components/camel-micrometer-observability/src/main/docs/micrometer-observability.adoc
index a3fde2f5d5b7..e502d493ee54 100644
--- 
a/components/camel-micrometer-observability/src/main/docs/micrometer-observability.adoc
+++ 
b/components/camel-micrometer-observability/src/main/docs/micrometer-observability.adoc
@@ -31,6 +31,7 @@ The configuration properties for the component are:
 |`excludePatterns` |  | Sets exclude pattern that will disable tracing for 
those spans that matches the pattern. The variable is a comma separated values 
of filters to execute (eg, `log*,direct*,setBody*`, ...)
 |`traceProcessors` | `false` | Setting this to true will create new spans for 
each Camel Processors.
 Use the excludePattern property to filter out Processors
+|`traceHeadersInclusion`| false | Add the generated telemetry `CAMEL_TRACE_ID` 
and `CAMEL_SPAN_ID` Exchange headers.
 |=======================================================================
 
 include::spring-boot:partial$starter.adoc[]
@@ -133,3 +134,9 @@ Once the application is instrumented and configured, you 
can observe the traces
 === Java Agents
 
 Your application may require a Java agent in order to get the traces generated 
by the Camel application and push to the tracing server (ie, Opentelemetry 
based instrumentation). You may need to configure such agent (or any other 
tool) directly via Java parameters.
+
+=== MDC logging
+
+You can leverage the `traceHeadersInclusion` to include the generated 
`CAMEL_TRACE_ID` and `CAMEL_SPAN_ID` into the Camel Exchange and together with 
`camel-mdc` you can make those headers available in the MDC context (via 
`camel.mdc.customHeaders=CAMEL_TRACE_ID,CAMEL_SPAN_ID` configuration). This is 
the idiomatic way in Camel.
+
+As an alternative, you can add Mapped Diagnostic Context tracing information 
(ie, `trace_id` and `span_id`) adding the specific 
https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/logger-mdc-instrumentation.md[Opentelemetry
 Logger MDC auto instrumentation]. This would be available if you configure the 
Opentelemetry. The logging configuration depends on the logging framework 
you're using.
\ No newline at end of file
diff --git 
a/components/camel-micrometer-observability/src/main/java/org/apache/camel/micrometer/observability/MicrometerObservabilityTracer.java
 
b/components/camel-micrometer-observability/src/main/java/org/apache/camel/micrometer/observability/MicrometerObservabilityTracer.java
index a581849815af..fa239a258558 100644
--- 
a/components/camel-micrometer-observability/src/main/java/org/apache/camel/micrometer/observability/MicrometerObservabilityTracer.java
+++ 
b/components/camel-micrometer-observability/src/main/java/org/apache/camel/micrometer/observability/MicrometerObservabilityTracer.java
@@ -172,12 +172,16 @@ public class MicrometerObservabilityTracer extends 
org.apache.camel.telemetry.Tr
         }
 
         @Override
-        public void inject(Span span, SpanContextPropagationInjector injector) 
{
+        public void inject(Span span, SpanContextPropagationInjector injector, 
boolean includeTracing) {
             MicrometerObservabilitySpanAdapter microObsSpan = 
(MicrometerObservabilitySpanAdapter) span;
             propagator.inject(
                     microObsSpan.getSpan().context(),
                     injector,
                     (carrier, key, value) -> carrier.put(key, value));
+            if (includeTracing) {
+                injector.put(org.apache.camel.telemetry.Tracer.TRACE_HEADER, 
microObsSpan.getSpan().context().traceId());
+                injector.put(org.apache.camel.telemetry.Tracer.SPAN_HEADER, 
microObsSpan.getSpan().context().spanId());
+            }
         }
     }
 
diff --git 
a/components/camel-micrometer-observability/src/test/java/org/apache/camel/micrometer/observability/HeadersTraceTest.java
 
b/components/camel-micrometer-observability/src/test/java/org/apache/camel/micrometer/observability/HeadersTraceTest.java
new file mode 100644
index 000000000000..194e35e78e07
--- /dev/null
+++ 
b/components/camel-micrometer-observability/src/test/java/org/apache/camel/micrometer/observability/HeadersTraceTest.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.micrometer.observability;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class HeadersTraceTest extends MicrometerObservabilityTracerTestSupport 
{
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        tst.setTraceHeadersInclusion(true);
+        return super.createCamelContext();
+    }
+
+    @Test
+    void testProcessorsTraceRequest() throws InterruptedException, IOException 
{
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMessageCount(1);
+        template.sendBody("direct:start", "my-body");
+        Map<String, MicrometerObservabilityTrace> traces = traces();
+        assertEquals(1, traces.size());
+        mock.assertIsSatisfied();
+        Map<String, Object> headers = 
mock.getExchanges().get(0).getIn().getHeaders();
+
+        // NOTE: the check on TRACE_ID and SPAN_ID instead of the related 
constant is on purpose
+        // We want to fail if there is any change in the constant by any 
chance and report into the
+        // documentation.
+        assertNotNull(headers.get("CAMEL_TRACE_ID"));
+        assertNotNull(headers.get("CAMEL_SPAN_ID"));
+        assertNotEquals("", headers.get("CAMEL_TRACE_ID"));
+        assertNotEquals("", headers.get("CAMEL_SPAN_ID"));
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start")
+                        .to("mock:result");
+            }
+        };
+    }
+
+}
diff --git 
a/components/camel-opentelemetry2/src/generated/java/org/apache/camel/opentelemetry2/OpenTelemetryTracerConfigurer.java
 
b/components/camel-opentelemetry2/src/generated/java/org/apache/camel/opentelemetry2/OpenTelemetryTracerConfigurer.java
index 1e97cb58200d..cc561a6e9841 100644
--- 
a/components/camel-opentelemetry2/src/generated/java/org/apache/camel/opentelemetry2/OpenTelemetryTracerConfigurer.java
+++ 
b/components/camel-opentelemetry2/src/generated/java/org/apache/camel/opentelemetry2/OpenTelemetryTracerConfigurer.java
@@ -29,6 +29,8 @@ public class OpenTelemetryTracerConfigurer extends 
org.apache.camel.support.comp
         case "excludePatterns": 
target.setExcludePatterns(property(camelContext, java.lang.String.class, 
value)); return true;
         case "spanlifecyclemanager":
         case "spanLifecycleManager": 
target.setSpanLifecycleManager(property(camelContext, 
org.apache.camel.telemetry.SpanLifecycleManager.class, value)); return true;
+        case "traceheadersinclusion":
+        case "traceHeadersInclusion": 
target.setTraceHeadersInclusion(property(camelContext, boolean.class, value)); 
return true;
         case "traceprocessors":
         case "traceProcessors": 
target.setTraceProcessors(property(camelContext, boolean.class, value)); return 
true;
         default: return false;
@@ -44,6 +46,8 @@ public class OpenTelemetryTracerConfigurer extends 
org.apache.camel.support.comp
         case "excludePatterns": return java.lang.String.class;
         case "spanlifecyclemanager":
         case "spanLifecycleManager": return 
org.apache.camel.telemetry.SpanLifecycleManager.class;
+        case "traceheadersinclusion":
+        case "traceHeadersInclusion": return boolean.class;
         case "traceprocessors":
         case "traceProcessors": return boolean.class;
         default: return null;
@@ -60,6 +64,8 @@ public class OpenTelemetryTracerConfigurer extends 
org.apache.camel.support.comp
         case "excludePatterns": return target.getExcludePatterns();
         case "spanlifecyclemanager":
         case "spanLifecycleManager": return target.getSpanLifecycleManager();
+        case "traceheadersinclusion":
+        case "traceHeadersInclusion": return target.isTraceHeadersInclusion();
         case "traceprocessors":
         case "traceProcessors": return target.isTraceProcessors();
         default: return null;
diff --git a/components/camel-opentelemetry2/src/main/docs/opentelemetry2.adoc 
b/components/camel-opentelemetry2/src/main/docs/opentelemetry2.adoc
index 1d92110a40ba..960f56b1ba4a 100644
--- a/components/camel-opentelemetry2/src/main/docs/opentelemetry2.adoc
+++ b/components/camel-opentelemetry2/src/main/docs/opentelemetry2.adoc
@@ -25,6 +25,7 @@ The configuration properties for the OpenTelemetry2 tracer 
are:
 |`excludePatterns` |  | Sets exclude pattern that will disable tracing for 
those spans that matches the pattern. The variable is a comma separated values 
of filters to execute (eg, `log*,direct*,setBody*`, ...)
 |`traceProcessors` | `false` | Setting this to true will create new 
OpenTelemetry Spans for each Camel Processors.
 Use the excludePattern property to filter out Processors
+|`traceHeadersInclusion`| false | Add the generated telemetry `CAMEL_TRACE_ID` 
and `CAMEL_SPAN_ID` Exchange headers.
 |=======================================================================
 
 === Using with standalone Camel
@@ -80,3 +81,10 @@ java -javaagent:path/to/opentelemetry-javaagent.jar \
 === Collect OpenTelemetry traces
 
 OpenTelemetry is a tracing protocol which is implemented by several vendors. 
You can use the Jaeger project which provides an open source all in one tracing 
application. See details how to run it in 
https://www.jaegertracing.io/docs/latest/getting-started/[Jaeger getting 
started guide].
+
+=== MDC logging
+
+You can leverage the `traceHeadersInclusion` to include the generated 
`CAMEL_TRACE_ID` and `CAMEL_SPAN_ID` into the Camel Exchange and together with 
`camel-mdc` you can make those headers available in the MDC context (via 
`camel.mdc.customHeaders=CAMEL_TRACE_ID,CAMEL_SPAN_ID` configuration). This is 
the idiomatic way in Camel.
+
+As an alternative, you can add Mapped Diagnostic Context tracing information 
(ie, `trace_id` and `span_id`) adding the specific 
https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/logger-mdc-instrumentation.md[Opentelemetry
 Logger MDC auto instrumentation]. The logging configuration depends on the 
logging framework you're using.
+
diff --git 
a/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OpenTelemetryTracer.java
 
b/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OpenTelemetryTracer.java
index 2ee1b76c3cc1..e1d0cefd52fd 100644
--- 
a/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OpenTelemetryTracer.java
+++ 
b/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OpenTelemetryTracer.java
@@ -154,7 +154,7 @@ public class OpenTelemetryTracer extends 
org.apache.camel.telemetry.Tracer {
         }
 
         @Override
-        public void inject(Span span, SpanContextPropagationInjector injector) 
{
+        public void inject(Span span, SpanContextPropagationInjector injector, 
boolean includeTracing) {
             OpenTelemetrySpanAdapter otelSpan = (OpenTelemetrySpanAdapter) 
span;
             Context ctx = Context.current().with(otelSpan.getSpan());
             if (otelSpan.getBaggage() != null) {
@@ -162,6 +162,10 @@ public class OpenTelemetryTracer extends 
org.apache.camel.telemetry.Tracer {
             }
             contextPropagators.getTextMapPropagator().inject(ctx, injector,
                     (carrier, key, value) -> carrier.put(key, value));
+            if (includeTracing) {
+                injector.put(org.apache.camel.telemetry.Tracer.TRACE_HEADER, 
otelSpan.getSpan().getSpanContext().getTraceId());
+                injector.put(org.apache.camel.telemetry.Tracer.SPAN_HEADER, 
otelSpan.getSpan().getSpanContext().getSpanId());
+            }
         }
 
     }
diff --git 
a/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/MDCHeadersTraceTest.java
 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/MDCHeadersTraceTest.java
new file mode 100644
index 000000000000..0eab0a484a07
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/MDCHeadersTraceTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.opentelemetry2;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.opentelemetry2.CamelOpenTelemetryExtension.OtelTrace;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class MDCHeadersTraceTest extends OpenTelemetryTracerTestSupport {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+        OpenTelemetryTracer tst = new OpenTelemetryTracer();
+        tst.setTraceHeadersInclusion(true);
+        tst.setTracer(otelExtension.getOpenTelemetry().getTracer("traceTest"));
+        
tst.setContextPropagators(otelExtension.getOpenTelemetry().getPropagators());
+        CamelContextAware.trySetCamelContext(tst, context);
+        tst.init(context);
+        return context;
+    }
+
+    @Test
+    void testProcessorsTraceRequest() throws InterruptedException, IOException 
{
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMessageCount(1);
+        template.sendBody("direct:start", "my-body");
+        Map<String, OtelTrace> traces = otelExtension.getTraces();
+        assertEquals(1, traces.size());
+        mock.assertIsSatisfied();
+        Map<String, Object> headers = 
mock.getExchanges().get(0).getIn().getHeaders();
+
+        // NOTE: the check on TRACE_ID and SPAN_ID instead of the related 
constant is on purpose
+        // We want to fail if there is any change in the constant by any 
chance and report into the
+        // documentation.
+        assertNotNull(headers.get("CAMEL_TRACE_ID"));
+        assertNotNull(headers.get("CAMEL_SPAN_ID"));
+        assertNotEquals("", headers.get("CAMEL_TRACE_ID"));
+        assertNotEquals("", headers.get("CAMEL_SPAN_ID"));
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start")
+                        .to("mock:result");
+            }
+        };
+    }
+
+}
diff --git 
a/components/camel-telemetry-dev/src/generated/java/org/apache/camel/telemetrydev/TelemetryDevTracerConfigurer.java
 
b/components/camel-telemetry-dev/src/generated/java/org/apache/camel/telemetrydev/TelemetryDevTracerConfigurer.java
index f2be9dfb3ea1..20d9f04a5fee 100644
--- 
a/components/camel-telemetry-dev/src/generated/java/org/apache/camel/telemetrydev/TelemetryDevTracerConfigurer.java
+++ 
b/components/camel-telemetry-dev/src/generated/java/org/apache/camel/telemetrydev/TelemetryDevTracerConfigurer.java
@@ -31,6 +31,8 @@ public class TelemetryDevTracerConfigurer extends 
org.apache.camel.support.compo
         case "spanLifecycleManager": 
target.setSpanLifecycleManager(property(camelContext, 
org.apache.camel.telemetry.SpanLifecycleManager.class, value)); return true;
         case "traceformat":
         case "traceFormat": target.setTraceFormat(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "traceheadersinclusion":
+        case "traceHeadersInclusion": 
target.setTraceHeadersInclusion(property(camelContext, boolean.class, value)); 
return true;
         case "traceprocessors":
         case "traceProcessors": 
target.setTraceProcessors(property(camelContext, boolean.class, value)); return 
true;
         default: return false;
@@ -48,6 +50,8 @@ public class TelemetryDevTracerConfigurer extends 
org.apache.camel.support.compo
         case "spanLifecycleManager": return 
org.apache.camel.telemetry.SpanLifecycleManager.class;
         case "traceformat":
         case "traceFormat": return java.lang.String.class;
+        case "traceheadersinclusion":
+        case "traceHeadersInclusion": return boolean.class;
         case "traceprocessors":
         case "traceProcessors": return boolean.class;
         default: return null;
@@ -66,6 +70,8 @@ public class TelemetryDevTracerConfigurer extends 
org.apache.camel.support.compo
         case "spanLifecycleManager": return target.getSpanLifecycleManager();
         case "traceformat":
         case "traceFormat": return target.getTraceFormat();
+        case "traceheadersinclusion":
+        case "traceHeadersInclusion": return target.isTraceHeadersInclusion();
         case "traceprocessors":
         case "traceProcessors": return target.isTraceProcessors();
         default: return null;
diff --git a/components/camel-telemetry-dev/src/main/docs/telemetry-dev.adoc 
b/components/camel-telemetry-dev/src/main/docs/telemetry-dev.adoc
index 4d75d0424a58..d3d9894814be 100644
--- a/components/camel-telemetry-dev/src/main/docs/telemetry-dev.adoc
+++ b/components/camel-telemetry-dev/src/main/docs/telemetry-dev.adoc
@@ -26,10 +26,11 @@ The configuration properties for the Telemetry component 
are:
 [width="100%",cols="10%,10%,80%",options="header",]
 |=======================================================================
 |Option |Default |Description
-|`camel.telemetryDev.enabled`| false | Turn the tracing on/off.
-|`camel.telemetryDev.traceFormat`| default | The format used to trace in the 
log (default, tree, json).
-|`camel.telemetryDev.traceProcessors`| false | Trace inner processors.
-|`camel.telemetryDev.excludePatterns` |  | Sets exclude pattern that will 
disable tracing for those spans that matches the pattern. The variable is a 
comma separated values of filters to execute (eg, `log*,direct*,setBody*`, ...)
+|`enabled`| false | Turn the tracing on/off.
+|`traceFormat`| default | The format used to trace in the log (default, tree, 
json).
+|`traceProcessors`| false | Trace inner processors.
+|`excludePatterns` |  | Sets exclude pattern that will disable tracing for 
those spans that matches the pattern. The variable is a comma separated values 
of filters to execute (eg, `log*,direct*,setBody*`, ...)
+|`traceHeadersInclusion`| false | Add the generated telemetry `CAMEL_TRACE_ID` 
and `CAMEL_SPAN_ID` Exchange headers.
 |=======================================================================
 
 == Tracing format
@@ -72,3 +73,7 @@ This format is suitable if you need to integrate with any 
third party. The outpu
 === Default
 
 Default is a very simple serialization into the default Java object 
`toString()` representation.
+
+=== MDC logging
+
+You can leverage the `traceHeadersInclusion` to include the generated 
`CAMEL_TRACE_ID` and `CAMEL_SPAN_ID` into the Camel Exchange and together with 
`camel-mdc` you can make those headers available in the MDC context (via 
`camel.mdc.customHeaders=CAMEL_TRACE_ID,CAMEL_SPAN_ID` configuration).
diff --git 
a/components/camel-telemetry-dev/src/main/java/org/apache/camel/telemetrydev/TelemetryDevTracer.java
 
b/components/camel-telemetry-dev/src/main/java/org/apache/camel/telemetrydev/TelemetryDevTracer.java
index 3107b1777397..f4d0cdee05a8 100644
--- 
a/components/camel-telemetry-dev/src/main/java/org/apache/camel/telemetrydev/TelemetryDevTracer.java
+++ 
b/components/camel-telemetry-dev/src/main/java/org/apache/camel/telemetrydev/TelemetryDevTracer.java
@@ -136,13 +136,18 @@ public class TelemetryDevTracer extends Tracer {
         }
 
         @Override
-        public void inject(Span span, SpanContextPropagationInjector injector) 
{
+        public void inject(Span span, SpanContextPropagationInjector injector, 
boolean includeTracing) {
             String[] split = span.toString().split("-");
             if (split.length < 2) {
                 LOG.error("TRACE ERROR: wrong format, could not split 
traceparent {}", span);
                 return;
             }
             injector.put("traceparent", split[0] + "-" + split[1]);
+            if (includeTracing) {
+                DevSpanAdapter spanAdapter = (DevSpanAdapter) span;
+                injector.put(Tracer.TRACE_HEADER, 
spanAdapter.getTag("traceid"));
+                injector.put(Tracer.SPAN_HEADER, spanAdapter.getTag("spanid"));
+            }
         }
 
     }
diff --git 
a/components/camel-telemetry-dev/src/test/java/org/apache/camel/telemetrydev/MDCHeadersTraceTest.java
 
b/components/camel-telemetry-dev/src/test/java/org/apache/camel/telemetrydev/MDCHeadersTraceTest.java
new file mode 100644
index 000000000000..2e9472aece6b
--- /dev/null
+++ 
b/components/camel-telemetry-dev/src/test/java/org/apache/camel/telemetrydev/MDCHeadersTraceTest.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.telemetrydev;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class MDCHeadersTraceTest extends TelemetryDevTracerTestSupport {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+        TelemetryDevTracer tst = new TelemetryDevTracer();
+        tst.setTraceFormat("json");
+        tst.setTraceHeadersInclusion(true);
+        CamelContextAware.trySetCamelContext(tst, context);
+        tst.init(context);
+        return context;
+    }
+
+    @Test
+    void testProcessorsTraceRequest() throws InterruptedException, IOException 
{
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMessageCount(1);
+        template.sendBody("direct:start", "my-body");
+        Map<String, DevTrace> traces = tracesFromLog();
+        assertEquals(1, traces.size());
+        mock.assertIsSatisfied();
+        Map<String, Object> headers = 
mock.getExchanges().get(0).getIn().getHeaders();
+
+        // NOTE: the check on TRACE_ID and SPAN_ID instead of the related 
constant is on purpose
+        // We want to fail if there is any change in the constant by any 
chance and report into the
+        // documentation.
+        assertNotNull(headers.get("CAMEL_TRACE_ID"));
+        assertNotNull(headers.get("CAMEL_SPAN_ID"));
+        assertNotEquals("", headers.get("CAMEL_TRACE_ID"));
+        assertNotEquals("", headers.get("CAMEL_SPAN_ID"));
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start")
+                        .to("mock:result");
+            }
+        };
+    }
+
+}
diff --git a/components/camel-telemetry/src/main/docs/telemetry.adoc 
b/components/camel-telemetry/src/main/docs/telemetry.adoc
index 908128ec5691..6daad9776f25 100644
--- a/components/camel-telemetry/src/main/docs/telemetry.adoc
+++ b/components/camel-telemetry/src/main/docs/telemetry.adoc
@@ -26,8 +26,9 @@ The configuration properties for the Telemetry component are:
 [width="100%",cols="10%,10%,80%",options="header",]
 |=======================================================================
 |Option |Default |Description
-|`camel.component.telemetry.traceProcessors`| false | Trace inner processors.
-|`camel.component.telemetry.excludePatterns` |  | Sets exclude pattern that 
will disable tracing for those spans that matches the pattern. The variable is 
a comma separated values of filters to execute (eg, `log*,direct*,setBody*`, 
...)
+|`traceProcessors`| false | Trace inner processors.
+|`excludePatterns` |  | Sets exclude pattern that will disable tracing for 
those spans that matches the pattern. The variable is a comma separated values 
of filters to execute (eg, `log*,direct*,setBody*`, ...)
+|`traceHeadersInclusion`| false | Add the generated telemetry `CAMEL_TRACE_ID` 
and `CAMEL_SPAN_ID` Exchange headers.
 |=======================================================================
 
 == Tracing structure
@@ -84,6 +85,10 @@ Camel uses a proprietary storage mechanism. The trace is 
serialized into each ge
 
 The component provide the possibility to exclude the trace of any component 
when using the `excludePatterns` parameter. This feature is not implementation 
specific.
 
+=== Exchange headers inclusion
+
+The component provide the possibility to include the generated `trace` and 
`span` into the Exchange header. These headers can be then used for any 
observability purposes, eg, included in MDC via `camel-mdc` component.
+
 === Component Span decoration
 
 The component automatically includes certain useful parameter out of the box 
for the different components you may use within Camel. As an example, if you're 
using the Kafka component (`camel-kafka`), then, it will include in the Kafka 
endpoint span a few useful information such as *partition* or *offset* which 
you will be able to verify later in the trace collector.
diff --git 
a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/SpanLifecycleManager.java
 
b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/SpanLifecycleManager.java
index 3abf2940a522..501dd2430f20 100644
--- 
a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/SpanLifecycleManager.java
+++ 
b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/SpanLifecycleManager.java
@@ -29,6 +29,6 @@ public interface SpanLifecycleManager {
 
     void close(Span span);
 
-    void inject(Span span, SpanContextPropagationInjector injector);
+    void inject(Span span, SpanContextPropagationInjector injector, boolean 
includeTracing);
 
 }
diff --git 
a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/Tracer.java
 
b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/Tracer.java
index eb608a08434f..514fd2044565 100644
--- 
a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/Tracer.java
+++ 
b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/Tracer.java
@@ -45,6 +45,9 @@ import org.slf4j.LoggerFactory;
 
 public abstract class Tracer extends ServiceSupport implements 
CamelTracingService, RoutePolicyFactory, StaticService {
 
+    public static final String TRACE_HEADER = "CAMEL_TRACE_ID";
+    public static final String SPAN_HEADER = "CAMEL_SPAN_ID";
+
     private static final Logger LOG = LoggerFactory.getLogger(Tracer.class);
 
     private CamelContext camelContext;
@@ -53,6 +56,7 @@ public abstract class Tracer extends ServiceSupport 
implements CamelTracingServi
      */
     private String excludePatterns;
     private boolean traceProcessors;
+    private boolean traceHeadersInclusion;
 
     private final TracingEventNotifier eventNotifier = new 
TracingEventNotifier();
     private final SpanStorageManager spanStorageManager = new 
SpanStorageManagerExchange();
@@ -84,6 +88,15 @@ public abstract class Tracer extends ServiceSupport 
implements CamelTracingServi
         this.excludePatterns = excludePatterns;
     }
 
+    @ManagedAttribute
+    public boolean isTraceHeadersInclusion() {
+        return traceHeadersInclusion;
+    }
+
+    public void setTraceHeadersInclusion(boolean traceHeadersInclusion) {
+        this.traceHeadersInclusion = traceHeadersInclusion;
+    }
+
     @ManagedAttribute
     public boolean isTraceProcessors() {
         return traceProcessors;
@@ -262,7 +275,7 @@ public abstract class Tracer extends ServiceSupport 
implements CamelTracingServi
         spanDecorator.beforeTracingEvent(span, exchange, endpoint);
         spanLifecycleManager.activate(span);
         spanStorageManager.push(exchange, span);
-        spanLifecycleManager.inject(span, spanDecorator.getInjector(exchange));
+        spanLifecycleManager.inject(span, spanDecorator.getInjector(exchange), 
this.traceHeadersInclusion);
         LOG.debug("Started event span: {}", span);
     }
 
diff --git 
a/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/HeadersTraceTest.java
 
b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/HeadersTraceTest.java
new file mode 100644
index 000000000000..06358fb2ad65
--- /dev/null
+++ 
b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/HeadersTraceTest.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.telemetry;
+
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.telemetry.mock.MockTrace;
+import org.apache.camel.telemetry.mock.MockTracer;
+import org.apache.camel.test.junit5.ExchangeTestSupport;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class HeadersTraceTest extends ExchangeTestSupport {
+
+    MockTracer mockTracer;
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+        this.mockTracer = new MockTracer();
+        mockTracer.setTraceHeadersInclusion(true);
+        CamelContextAware.trySetCamelContext(mockTracer, context);
+        mockTracer.init(context);
+        return context;
+    }
+
+    @Test
+    void testProcessorsTraceRequest() throws InterruptedException {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMessageCount(1);
+        template.sendBody("direct:start", "my-body");
+        Map<String, MockTrace> traces = mockTracer.traces();
+        assertEquals(1, traces.size());
+        mock.assertIsSatisfied();
+        Map<String, Object> headers = 
mock.getExchanges().get(0).getIn().getHeaders();
+
+        // NOTE: the check on TRACE_ID and SPAN_ID instead of the related 
constant is on purpose
+        // We want to fail if there is any change in the constant by any 
chance and report into the
+        // documentation.
+        assertNotNull(headers.get("CAMEL_TRACE_ID"));
+        assertNotNull(headers.get("CAMEL_SPAN_ID"));
+        assertNotEquals("", headers.get("CAMEL_TRACE_ID"));
+        assertNotEquals("", headers.get("CAMEL_SPAN_ID"));
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start")
+                        .to("mock:result");
+            }
+        };
+    }
+
+}
diff --git 
a/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/mock/MockTracer.java
 
b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/mock/MockTracer.java
index 3301334ecef7..c1ea641fd9b9 100644
--- 
a/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/mock/MockTracer.java
+++ 
b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/mock/MockTracer.java
@@ -89,8 +89,13 @@ public class MockTracer extends Tracer {
         }
 
         @Override
-        public void inject(Span span, SpanContextPropagationInjector injector) 
{
+        public void inject(Span span, SpanContextPropagationInjector injector, 
boolean includeTracing) {
             injector.put("traceparent", span.toString());
+            if (includeTracing) {
+                MockSpanAdapter msa = (MockSpanAdapter) span;
+                injector.put(Tracer.TRACE_HEADER, msa.getTag("traceid"));
+                injector.put(Tracer.SPAN_HEADER, msa.getTag("spanid"));
+            }
         }
 
         public Map<String, MockTrace> traces() {
diff --git a/proposals/tracing.adoc b/proposals/tracing.adoc
index 1c41d3e9b805..3001fa16496b 100644
--- a/proposals/tracing.adoc
+++ b/proposals/tracing.adoc
@@ -108,10 +108,6 @@ If we move most of the logic into the abstraction, the 
implementation of a simpl
 
 The feature specific implementation should be therefore limited to the 
implementation of the abstract methods, as it would happen in the simple 
implementation. With this approach we are limiting to the bare minimum the 
maintenance of each specific technology. With this proposal we will need to 
rework massively on the reduction of code in the existing implementations 
(`camel-opentelemetry`).
 
-== Tracing refactoring POC
-
-In order to prove most of the above assumptions, I've developed a simple POC 
which I used as a 
https://github.com/squakez/camel/tree/feat/tracing_refactoring[base for this 
proposal]. Testing this against some application, we can see traces are managed 
correctly and in line with the structure proposed in this document.
-
 == Development
 
 This design proposals may introduce certain breaking compatibility changes, 
reason why we must clarify the scope and plan the work in order to avoid adding 
breaking compatibility within any non major version. We may work by adding a 
new abstract component which will be compliant with this new specification and 
once the new development is stable enough, we can deprecate the older 
`camel-tracing` and let the user replace with the newer one.
@@ -132,4 +128,8 @@ Developed concrete OpenTelemetry component implementing the 
`camel-telemetry` sp
 
 === `camel-micrometer-observability` component (2025-08-21)
 
-Developed concrete Micrometer Observability component implementing the 
`camel-telemetry` specification. This component will eventually replace 
`camel-observation` component.
\ No newline at end of file
+Developed concrete Micrometer Observability component implementing the 
`camel-telemetry` specification. This component will eventually replace 
`camel-observation` component.
+
+=== Inclusion of generated traces headers (2025-10-21)
+
+A new feature is available to add `TRACE_ID` and `SPAN_ID` Exchange headers. 
This is very useful in conjunction with MDC header usage. From now on we have a 
consistent setting of generated telemetry traces consumable from MDC mechanism.


Reply via email to