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

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

commit 10bb7ca2411f386cf1e091601ea24835f1882faa
Author: Pasquale Congiusti <[email protected]>
AuthorDate: Mon Feb 24 13:01:20 2025 +0100

    feat(components): Camel Opentemeletry 2
    
    New component based on the camel-telemetry abstraction
    
    Ref CAMEL-21786
---
 bom/camel-bom/pom.xml                              |  10 +
 catalog/camel-allcomponents/pom.xml                |   5 +
 .../main/camel-main-configuration-metadata.json    |   6 +
 .../org/apache/camel/catalog/others.properties     |   1 +
 .../camel/catalog/others/opentelemetry2.json       |  15 ++
 components/camel-opentelemetry2/pom.xml            | 118 ++++++++++
 .../OpenTelemetryTracerConfigurer.java             |  69 ++++++
 ...apache.camel.opentelemetry2.OpenTelemetryTracer |   2 +
 .../org/apache/camel/opentelemetry-tracer-2        |   2 +
 .../services/org/apache/camel/other.properties     |   7 +
 .../src/generated/resources/opentelemetry2.json    |  15 ++
 .../src/main/docs/opentelemetry2.adoc              |  82 +++++++
 .../opentelemetry2/OpenTelemetrySpanAdapter.java   | 122 ++++++++++
 .../camel/opentelemetry2/OpenTelemetryTracer.java  | 169 ++++++++++++++
 .../apache/camel/opentelemetry2/AsyncCXFTest.java  | 183 +++++++++++++++
 .../camel/opentelemetry2/AsyncDirectTest.java      | 173 ++++++++++++++
 .../camel/opentelemetry2/AsyncWiretapTest.java     | 175 +++++++++++++++
 .../CamelOpenTelemetryExtension.java               | 248 +++++++++++++++++++++
 .../camel/opentelemetry2/DisableEndpointTest.java  |  89 ++++++++
 .../camel/opentelemetry2/EnableProcessorsTest.java | 118 ++++++++++
 .../opentelemetry2/OpenTelemetryTracerTest.java    | 131 +++++++++++
 .../OpenTelemetryTracerTestSupport.java            |  44 ++++
 .../camel/opentelemetry2/SpanPropagationTest.java  |  92 ++++++++
 .../src/test/resources/log4j2.properties           |  45 ++++
 components/pom.xml                                 |   1 +
 .../Otel2ConfigurationPropertiesConfigurer.java    |  85 +++++++
 .../camel-main-configuration-metadata.json         |   6 +
 ....apache.camel.main.Otel2ConfigurationProperties |   2 +
 core/camel-main/src/main/docs/main.adoc            |  21 +-
 .../org/apache/camel/main/BaseMainSupport.java     |  55 ++++-
 .../camel/main/MainConfigurationProperties.java    |  16 ++
 .../camel/main/Otel2ConfigurationProperties.java   | 154 +++++++++++++
 .../others/examples/json/opentelemetry2.json       |   1 +
 docs/components/modules/others/nav.adoc            |   1 +
 .../modules/others/pages/opentelemetry2.adoc       |   1 +
 parent/pom.xml                                     |  10 +
 .../maven/packaging/PrepareCamelMainMojo.java      |   7 +-
 37 files changed, 2278 insertions(+), 3 deletions(-)

diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml
index 7cbcc7e5e7a..55c538a631d 100644
--- a/bom/camel-bom/pom.xml
+++ b/bom/camel-bom/pom.xml
@@ -1587,6 +1587,16 @@
         <artifactId>camel-opentelemetry</artifactId>
         <version>4.11.0-SNAPSHOT</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-opentelemetry-2</artifactId>
+        <version>4.11.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-opentelemetry2</artifactId>
+        <version>4.11.0-SNAPSHOT</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
         <artifactId>camel-optaplanner</artifactId>
diff --git a/catalog/camel-allcomponents/pom.xml 
b/catalog/camel-allcomponents/pom.xml
index f1a60cc6cc0..7a95d3a5766 100644
--- a/catalog/camel-allcomponents/pom.xml
+++ b/catalog/camel-allcomponents/pom.xml
@@ -1401,6 +1401,11 @@
             <artifactId>camel-opentelemetry</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-opentelemetry2</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-optaplanner</artifactId>
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
index 0c820eb09e6..626329f7b43 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
@@ -17,6 +17,7 @@
     { "name": "camel.vault.kubernetescm", "description": "Camel Kubernetes 
Configmaps Vault configurations", "sourceType": 
"org.apache.camel.vault.KubernetesConfigMapVaultConfiguration" },
     { "name": "camel.vault.hashicorp", "description": "Camel Hashicorp Vault 
configurations", "sourceType": 
"org.apache.camel.vault.HashicorpVaultConfiguration" },
     { "name": "camel.opentelemetry", "description": "Camel OpenTelemetry 
configurations", "sourceType": 
"org.apache.camel.main.OtelConfigurationProperties" },
+    { "name": "camel.opentelemetry2", "description": "Camel OpenTelemetry 2 
configurations", "sourceType": 
"org.apache.camel.main.Otel2ConfigurationProperties" },
     { "name": "camel.telemetryDev", "description": "Camel Telemetry Dev 
configurations", "sourceType": 
"org.apache.camel.main.TelemetryDevConfigurationProperties" },
     { "name": "camel.metrics", "description": "Camel Micrometer Metrics 
configurations", "sourceType": 
"org.apache.camel.main.MetricsConfigurationProperties" },
     { "name": "camel.faulttolerance", "description": "Fault Tolerance EIP 
Circuit Breaker configurations", "sourceType": 
"org.apache.camel.main.FaultToleranceConfigurationProperties" },
@@ -205,6 +206,11 @@
     { "name": "camel.opentelemetry.excludePatterns", "description": "Adds an 
exclude pattern that will disable tracing for Camel messages that matches the 
pattern. Multiple patterns can be separated by comma.", "sourceType": 
"org.apache.camel.main.OtelConfigurationProperties", "type": "string", 
"javaType": "java.lang.String" },
     { "name": "camel.opentelemetry.instrumentationName", "description": "A 
name uniquely identifying the instrumentation scope, such as the 
instrumentation library, package, or fully qualified class name. Must not be 
null.", "sourceType": "org.apache.camel.main.OtelConfigurationProperties", 
"type": "string", "javaType": "java.lang.String", "defaultValue": "camel" },
     { "name": "camel.opentelemetry.traceProcessors", "description": "Setting 
this to true will create new OpenTelemetry Spans for each Camel Processors. Use 
the excludePattern property to filter out Processors.", "sourceType": 
"org.apache.camel.main.OtelConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
+    { "name": "camel.opentelemetry2.enabled", "description": "To enable 
OpenTelemetry 2", "sourceType": 
"org.apache.camel.main.Otel2ConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
+    { "name": "camel.opentelemetry2.encoding", "description": "Sets whether 
the header keys need to be encoded (connector specific) or not. The value is a 
boolean. Dashes need for instances to be encoded for JMS property keys.", 
"sourceType": "org.apache.camel.main.Otel2ConfigurationProperties", "type": 
"boolean", "javaType": "boolean", "defaultValue": "false" },
+    { "name": "camel.opentelemetry2.excludePatterns", "description": "Adds an 
exclude pattern that will disable tracing for Camel messages that matches the 
pattern. Multiple patterns can be separated by comma.", "sourceType": 
"org.apache.camel.main.Otel2ConfigurationProperties", "type": "string", 
"javaType": "java.lang.String" },
+    { "name": "camel.opentelemetry2.instrumentationName", "description": "A 
name uniquely identifying the instrumentation scope, such as the 
instrumentation library, package, or fully qualified class name. Must not be 
null.", "sourceType": "org.apache.camel.main.Otel2ConfigurationProperties", 
"type": "string", "javaType": "java.lang.String", "defaultValue": "camel" },
+    { "name": "camel.opentelemetry2.traceProcessors", "description": "Setting 
this to true will create new OpenTelemetry Spans for each Camel Processors. Use 
the excludePattern property to filter out Processors.", "sourceType": 
"org.apache.camel.main.Otel2ConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
     { "name": 
"camel.resilience4j.automaticTransitionFromOpenToHalfOpenEnabled", 
"description": "Enables automatic transition from OPEN to HALF_OPEN state once 
the waitDurationInOpenState has passed.", "sourceType": 
"org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", 
"javaType": "java.lang.Boolean", "defaultValue": "false" },
     { "name": "camel.resilience4j.bulkheadEnabled", "description": "Whether 
bulkhead is enabled or not on the circuit breaker.", "sourceType": 
"org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", 
"javaType": "java.lang.Boolean", "defaultValue": false },
     { "name": "camel.resilience4j.bulkheadMaxConcurrentCalls", "description": 
"Configures the max amount of concurrent calls the bulkhead will support.", 
"sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", 
"type": "integer", "javaType": "java.lang.Integer" },
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others.properties
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others.properties
index 1c26a3657eb..dca62a83195 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others.properties
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others.properties
@@ -34,6 +34,7 @@ observation
 openapi-java
 openapi-validator
 opentelemetry
+opentelemetry2
 platform-http-jolokia
 platform-http-main
 platform-http-vertx
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/opentelemetry2.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/opentelemetry2.json
new file mode 100644
index 00000000000..39e3d92475b
--- /dev/null
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/opentelemetry2.json
@@ -0,0 +1,15 @@
+{
+  "other": {
+    "kind": "other",
+    "name": "opentelemetry2",
+    "title": "Opentelemetry2",
+    "description": "Implementation of Camel Opentelemetry based on the Camel 
Telemetry spec",
+    "deprecated": false,
+    "firstVersion": "4.11.0",
+    "label": "monitoring,microservice",
+    "supportLevel": "Preview",
+    "groupId": "org.apache.camel",
+    "artifactId": "camel-opentelemetry2",
+    "version": "4.11.0-SNAPSHOT"
+  }
+}
diff --git a/components/camel-opentelemetry2/pom.xml 
b/components/camel-opentelemetry2/pom.xml
new file mode 100644
index 00000000000..5c536fbb8dd
--- /dev/null
+++ b/components/camel-opentelemetry2/pom.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>components</artifactId>
+        <version>4.11.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-opentelemetry2</artifactId>
+    <packaging>jar</packaging>
+    <name>Camel :: Opentelemetry 2</name>
+    <description>Implementation of Camel Opentelemetry based on the Camel 
Telemetry spec</description>
+
+    <properties>
+        <firstVersion>4.11.0</firstVersion>
+        <label>monitoring,microservice</label>
+        <title>Opentelemetry2</title>
+        <supportLevel>Preview</supportLevel>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>io.opentelemetry</groupId>
+                <artifactId>opentelemetry-bom</artifactId>
+                <version>${opentelemetry-version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-telemetry</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.opentelemetry</groupId>
+            <artifactId>opentelemetry-sdk</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-spring-junit5</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.opentelemetry</groupId>
+            <artifactId>opentelemetry-sdk-testing</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.opentelemetry.instrumentation</groupId>
+            <artifactId>opentelemetry-log4j-appender-2.17</artifactId>
+            <version>${opentelemetry-log4j2-version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Required to test CXF async -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-cxf-rest</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-cxf-common</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-transports-http-undertow</artifactId>
+            <version>${cxf-version}</version>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>io.undertow</groupId>
+                    <artifactId>undertow-servlet</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>io.undertow</groupId>
+                    <artifactId>undertow-servlet-jakarta</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>io.undertow</groupId>
+                    <artifactId>undertow-core</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-undertow</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
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
new file mode 100644
index 00000000000..1e97cb58200
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/generated/java/org/apache/camel/opentelemetry2/OpenTelemetryTracerConfigurer.java
@@ -0,0 +1,69 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.opentelemetry2;
+
+import javax.annotation.processing.Generated;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.spi.ConfigurerStrategy;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.opentelemetry2.OpenTelemetryTracer;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.GenerateConfigurerMojo")
+@SuppressWarnings("unchecked")
+public class OpenTelemetryTracerConfigurer extends 
org.apache.camel.support.component.PropertyConfigurerSupport implements 
GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String 
name, Object value, boolean ignoreCase) {
+        org.apache.camel.opentelemetry2.OpenTelemetryTracer target = 
(org.apache.camel.opentelemetry2.OpenTelemetryTracer) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "camelcontext":
+        case "camelContext": target.setCamelContext(property(camelContext, 
org.apache.camel.CamelContext.class, value)); return true;
+        case "excludepatterns":
+        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 "traceprocessors":
+        case "traceProcessors": 
target.setTraceProcessors(property(camelContext, boolean.class, value)); return 
true;
+        default: return false;
+        }
+    }
+
+    @Override
+    public Class<?> getOptionType(String name, boolean ignoreCase) {
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "camelcontext":
+        case "camelContext": return org.apache.camel.CamelContext.class;
+        case "excludepatterns":
+        case "excludePatterns": return java.lang.String.class;
+        case "spanlifecyclemanager":
+        case "spanLifecycleManager": return 
org.apache.camel.telemetry.SpanLifecycleManager.class;
+        case "traceprocessors":
+        case "traceProcessors": return boolean.class;
+        default: return null;
+        }
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        org.apache.camel.opentelemetry2.OpenTelemetryTracer target = 
(org.apache.camel.opentelemetry2.OpenTelemetryTracer) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "camelcontext":
+        case "camelContext": return target.getCamelContext();
+        case "excludepatterns":
+        case "excludePatterns": return target.getExcludePatterns();
+        case "spanlifecyclemanager":
+        case "spanLifecycleManager": return target.getSpanLifecycleManager();
+        case "traceprocessors":
+        case "traceProcessors": return target.isTraceProcessors();
+        default: return null;
+        }
+    }
+}
+
diff --git 
a/components/camel-opentelemetry2/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.opentelemetry2.OpenTelemetryTracer
 
b/components/camel-opentelemetry2/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.opentelemetry2.OpenTelemetryTracer
new file mode 100644
index 00000000000..e94619a797c
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.opentelemetry2.OpenTelemetryTracer
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.opentelemetry2.OpenTelemetryTracerConfigurer
diff --git 
a/components/camel-opentelemetry2/src/generated/resources/META-INF/services/org/apache/camel/opentelemetry-tracer-2
 
b/components/camel-opentelemetry2/src/generated/resources/META-INF/services/org/apache/camel/opentelemetry-tracer-2
new file mode 100644
index 00000000000..f454b1c5167
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/generated/resources/META-INF/services/org/apache/camel/opentelemetry-tracer-2
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.opentelemetry2.OpenTelemetryTracer
diff --git 
a/components/camel-opentelemetry2/src/generated/resources/META-INF/services/org/apache/camel/other.properties
 
b/components/camel-opentelemetry2/src/generated/resources/META-INF/services/org/apache/camel/other.properties
new file mode 100644
index 00000000000..e3f722054ca
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/generated/resources/META-INF/services/org/apache/camel/other.properties
@@ -0,0 +1,7 @@
+# Generated by camel build tools - do NOT edit this file!
+name=opentelemetry2
+groupId=org.apache.camel
+artifactId=camel-opentelemetry2
+version=4.11.0-SNAPSHOT
+projectName=Camel :: Opentelemetry 2
+projectDescription=Implementation of Camel Opentelemetry based on the Camel 
Telemetry spec
diff --git 
a/components/camel-opentelemetry2/src/generated/resources/opentelemetry2.json 
b/components/camel-opentelemetry2/src/generated/resources/opentelemetry2.json
new file mode 100644
index 00000000000..39e3d92475b
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/generated/resources/opentelemetry2.json
@@ -0,0 +1,15 @@
+{
+  "other": {
+    "kind": "other",
+    "name": "opentelemetry2",
+    "title": "Opentelemetry2",
+    "description": "Implementation of Camel Opentelemetry based on the Camel 
Telemetry spec",
+    "deprecated": false,
+    "firstVersion": "4.11.0",
+    "label": "monitoring,microservice",
+    "supportLevel": "Preview",
+    "groupId": "org.apache.camel",
+    "artifactId": "camel-opentelemetry2",
+    "version": "4.11.0-SNAPSHOT"
+  }
+}
diff --git a/components/camel-opentelemetry2/src/main/docs/opentelemetry2.adoc 
b/components/camel-opentelemetry2/src/main/docs/opentelemetry2.adoc
new file mode 100644
index 00000000000..650cf80d288
--- /dev/null
+++ b/components/camel-opentelemetry2/src/main/docs/opentelemetry2.adoc
@@ -0,0 +1,82 @@
+= Opentelemetry2 Component
+:doctitle: Opentelemetry2
+:shortname: opentelemetry2
+:artifactid: camel-opentelemetry2
+:description: Implementation of Camel Opentelemetry based on the Camel 
Telemetry spec
+:since: 4.11
+:supportlevel: Preview
+:tabs-sync-option:
+
+*Since Camel {since}*
+
+This module is the implementation of the common `camel-telemetry` interface 
based on https://opentelemetry.io/[OpenTelemetry] technology. The name used 
here as `camel-opentelemetry2` is done to distinguish on the existing 
`camel-opentelemetry` which was based on an older Camel tracing specification. 
You're invited to start replacing the older `camel-opentelemetry` with this one 
instead as it may become the default component in future version of Camel.
+
+NOTE: this component has slight differences compared to the 
`camel-openetelemetry` and is meant to solve a few inconsistencies identified.
+
+== Configuration
+
+The configuration properties for the OpenTelemetry2 tracer are:
+
+[width="100%",cols="10%,10%,80%",options="header",]
+|=======================================================================
+|Option |Default |Description
+|`excludePatterns` |  | Sets exclude pattern(s) that will disable tracing for 
Camel
+messages that matches the pattern. The content is a Set<String> where the key 
is a pattern. The pattern
+uses the rules from Intercept.
+|`traceProcessors` | `false` | Setting this to true will create new 
OpenTelemetry Spans for each Camel Processors.
+Use the excludePattern property to filter out Processors
+|=======================================================================
+
+=== Using with standalone Camel
+
+If you use `camel-main` as standalone Camel, then you can enable and use 
OpenTelemetry without Java code.
+
+Add `camel-opentelemetry2` component in your POM, and configure in 
`application.properties`:
+
+[source,properties]
+----
+camel.opentelemetry2.enabled = true
+# you can configure the other options
+# camel.opentelemetry2.traceProcessors = true
+----
+
+When starting the application, you may need to configure a few OpenTelemetry 
SDK variables, as you can see in te following example:
+
+```bash
+$ java -Dotel.metrics.exporter=none -Dotel.logs.exporter=none -jar my-app.jar
+```
+
+[[OpenTelemetry-JavaAgent]]
+=== Java Agent
+
+Your application will require a Java agent in order to get the traces 
generated by the Camel application and push to the tracing server.
+
+NOTE: certain runtimes (ie, Quarkus) may provide an inner client which pushes 
traces to the server. Make sure to read each specific Camel runtime 
documentation.
+
+Download the 
https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/[latest
 version].
+
+This package includes the instrumentation agent as well as instrumentation for 
all supported libraries and all available data exporters. The package provides 
a completely automatic, out-of-the-box experience. Enable the instrumentation 
agent using the `-javaagent` flag to the JVM.
+
+[source,bash]
+----
+java -javaagent:path/to/opentelemetry-javaagent.jar \
+     -Dotel. ... \
+     -jar myapp.jar
+----
+
+By default, the OpenTelemetry Java agent uses 
https://github.com/open-telemetry/opentelemetry-java/tree/main/exporters/otlp[OTLP
 exporter] configured to send data to 
https://github.com/open-telemetry/opentelemetry-collector/blob/main/receiver/otlpreceiver/README.md[OpenTelemetry
 collector] at `http://localhost:4318`.
+
+Configuration parameters are passed as Java system properties (`-D` flags) or 
as environment variables. See 
https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/agent-config.md[the
 configuration documentation] for the full list of configuration items. For 
example:
+
+[source,bash]
+----
+java -javaagent:path/to/opentelemetry-javaagent.jar \
+     -Dotel.service.name=your-service-name \
+     -Dotel.traces.exporter=otlp \
+     -jar myapp.jar
+----
+
+[[OpenTelemetry-Collection]]
+=== 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].
diff --git 
a/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OpenTelemetrySpanAdapter.java
 
b/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OpenTelemetrySpanAdapter.java
new file mode 100644
index 00000000000..144a1e6c395
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OpenTelemetrySpanAdapter.java
@@ -0,0 +1,122 @@
+/*
+ * 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.util.Map;
+
+import io.opentelemetry.api.baggage.Baggage;
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.common.AttributesBuilder;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.context.Scope;
+import org.apache.camel.telemetry.TagConstants;
+
+public class OpenTelemetrySpanAdapter implements 
org.apache.camel.telemetry.Span {
+
+    private static final String DEFAULT_EVENT_NAME = "log";
+
+    private final Span otelSpan;
+    private final Baggage baggage;
+    private Scope scope;
+
+    protected OpenTelemetrySpanAdapter(Span otelSpan, Baggage baggage) {
+        this.otelSpan = otelSpan;
+        this.baggage = baggage;
+    }
+
+    protected Span getSpan() {
+        return this.otelSpan;
+    }
+
+    protected void makeCurrent() {
+        this.scope = this.otelSpan.makeCurrent();
+    }
+
+    protected void end() {
+        this.otelSpan.end();
+    }
+
+    protected void close() {
+        if (scope != null) {
+            this.scope.close();
+        }
+    }
+
+    protected Baggage getBaggage() {
+        return this.baggage;
+    }
+
+    @Override
+    public void log(Map<String, String> fields) {
+        this.otelSpan.addEvent(getEventNameFromFields(fields), 
convertToAttributes(fields));
+    }
+
+    @Override
+    public void setTag(String key, String value) {
+        this.otelSpan.setAttribute(key, value);
+    }
+
+    @Override
+    public void setComponent(String component) {
+        this.setTag(TagConstants.COMPONENT, component);
+    }
+
+    @Override
+    public void setError(boolean isError) {
+        this.setTag(TagConstants.ERROR, "" + isError);
+    }
+
+    private String getEventNameFromFields(Map<String, ?> fields) {
+        Object eventValue = fields == null ? null : fields.get("event");
+        if (eventValue != null) {
+            return eventValue.toString();
+        }
+
+        return DEFAULT_EVENT_NAME;
+    }
+
+    private Attributes convertToAttributes(Map<String, ?> fields) {
+        AttributesBuilder attributesBuilder = Attributes.builder();
+
+        for (Map.Entry<String, ?> entry : fields.entrySet()) {
+            String key = entry.getKey();
+            Object value = entry.getValue();
+            if (value == null) {
+                continue;
+            }
+            if (value instanceof Byte
+                    || value instanceof Short
+                    || value instanceof Integer
+                    || value instanceof Long) {
+                attributesBuilder.put(key, ((Number) value).longValue());
+            } else if (value instanceof Float || value instanceof Double) {
+                attributesBuilder.put(key, ((Number) value).doubleValue());
+            } else if (value instanceof Boolean) {
+                attributesBuilder.put(key, (Boolean) value);
+            } else {
+                attributesBuilder.put(key, value.toString());
+            }
+        }
+        return attributesBuilder.build();
+    }
+
+    @Override
+    public String toString() {
+        return "OpenTelemetrySpanAdapter [span=" + otelSpan + ", baggage=" + 
baggage + "]";
+    }
+
+}
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
new file mode 100644
index 00000000000..2ee1b76c3cc
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OpenTelemetryTracer.java
@@ -0,0 +1,169 @@
+/*
+ * 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 io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.api.baggage.Baggage;
+import io.opentelemetry.api.trace.SpanBuilder;
+import io.opentelemetry.api.trace.Tracer;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.context.propagation.ContextPropagators;
+import io.opentelemetry.context.propagation.TextMapGetter;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.api.management.ManagedResource;
+import org.apache.camel.spi.Configurer;
+import org.apache.camel.spi.annotations.JdkService;
+import org.apache.camel.support.CamelContextHelper;
+import org.apache.camel.telemetry.Span;
+import org.apache.camel.telemetry.SpanContextPropagationExtractor;
+import org.apache.camel.telemetry.SpanContextPropagationInjector;
+import org.apache.camel.telemetry.SpanLifecycleManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@JdkService("opentelemetry-tracer-2")
+@Configurer
+@ManagedResource(description = "OpenTelemetry2")
+public class OpenTelemetryTracer extends org.apache.camel.telemetry.Tracer {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(OpenTelemetryTracer.class);
+
+    private Tracer tracer;
+    private ContextPropagators contextPropagators;
+
+    @Override
+    protected void initTracer() {
+        if (tracer == null) {
+            this.tracer = 
CamelContextHelper.findSingleByType(getCamelContext(), Tracer.class);
+        }
+        if (tracer == null) {
+            this.tracer = GlobalOpenTelemetry.get().getTracer("camel");
+        }
+        if (tracer == null) {
+            throw new RuntimeCamelException("Could not find any Opentelemetry 
tracer!");
+        }
+
+        if (contextPropagators == null) {
+            contextPropagators = CamelContextHelper.findSingleByType(
+                    getCamelContext(), ContextPropagators.class);
+        }
+        if (contextPropagators == null) {
+            contextPropagators = GlobalOpenTelemetry.get().getPropagators();
+        }
+        if (contextPropagators == null) {
+            throw new RuntimeCamelException("Could not find any Opentelemetry 
context propagator!");
+        }
+
+        this.setSpanLifecycleManager(new 
OpentelemetrySpanLifecycleManager(tracer, contextPropagators));
+    }
+
+    void setTracer(Tracer tracer) {
+        this.tracer = tracer;
+    }
+
+    void setContextPropagators(ContextPropagators cp) {
+        this.contextPropagators = cp;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+        LOG.info("Opentelemetry2 enabled");
+    }
+
+    private class OpentelemetrySpanLifecycleManager implements 
SpanLifecycleManager {
+
+        private final Tracer tracer;
+        private final ContextPropagators contextPropagators;
+
+        private OpentelemetrySpanLifecycleManager(Tracer tracer, 
ContextPropagators contextPropagators) {
+            this.tracer = tracer;
+            this.contextPropagators = contextPropagators;
+        }
+
+        @Override
+        public Span create(String spanName, Span parent, 
SpanContextPropagationExtractor extractor) {
+            SpanBuilder builder = tracer.spanBuilder(spanName);
+            Baggage baggage = null;
+
+            if (parent != null) {
+                OpenTelemetrySpanAdapter otelParentSpan = 
(OpenTelemetrySpanAdapter) parent;
+                builder = 
builder.setParent(Context.current().with(otelParentSpan.getSpan()));
+                baggage = otelParentSpan.getBaggage();
+            } else {
+                /*
+                 * This part is a bit tricky in Opentelemetry. We need to 
verify if the extractor
+                 * (ie, the Camel Exchange) holds a propagated parent. If it 
doesn't, then, we must use a null Context.
+                 */
+                Context current = null;
+                if (extractor.get("traceparent") != null) {
+                    current = Context.current();
+                }
+                // Try to get parent from context propagation (upstream traces)
+                Context ctx = 
contextPropagators.getTextMapPropagator().extract(current, extractor,
+                        new TextMapGetter<SpanContextPropagationExtractor>() {
+                            @Override
+                            public Iterable<String> 
keys(SpanContextPropagationExtractor carrier) {
+                                return carrier.keys();
+                            }
+
+                            @Override
+                            public String get(SpanContextPropagationExtractor 
carrier, String key) {
+                                if (carrier.get(key) == null) {
+                                    return null;
+                                }
+                                return carrier.get(key).toString();
+                            }
+                        });
+                builder = builder.setParent(ctx);
+            }
+
+            return new OpenTelemetrySpanAdapter(builder.startSpan(), baggage);
+        }
+
+        @Override
+        public void activate(Span span) {
+            OpenTelemetrySpanAdapter otelSpan = (OpenTelemetrySpanAdapter) 
span;
+            otelSpan.makeCurrent();
+        }
+
+        @Override
+        public void deactivate(Span span) {
+            OpenTelemetrySpanAdapter otelSpan = (OpenTelemetrySpanAdapter) 
span;
+            otelSpan.end();
+        }
+
+        @Override
+        public void close(Span span) {
+            OpenTelemetrySpanAdapter otelSpan = (OpenTelemetrySpanAdapter) 
span;
+            otelSpan.close();
+        }
+
+        @Override
+        public void inject(Span span, SpanContextPropagationInjector injector) 
{
+            OpenTelemetrySpanAdapter otelSpan = (OpenTelemetrySpanAdapter) 
span;
+            Context ctx = Context.current().with(otelSpan.getSpan());
+            if (otelSpan.getBaggage() != null) {
+                ctx = ctx.with(otelSpan.getBaggage());
+            }
+            contextPropagators.getTextMapPropagator().inject(ctx, injector,
+                    (carrier, key, value) -> carrier.put(key, value));
+        }
+
+    }
+
+}
diff --git 
a/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/AsyncCXFTest.java
 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/AsyncCXFTest.java
new file mode 100644
index 00000000000..278fddd9076
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/AsyncCXFTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.List;
+import java.util.Map;
+
+import io.opentelemetry.api.common.AttributeKey;
+import io.opentelemetry.sdk.trace.data.SpanData;
+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.apache.camel.telemetry.Op;
+import org.apache.camel.test.AvailablePortFinder;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/*
+ * AsyncCXFTest tests the execution of CXF async which was reported as a 
potential candidate to
+ * inconsistent Span creation in async mode.
+ */
+public class AsyncCXFTest extends OpenTelemetryTracerTestSupport {
+
+    private static int cxfPort = AvailablePortFinder.getNextRandomAvailable();
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        OpenTelemetryTracer tst = new OpenTelemetryTracer();
+        tst.setTracer(otelExtension.getOpenTelemetry().getTracer("traceTest"));
+        
tst.setContextPropagators(otelExtension.getOpenTelemetry().getPropagators());
+        CamelContext context = super.createCamelContext();
+        CamelContextAware.trySetCamelContext(tst, context);
+        tst.init(context);
+        return context;
+    }
+
+    @Test
+    void testRouteMultipleRequests() throws InterruptedException, IOException {
+        int j = 10;
+        MockEndpoint mock = getMockEndpoint("mock:end");
+        mock.expectedMessageCount(j);
+        mock.setAssertPeriod(5000);
+        for (int i = 0; i < j; i++) {
+            context.createProducerTemplate().sendBody("direct:start", 
"Hello!");
+        }
+        mock.assertIsSatisfied(1000);
+        Map<String, OtelTrace> traces = otelExtension.getTraces();
+        // Each trace should have a unique trace id. It is enough to assert 
that
+        // the number of elements in the map is the same of the requests to 
prove
+        // all traces have been generated uniquely.
+        assertEquals(j, traces.size());
+        // Each trace should have the same structure
+        for (OtelTrace trace : traces.values()) {
+            checkTrace(trace);
+        }
+
+    }
+
+    private void checkTrace(OtelTrace trace) {
+        List<SpanData> spans = trace.getSpans();
+        assertEquals(8, spans.size());
+        SpanData testProducer = OpenTelemetryTracerTestSupport.getSpan(spans, 
"direct://start", Op.EVENT_SENT);
+        SpanData direct = OpenTelemetryTracerTestSupport.getSpan(spans, 
"direct://start", Op.EVENT_RECEIVED);
+        SpanData directSendTo = OpenTelemetryTracerTestSupport.getSpan(spans, 
"direct://send", Op.EVENT_SENT);
+        SpanData directSendFrom = 
OpenTelemetryTracerTestSupport.getSpan(spans, "direct://send", 
Op.EVENT_RECEIVED);
+        SpanData cxfRs = OpenTelemetryTracerTestSupport.getSpan(
+                spans,
+                "cxfrs://http://localhost:"; + cxfPort + 
"/rest/helloservice/sayHello?synchronous=false",
+                Op.EVENT_SENT);
+        SpanData rest = OpenTelemetryTracerTestSupport.getSpan(
+                spans,
+                "rest://post:/rest/helloservice:/sayHello?routeId=direct-hi",
+                Op.EVENT_RECEIVED);
+        SpanData log = OpenTelemetryTracerTestSupport.getSpan(spans, 
"log://hi", Op.EVENT_SENT);
+        SpanData mock = OpenTelemetryTracerTestSupport.getSpan(spans, 
"mock://end", Op.EVENT_SENT);
+
+        // Validate span completion
+        assertTrue(testProducer.hasEnded());
+        assertTrue(direct.hasEnded());
+        assertTrue(directSendTo.hasEnded());
+        assertTrue(directSendFrom.hasEnded());
+        assertTrue(cxfRs.hasEnded());
+        assertTrue(rest.hasEnded());
+        assertTrue(log.hasEnded());
+        assertTrue(mock.hasEnded());
+
+        // Validate same trace
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
direct.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
directSendTo.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
directSendFrom.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
cxfRs.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
rest.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
log.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
mock.getSpanContext().getTraceId());
+
+        // Validate different Exchange ID
+        
assertNotEquals(testProducer.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                
rest.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+        
assertEquals(testProducer.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                
direct.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+        
assertEquals(testProducer.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                
directSendTo.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+        
assertEquals(testProducer.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                
directSendFrom.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+        
assertEquals(testProducer.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                
cxfRs.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+        
assertEquals(rest.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                log.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+        
assertEquals(rest.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                
mock.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+
+        // Validate hierarchy
+        assertFalse(testProducer.getParentSpanContext().isValid());
+        assertEquals(testProducer.getSpanContext().getSpanId(), 
direct.getParentSpanContext().getSpanId());
+        assertEquals(direct.getSpanContext().getSpanId(), 
directSendTo.getParentSpanContext().getSpanId());
+        assertEquals(directSendTo.getSpanContext().getSpanId(), 
directSendFrom.getParentSpanContext().getSpanId());
+        assertEquals(directSendFrom.getSpanContext().getSpanId(), 
cxfRs.getParentSpanContext().getSpanId());
+        assertEquals(cxfRs.getSpanContext().getSpanId(), 
rest.getParentSpanContext().getSpanId());
+        assertEquals(rest.getSpanContext().getSpanId(), 
log.getParentSpanContext().getSpanId());
+        assertEquals(rest.getSpanContext().getSpanId(), 
mock.getParentSpanContext().getSpanId());
+
+        // Validate message logging
+        assertEquals("A direct message", 
directSendFrom.getEvents().get(0).getAttributes().get(
+                AttributeKey.stringKey("message")));
+        assertEquals("say-hi", rest.getEvents().get(0).getAttributes().get(
+                AttributeKey.stringKey("message")));
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start")
+                        .routeId("myRoute")
+                        .to("direct:send");
+
+                from("direct:send")
+                        .log("A direct message")
+                        .to("cxfrs:http://localhost:"; + cxfPort
+                            + "/rest/helloservice/sayHello?synchronous=false");
+
+                restConfiguration()
+                        .port(cxfPort);
+
+                rest("/rest/helloservice")
+                    .post("/sayHello")
+                    .routeId("rest-GET-say-hi")
+                    .to("direct:hi");
+
+                from("direct:hi")
+                        .routeId("direct-hi")
+                        .delay(2000)
+                        .log("say-hi")
+                        .to("log:hi")
+                        .to("mock:end");
+            }
+        };
+    }
+
+}
diff --git 
a/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/AsyncDirectTest.java
 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/AsyncDirectTest.java
new file mode 100644
index 00000000000..4b010c617e1
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/AsyncDirectTest.java
@@ -0,0 +1,173 @@
+/*
+ * 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.List;
+import java.util.Map;
+
+import io.opentelemetry.api.common.AttributeKey;
+import io.opentelemetry.sdk.trace.data.SpanData;
+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.apache.camel.telemetry.Op;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class AsyncDirectTest extends OpenTelemetryTracerTestSupport {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        OpenTelemetryTracer tst = new OpenTelemetryTracer();
+        tst.setTracer(otelExtension.getOpenTelemetry().getTracer("traceTest"));
+        
tst.setContextPropagators(otelExtension.getOpenTelemetry().getPropagators());
+        CamelContext context = super.createCamelContext();
+        CamelContextAware.trySetCamelContext(tst, context);
+        tst.init(context);
+        return context;
+    }
+
+    @Test
+    void testRouteMultipleRequests() throws InterruptedException, IOException {
+        int j = 10;
+        MockEndpoint mock = getMockEndpoint("mock:end");
+        mock.expectedMessageCount(j);
+        mock.setAssertPeriod(5000);
+        for (int i = 0; i < j; i++) {
+            context.createProducerTemplate().sendBody("direct:start", 
"Hello!");
+        }
+        mock.assertIsSatisfied(1000);
+        Map<String, OtelTrace> traces = otelExtension.getTraces();
+        // Each trace should have a unique trace id. It is enough to assert 
that
+        // the number of elements in the map is the same of the requests to 
prove
+        // all traces have been generated uniquely.
+        assertEquals(j, traces.size());
+        // Each trace should have the same structure
+        for (OtelTrace trace : traces.values()) {
+            checkTrace(trace, "Hello!");
+        }
+
+    }
+
+    private void checkTrace(OtelTrace trace, String expectedBody) {
+        List<SpanData> spans = trace.getSpans();
+        assertEquals(7, spans.size());
+        SpanData testProducer = OpenTelemetryTracerTestSupport.getSpan(spans, 
"direct://start", Op.EVENT_SENT);
+        SpanData direct = OpenTelemetryTracerTestSupport.getSpan(spans, 
"direct://start", Op.EVENT_RECEIVED);
+        SpanData newDirectTo = OpenTelemetryTracerTestSupport.getSpan(spans, 
"direct://new", Op.EVENT_SENT);
+        SpanData log = OpenTelemetryTracerTestSupport.getSpan(spans, 
"log://info", Op.EVENT_SENT);
+        SpanData newDirectFrom = OpenTelemetryTracerTestSupport.getSpan(spans, 
"direct://new", Op.EVENT_RECEIVED);
+        SpanData newLog = OpenTelemetryTracerTestSupport.getSpan(spans, 
"log://new", Op.EVENT_SENT);
+        SpanData newMock = OpenTelemetryTracerTestSupport.getSpan(spans, 
"mock://end", Op.EVENT_SENT);
+
+        // Validate span completion
+        assertTrue(testProducer.hasEnded());
+        assertTrue(direct.hasEnded());
+        assertTrue(newDirectTo.hasEnded());
+        assertTrue(log.hasEnded());
+        assertTrue(newDirectFrom.hasEnded());
+        assertTrue(newLog.hasEnded());
+        assertTrue(newMock.hasEnded());
+
+        // Validate same trace
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
direct.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
newDirectTo.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
log.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
newDirectFrom.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
newLog.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
newMock.getSpanContext().getTraceId());
+
+        // Validate same Exchange ID
+        // As it's a "direct" component, we expect the logic to happen within 
the same
+        // Exchange boundary
+        
assertEquals(testProducer.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                
direct.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+        
assertEquals(testProducer.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                
newDirectTo.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+        
assertEquals(testProducer.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                
newDirectFrom.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+        
assertEquals(testProducer.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                log.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+        
assertEquals(testProducer.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                
newLog.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+        
assertEquals(testProducer.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                
newMock.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+
+        // Validate hierarchy
+        assertFalse(testProducer.getParentSpanContext().isValid());
+        assertEquals(testProducer.getSpanContext().getSpanId(), 
direct.getParentSpanContext().getSpanId());
+        assertEquals(direct.getSpanContext().getSpanId(), 
newDirectTo.getParentSpanContext().getSpanId());
+        assertEquals(direct.getSpanContext().getSpanId(), 
log.getParentSpanContext().getSpanId());
+        assertEquals(newDirectTo.getSpanContext().getSpanId(), 
newDirectFrom.getParentSpanContext().getSpanId());
+        assertEquals(newDirectFrom.getSpanContext().getSpanId(), 
newLog.getParentSpanContext().getSpanId());
+        assertEquals(newDirectFrom.getSpanContext().getSpanId(), 
newMock.getParentSpanContext().getSpanId());
+
+        // Validate message logging
+        assertEquals("A direct message", 
direct.getEvents().get(0).getAttributes().get(
+                AttributeKey.stringKey("message")));
+        assertEquals("A new message", 
newDirectFrom.getEvents().get(0).getAttributes().get(
+                AttributeKey.stringKey("message")));
+        if (expectedBody == null) {
+            assertEquals(
+                    "Exchange[ExchangePattern: InOut, BodyType: null, Body: 
[Body is null]]",
+                    log.getEvents().get(0).getAttributes().get(
+                            AttributeKey.stringKey("message")));
+            assertEquals(
+                    "Exchange[ExchangePattern: InOut, BodyType: null, Body: 
[Body is null]]",
+                    newLog.getEvents().get(0).getAttributes().get(
+                            AttributeKey.stringKey("message")));
+        } else {
+            assertEquals(
+                    "Exchange[ExchangePattern: InOnly, BodyType: String, Body: 
" + expectedBody + "]",
+                    log.getEvents().get(0).getAttributes().get(
+                            AttributeKey.stringKey("message")));
+            assertEquals(
+                    "Exchange[ExchangePattern: InOnly, BodyType: String, Body: 
" + expectedBody + "]",
+                    newLog.getEvents().get(0).getAttributes().get(
+                            AttributeKey.stringKey("message")));
+        }
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start")
+                        .routeId("start")
+                        .to("direct:new")
+                        .log("A direct message")
+                        .to("log:info");
+
+                from("direct:new")
+                        .delay(2000)
+                        .routeId("new")
+                        .log("A new message")
+                        .to("log:new")
+                        .to("mock:end");
+            }
+        };
+    }
+
+}
diff --git 
a/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/AsyncWiretapTest.java
 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/AsyncWiretapTest.java
new file mode 100644
index 00000000000..6b1ced29627
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/AsyncWiretapTest.java
@@ -0,0 +1,175 @@
+/*
+ * 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.List;
+import java.util.Map;
+
+import io.opentelemetry.api.common.AttributeKey;
+import io.opentelemetry.sdk.trace.data.SpanData;
+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.apache.camel.telemetry.Op;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/*
+ * WiretappedRouteTest tests the execution of a new spin off component which 
would create a new exchange, for example,
+ * using the wiretap component.
+ */
+public class AsyncWiretapTest extends OpenTelemetryTracerTestSupport {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        OpenTelemetryTracer tst = new OpenTelemetryTracer();
+        tst.setTracer(otelExtension.getOpenTelemetry().getTracer("traceTest"));
+        
tst.setContextPropagators(otelExtension.getOpenTelemetry().getPropagators());
+        CamelContext context = super.createCamelContext();
+        CamelContextAware.trySetCamelContext(tst, context);
+        tst.init(context);
+        return context;
+    }
+
+    @Test
+    void testRouteMultipleRequests() throws InterruptedException, IOException {
+        int j = 10;
+        MockEndpoint mock = getMockEndpoint("mock:end");
+        mock.expectedMessageCount(j);
+        mock.setAssertPeriod(5000);
+        for (int i = 0; i < j; i++) {
+            context.createProducerTemplate().sendBody("direct:start", 
"Hello!");
+        }
+        mock.assertIsSatisfied(1000);
+        Map<String, OtelTrace> traces = otelExtension.getTraces();
+        // Each trace should have a unique trace id. It is enough to assert 
that
+        // the number of elements in the map is the same of the requests to 
prove
+        // all traces have been generated uniquely.
+        assertEquals(j, traces.size());
+        // Each trace should have the same structure
+        for (OtelTrace trace : traces.values()) {
+            checkTrace(trace, "Hello!");
+        }
+
+    }
+
+    private void checkTrace(OtelTrace trace, String expectedBody) {
+        List<SpanData> spans = trace.getSpans();
+        assertEquals(7, spans.size());
+        SpanData testProducer = OpenTelemetryTracerTestSupport.getSpan(spans, 
"direct://start", Op.EVENT_SENT);
+        SpanData direct = OpenTelemetryTracerTestSupport.getSpan(spans, 
"direct://start", Op.EVENT_RECEIVED);
+        SpanData wiretapDirectTo = 
OpenTelemetryTracerTestSupport.getSpan(spans, "direct://tap", Op.EVENT_SENT);
+        SpanData wiretapDirectFrom = 
OpenTelemetryTracerTestSupport.getSpan(spans, "direct://tap", 
Op.EVENT_RECEIVED);
+        SpanData log = OpenTelemetryTracerTestSupport.getSpan(spans, 
"log://info", Op.EVENT_SENT);
+        SpanData wiretapLog = OpenTelemetryTracerTestSupport.getSpan(spans, 
"log://tapped", Op.EVENT_SENT);
+        SpanData wiretapMock = OpenTelemetryTracerTestSupport.getSpan(spans, 
"mock://end", Op.EVENT_SENT);
+
+        // Validate span completion
+        assertTrue(testProducer.hasEnded());
+        assertTrue(direct.hasEnded());
+        assertTrue(wiretapDirectTo.hasEnded());
+        assertTrue(wiretapDirectFrom.hasEnded());
+        assertTrue(log.hasEnded());
+        assertTrue(wiretapLog.hasEnded());
+        assertTrue(wiretapMock.hasEnded());
+
+        // Validate same trace
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
direct.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
wiretapDirectTo.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
wiretapDirectFrom.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
log.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
wiretapLog.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
wiretapMock.getSpanContext().getTraceId());
+
+        // Validate different Exchange ID
+        
assertNotEquals(testProducer.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                
wiretapDirectTo.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+        
assertEquals(testProducer.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                
direct.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+        
assertEquals(testProducer.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                log.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+        
assertEquals(wiretapDirectTo.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                
wiretapDirectFrom.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+        
assertEquals(wiretapDirectTo.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                
wiretapLog.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+        
assertEquals(wiretapDirectTo.getAttributes().get(AttributeKey.stringKey("exchangeId")),
+                
wiretapMock.getAttributes().get(AttributeKey.stringKey("exchangeId")));
+
+        // Validate hierarchy
+        assertFalse(testProducer.getParentSpanContext().isValid());
+        assertEquals(testProducer.getSpanContext().getSpanId(), 
direct.getParentSpanContext().getSpanId());
+        assertEquals(direct.getSpanContext().getSpanId(), 
log.getParentSpanContext().getSpanId());
+        assertEquals(direct.getSpanContext().getSpanId(), 
wiretapDirectTo.getParentSpanContext().getSpanId());
+        assertEquals(wiretapDirectTo.getSpanContext().getSpanId(), 
wiretapDirectFrom.getParentSpanContext().getSpanId());
+        assertEquals(wiretapDirectFrom.getSpanContext().getSpanId(), 
wiretapLog.getParentSpanContext().getSpanId());
+        assertEquals(wiretapDirectFrom.getSpanContext().getSpanId(), 
wiretapMock.getParentSpanContext().getSpanId());
+
+        // Validate message logging
+        assertEquals("A direct message", 
direct.getEvents().get(0).getAttributes().get(
+                AttributeKey.stringKey("message")));
+        assertEquals("A tapped message", 
wiretapDirectFrom.getEvents().get(0).getAttributes().get(
+                AttributeKey.stringKey("message")));
+        if (expectedBody == null) {
+            assertEquals(
+                    "Exchange[ExchangePattern: InOut, BodyType: null, Body: 
[Body is null]]",
+                    log.getEvents().get(0).getAttributes().get(
+                            AttributeKey.stringKey("message")));
+            assertEquals(
+                    "Exchange[ExchangePattern: InOut, BodyType: null, Body: 
[Body is null]]",
+                    wiretapLog.getEvents().get(0).getAttributes().get(
+                            AttributeKey.stringKey("message")));
+        } else {
+            assertEquals(
+                    "Exchange[ExchangePattern: InOnly, BodyType: String, Body: 
" + expectedBody + "]",
+                    log.getEvents().get(0).getAttributes().get(
+                            AttributeKey.stringKey("message")));
+            assertEquals(
+                    "Exchange[ExchangePattern: InOnly, BodyType: String, Body: 
" + expectedBody + "]",
+                    wiretapLog.getEvents().get(0).getAttributes().get(
+                            AttributeKey.stringKey("message")));
+        }
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start")
+                        .routeId("start")
+                        .wireTap("direct:tap")
+                        .log("A direct message")
+                        .to("log:info");
+
+                from("direct:tap")
+                        .delay(2000)
+                        .routeId("wiretapped")
+                        .log("A tapped message")
+                        .to("log:tapped")
+                        .to("mock:end");
+            }
+        };
+    }
+}
diff --git 
a/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/CamelOpenTelemetryExtension.java
 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/CamelOpenTelemetryExtension.java
new file mode 100644
index 00000000000..544018fa27f
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/CamelOpenTelemetryExtension.java
@@ -0,0 +1,248 @@
+/*
+ * 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.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.context.propagation.ContextPropagators;
+import 
io.opentelemetry.instrumentation.log4j.appender.v2_17.OpenTelemetryAppender;
+import io.opentelemetry.sdk.OpenTelemetrySdk;
+//import 
io.opentelemetry.sdk.extension.incubator.trace.LeakDetectingSpanProcessor;
+import io.opentelemetry.sdk.logs.SdkLoggerProvider;
+import io.opentelemetry.sdk.logs.data.LogRecordData;
+import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor;
+import io.opentelemetry.sdk.metrics.SdkMeterProvider;
+import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
+import io.opentelemetry.sdk.metrics.data.MetricData;
+import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil;
+import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter;
+import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader;
+import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter;
+import io.opentelemetry.sdk.trace.ReadWriteSpan;
+import io.opentelemetry.sdk.trace.ReadableSpan;
+import io.opentelemetry.sdk.trace.SdkTracerProvider;
+import io.opentelemetry.sdk.trace.SpanProcessor;
+import io.opentelemetry.sdk.trace.data.SpanData;
+import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Marker;
+import org.slf4j.MarkerFactory;
+
+/**
+ * Adapted from
+ * 
https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit5/OpenTelemetryExtension.java
+ */
+final class CamelOpenTelemetryExtension implements BeforeEachCallback, 
AfterEachCallback {
+
+    /**
+     * Returns an extension with a default SDK initialized with an in-memory 
span exporter and W3C trace context
+     * propagation.
+     */
+    static CamelOpenTelemetryExtension create() {
+        InMemorySpanExporter spanExporter = InMemorySpanExporter.create();
+        SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
+                //.addSpanProcessor(LeakDetectingSpanProcessor.create())
+                .addSpanProcessor(new LoggingSpanProcessor())
+                .addSpanProcessor(SimpleSpanProcessor.create(spanExporter))
+                .build();
+
+        InMemoryMetricReader metricReader = InMemoryMetricReader.create();
+        SdkMeterProvider meterProvider = 
SdkMeterProvider.builder().registerMetricReader(metricReader).build();
+
+        InMemoryLogRecordExporter logRecordExporter = 
InMemoryLogRecordExporter.create();
+        SdkLoggerProvider loggerProvider = SdkLoggerProvider.builder()
+                
.addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter))
+                .build();
+
+        OpenTelemetrySdk openTelemetry = OpenTelemetrySdk.builder()
+                
.setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
+                .setTracerProvider(tracerProvider)
+                .setMeterProvider(meterProvider)
+                .setLoggerProvider(loggerProvider)
+                .build();
+
+        return new CamelOpenTelemetryExtension(openTelemetry, spanExporter, 
metricReader, logRecordExporter);
+    }
+
+    private final OpenTelemetrySdk openTelemetry;
+    private final InMemorySpanExporter spanExporter;
+    private final InMemoryMetricReader metricReader;
+    private final InMemoryLogRecordExporter logRecordExporter;
+
+    private CamelOpenTelemetryExtension(OpenTelemetrySdk openTelemetry, 
InMemorySpanExporter spanExporter,
+                                        InMemoryMetricReader metricReader, 
InMemoryLogRecordExporter logRecordExporter) {
+        this.openTelemetry = openTelemetry;
+        this.spanExporter = spanExporter;
+        this.metricReader = metricReader;
+        this.logRecordExporter = logRecordExporter;
+    }
+
+    /**
+     * Returns the {@link OpenTelemetrySdk} created by this extension.
+     */
+    public OpenTelemetry getOpenTelemetry() {
+        return openTelemetry;
+    }
+
+    /**
+     * Returns all the exported {@link SpanData} so far.
+     */
+    public List<SpanData> getSpans() {
+        return spanExporter.getFinishedSpanItems();
+    }
+
+    /**
+     * Returns the current {@link MetricData} in {@link 
AggregationTemporality#CUMULATIVE} format.
+     */
+    public List<MetricData> getMetrics() {
+        return new ArrayList<>(metricReader.collectAllMetrics());
+    }
+
+    /**
+     * Returns all the exported {@link LogRecordData} so far.
+     */
+    public List<LogRecordData> getLogRecords() {
+        return new ArrayList<>(logRecordExporter.getFinishedLogRecordItems());
+    }
+
+    /**
+     * Clears the collected exported {@link SpanData}. Consider making your 
test smaller instead of manually clearing
+     * state using this method.
+     */
+    public void clearSpans() {
+        spanExporter.reset();
+    }
+
+    /**
+     * Clears all registered metric instruments, such that {@link 
#getMetrics()} is empty.
+     */
+    public void clearMetrics() {
+        SdkMeterProviderUtil.resetForTest(openTelemetry.getSdkMeterProvider());
+    }
+
+    /**
+     * Clears the collected exported {@link LogRecordData}. Consider making 
your test smaller instead of manually
+     * clearing state using this method.
+     */
+    public void clearLogRecords() {
+        logRecordExporter.reset();
+    }
+
+    @Override
+    public void beforeEach(ExtensionContext context) {
+        GlobalOpenTelemetry.resetForTest();
+        GlobalOpenTelemetry.set(openTelemetry);
+        OpenTelemetryAppender.install(openTelemetry);
+    }
+
+    @Override
+    public void afterEach(ExtensionContext context) {
+        GlobalOpenTelemetry.resetForTest();
+        openTelemetry.close();
+    }
+
+    static class LoggingSpanProcessor implements SpanProcessor {
+        private static final Logger LOG = 
LoggerFactory.getLogger(LoggingSpanProcessor.class);
+        private static final Marker OTEL_MARKER = 
MarkerFactory.getMarker("OTEL");
+
+        @Override
+        public void onStart(Context context, ReadWriteSpan readWriteSpan) {
+            LOG.info(OTEL_MARKER, "Span started: name - '{}', kind - '{}', id 
- '{}-{}", readWriteSpan.getName(),
+                    readWriteSpan.getKind(),
+                    readWriteSpan.getSpanContext().getTraceId(), 
readWriteSpan.getSpanContext().getSpanId());
+        }
+
+        @Override
+        public boolean isStartRequired() {
+            return true;
+        }
+
+        @Override
+        public void onEnd(ReadableSpan readableSpan) {
+            LOG.info(OTEL_MARKER, "Span ended: name - '{}', kind - '{}', id - 
'{}-{}", readableSpan.getName(),
+                    readableSpan.getKind(),
+                    readableSpan.getSpanContext().getTraceId(), 
readableSpan.getSpanContext().getSpanId());
+        }
+
+        @Override
+        public boolean isEndRequired() {
+            return true;
+        }
+    }
+
+    Map<String, OtelTrace> getTraces() {
+        Map<String, OtelTrace> answer = new HashMap<>();
+        for (SpanData span : this.getSpans()) {
+            String traceId = span.getTraceId();
+            OtelTrace trace = answer.get(traceId);
+            if (trace == null) {
+                trace = new OtelTrace(traceId);
+                answer.put(traceId, trace);
+            }
+            trace.addSpan(span);
+        }
+
+        // Sort the spans for all traces
+        answer.forEach((id, trace) -> Collections.sort(trace.getSpans(), new 
SpanComparator()));
+
+        return answer;
+    }
+
+    class OtelTrace {
+        String traceId;
+        List<SpanData> spans;
+
+        OtelTrace(String traceId) {
+            this.traceId = traceId;
+            this.spans = new ArrayList<>();
+        }
+
+        void addSpan(SpanData span) {
+            this.spans.add(span);
+        }
+
+        List<SpanData> getSpans() {
+            return this.spans;
+        }
+
+        @Override
+        public String toString() {
+            return traceId + " " + spans;
+        }
+    }
+
+    class SpanComparator implements java.util.Comparator<SpanData> {
+        @Override
+        public int compare(SpanData a, SpanData b) {
+            Long nanosA = a.getStartEpochNanos();
+            Long nanosB = b.getStartEpochNanos();
+            return (int) (nanosA - nanosB);
+        }
+    }
+}
diff --git 
a/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/DisableEndpointTest.java
 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/DisableEndpointTest.java
new file mode 100644
index 00000000000..a8a805cde43
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/DisableEndpointTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.List;
+import java.util.Map;
+
+import io.opentelemetry.sdk.trace.data.SpanData;
+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.opentelemetry2.CamelOpenTelemetryExtension.OtelTrace;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class DisableEndpointTest extends OpenTelemetryTracerTestSupport {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        OpenTelemetryTracer tst = new OpenTelemetryTracer();
+        tst.setTraceProcessors(true);
+        tst.setExcludePatterns("log*,to*");
+        tst.setTracer(otelExtension.getOpenTelemetry().getTracer("traceTest"));
+        
tst.setContextPropagators(otelExtension.getOpenTelemetry().getPropagators());
+        CamelContext context = super.createCamelContext();
+        CamelContextAware.trySetCamelContext(tst, context);
+        tst.init(context);
+        return context;
+    }
+
+    @Test
+    void testProcessorsTraceRequest() throws IOException {
+        template.sendBody("direct:start", "my-body");
+        Map<String, OtelTrace> traces = otelExtension.getTraces();
+        assertEquals(1, traces.size());
+        checkTrace(traces.values().iterator().next());
+    }
+
+    private void checkTrace(OtelTrace trace) {
+        List<SpanData> spans = trace.getSpans();
+        assertEquals(2, spans.size());
+        SpanData testProducer = spans.get(0);
+        SpanData direct = spans.get(1);
+
+        // Validate span completion
+        assertTrue(testProducer.hasEnded());
+        assertTrue(direct.hasEnded());
+
+        // Validate same trace
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
direct.getSpanContext().getTraceId());
+
+        // Validate hierarchy
+        assertFalse(testProducer.getParentSpanContext().isValid());
+        assertEquals(testProducer.getSpanContext().getSpanId(), 
direct.getParentSpanContext().getSpanId());
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start")
+                        .routeId("start")
+                        .log("A message")
+                        .to("log:info");
+            }
+        };
+    }
+
+}
diff --git 
a/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/EnableProcessorsTest.java
 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/EnableProcessorsTest.java
new file mode 100644
index 00000000000..76f4abe6868
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/EnableProcessorsTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.List;
+import java.util.Map;
+
+import io.opentelemetry.api.common.AttributeKey;
+import io.opentelemetry.sdk.trace.data.SpanData;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.opentelemetry2.CamelOpenTelemetryExtension.OtelTrace;
+import org.apache.camel.telemetry.Op;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class EnableProcessorsTest extends OpenTelemetryTracerTestSupport {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        OpenTelemetryTracer tst = new OpenTelemetryTracer();
+        tst.setTraceProcessors(true);
+        tst.setTracer(otelExtension.getOpenTelemetry().getTracer("traceTest"));
+        
tst.setContextPropagators(otelExtension.getOpenTelemetry().getPropagators());
+        CamelContext context = super.createCamelContext();
+        CamelContextAware.trySetCamelContext(tst, context);
+        tst.init(context);
+        return context;
+    }
+
+    @Test
+    void testProcessorsTraceRequest() throws IOException {
+        template.sendBody("direct:start", "my-body");
+        Map<String, OtelTrace> traces = otelExtension.getTraces();
+        assertEquals(1, traces.size());
+        checkTrace(traces.values().iterator().next());
+    }
+
+    private void checkTrace(OtelTrace trace) {
+        List<SpanData> spans = trace.getSpans();
+        assertEquals(6, spans.size());
+        SpanData testProducer = spans.get(0);
+        SpanData direct = spans.get(1);
+        SpanData innerLog = spans.get(2);
+        SpanData innerProcessor = spans.get(3);
+        SpanData log = spans.get(4);
+        SpanData innerToLog = spans.get(5);
+
+        // Validate span completion
+        assertTrue(testProducer.hasEnded());
+        assertTrue(direct.hasEnded());
+        assertTrue(innerLog.hasEnded());
+        assertTrue(innerProcessor.hasEnded());
+        assertTrue(log.hasEnded());
+        assertTrue(innerToLog.hasEnded());
+
+        // Validate same trace
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
direct.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
innerLog.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
innerProcessor.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
log.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
innerToLog.getSpanContext().getTraceId());
+
+        // Validate operations
+        assertEquals(Op.EVENT_RECEIVED.toString(), 
direct.getAttributes().get(AttributeKey.stringKey("op")));
+        assertEquals(Op.EVENT_PROCESS.toString(), 
innerProcessor.getAttributes().get(AttributeKey.stringKey("op")));
+
+        // Validate hierarchy
+        assertFalse(testProducer.getParentSpanContext().isValid());
+        assertEquals(testProducer.getSpanContext().getSpanId(), 
direct.getParentSpanContext().getSpanId());
+        assertEquals(direct.getSpanContext().getSpanId(), 
innerLog.getParentSpanContext().getSpanId());
+        assertEquals(direct.getSpanContext().getSpanId(), 
innerProcessor.getParentSpanContext().getSpanId());
+        assertEquals(direct.getSpanContext().getSpanId(), 
log.getParentSpanContext().getSpanId());
+        assertEquals(log.getSpanContext().getSpanId(), 
innerToLog.getParentSpanContext().getSpanId());
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start")
+                        .routeId("start")
+                        .log("A message")
+                        .process(new Processor() {
+                            @Override
+                            public void process(Exchange exchange) throws 
Exception {
+                                exchange.getIn().setHeader("operation", 
"fake");
+                            }
+                        })
+                        .to("log:info");
+            }
+        };
+    }
+
+}
diff --git 
a/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/OpenTelemetryTracerTest.java
 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/OpenTelemetryTracerTest.java
new file mode 100644
index 00000000000..3b4118656f6
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/OpenTelemetryTracerTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.List;
+import java.util.Map;
+
+import io.opentelemetry.api.common.AttributeKey;
+import io.opentelemetry.sdk.trace.data.SpanData;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.Exchange;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.opentelemetry2.CamelOpenTelemetryExtension.OtelTrace;
+import org.apache.camel.telemetry.Op;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class OpenTelemetryTracerTest extends OpenTelemetryTracerTestSupport {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        OpenTelemetryTracer tst = new OpenTelemetryTracer();
+        tst.setTracer(otelExtension.getOpenTelemetry().getTracer("traceTest"));
+        
tst.setContextPropagators(otelExtension.getOpenTelemetry().getPropagators());
+        CamelContext context = super.createCamelContext();
+        CamelContextAware.trySetCamelContext(tst, context);
+        tst.init(context);
+        return context;
+    }
+
+    @Test
+    void testRouteSingleRequest() throws IOException {
+        Exchange result = template.request("direct:start", null);
+        // Make sure the trace is propagated downstream
+        assertNotNull(result.getIn().getHeader("traceparent"));
+        Map<String, OtelTrace> traces = otelExtension.getTraces();
+        assertEquals(1, traces.size());
+        checkTrace(traces.values().iterator().next(), null);
+    }
+
+    @Test
+    void testRouteMultipleRequests() throws IOException {
+        for (int i = 1; i <= 10; i++) {
+            context.createProducerTemplate().sendBody("direct:start", 
"Hello!");
+        }
+        Map<String, OtelTrace> traces = otelExtension.getTraces();
+        // Each trace should have a unique trace id. It is enough to assert 
that
+        // the number of elements in the map is the same of the requests to 
prove
+        // all traces have been generated uniquely.
+        assertEquals(10, traces.size());
+        // Each trace should have the same structure
+        for (OtelTrace trace : traces.values()) {
+            checkTrace(trace, "Hello!");
+        }
+
+    }
+
+    private void checkTrace(OtelTrace trace, String expectedBody) {
+        List<SpanData> spans = trace.getSpans();
+        assertEquals(3, spans.size());
+        SpanData testProducer = spans.get(0);
+        SpanData direct = spans.get(1);
+        SpanData log = spans.get(2);
+
+        // Validate span completion
+        assertTrue(testProducer.hasEnded());
+        assertTrue(direct.hasEnded());
+        assertTrue(log.hasEnded());
+
+        // Validate same trace
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
direct.getSpanContext().getTraceId());
+        assertEquals(direct.getSpanContext().getTraceId(), 
log.getSpanContext().getTraceId());
+
+        // Validate hierarchy
+        assertFalse(testProducer.getParentSpanContext().isValid());
+        assertEquals(testProducer.getSpanContext().getSpanId(), 
direct.getParentSpanContext().getSpanId());
+        assertEquals(direct.getSpanContext().getSpanId(), 
log.getParentSpanContext().getSpanId());
+
+        // Validate operations
+        assertEquals(Op.EVENT_SENT.toString(), 
testProducer.getAttributes().get(AttributeKey.stringKey("op")));
+        assertEquals(Op.EVENT_RECEIVED.toString(), 
direct.getAttributes().get(AttributeKey.stringKey("op")));
+
+        // Validate message logging
+        assertEquals("A message", 
direct.getEvents().get(0).getAttributes().get(AttributeKey.stringKey("message")));
+        if (expectedBody == null) {
+            assertEquals(
+                    "Exchange[ExchangePattern: InOut, BodyType: null, Body: 
[Body is null]]",
+                    
log.getEvents().get(0).getAttributes().get(AttributeKey.stringKey("message")));
+        } else {
+            assertEquals(
+                    "Exchange[ExchangePattern: InOnly, BodyType: String, Body: 
" + expectedBody + "]",
+                    
log.getEvents().get(0).getAttributes().get(AttributeKey.stringKey("message")));
+        }
+
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start")
+                        .routeId("start")
+                        .log("A message")
+                        .to("log:info");
+            }
+        };
+    }
+
+}
diff --git 
a/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/OpenTelemetryTracerTestSupport.java
 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/OpenTelemetryTracerTestSupport.java
new file mode 100644
index 00000000000..416cedb5999
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/OpenTelemetryTracerTestSupport.java
@@ -0,0 +1,44 @@
+/*
+ * 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.util.List;
+
+import io.opentelemetry.api.common.AttributeKey;
+import io.opentelemetry.sdk.trace.data.SpanData;
+import org.apache.camel.telemetry.Op;
+import org.apache.camel.telemetry.TagConstants;
+import org.apache.camel.test.junit5.ExchangeTestSupport;
+
+public class OpenTelemetryTracerTestSupport extends ExchangeTestSupport {
+
+    protected CamelOpenTelemetryExtension otelExtension = 
CamelOpenTelemetryExtension.create();
+
+    protected static SpanData getSpan(List<SpanData> trace, String uri, Op op) 
{
+        for (SpanData span : trace) {
+            String camelURI = 
span.getAttributes().get(AttributeKey.stringKey("camel.uri"));
+            if (camelURI != null && camelURI.equals(uri)) {
+                String operation = 
span.getAttributes().get(AttributeKey.stringKey(TagConstants.OP));
+                if (operation != null && operation.equals(op.toString())) {
+                    return span;
+                }
+            }
+        }
+        throw new IllegalArgumentException("Trying to get a non existing 
span!");
+    }
+
+}
diff --git 
a/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/SpanPropagationTest.java
 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/SpanPropagationTest.java
new file mode 100644
index 00000000000..8e45472bf65
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/test/java/org/apache/camel/opentelemetry2/SpanPropagationTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.List;
+import java.util.Map;
+
+import io.opentelemetry.sdk.trace.data.SpanData;
+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.opentelemetry2.CamelOpenTelemetryExtension.OtelTrace;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class SpanPropagationTest extends OpenTelemetryTracerTestSupport {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        OpenTelemetryTracer tst = new OpenTelemetryTracer();
+        tst.setTracer(otelExtension.getOpenTelemetry().getTracer("traceTest"));
+        
tst.setContextPropagators(otelExtension.getOpenTelemetry().getPropagators());
+        CamelContext context = super.createCamelContext();
+        CamelContextAware.trySetCamelContext(tst, context);
+        tst.init(context);
+        return context;
+    }
+
+    @Test
+    void testPropagateUpstreamTraceRequest() throws IOException {
+        template.requestBodyAndHeader("direct:start", "sample body",
+                "traceparent", 
"00-0af044aea5c127fd5ab5f839de2b8ae2-d362a8a943c2b289-01");
+        Map<String, OtelTrace> traces = otelExtension.getTraces();
+        assertEquals(1, traces.size());
+        checkTrace(traces.values().iterator().next());
+    }
+
+    private void checkTrace(OtelTrace trace) {
+        List<SpanData> spans = trace.getSpans();
+        assertEquals(3, spans.size());
+        SpanData testProducer = spans.get(0);
+        SpanData direct = spans.get(1);
+        SpanData log = spans.get(2);
+
+        // Validate span completion
+        assertTrue(testProducer.hasEnded());
+        assertTrue(direct.hasEnded());
+        assertTrue(log.hasEnded());
+
+        // Validate same trace
+        assertEquals("0af044aea5c127fd5ab5f839de2b8ae2", 
testProducer.getSpanContext().getTraceId());
+        assertEquals(testProducer.getSpanContext().getTraceId(), 
direct.getSpanContext().getTraceId());
+        assertEquals(direct.getSpanContext().getTraceId(), 
log.getSpanContext().getTraceId());
+
+        // Validate hierarchy
+        assertEquals("d362a8a943c2b289", 
testProducer.getParentSpanContext().getSpanId());
+        assertEquals(testProducer.getSpanContext().getSpanId(), 
direct.getParentSpanContext().getSpanId());
+        assertEquals(direct.getSpanContext().getSpanId(), 
log.getParentSpanContext().getSpanId());
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start")
+                        .routeId("start")
+                        .log("A message")
+                        .to("log:info");
+            }
+        };
+    }
+
+}
diff --git 
a/components/camel-opentelemetry2/src/test/resources/log4j2.properties 
b/components/camel-opentelemetry2/src/test/resources/log4j2.properties
new file mode 100644
index 00000000000..c75cd8e27dd
--- /dev/null
+++ b/components/camel-opentelemetry2/src/test/resources/log4j2.properties
@@ -0,0 +1,45 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+appender.file.type=File
+appender.file.name=file
+appender.file.fileName=target/camel-opentelemetry-test.log
+appender.file.layout.type=PatternLayout
+appender.file.layout.pattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+appender.out.type=Console
+appender.out.name=out
+appender.out.layout.type=PatternLayout
+appender.out.layout.pattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+# The CamelOpenTelemetryExtension relies on logs with the marker "OTEL" to 
identify which logs were actually sent
+# to trace.
+# If the rootLogger level is changed, the logging calls on 
`CamelOpenTelemetryExtension.LoggingSpanProcessor`
+# may need to be adjusted.
+appender.opentelemetry.type=OpenTelemetry
+appender.opentelemetry.name=opentelemetry
+appender.opentelemetry.filter.marker.type=MarkerFilter
+appender.opentelemetry.filter.marker.onMatch=ACCEPT
+appender.opentelemetry.filter.marker.onMismatch=DENY
+appender.opentelemetry.filter.marker.marker=OTEL
+appender.opentelemetry.layout.type=PatternLayout
+appender.opentelemetry.layout.pattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+rootLogger.level=INFO
+rootLogger.appenderRefs=file,out,opentelemetry
+rootLogger.appenderRef.file.ref=file
+#rootLogger.appenderRef.out.ref=out
+rootLogger.appenderRef.opentelemetry.ref=opentelemetry
diff --git a/components/pom.xml b/components/pom.xml
index cd617f5b62a..ad1a2ec9954 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -235,6 +235,7 @@
         <module>camel-olingo4</module>
         <module>camel-openstack</module>
         <module>camel-opentelemetry</module>
+        <module>camel-opentelemetry2</module>
         <module>camel-paho</module>
         <module>camel-paho-mqtt5</module>
         <module>camel-parquet-avro</module>
diff --git 
a/core/camel-main/src/generated/java/org/apache/camel/main/Otel2ConfigurationPropertiesConfigurer.java
 
b/core/camel-main/src/generated/java/org/apache/camel/main/Otel2ConfigurationPropertiesConfigurer.java
new file mode 100644
index 00000000000..4fd58303ebc
--- /dev/null
+++ 
b/core/camel-main/src/generated/java/org/apache/camel/main/Otel2ConfigurationPropertiesConfigurer.java
@@ -0,0 +1,85 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.main;
+
+import javax.annotation.processing.Generated;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.spi.ConfigurerStrategy;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.main.Otel2ConfigurationProperties;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.GenerateConfigurerMojo")
+@SuppressWarnings("unchecked")
+public class Otel2ConfigurationPropertiesConfigurer extends 
org.apache.camel.support.component.PropertyConfigurerSupport implements 
GeneratedPropertyConfigurer, ExtendedPropertyConfigurerGetter {
+
+    private static final Map<String, Object> ALL_OPTIONS;
+    static {
+        Map<String, Object> map = new CaseInsensitiveMap();
+        map.put("Enabled", boolean.class);
+        map.put("Encoding", boolean.class);
+        map.put("ExcludePatterns", java.lang.String.class);
+        map.put("InstrumentationName", java.lang.String.class);
+        map.put("TraceProcessors", boolean.class);
+        ALL_OPTIONS = map;
+    }
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String 
name, Object value, boolean ignoreCase) {
+        org.apache.camel.main.Otel2ConfigurationProperties target = 
(org.apache.camel.main.Otel2ConfigurationProperties) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "enabled": target.setEnabled(property(camelContext, 
boolean.class, value)); return true;
+        case "encoding": target.setEncoding(property(camelContext, 
boolean.class, value)); return true;
+        case "excludepatterns":
+        case "excludePatterns": 
target.setExcludePatterns(property(camelContext, java.lang.String.class, 
value)); return true;
+        case "instrumentationname":
+        case "instrumentationName": 
target.setInstrumentationName(property(camelContext, java.lang.String.class, 
value)); return true;
+        case "traceprocessors":
+        case "traceProcessors": 
target.setTraceProcessors(property(camelContext, boolean.class, value)); return 
true;
+        default: return false;
+        }
+    }
+
+    @Override
+    public Map<String, Object> getAllOptions(Object target) {
+        return ALL_OPTIONS;
+    }
+
+    @Override
+    public Class<?> getOptionType(String name, boolean ignoreCase) {
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "enabled": return boolean.class;
+        case "encoding": return boolean.class;
+        case "excludepatterns":
+        case "excludePatterns": return java.lang.String.class;
+        case "instrumentationname":
+        case "instrumentationName": return java.lang.String.class;
+        case "traceprocessors":
+        case "traceProcessors": return boolean.class;
+        default: return null;
+        }
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        org.apache.camel.main.Otel2ConfigurationProperties target = 
(org.apache.camel.main.Otel2ConfigurationProperties) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "enabled": return target.isEnabled();
+        case "encoding": return target.isEncoding();
+        case "excludepatterns":
+        case "excludePatterns": return target.getExcludePatterns();
+        case "instrumentationname":
+        case "instrumentationName": return target.getInstrumentationName();
+        case "traceprocessors":
+        case "traceProcessors": return target.isTraceProcessors();
+        default: return null;
+        }
+    }
+}
+
diff --git 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
index 0c820eb09e6..626329f7b43 100644
--- 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
+++ 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
@@ -17,6 +17,7 @@
     { "name": "camel.vault.kubernetescm", "description": "Camel Kubernetes 
Configmaps Vault configurations", "sourceType": 
"org.apache.camel.vault.KubernetesConfigMapVaultConfiguration" },
     { "name": "camel.vault.hashicorp", "description": "Camel Hashicorp Vault 
configurations", "sourceType": 
"org.apache.camel.vault.HashicorpVaultConfiguration" },
     { "name": "camel.opentelemetry", "description": "Camel OpenTelemetry 
configurations", "sourceType": 
"org.apache.camel.main.OtelConfigurationProperties" },
+    { "name": "camel.opentelemetry2", "description": "Camel OpenTelemetry 2 
configurations", "sourceType": 
"org.apache.camel.main.Otel2ConfigurationProperties" },
     { "name": "camel.telemetryDev", "description": "Camel Telemetry Dev 
configurations", "sourceType": 
"org.apache.camel.main.TelemetryDevConfigurationProperties" },
     { "name": "camel.metrics", "description": "Camel Micrometer Metrics 
configurations", "sourceType": 
"org.apache.camel.main.MetricsConfigurationProperties" },
     { "name": "camel.faulttolerance", "description": "Fault Tolerance EIP 
Circuit Breaker configurations", "sourceType": 
"org.apache.camel.main.FaultToleranceConfigurationProperties" },
@@ -205,6 +206,11 @@
     { "name": "camel.opentelemetry.excludePatterns", "description": "Adds an 
exclude pattern that will disable tracing for Camel messages that matches the 
pattern. Multiple patterns can be separated by comma.", "sourceType": 
"org.apache.camel.main.OtelConfigurationProperties", "type": "string", 
"javaType": "java.lang.String" },
     { "name": "camel.opentelemetry.instrumentationName", "description": "A 
name uniquely identifying the instrumentation scope, such as the 
instrumentation library, package, or fully qualified class name. Must not be 
null.", "sourceType": "org.apache.camel.main.OtelConfigurationProperties", 
"type": "string", "javaType": "java.lang.String", "defaultValue": "camel" },
     { "name": "camel.opentelemetry.traceProcessors", "description": "Setting 
this to true will create new OpenTelemetry Spans for each Camel Processors. Use 
the excludePattern property to filter out Processors.", "sourceType": 
"org.apache.camel.main.OtelConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
+    { "name": "camel.opentelemetry2.enabled", "description": "To enable 
OpenTelemetry 2", "sourceType": 
"org.apache.camel.main.Otel2ConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
+    { "name": "camel.opentelemetry2.encoding", "description": "Sets whether 
the header keys need to be encoded (connector specific) or not. The value is a 
boolean. Dashes need for instances to be encoded for JMS property keys.", 
"sourceType": "org.apache.camel.main.Otel2ConfigurationProperties", "type": 
"boolean", "javaType": "boolean", "defaultValue": "false" },
+    { "name": "camel.opentelemetry2.excludePatterns", "description": "Adds an 
exclude pattern that will disable tracing for Camel messages that matches the 
pattern. Multiple patterns can be separated by comma.", "sourceType": 
"org.apache.camel.main.Otel2ConfigurationProperties", "type": "string", 
"javaType": "java.lang.String" },
+    { "name": "camel.opentelemetry2.instrumentationName", "description": "A 
name uniquely identifying the instrumentation scope, such as the 
instrumentation library, package, or fully qualified class name. Must not be 
null.", "sourceType": "org.apache.camel.main.Otel2ConfigurationProperties", 
"type": "string", "javaType": "java.lang.String", "defaultValue": "camel" },
+    { "name": "camel.opentelemetry2.traceProcessors", "description": "Setting 
this to true will create new OpenTelemetry Spans for each Camel Processors. Use 
the excludePattern property to filter out Processors.", "sourceType": 
"org.apache.camel.main.Otel2ConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false" },
     { "name": 
"camel.resilience4j.automaticTransitionFromOpenToHalfOpenEnabled", 
"description": "Enables automatic transition from OPEN to HALF_OPEN state once 
the waitDurationInOpenState has passed.", "sourceType": 
"org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", 
"javaType": "java.lang.Boolean", "defaultValue": "false" },
     { "name": "camel.resilience4j.bulkheadEnabled", "description": "Whether 
bulkhead is enabled or not on the circuit breaker.", "sourceType": 
"org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", 
"javaType": "java.lang.Boolean", "defaultValue": false },
     { "name": "camel.resilience4j.bulkheadMaxConcurrentCalls", "description": 
"Configures the max amount of concurrent calls the bulkhead will support.", 
"sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", 
"type": "integer", "javaType": "java.lang.Integer" },
diff --git 
a/core/camel-main/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.main.Otel2ConfigurationProperties
 
b/core/camel-main/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.main.Otel2ConfigurationProperties
new file mode 100644
index 00000000000..1081406fa21
--- /dev/null
+++ 
b/core/camel-main/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.main.Otel2ConfigurationProperties
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.main.Otel2ConfigurationPropertiesConfigurer
diff --git a/core/camel-main/src/main/docs/main.adoc 
b/core/camel-main/src/main/docs/main.adoc
index 6f8138ba3cb..e41711d5f19 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -468,7 +468,7 @@ The camel.vault.hashicorp supports 6 options, which are 
listed below.
 
 
 === Camel OpenTelemetry configurations
-The camel.opentelemetry supports 5 options, which are listed below.
+The camel.opentelemetry supports 10 options, which are listed below.
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
@@ -478,6 +478,25 @@ The camel.opentelemetry supports 5 options, which are 
listed below.
 | *camel.opentelemetry.exclude{zwsp}Patterns* | Adds an exclude pattern that 
will disable tracing for Camel messages that matches the pattern. Multiple 
patterns can be separated by comma. |  | String
 | *camel.opentelemetry.instrumentation{zwsp}Name* | A name uniquely 
identifying the instrumentation scope, such as the instrumentation library, 
package, or fully qualified class name. Must not be null. | camel | String
 | *camel.opentelemetry.trace{zwsp}Processors* | Setting this to true will 
create new OpenTelemetry Spans for each Camel Processors. Use the 
excludePattern property to filter out Processors. | false | boolean
+| *camel.opentelemetry2.enabled* | To enable OpenTelemetry 2 | false | boolean
+| *camel.opentelemetry2.encoding* | Sets whether the header keys need to be 
encoded (connector specific) or not. The value is a boolean. Dashes need for 
instances to be encoded for JMS property keys. | false | boolean
+| *camel.opentelemetry2.exclude{zwsp}Patterns* | Adds an exclude pattern that 
will disable tracing for Camel messages that matches the pattern. Multiple 
patterns can be separated by comma. |  | String
+| *camel.opentelemetry2.instrumentation{zwsp}Name* | A name uniquely 
identifying the instrumentation scope, such as the instrumentation library, 
package, or fully qualified class name. Must not be null. | camel | String
+| *camel.opentelemetry2.trace{zwsp}Processors* | Setting this to true will 
create new OpenTelemetry Spans for each Camel Processors. Use the 
excludePattern property to filter out Processors. | false | boolean
+|===
+
+
+=== Camel OpenTelemetry 2 configurations
+The camel.opentelemetry2 supports 5 options, which are listed below.
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *camel.opentelemetry2.enabled* | To enable OpenTelemetry 2 | false | boolean
+| *camel.opentelemetry2.encoding* | Sets whether the header keys need to be 
encoded (connector specific) or not. The value is a boolean. Dashes need for 
instances to be encoded for JMS property keys. | false | boolean
+| *camel.opentelemetry2.exclude{zwsp}Patterns* | Adds an exclude pattern that 
will disable tracing for Camel messages that matches the pattern. Multiple 
patterns can be separated by comma. |  | String
+| *camel.opentelemetry2.instrumentation{zwsp}Name* | A name uniquely 
identifying the instrumentation scope, such as the instrumentation library, 
package, or fully qualified class name. Must not be null. | camel | String
+| *camel.opentelemetry2.trace{zwsp}Processors* | Setting this to true will 
create new OpenTelemetry Spans for each Camel Processors. Use the 
excludePattern property to filter out Processors. | false | boolean
 |===
 
 
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java 
b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index c409ca4f2cc..31580cf06fa 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -135,7 +135,8 @@ public abstract class BaseMainSupport extends BaseService {
     private static final String[] GROUP_PREFIXES = new String[] {
             "camel.context.", "camel.resilience4j.", "camel.faulttolerance.",
             "camel.rest.", "camel.vault.", "camel.threadpool.", 
"camel.health.",
-            "camel.lra.", "camel.opentelemetry.", "camel.telemetryDev.", 
"camel.metrics.", "camel.routeTemplate",
+            "camel.lra.", "camel.opentelemetry2.", "camel.opentelemetry.",
+            "camel.telemetryDev.", "camel.metrics.", "camel.routeTemplate",
             "camel.devConsole.", "camel.variable.", "camel.beans.", 
"camel.globalOptions.",
             "camel.server.", "camel.ssl.", "camel.debug.", "camel.trace.", 
"camel.routeController." };
 
@@ -1244,6 +1245,7 @@ public abstract class BaseMainSupport extends BaseService 
{
         OrderedLocationProperties healthProperties = new 
OrderedLocationProperties();
         OrderedLocationProperties lraProperties = new 
OrderedLocationProperties();
         OrderedLocationProperties otelProperties = new 
OrderedLocationProperties();
+        OrderedLocationProperties otel2Properties = new 
OrderedLocationProperties();
         OrderedLocationProperties telemetryDevProperties = new 
OrderedLocationProperties();
         OrderedLocationProperties metricsProperties = new 
OrderedLocationProperties();
         OrderedLocationProperties routeTemplateProperties = new 
OrderedLocationProperties();
@@ -1301,6 +1303,12 @@ public abstract class BaseMainSupport extends 
BaseService {
                 String option = key.substring(10);
                 validateOptionAndValue(key, option, value);
                 lraProperties.put(loc, optionKey(option), value);
+            } else if (startsWithIgnoreCase(key, "camel.opentelemetry2.")) {
+                // grab the value
+                String value = prop.getProperty(key);
+                String option = key.substring(21);
+                validateOptionAndValue(key, option, value);
+                otel2Properties.put(loc, optionKey(option), value);
             } else if (startsWithIgnoreCase(key, "camel.opentelemetry.")) {
                 // grab the value
                 String value = prop.getProperty(key);
@@ -1448,6 +1456,10 @@ public abstract class BaseMainSupport extends 
BaseService {
             LOG.debug("Auto-configuring OpenTelemetry from loaded properties: 
{}", otelProperties.size());
             setOtelProperties(camelContext, otelProperties, 
mainConfigurationProperties.isAutoConfigurationFailFast(),
                     autoConfiguredProperties);
+        } else if (!otel2Properties.isEmpty() || 
mainConfigurationProperties.hasOtel2Configuration()) {
+            LOG.debug("Auto-configuring OpenTelemetry 2 from loaded 
properties: {}", otel2Properties.size());
+            setOtel2Properties(camelContext, otel2Properties, 
mainConfigurationProperties.isAutoConfigurationFailFast(),
+                    autoConfiguredProperties);
         } else {
             // Attempt to fallback to Telemetry simple only if no other 
tracing service is found
             if (!telemetryDevProperties.isEmpty() || 
mainConfigurationProperties.hasTelemetryDevConfiguration()) {
@@ -1573,6 +1585,11 @@ public abstract class BaseMainSupport extends 
BaseService {
                 LOG.warn("Property not auto-configured: 
camel.opentelemetry.{}={}", k, v);
             });
         }
+        if (!otel2Properties.isEmpty()) {
+            otel2Properties.forEach((k, v) -> {
+                LOG.warn("Property not auto-configured: 
camel.opentelemetry2.{}={}", k, v);
+            });
+        }
         if (!telemetryDevProperties.isEmpty()) {
             telemetryDevProperties.forEach((k, v) -> {
                 LOG.warn("Property not auto-configured: 
camel.telemetryDev.{}={}", k, v);
@@ -1756,6 +1773,28 @@ public abstract class BaseMainSupport extends 
BaseService {
         }
     }
 
+    private void setOtel2Properties(
+            CamelContext camelContext, OrderedLocationProperties 
otel2Properties,
+            boolean failIfNotSet, OrderedLocationProperties 
autoConfiguredProperties)
+            throws Exception {
+
+        String loc = otel2Properties.getLocation("enabled");
+        Object obj = otel2Properties.remove("enabled");
+        if (ObjectHelper.isNotEmpty(obj)) {
+            autoConfiguredProperties.put(loc, "camel.opentelemetry2.enabled", 
obj.toString());
+        }
+        boolean enabled = obj != null ? 
CamelContextHelper.parseBoolean(camelContext, obj.toString()) : true;
+        if (enabled) {
+            CamelTracingService otel = resolveOtel2Service(camelContext);
+            setPropertiesOnTarget(camelContext, otel, otel2Properties, 
"camel.opentelemetry2.", failIfNotSet, true,
+                    autoConfiguredProperties);
+            if (camelContext.hasService(CamelTracingService.class) == null) {
+                // add as service so tracing can be active
+                camelContext.addService(otel, true, true);
+            }
+        }
+    }
+
     private void setTelemetryDevProperties(
             CamelContext camelContext, OrderedLocationProperties 
telemetryDevProperties,
             boolean failIfNotSet, OrderedLocationProperties 
autoConfiguredProperties)
@@ -2623,6 +2662,20 @@ public abstract class BaseMainSupport extends 
BaseService {
         return answer;
     }
 
+    private static CamelTracingService resolveOtel2Service(CamelContext 
camelContext) throws Exception {
+        CamelTracingService answer = 
camelContext.hasService(CamelTracingService.class);
+        if (answer == null) {
+            answer = 
camelContext.getRegistry().findSingleByType(CamelTracingService.class);
+        }
+        if (answer == null) {
+            answer = 
camelContext.getCamelContextExtension().getBootstrapFactoryFinder()
+                    .newInstance("opentelemetry-tracer-2", 
CamelTracingService.class)
+                    .orElseThrow(() -> new IllegalArgumentException(
+                            "Cannot find OpenTelemetryTracer2 on classpath. 
Add camel-opentelemetry-2 to classpath."));
+        }
+        return answer;
+    }
+
     private static CamelTracingService resolveTelemetryDevService(CamelContext 
camelContext) throws Exception {
         CamelTracingService answer = 
camelContext.hasService(CamelTracingService.class);
         if (answer == null) {
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
 
b/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
index a83912e9060..29de01e0fc2 100644
--- 
a/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
@@ -60,6 +60,7 @@ public class MainConfigurationProperties extends 
DefaultConfigurationProperties<
     private StartupConditionConfigurationProperties 
startupConditionConfigurationProperties;
     private LraConfigurationProperties lraConfigurationProperties;
     private OtelConfigurationProperties otelConfigurationProperties;
+    private Otel2ConfigurationProperties otel2ConfigurationProperties;
     private TelemetryDevConfigurationProperties 
telemetryDevConfigurationProperties;
     private MetricsConfigurationProperties metricsConfigurationProperties;
     private ThreadPoolConfigurationProperties threadPoolProperties;
@@ -87,6 +88,14 @@ public class MainConfigurationProperties extends 
DefaultConfigurationProperties<
             otelConfigurationProperties.close();
             otelConfigurationProperties = null;
         }
+        if (otel2ConfigurationProperties != null) {
+            otel2ConfigurationProperties.close();
+            otel2ConfigurationProperties = null;
+        }
+        if (telemetryDevConfigurationProperties != null) {
+            telemetryDevConfigurationProperties.close();
+            telemetryDevConfigurationProperties = null;
+        }
         if (metricsConfigurationProperties != null) {
             metricsConfigurationProperties.close();
             metricsConfigurationProperties = null;
@@ -209,6 +218,13 @@ public class MainConfigurationProperties extends 
DefaultConfigurationProperties<
         return otelConfigurationProperties != null;
     }
 
+    /**
+     * Whether there has been any OpenTelemetry configuration specified
+     */
+    public boolean hasOtel2Configuration() {
+        return otel2ConfigurationProperties != null;
+    }
+
     /**
      * Whether there has been any TelemetryDev configuration specified
      */
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/Otel2ConfigurationProperties.java
 
b/core/camel-main/src/main/java/org/apache/camel/main/Otel2ConfigurationProperties.java
new file mode 100644
index 00000000000..248051521af
--- /dev/null
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/Otel2ConfigurationProperties.java
@@ -0,0 +1,154 @@
+/*
+ * 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.main;
+
+import org.apache.camel.spi.BootstrapCloseable;
+import org.apache.camel.spi.Configurer;
+import org.apache.camel.spi.Metadata;
+
+/**
+ * Global configuration for OpenTelemetry 2 (based on camel-telemetry)
+ */
+@Configurer(extended = true)
+public class Otel2ConfigurationProperties implements BootstrapCloseable {
+
+    private MainConfigurationProperties parent;
+
+    private boolean enabled;
+    @Metadata(defaultValue = "camel", required = true)
+    private String instrumentationName = "camel";
+    private boolean encoding;
+    private String excludePatterns;
+    private boolean traceProcessors;
+
+    public Otel2ConfigurationProperties(MainConfigurationProperties parent) {
+        this.parent = parent;
+    }
+
+    public MainConfigurationProperties end() {
+        return parent;
+    }
+
+    @Override
+    public void close() {
+        parent = null;
+    }
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    /**
+     * To enable OpenTelemetry 2
+     */
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    public String getInstrumentationName() {
+        return instrumentationName;
+    }
+
+    /**
+     * A name uniquely identifying the instrumentation scope, such as the 
instrumentation library, package, or fully
+     * qualified class name. Must not be null.
+     */
+    public void setInstrumentationName(String instrumentationName) {
+        this.instrumentationName = instrumentationName;
+    }
+
+    public boolean isEncoding() {
+        return encoding;
+    }
+
+    /**
+     * Sets whether the header keys need to be encoded (connector specific) or 
not. The value is a boolean. Dashes need
+     * for instances to be encoded for JMS property keys.
+     */
+    public void setEncoding(boolean encoding) {
+        this.encoding = encoding;
+    }
+
+    public String getExcludePatterns() {
+        return excludePatterns;
+    }
+
+    /**
+     * Adds an exclude pattern that will disable tracing for Camel messages 
that matches the pattern. Multiple patterns
+     * can be separated by comma.
+     */
+    public void setExcludePatterns(String excludePatterns) {
+        this.excludePatterns = excludePatterns;
+    }
+
+    public boolean isTraceProcessors() {
+        return traceProcessors;
+    }
+
+    /**
+     * Setting this to true will create new OpenTelemetry Spans for each Camel 
Processors. Use the excludePattern
+     * property to filter out Processors.
+     */
+    public void setTraceProcessors(boolean traceProcessors) {
+        this.traceProcessors = traceProcessors;
+    }
+
+    /**
+     * A name uniquely identifying the instrumentation scope, such as the 
instrumentation library, package, or fully
+     * qualified class name. Must not be null.
+     */
+    public Otel2ConfigurationProperties withInstrumentationName(String 
instrumentationName) {
+        this.instrumentationName = instrumentationName;
+        return this;
+    }
+
+    /**
+     * To enable OpenTelemetry
+     */
+    public Otel2ConfigurationProperties withEnabled(boolean enabled) {
+        this.enabled = enabled;
+        return this;
+    }
+
+    /**
+     * Sets whether the header keys need to be encoded (connector specific) or 
not. The value is a boolean. Dashes need
+     * for instances to be encoded for JMS property keys.
+     */
+    public Otel2ConfigurationProperties withEncoding(boolean encoding) {
+        this.encoding = encoding;
+        return this;
+    }
+
+    /**
+     * Adds an exclude pattern that will disable tracing for Camel messages 
that matches the pattern. Multiple patterns
+     * can be separated by comma.
+     */
+    public Otel2ConfigurationProperties withExcludePatterns(String 
excludePatterns) {
+        this.excludePatterns = excludePatterns;
+        return this;
+    }
+
+    /**
+     * Setting this to true will create new OpenTelemetry Spans for each Camel 
Processors. Use the excludePattern
+     * property to filter out Processors.
+     */
+    public Otel2ConfigurationProperties withTraceProcessors(boolean 
traceProcessors) {
+        this.traceProcessors = traceProcessors;
+        return this;
+    }
+
+}
diff --git a/docs/components/modules/others/examples/json/opentelemetry2.json 
b/docs/components/modules/others/examples/json/opentelemetry2.json
new file mode 120000
index 00000000000..f10f410b35c
--- /dev/null
+++ b/docs/components/modules/others/examples/json/opentelemetry2.json
@@ -0,0 +1 @@
+../../../../../../components/camel-opentelemetry2/src/generated/resources/opentelemetry2.json
\ No newline at end of file
diff --git a/docs/components/modules/others/nav.adoc 
b/docs/components/modules/others/nav.adoc
index 5c970bc5b4f..a50714416d4 100644
--- a/docs/components/modules/others/nav.adoc
+++ b/docs/components/modules/others/nav.adoc
@@ -36,6 +36,7 @@
 ** xref:openapi-java.adoc[Openapi Java]
 ** xref:openapi-validator.adoc[Openapi Validator]
 ** xref:opentelemetry.adoc[OpenTelemetry]
+** xref:opentelemetry2.adoc[Opentelemetry2]
 ** xref:platform-http-jolokia.adoc[Platform HTTP Jolokia]
 ** xref:platform-http-main.adoc[Platform Http Main]
 ** xref:platform-http-vertx.adoc[Platform Http Vertx]
diff --git a/docs/components/modules/others/pages/opentelemetry2.adoc 
b/docs/components/modules/others/pages/opentelemetry2.adoc
new file mode 120000
index 00000000000..04bcced0884
--- /dev/null
+++ b/docs/components/modules/others/pages/opentelemetry2.adoc
@@ -0,0 +1 @@
+../../../../../components/camel-opentelemetry2/src/main/docs/opentelemetry2.adoc
\ No newline at end of file
diff --git a/parent/pom.xml b/parent/pom.xml
index 39354127791..145e208ff2e 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -2036,6 +2036,16 @@
                 <artifactId>camel-opentelemetry</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.camel</groupId>
+                <artifactId>camel-opentelemetry-2</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.camel</groupId>
+                <artifactId>camel-opentelemetry2</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.camel</groupId>
                 <artifactId>camel-optaplanner</artifactId>
diff --git 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelMainMojo.java
 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelMainMojo.java
index c21082592c6..703695c1305 100644
--- 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelMainMojo.java
+++ 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelMainMojo.java
@@ -217,7 +217,9 @@ public class PrepareCamelMainMojo extends 
AbstractGeneratorMojo {
                     prefix = "camel.startupcondition.";
                 } else if (file.getName().contains("Lra")) {
                     prefix = "camel.lra.";
-                } else if (file.getName().contains("Otel")) {
+                } else if (file.getName().contains("Otel2")) {
+                    prefix = "camel.opentelemetry2.";
+                } else if (file.getName().contains("Otel") && 
!file.getName().contains("Otel2")) {
                     prefix = "camel.opentelemetry.";
                 } else if (file.getName().contains("TelemetryDev")) {
                     prefix = "camel.telemetryDev.";
@@ -395,6 +397,9 @@ public class PrepareCamelMainMojo extends 
AbstractGeneratorMojo {
             model.getGroups().add(new MainGroupModel(
                     "camel.opentelemetry", "Camel OpenTelemetry 
configurations",
                     "org.apache.camel.main.OtelConfigurationProperties"));
+            model.getGroups().add(new MainGroupModel(
+                    "camel.opentelemetry2", "Camel OpenTelemetry 2 
configurations",
+                    "org.apache.camel.main.Otel2ConfigurationProperties"));
             model.getGroups().add(new MainGroupModel(
                     "camel.telemetryDev", "Camel Telemetry Dev configurations",
                     
"org.apache.camel.main.TelemetryDevConfigurationProperties"));

Reply via email to