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

davsclaus pushed a commit to branch 
feature/CAMEL-23718-otel-agent-embedded-receiver
in repository https://gitbox.apache.org/repos/asf/camel.git

commit fee014942e18622db4949a1208fd83c97e5b2c1d
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Jun 8 22:03:46 2026 +0200

    CAMEL-23718: Embedded OTLP receiver for OpenTelemetry Java Agent in Camel 
JBang
    
    Add --open-telemetry-agent flag to camel run/dev/debug that automatically
    attaches the OpenTelemetry Java Agent and configures an embedded OTLP 
receiver
    inside the Camel process. The agent's protobuf-encoded spans are received on
    /v1/traces and fed into the in-memory DevSpanExporter, making them visible
    in the TUI OTel Spans tab — zero config, no external collector needed.
    
    Also adds a Process tab in the TUI (under More) showing PID, Java version,
    command line and other process metadata, and an F2 checkbox to toggle the
    OTel Agent option from the run options form.
    
    Co-Authored-By: Claude <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 components/camel-opentelemetry2/pom.xml            |   9 +
 .../OpenTelemetryTracerConfigurer.java             |   6 +
 .../src/main/docs/opentelemetry2.adoc              |  41 +++
 .../camel/opentelemetry2/OpenTelemetryTracer.java  |  32 +++
 .../camel/opentelemetry2/OtlpProtobufSpanData.java | 280 +++++++++++++++++++++
 .../opentelemetry2/OtlpReceiverProcessor.java      |  64 +++++
 .../pages/jbang-commands/camel-jbang-debug.adoc    |   1 +
 .../ROOT/pages/jbang-commands/camel-jbang-dev.adoc |   1 +
 .../ROOT/pages/jbang-commands/camel-jbang-run.adoc |   1 +
 .../META-INF/camel-jbang-commands-metadata.json    |   6 +-
 .../apache/camel/dsl/jbang/core/commands/Run.java  |  32 ++-
 .../dsl/jbang/core/commands/tui/CamelMonitor.java  |  20 +-
 .../dsl/jbang/core/commands/tui/ProcessTab.java    | 252 +++++++++++++++++++
 .../jbang/core/commands/tui/RunOptionsForm.java    |  27 +-
 parent/pom.xml                                     |   6 +
 15 files changed, 760 insertions(+), 18 deletions(-)

diff --git a/components/camel-opentelemetry2/pom.xml 
b/components/camel-opentelemetry2/pom.xml
index 94b298e19c90..1c0e8f6dda5e 100644
--- a/components/camel-opentelemetry2/pom.xml
+++ b/components/camel-opentelemetry2/pom.xml
@@ -54,10 +54,19 @@
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-telemetry</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-core-model</artifactId>
+        </dependency>
         <dependency>
             <groupId>io.opentelemetry</groupId>
             <artifactId>opentelemetry-sdk</artifactId>
         </dependency>
+        <dependency>
+            <groupId>io.opentelemetry.proto</groupId>
+            <artifactId>opentelemetry-proto</artifactId>
+            <scope>provided</scope>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-test-spring-junit6</artifactId>
diff --git 
a/components/camel-opentelemetry2/src/generated/java/org/apache/camel/opentelemetry2/OpenTelemetryTracerConfigurer.java
 
b/components/camel-opentelemetry2/src/generated/java/org/apache/camel/opentelemetry2/OpenTelemetryTracerConfigurer.java
index 98722d317372..16a6995a0166 100644
--- 
a/components/camel-opentelemetry2/src/generated/java/org/apache/camel/opentelemetry2/OpenTelemetryTracerConfigurer.java
+++ 
b/components/camel-opentelemetry2/src/generated/java/org/apache/camel/opentelemetry2/OpenTelemetryTracerConfigurer.java
@@ -33,6 +33,8 @@ public class OpenTelemetryTracerConfigurer extends 
org.apache.camel.support.comp
         case "includePatterns": 
target.setIncludePatterns(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 "tracecustomidonly":
+        case "traceCustomIdOnly": 
target.setTraceCustomIdOnly(property(camelContext, boolean.class, value)); 
return true;
         case "traceheadersinclusion":
         case "traceHeadersInclusion": 
target.setTraceHeadersInclusion(property(camelContext, boolean.class, value)); 
return true;
         case "traceprocessors":
@@ -54,6 +56,8 @@ public class OpenTelemetryTracerConfigurer extends 
org.apache.camel.support.comp
         case "includePatterns": return java.lang.String.class;
         case "spanlifecyclemanager":
         case "spanLifecycleManager": return 
org.apache.camel.telemetry.SpanLifecycleManager.class;
+        case "tracecustomidonly":
+        case "traceCustomIdOnly": return boolean.class;
         case "traceheadersinclusion":
         case "traceHeadersInclusion": return boolean.class;
         case "traceprocessors":
@@ -76,6 +80,8 @@ public class OpenTelemetryTracerConfigurer extends 
org.apache.camel.support.comp
         case "includePatterns": return target.getIncludePatterns();
         case "spanlifecyclemanager":
         case "spanLifecycleManager": return target.getSpanLifecycleManager();
+        case "tracecustomidonly":
+        case "traceCustomIdOnly": return target.isTraceCustomIdOnly();
         case "traceheadersinclusion":
         case "traceHeadersInclusion": return target.isTraceHeadersInclusion();
         case "traceprocessors":
diff --git a/components/camel-opentelemetry2/src/main/docs/opentelemetry2.adoc 
b/components/camel-opentelemetry2/src/main/docs/opentelemetry2.adoc
index 9179c7bb1547..0d418abc3ed6 100644
--- a/components/camel-opentelemetry2/src/main/docs/opentelemetry2.adoc
+++ b/components/camel-opentelemetry2/src/main/docs/opentelemetry2.adoc
@@ -89,6 +89,47 @@ NOTE: The in-memory exporter is only activated when the 
Camel profile is `dev` a
 OTel `Tracer` bean is registered. For production deployments, configure a 
proper span exporter
 (OTLP, Jaeger, Zipkin, etc.).
 
+=== Camel JBang with OpenTelemetry Java Agent
+
+When running with Camel JBang, you can use the `--open-telemetry-agent` flag 
to automatically attach the
+https://opentelemetry.io/docs/zero-code/java/agent/[OpenTelemetry Java Agent] 
to your application.
+This provides deep instrumentation beyond Camel routes, including JVM metrics, 
HTTP clients, database
+drivers, and other libraries — all with zero configuration and no external 
collector required.
+
+[source,bash]
+----
+camel run my-route.yaml --open-telemetry-agent
+----
+
+This single flag handles the entire setup:
+
+- Downloads and attaches the OpenTelemetry Java Agent to the JVM
+- Adds `camel-opentelemetry2` and `camel-platform-http-main` as dependencies
+- Starts an embedded OTLP receiver on the Vert.x HTTP server (at `/v1/traces`)
+- Configures the agent to export traces to the embedded receiver
+- Starts an HTTP server on port 8080 (if not already specified)
+
+The agent sends protobuf-encoded spans to the embedded OTLP receiver, which 
parses them and feeds
+them into the in-memory `DevSpanExporter`. The captured spans are then visible 
in the Camel TUI
+under the OTel Spans tab, or through the dev console.
+
+==== When to use `--open-telemetry-agent` vs `--observe`
+
+Both flags enable tracing during development, but they cover different scopes:
+
+[width="100%",cols="30%,35%,35%",options="header"]
+|=======================================================================
+| | `--observe` | `--open-telemetry-agent`
+| *Instrumentation* | Camel routes only | Camel routes + JVM, HTTP clients, 
databases, messaging, and other libraries
+| *Setup* | Built-in SDK | Downloads OTel Java Agent
+| *Collector* | Not needed | Not needed (embedded OTLP receiver)
+| *Use case* | Quick Camel route debugging | Full-stack observability during 
development
+|=======================================================================
+
+NOTE: The embedded OTLP receiver is only activated in `dev` profile mode and 
is intended for local
+development. For production deployments, configure the OpenTelemetry Java 
Agent to export to an
+external collector such as Jaeger or an OpenTelemetry Collector.
+
 [[OpenTelemetry-JavaAgent]]
 === Using the OpenTelemetry Java Agent
 
diff --git 
a/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OpenTelemetryTracer.java
 
b/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OpenTelemetryTracer.java
index 3996e8a24ad6..5e518a695c1c 100644
--- 
a/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OpenTelemetryTracer.java
+++ 
b/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OpenTelemetryTracer.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.opentelemetry2;
 
+import java.lang.management.ManagementFactory;
 import java.util.Iterator;
 import java.util.Map;
 
@@ -33,6 +34,7 @@ import io.opentelemetry.sdk.trace.SdkTracerProvider;
 import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.api.management.ManagedResource;
+import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.spi.Configurer;
 import org.apache.camel.spi.InterceptStrategy;
 import org.apache.camel.spi.annotations.JdkService;
@@ -91,6 +93,11 @@ public class OpenTelemetryTracer extends 
org.apache.camel.telemetry.Tracer {
     }
 
     private void initDevSpanExporter() {
+        if (isOpenTelemetryAgentPresent()) {
+            LOG.info("OpenTelemetry Java Agent detected, using agent's tracer 
for proper trace context propagation");
+            initOtlpReceiver();
+            return;
+        }
         DevSpanExporter exporter = new DevSpanExporter();
         SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
                 .addSpanProcessor(SimpleSpanProcessor.create(exporter))
@@ -99,12 +106,37 @@ public class OpenTelemetryTracer extends 
org.apache.camel.telemetry.Tracer {
                 
.setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
                 .setTracerProvider(tracerProvider)
                 .build();
+        GlobalOpenTelemetry.set(devSdk);
         this.tracer = devSdk.getTracer("camel");
         this.contextPropagators = devSdk.getPropagators();
         getCamelContext().getRegistry().bind("DevSpanExporter", exporter);
         LOG.info("OpenTelemetry in-memory span exporter enabled (dev 
profile)");
     }
 
+    private void initOtlpReceiver() {
+        DevSpanExporter exporter = new DevSpanExporter();
+        getCamelContext().getRegistry().bind("DevSpanExporter", exporter);
+
+        try {
+            getCamelContext().addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from("platform-http:/v1/traces?httpMethodRestrict=POST")
+                            .routeId("otlp-receiver")
+                            .process(new OtlpReceiverProcessor(exporter));
+                }
+            });
+            LOG.info("Embedded OTLP receiver enabled on /v1/traces for Java 
Agent span collection");
+        } catch (Exception e) {
+            LOG.warn("Failed to start embedded OTLP receiver: {}", 
e.getMessage());
+        }
+    }
+
+    private boolean isOpenTelemetryAgentPresent() {
+        return 
ManagementFactory.getRuntimeMXBean().getInputArguments().stream()
+                .anyMatch(arg -> arg.startsWith("-javaagent") && 
arg.contains("opentelemetry"));
+    }
+
     void setTracer(Tracer tracer) {
         this.tracer = tracer;
     }
diff --git 
a/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OtlpProtobufSpanData.java
 
b/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OtlpProtobufSpanData.java
new file mode 100644
index 000000000000..31d7f62413a4
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OtlpProtobufSpanData.java
@@ -0,0 +1,280 @@
+/*
+ * 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.List;
+
+import com.google.protobuf.ByteString;
+import io.opentelemetry.api.common.AttributeKey;
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.common.AttributesBuilder;
+import io.opentelemetry.api.trace.SpanContext;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.api.trace.StatusCode;
+import io.opentelemetry.api.trace.TraceFlags;
+import io.opentelemetry.api.trace.TraceState;
+import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest;
+import io.opentelemetry.proto.common.v1.AnyValue;
+import io.opentelemetry.proto.common.v1.InstrumentationScope;
+import io.opentelemetry.proto.common.v1.KeyValue;
+import io.opentelemetry.proto.trace.v1.ResourceSpans;
+import io.opentelemetry.proto.trace.v1.ScopeSpans;
+import io.opentelemetry.proto.trace.v1.Span;
+import io.opentelemetry.proto.trace.v1.Status;
+import io.opentelemetry.sdk.common.InstrumentationLibraryInfo;
+import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
+import io.opentelemetry.sdk.resources.Resource;
+import io.opentelemetry.sdk.trace.data.EventData;
+import io.opentelemetry.sdk.trace.data.LinkData;
+import io.opentelemetry.sdk.trace.data.SpanData;
+import io.opentelemetry.sdk.trace.data.StatusData;
+
+/**
+ * Lightweight {@link SpanData} adapter that wraps an OTLP protobuf span. Used 
by the embedded OTLP receiver to feed
+ * spans from the OpenTelemetry Java Agent into {@link DevSpanExporter}.
+ */
+final class OtlpProtobufSpanData implements SpanData {
+
+    private final SpanContext spanContext;
+    private final SpanContext parentSpanContext;
+    private final String name;
+    private final SpanKind kind;
+    private final StatusData status;
+    private final long startEpochNanos;
+    private final long endEpochNanos;
+    private final Attributes attributes;
+    private final InstrumentationScopeInfo scopeInfo;
+    private final Resource resource;
+
+    private OtlpProtobufSpanData(SpanContext spanContext, SpanContext 
parentSpanContext, String name,
+                                 SpanKind kind, StatusData status, long 
startEpochNanos, long endEpochNanos,
+                                 Attributes attributes, 
InstrumentationScopeInfo scopeInfo, Resource resource) {
+        this.spanContext = spanContext;
+        this.parentSpanContext = parentSpanContext;
+        this.name = name;
+        this.kind = kind;
+        this.status = status;
+        this.startEpochNanos = startEpochNanos;
+        this.endEpochNanos = endEpochNanos;
+        this.attributes = attributes;
+        this.scopeInfo = scopeInfo;
+        this.resource = resource;
+    }
+
+    static List<SpanData> fromProtobuf(byte[] body) throws Exception {
+        ExportTraceServiceRequest request = 
ExportTraceServiceRequest.parseFrom(body);
+        List<SpanData> result = new ArrayList<>();
+
+        for (ResourceSpans rs : request.getResourceSpansList()) {
+            Resource resource = parseResource(rs.getResource());
+            for (ScopeSpans ss : rs.getScopeSpansList()) {
+                InstrumentationScopeInfo scopeInfo = parseScope(ss.getScope());
+                for (Span span : ss.getSpansList()) {
+                    result.add(fromSpan(span, resource, scopeInfo));
+                }
+            }
+        }
+        return result;
+    }
+
+    private static OtlpProtobufSpanData fromSpan(
+            Span span, Resource resource, InstrumentationScopeInfo scopeInfo) {
+
+        String traceId = hex(span.getTraceId());
+        String spanId = hex(span.getSpanId());
+        String parentSpanId = hex(span.getParentSpanId());
+
+        SpanContext sc = SpanContext.create(traceId, spanId, 
TraceFlags.getSampled(), TraceState.getDefault());
+        SpanContext parentSc;
+        if (parentSpanId.isEmpty()) {
+            parentSc = SpanContext.getInvalid();
+        } else {
+            parentSc = SpanContext.create(traceId, parentSpanId, 
TraceFlags.getSampled(), TraceState.getDefault());
+        }
+
+        return new OtlpProtobufSpanData(
+                sc, parentSc, span.getName(),
+                toSpanKind(span.getKind()),
+                toStatusData(span.getStatus()),
+                span.getStartTimeUnixNano(),
+                span.getEndTimeUnixNano(),
+                toAttributes(span.getAttributesList()),
+                scopeInfo, resource);
+    }
+
+    private static Resource 
parseResource(io.opentelemetry.proto.resource.v1.Resource res) {
+        if (res == null) {
+            return Resource.getDefault();
+        }
+        return Resource.create(toAttributes(res.getAttributesList()));
+    }
+
+    private static InstrumentationScopeInfo parseScope(InstrumentationScope 
scope) {
+        if (scope == null) {
+            return InstrumentationScopeInfo.create("unknown");
+        }
+        String name = scope.getName().isEmpty() ? "unknown" : scope.getName();
+        String version = scope.getVersion().isEmpty() ? null : 
scope.getVersion();
+        if (version != null) {
+            return 
InstrumentationScopeInfo.builder(name).setVersion(version).build();
+        }
+        return InstrumentationScopeInfo.create(name);
+    }
+
+    private static SpanKind toSpanKind(Span.SpanKind kind) {
+        return switch (kind) {
+            case SPAN_KIND_SERVER -> SpanKind.SERVER;
+            case SPAN_KIND_CLIENT -> SpanKind.CLIENT;
+            case SPAN_KIND_PRODUCER -> SpanKind.PRODUCER;
+            case SPAN_KIND_CONSUMER -> SpanKind.CONSUMER;
+            default -> SpanKind.INTERNAL;
+        };
+    }
+
+    private static StatusData toStatusData(Status status) {
+        if (status == null) {
+            return StatusData.unset();
+        }
+        return switch (status.getCode()) {
+            case STATUS_CODE_OK -> StatusData.ok();
+            case STATUS_CODE_ERROR -> StatusData.create(StatusCode.ERROR, 
status.getMessage());
+            default -> StatusData.unset();
+        };
+    }
+
+    private static Attributes toAttributes(List<KeyValue> kvs) {
+        if (kvs == null || kvs.isEmpty()) {
+            return Attributes.empty();
+        }
+        AttributesBuilder ab = Attributes.builder();
+        for (KeyValue kv : kvs) {
+            String key = kv.getKey();
+            AnyValue value = kv.getValue();
+            if (value.hasStringValue()) {
+                ab.put(AttributeKey.stringKey(key), value.getStringValue());
+            } else if (value.hasIntValue()) {
+                ab.put(AttributeKey.longKey(key), value.getIntValue());
+            } else if (value.hasDoubleValue()) {
+                ab.put(AttributeKey.doubleKey(key), value.getDoubleValue());
+            } else if (value.hasBoolValue()) {
+                ab.put(AttributeKey.booleanKey(key), value.getBoolValue());
+            }
+        }
+        return ab.build();
+    }
+
+    private static String hex(ByteString bytes) {
+        if (bytes == null || bytes.isEmpty()) {
+            return "";
+        }
+        StringBuilder sb = new StringBuilder(bytes.size() * 2);
+        for (int i = 0; i < bytes.size(); i++) {
+            int b = bytes.byteAt(i) & 0xFF;
+            sb.append(Character.forDigit(b >>> 4, 16));
+            sb.append(Character.forDigit(b & 0x0F, 16));
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public SpanContext getSpanContext() {
+        return spanContext;
+    }
+
+    @Override
+    public SpanContext getParentSpanContext() {
+        return parentSpanContext;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public SpanKind getKind() {
+        return kind;
+    }
+
+    @Override
+    public StatusData getStatus() {
+        return status;
+    }
+
+    @Override
+    public long getStartEpochNanos() {
+        return startEpochNanos;
+    }
+
+    @Override
+    public long getEndEpochNanos() {
+        return endEpochNanos;
+    }
+
+    @Override
+    public Attributes getAttributes() {
+        return attributes;
+    }
+
+    @Override
+    public List<EventData> getEvents() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public List<LinkData> getLinks() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public boolean hasEnded() {
+        return true;
+    }
+
+    @Override
+    public int getTotalRecordedEvents() {
+        return 0;
+    }
+
+    @Override
+    public int getTotalRecordedLinks() {
+        return 0;
+    }
+
+    @Override
+    public int getTotalAttributeCount() {
+        return attributes.size();
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public InstrumentationLibraryInfo getInstrumentationLibraryInfo() {
+        return InstrumentationLibraryInfo.create(scopeInfo.getName(), 
scopeInfo.getVersion());
+    }
+
+    @Override
+    public InstrumentationScopeInfo getInstrumentationScopeInfo() {
+        return scopeInfo;
+    }
+
+    @Override
+    public Resource getResource() {
+        return resource;
+    }
+}
diff --git 
a/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OtlpReceiverProcessor.java
 
b/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OtlpReceiverProcessor.java
new file mode 100644
index 000000000000..a01a18159f66
--- /dev/null
+++ 
b/components/camel-opentelemetry2/src/main/java/org/apache/camel/opentelemetry2/OtlpReceiverProcessor.java
@@ -0,0 +1,64 @@
+/*
+ * 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.sdk.trace.data.SpanData;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Processes incoming OTLP protobuf trace export requests and feeds parsed 
spans into the {@link DevSpanExporter}.
+ */
+final class OtlpReceiverProcessor implements Processor {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(OtlpReceiverProcessor.class);
+
+    private final DevSpanExporter exporter;
+
+    OtlpReceiverProcessor(DevSpanExporter exporter) {
+        this.exporter = exporter;
+    }
+
+    @Override
+    public void process(Exchange exchange) throws Exception {
+        byte[] body = exchange.getMessage().getBody(byte[].class);
+        if (body == null || body.length == 0) {
+            exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, 200);
+            exchange.getMessage().setBody(new byte[0]);
+            return;
+        }
+
+        try {
+            List<SpanData> spans = OtlpProtobufSpanData.fromProtobuf(body);
+            if (!spans.isEmpty()) {
+                exporter.export(spans);
+                if (LOG.isTraceEnabled()) {
+                    LOG.trace("Received {} spans from OTLP exporter", 
spans.size());
+                }
+            }
+        } catch (Exception e) {
+            LOG.debug("Failed to parse OTLP protobuf: {}", e.getMessage());
+        }
+
+        exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, 200);
+        exchange.getMessage().setBody(new byte[0]);
+    }
+}
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-debug.adoc 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-debug.adoc
index 9b1701b5cdd2..e1a8bcc3d221 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-debug.adoc
+++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-debug.adoc
@@ -65,6 +65,7 @@ camel debug [options]
 | `--name` | The name of the Camel application | CamelJBang | String
 | `--observe` | Enable observability services | false | boolean
 | `--open-api` | Adds an OpenAPI spec from the given file (json or yaml file) 
|  | String
+| `--open-telemetry-agent` | Enable OpenTelemetry Java Agent for 
auto-instrumentation of third-party libraries | false | boolean
 | `--output` | File to store the current message body (will override). This 
allows for manual inspecting the message later. |  | String
 | `--package-scan-jars` | Whether to automatic package scan JARs for custom 
Spring or Quarkus beans making them available for Camel JBang | false | boolean
 | `--port` | Embeds a local HTTP server on this port (port 8080 by default; 
use 0 to dynamic assign a free random port number) |  | int
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dev.adoc 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dev.adoc
index 2d3e8e603461..51b2298612c6 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dev.adoc
+++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dev.adoc
@@ -61,6 +61,7 @@ camel dev [options]
 | `--name` | The name of the Camel application | CamelJBang | String
 | `--observe` | Enable observability services | false | boolean
 | `--open-api` | Adds an OpenAPI spec from the given file (json or yaml file) 
|  | String
+| `--open-telemetry-agent` | Enable OpenTelemetry Java Agent for 
auto-instrumentation of third-party libraries | false | boolean
 | `--package-scan-jars` | Whether to automatic package scan JARs for custom 
Spring or Quarkus beans making them available for Camel JBang | false | boolean
 | `--port` | Embeds a local HTTP server on this port (port 8080 by default; 
use 0 to dynamic assign a free random port number) |  | int
 | `--profile` | Profile to run (dev, test, prod). | dev | String
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-run.adoc 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-run.adoc
index 18c48842fba5..115c6420d7e8 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-run.adoc
+++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-run.adoc
@@ -61,6 +61,7 @@ camel run [options]
 | `--name` | The name of the Camel application | CamelJBang | String
 | `--observe` | Enable observability services | false | boolean
 | `--open-api` | Adds an OpenAPI spec from the given file (json or yaml file) 
|  | String
+| `--open-telemetry-agent` | Enable OpenTelemetry Java Agent for 
auto-instrumentation of third-party libraries | false | boolean
 | `--package-scan-jars` | Whether to automatic package scan JARs for custom 
Spring or Quarkus beans making them available for Camel JBang | false | boolean
 | `--port` | Embeds a local HTTP server on this port (port 8080 by default; 
use 0 to dynamic assign a free random port number) |  | int
 | `--profile` | Profile to run (dev, test, prod). | dev | String
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
index 817a2a70d40c..ed56b7ae15f5 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
@@ -6,9 +6,9 @@
     { "name": "cmd", "fullName": "cmd", "description": "Performs commands in 
the running Camel integrations, such as start\/stop route, or change logging 
levels.", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.action.CamelAction", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": 
"browse", "fullName": "cmd browse", "description": "Browse pending messages on 
endpoints [...]
     { "name": "completion", "fullName": "completion", "description": "Generate 
completion script for bash\/zsh", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Complete", "options": [ { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ] },
     { "name": "config", "fullName": "config", "description": "Get and set user 
configuration values", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.config.ConfigCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": "get", 
"fullName": "config get", "description": "Display user configuration value", 
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.config. [...]
-    { "name": "debug", "fullName": "debug", "description": "Debug local Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Debug", 
"options": [ { "names": "--ago", "description": "Use ago instead of yyyy-MM-dd 
HH:mm:ss in timestamp.", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background", "description": "Run in the background", "defaultValue": 
"false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To  [...]
+    { "name": "debug", "fullName": "debug", "description": "Debug local Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Debug", 
"options": [ { "names": "--ago", "description": "Use ago instead of yyyy-MM-dd 
HH:mm:ss in timestamp.", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background", "description": "Run in the background", "defaultValue": 
"false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To  [...]
     { "name": "dependency", "fullName": "dependency", "description": "Displays 
all Camel dependencies required to run", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.DependencyCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": 
"copy", "fullName": "dependency copy", "description": "Copies all Camel 
dependencies required to run to a specific directory", "sourc [...]
-    { "name": "dev", "fullName": "dev", "description": "Run in dev mode with 
live reload", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Dev", 
"options": [ { "names": "--background", "description": "Run in the background", 
"defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To wait for run in background to startup 
successfully, before returning", "defaultValue": "true", "javaType": "boolean", 
"type": "boolean" }, [...]
+    { "name": "dev", "fullName": "dev", "description": "Run in dev mode with 
live reload", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Dev", 
"options": [ { "names": "--background", "description": "Run in the background", 
"defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To wait for run in background to startup 
successfully, before returning", "defaultValue": "true", "javaType": "boolean", 
"type": "boolean" }, [...]
     { "name": "dirty", "fullName": "dirty", "description": "Check if there are 
dirty files from previous Camel runs that did not terminate gracefully", 
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.process.Dirty", 
"options": [ { "names": "--clean", "description": "Clean dirty files which are 
no longer in use", "defaultValue": "false", "javaType": "boolean", "type": 
"boolean" }, { "names": "-h,--help", "description": "Display the help and 
sub-commands", "javaType": "boolean", " [...]
     { "name": "doc", "fullName": "doc", "description": "Shows documentation 
for kamelet, component, and other Camel resources", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.catalog.CatalogDoc", "options": [ { 
"names": "--camel-version", "description": "To use a different Camel version 
than the default version", "javaType": "java.lang.String", "type": "string" }, 
{ "names": "--download", "description": "Whether to allow automatic downloading 
JAR dependencies (over the internet [...]
     { "name": "doctor", "fullName": "doctor", "description": "Checks the 
environment and reports potential issues", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Doctor", "options": [ { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ] },
@@ -26,7 +26,7 @@
     { "name": "plugin", "fullName": "plugin", "description": "Manage plugins 
that add sub-commands to this CLI", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.plugin.PluginCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": "add", 
"fullName": "plugin add", "description": "Add new plugin", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.plugin.PluginA [...]
     { "name": "ps", "fullName": "ps", "description": "List running Camel 
integrations", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.ListProcess", "options": [ { 
"names": "--json", "description": "Output in JSON Format", "javaType": 
"boolean", "type": "boolean" }, { "names": "--pid", "description": "List only 
pid in the output", "javaType": "boolean", "type": "boolean" }, { "names": 
"--remote", "description": "Break down counters into remote\/total pairs", 
"javaType": [...]
     { "name": "restart", "fullName": "restart", "description": "Restarts 
running Camel integrations (stop + re-launch)", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.RestartProcess", "options": [ 
{ "names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ] },
-    { "name": "run", "fullName": "run", "description": "Run as local Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Run", 
"options": [ { "names": "--background", "description": "Run in the background", 
"defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To wait for run in background to startup 
successfully, before returning", "defaultValue": "true", "javaType": "boolean", 
"type": "boolean" }, { [...]
+    { "name": "run", "fullName": "run", "description": "Run as local Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Run", 
"options": [ { "names": "--background", "description": "Run in the background", 
"defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To wait for run in background to startup 
successfully, before returning", "defaultValue": "true", "javaType": "boolean", 
"type": "boolean" }, { [...]
     { "name": "sbom", "fullName": "sbom", "description": "Generate a CycloneDX 
or SPDX SBOM for a specific project", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.SBOMGenerator", "options": [ { 
"names": "--build-property", "description": "Maven build properties, ex. 
--build-property=prop1=foo", "javaType": "java.util.List", "type": "array" }, { 
"names": "--camel-spring-boot-version", "description": "Camel version to use 
with Spring Boot", "javaType": "java.lang.String", "type" [...]
     { "name": "script", "fullName": "script", "description": "Run Camel 
integration as shell script for terminal scripting", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Script", "options": [ { "names": 
"--logging", "description": "Can be used to turn on logging (logs to file in 
<user home>\/.camel directory)", "defaultValue": "false", "javaType": 
"boolean", "type": "boolean" }, { "names": "--logging-level", "description": 
"Logging level (ERROR, WARN, INFO, DEBUG, TRACE)", "d [...]
     { "name": "shell", "fullName": "shell", "description": "Interactive Camel 
JBang shell.", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Shell", 
"options": [ { "names": "-h,--help", "description": "Display the help and 
sub-commands", "javaType": "boolean", "type": "boolean" } ] },
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
index f3cd2c2385cc..a856a0a8e829 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
@@ -558,7 +558,7 @@ public class Run extends CamelCommand {
     }
 
     private boolean isDebugMode() {
-        return jvmDebugPort > 0;
+        return jvmDebugPort > 0 || debugOptions.openTelemetryAgent;
     }
 
     private void writeSetting(KameletMain main, Properties existing, String 
key, String value) {
@@ -1186,6 +1186,14 @@ public class Run extends CamelCommand {
             dependencies.add("camel:observability-services");
             main.addOverrideProperty("camel.metrics.logMetricsOnShutdown", 
"false");
         }
+        if (debugOptions.openTelemetryAgent) {
+            dependencies.add("camel:opentelemetry2");
+            dependencies.add("camel:platform-http-main");
+            if (serverOptions.port == -1) {
+                serverOptions.port = 8080;
+            }
+            writeSetting(main, profileProperties, "camel.server.enabled", 
"true");
+        }
         if (!dependencies.isEmpty()) {
             var joined = String.join(",", dependencies);
             main.addInitialProperty(DEPENDENCIES, joined);
@@ -1688,10 +1696,26 @@ public class Run extends CamelCommand {
         if (debugSuspend != null) {
             jbangArgs.add("-D" + BacklogDebugger.SUSPEND_MODE_SYSTEM_PROP_NAME 
+ "=" + debugSuspend);
         }
-        if (isDebugMode()) {
+        if (jvmDebugPort > 0) {
             jbangArgs.add("--debug=" + jvmDebugPort); // jbang --debug=port
             cmds.removeIf(arg -> arg.startsWith("--jvm-debug"));
         }
+        if (debugOptions.openTelemetryAgent) {
+            
jbangArgs.add("--javaagent=io.opentelemetry.javaagent:opentelemetry-javaagent:RELEASE");
+            int port = serverOptions.port > 0 ? serverOptions.port : 8080;
+            
jbangArgs.add("-Dotel.exporter.otlp.traces.endpoint=http://localhost:"; + port + 
"/v1/traces");
+            jbangArgs.add("-Dotel.metrics.exporter=none");
+            jbangArgs.add("-Dotel.logs.exporter=none");
+            jbangArgs.add("-Dotel.service.name=camel");
+            cmds.removeIf(arg -> arg.startsWith("--open-telemetry-agent"));
+            cmds.add("--dep=camel:opentelemetry2");
+            cmds.add("--dep=camel:platform-http-main");
+            
cmds.add("--dep=mvn:io.opentelemetry.proto:opentelemetry-proto:RELEASE");
+            cmds.add("--prop=camel.opentelemetry2.enabled=true");
+            if (cmds.stream().noneMatch(a -> a.startsWith("--port"))) {
+                cmds.add("--port=" + port);
+            }
+        }
 
         if (javaVersion != null) {
             jbangArgs.add("--java=" + javaVersion);
@@ -2412,6 +2436,10 @@ public class Run extends CamelCommand {
         @Option(names = { "--backlog-trace" }, defaultValue = "false",
                 description = "Enables backlog tracing of the routed messages")
         boolean backlogTrace;
+
+        @Option(names = { "--open-telemetry-agent" }, defaultValue = "false",
+                description = "Enable OpenTelemetry Java Agent for 
auto-instrumentation of third-party libraries")
+        boolean openTelemetryAgent;
     }
 
     public static class ExecutionLimitOptions {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
index 3437eee08aaf..9afb360b667e 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
@@ -220,6 +220,7 @@ public class CamelMonitor extends CamelCommand {
     private MemoryTab memoryTab;
     private ThreadsTab threadsTab;
     private SpansTab spansTab;
+    private ProcessTab processTab;
     private OverviewTab overviewTab;
 
     // "Switch integration" popup state
@@ -289,6 +290,7 @@ public class CamelMonitor extends CamelCommand {
         memoryTab = new MemoryTab(ctx, metrics);
         threadsTab = new ThreadsTab(ctx);
         spansTab = new SpansTab(ctx, otelSpans);
+        processTab = new ProcessTab(ctx);
         overviewTab = new OverviewTab(
                 ctx, metrics, stoppingPids,
                 this::resetIntegrationTabState);
@@ -440,8 +442,9 @@ public class CamelMonitor extends CamelCommand {
                         case 7 -> memoryTab;
                         case 8 -> metricsTab;
                         case 9 -> spansTab;
-                        case 10 -> startupTab;
-                        case 11 -> threadsTab;
+                        case 10 -> processTab;
+                        case 11 -> startupTab;
+                        case 12 -> threadsTab;
                         default -> null;
                     };
                     if (activeMoreTab != null) {
@@ -906,6 +909,9 @@ public class CamelMonitor extends CamelCommand {
         consumersTab.onIntegrationChanged();
         circuitBreakerTab.onIntegrationChanged();
         inflightTab.onIntegrationChanged();
+        spansTab.onIntegrationChanged();
+        processTab.onIntegrationChanged();
+        otelSpans.set(List.of());
 
         filesBrowser.reset();
 
@@ -1191,7 +1197,7 @@ public class CamelMonitor extends CamelCommand {
 
     private void renderMorePopup(Frame frame, Rect area) {
         int popupW = 22;
-        int popupH = 12;
+        int popupH = 15;
         // Position just below the "0 More▾" tab label
         int dividerW = CharWidth.of(" | ");
         int tabBarX = 0;
@@ -1223,6 +1229,7 @@ public class CamelMonitor extends CamelCommand {
                 ListItem.from(Line.from(Span.raw("  "), Span.styled("M", 
keyStyle), Span.raw("emory"))),
                 ListItem.from(Line.from(Span.raw("  M"), Span.styled("e", 
keyStyle), Span.raw("trics"))),
                 ListItem.from(Line.from(Span.raw("  "), Span.styled("O", 
keyStyle), Span.raw("Tel Spans"))),
+                ListItem.from(Line.from(Span.raw("  "), Span.styled("P", 
keyStyle), Span.raw("rocess"))),
                 ListItem.from(Line.from(Span.raw("  "), Span.styled("S", 
keyStyle), Span.raw("tartup"))),
                 ListItem.from(Line.from(Span.raw("  "), Span.styled("T", 
keyStyle), Span.raw("hreads"))),
         };
@@ -1332,12 +1339,15 @@ public class CamelMonitor extends CamelCommand {
         if (ke.isChar('o')) {
             return 9;
         }
-        if (ke.isChar('s')) {
+        if (ke.isChar('p')) {
             return 10;
         }
-        if (ke.isChar('t')) {
+        if (ke.isChar('s')) {
             return 11;
         }
+        if (ke.isChar('t')) {
+            return 12;
+        }
         return -1;
     }
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ProcessTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ProcessTab.java
new file mode 100644
index 000000000000..a9366549b413
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ProcessTab.java
@@ -0,0 +1,252 @@
+/*
+ * 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.dsl.jbang.core.commands.tui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import dev.tamboui.layout.Constraint;
+import dev.tamboui.layout.Layout;
+import dev.tamboui.layout.Rect;
+import dev.tamboui.style.Color;
+import dev.tamboui.style.Overflow;
+import dev.tamboui.style.Style;
+import dev.tamboui.terminal.Frame;
+import dev.tamboui.text.Line;
+import dev.tamboui.text.Span;
+import dev.tamboui.text.Text;
+import dev.tamboui.tui.event.KeyEvent;
+import dev.tamboui.widgets.block.Block;
+import dev.tamboui.widgets.block.BorderType;
+import dev.tamboui.widgets.paragraph.Paragraph;
+import dev.tamboui.widgets.scrollbar.Scrollbar;
+import dev.tamboui.widgets.scrollbar.ScrollbarState;
+import org.apache.camel.util.json.JsonObject;
+
+import static org.apache.camel.dsl.jbang.core.commands.tui.MonitorContext.*;
+
+class ProcessTab implements MonitorTab {
+
+    private final MonitorContext ctx;
+    private boolean wrap;
+    private int scroll;
+    private final ScrollbarState scrollState = new ScrollbarState();
+
+    ProcessTab(MonitorContext ctx) {
+        this.ctx = ctx;
+    }
+
+    @Override
+    public boolean handleKeyEvent(KeyEvent ke) {
+        if (ke.isChar('w')) {
+            wrap = !wrap;
+            scroll = 0;
+            return true;
+        }
+        if (ke.isPageUp()) {
+            scroll = Math.max(0, scroll - 5);
+            return true;
+        }
+        if (ke.isPageDown()) {
+            scroll += 5;
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean handleEscape() {
+        return false;
+    }
+
+    @Override
+    public void navigateUp() {
+        scroll = Math.max(0, scroll - 1);
+    }
+
+    @Override
+    public void navigateDown() {
+        scroll += 1;
+    }
+
+    @Override
+    public void render(Frame frame, Rect area) {
+        IntegrationInfo info = ctx.findSelectedIntegration();
+        if (info == null) {
+            renderNoSelection(frame, area);
+            return;
+        }
+
+        List<Line> lines = new ArrayList<>();
+
+        addField(lines, "PID", info.pid);
+        addField(lines, "Name", info.name);
+        addField(lines, "Camel", info.camelVersion);
+
+        String platform = info.platform;
+        if (platform != null && info.platformVersion != null) {
+            platform = platform + " " + info.platformVersion;
+        }
+        addField(lines, "Platform", platform);
+        addField(lines, "Profile", info.profile);
+
+        String java = info.javaVersion;
+        if (java != null) {
+            StringBuilder sb = new StringBuilder(java);
+            if (info.javaVendor != null) {
+                sb.append(" (").append(info.javaVendor);
+                if (info.javaVmName != null) {
+                    sb.append(", ").append(info.javaVmName);
+                }
+                sb.append(")");
+            }
+            java = sb.toString();
+        }
+        addField(lines, "Java", java);
+        addField(lines, "Directory", info.directory);
+        addField(lines, "Uptime", info.ago);
+
+        lines.add(Line.from(Span.raw("")));
+
+        String cmdLine = getCommandLine(info.pid);
+        if (cmdLine != null) {
+            lines.add(Line.from(
+                    Span.styled("  Command Line", 
Style.EMPTY.fg(Color.CYAN).bold())));
+            lines.add(Line.from(Span.raw("")));
+            if (wrap) {
+                lines.add(Line.from(Span.raw("  " + cmdLine)));
+            } else {
+                for (String part : splitCommandLine(cmdLine)) {
+                    lines.add(Line.from(Span.raw("  " + part)));
+                }
+            }
+        }
+
+        Block block = Block.builder().borderType(BorderType.ROUNDED).title(" 
Process ").build();
+        frame.renderWidget(block, area);
+
+        Rect inner = block.inner(area);
+        int visibleHeight = Math.max(1, inner.height());
+        int visibleWidth = Math.max(1, inner.width() - 1);
+        int contentHeight;
+        if (wrap) {
+            contentHeight = 0;
+            for (Line l : lines) {
+                int w = l.width();
+                contentHeight += Math.max(1, (w + visibleWidth - 1) / 
visibleWidth);
+            }
+            contentHeight += visibleHeight;
+        } else {
+            contentHeight = lines.size();
+        }
+        int maxScroll = Math.max(0, contentHeight - visibleHeight);
+        if (scroll > maxScroll) {
+            scroll = maxScroll;
+        }
+
+        List<Rect> hChunks = Layout.horizontal()
+                .constraints(Constraint.fill(), Constraint.length(1))
+                .split(inner);
+
+        Paragraph paragraph = Paragraph.builder()
+                .text(Text.from(lines))
+                .overflow(wrap ? Overflow.WRAP_WORD : Overflow.CLIP)
+                .scroll(scroll)
+                .build();
+        frame.renderWidget(paragraph, hChunks.get(0));
+
+        if (contentHeight > visibleHeight) {
+            scrollState.contentLength(contentHeight);
+            scrollState.viewportContentLength(visibleHeight);
+            scrollState.position(scroll);
+            frame.renderStatefulWidget(
+                    Scrollbar.builder().build(),
+                    hChunks.get(1), scrollState);
+        }
+    }
+
+    @Override
+    public void renderFooter(List<Span> spans) {
+        hint(spans, "↑↓", "scroll");
+        hint(spans, "w", "wrap [" + (wrap ? "on" : "off") + "]");
+        hintLast(spans, "Esc", "back");
+    }
+
+    @Override
+    public JsonObject getTableDataAsJson() {
+        IntegrationInfo info = ctx.findSelectedIntegration();
+        if (info == null) {
+            return null;
+        }
+        JsonObject result = new JsonObject();
+        result.put("tab", "Process");
+        JsonObject data = new JsonObject();
+        data.put("pid", info.pid);
+        data.put("name", info.name);
+        data.put("camelVersion", info.camelVersion);
+        data.put("platform", info.platform);
+        data.put("platformVersion", info.platformVersion);
+        data.put("profile", info.profile);
+        data.put("javaVersion", info.javaVersion);
+        data.put("javaVendor", info.javaVendor);
+        data.put("javaVmName", info.javaVmName);
+        data.put("directory", info.directory);
+        data.put("uptime", info.ago);
+        String cmdLine = getCommandLine(info.pid);
+        if (cmdLine != null) {
+            data.put("commandLine", cmdLine);
+        }
+        result.put("process", data);
+        return result;
+    }
+
+    private void addField(List<Line> lines, String label, String value) {
+        if (value == null || value.isEmpty()) {
+            return;
+        }
+        String padded = String.format("  %-12s", label + ":");
+        lines.add(Line.from(
+                Span.styled(padded, Style.EMPTY.dim()),
+                Span.styled(value, Style.EMPTY.fg(Color.WHITE).bold())));
+    }
+
+    private static String getCommandLine(String pid) {
+        try {
+            long p = Long.parseLong(pid);
+            return ProcessHandle.of(p)
+                    .flatMap(ph -> ph.info().commandLine())
+                    .orElse(null);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    private static List<String> splitCommandLine(String cmdLine) {
+        List<String> parts = new ArrayList<>();
+        for (String token : cmdLine.split("\\s+")) {
+            if (token.startsWith("-") && !parts.isEmpty()) {
+                parts.add(token);
+            } else if (parts.isEmpty()) {
+                parts.add(token);
+            } else {
+                String last = parts.get(parts.size() - 1);
+                parts.set(parts.size() - 1, last + " " + token);
+            }
+        }
+        return parts;
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RunOptionsForm.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RunOptionsForm.java
index 3e4f6b0ae5af..6ddcce8d9b05 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RunOptionsForm.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RunOptionsForm.java
@@ -50,7 +50,8 @@ class RunOptionsForm {
     private static final int ROW_OBSERVE = 4;
     private static final int ROW_TRACE = 5;
     private static final int ROW_STUB = 6;
-    private static final int ROW_COUNT = 7;
+    private static final int ROW_OTEL_AGENT = 7;
+    private static final int ROW_COUNT = 8;
 
     private boolean visible;
     private int page;
@@ -70,6 +71,7 @@ class RunOptionsForm {
     private boolean observe;
     private boolean backlogTrace;
     private boolean stubMode;
+    private boolean otelAgent;
 
     private String exampleTitle;
 
@@ -95,6 +97,7 @@ class RunOptionsForm {
         observe = false;
         backlogTrace = false;
         stubMode = false;
+        otelAgent = false;
         selectedRow = ROW_NAME;
         page = PAGE_OPTIONS;
         selectedProperty = 0;
@@ -192,6 +195,9 @@ class RunOptionsForm {
         if (stubMode) {
             args.add("--stub=remote");
         }
+        if (otelAgent) {
+            args.add("--open-telemetry-agent");
+        }
         if (properties != null) {
             for (PropertyEntry pe : properties) {
                 String current = pe.valueInput().text();
@@ -215,7 +221,7 @@ class RunOptionsForm {
             return true;
         }
         if (ke.isDown()) {
-            if (selectedRow == ROW_STUB && hasProperties()) {
+            if (selectedRow == ROW_OTEL_AGENT && hasProperties()) {
                 page = PAGE_PROPERTIES;
                 selectedProperty = 0;
             } else {
@@ -224,7 +230,7 @@ class RunOptionsForm {
             return true;
         }
         if (ke.isFocusNext()) {
-            if (selectedRow == ROW_STUB && hasProperties()) {
+            if (selectedRow == ROW_OTEL_AGENT && hasProperties()) {
                 page = PAGE_PROPERTIES;
                 selectedProperty = 0;
             } else {
@@ -236,7 +242,7 @@ class RunOptionsForm {
             selectedRow = (selectedRow - 1 + ROW_COUNT) % ROW_COUNT;
             return true;
         }
-        if (ke.isRight() && hasProperties() && selectedRow >= ROW_STUB) {
+        if (ke.isRight() && hasProperties() && selectedRow >= ROW_OTEL_AGENT) {
             page = PAGE_PROPERTIES;
             selectedProperty = 0;
             return true;
@@ -261,6 +267,7 @@ class RunOptionsForm {
                 case ROW_OBSERVE -> observe = !observe;
                 case ROW_TRACE -> backlogTrace = !backlogTrace;
                 case ROW_STUB -> stubMode = !stubMode;
+                case ROW_OTEL_AGENT -> otelAgent = !otelAgent;
             }
             return true;
         }
@@ -287,7 +294,7 @@ class RunOptionsForm {
             editingKey = false;
             if (selectedProperty == 0) {
                 page = PAGE_OPTIONS;
-                selectedRow = ROW_STUB;
+                selectedRow = ROW_OTEL_AGENT;
             } else {
                 selectedProperty--;
             }
@@ -317,7 +324,7 @@ class RunOptionsForm {
             } else if (selectedProperty == 0) {
                 editingKey = false;
                 page = PAGE_OPTIONS;
-                selectedRow = ROW_STUB;
+                selectedRow = ROW_OTEL_AGENT;
             } else {
                 editingKey = false;
                 selectedProperty--;
@@ -333,7 +340,7 @@ class RunOptionsForm {
                     return true;
                 }
                 page = PAGE_OPTIONS;
-                selectedRow = ROW_STUB;
+                selectedRow = ROW_OTEL_AGENT;
                 editingKey = false;
                 return true;
             }
@@ -376,7 +383,7 @@ class RunOptionsForm {
 
     private void renderOptionsPage(Frame frame, Rect area) {
         int popupW = Math.min(56, area.width() - 4);
-        int popupH = 11;
+        int popupH = 12;
         int x = area.left() + Math.max(0, (area.width() - popupW) / 2);
         int y = area.top() + Math.max(0, (area.height() - popupH) / 4);
         Rect popup = new Rect(x, y, Math.min(popupW, area.width()), 
Math.min(popupH, area.height()));
@@ -441,6 +448,10 @@ class RunOptionsForm {
         rowY++;
 
         renderCheckbox(frame, innerX, rowY, innerW, "Stub (no Docker needed)", 
stubMode, selectedRow == ROW_STUB);
+        rowY++;
+
+        renderCheckbox(frame, innerX, rowY, innerW, "OTel Java Agent 
(auto-instrument)", otelAgent,
+                selectedRow == ROW_OTEL_AGENT);
     }
 
     private void renderPropertiesPage(Frame frame, Rect area) {
diff --git a/parent/pom.xml b/parent/pom.xml
index 2e6e63c36427..a830731e4a38 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -413,6 +413,7 @@
         <openstack4j-version>3.12</openstack4j-version>
         <opentelemetry-version>1.63.0</opentelemetry-version>
         <opentelemetry-alpha-version>1.63.0-alpha</opentelemetry-alpha-version>
+        <opentelemetry-proto-version>1.9.0-alpha</opentelemetry-proto-version>
         
<opentelemetry-log4j2-version>2.28.1-alpha</opentelemetry-log4j2-version>
         
<opentelemetry-incubator-version>1.43.0-alpha</opentelemetry-incubator-version>
         
<opentelemetry-semconv-version>1.30.1-alpha</opentelemetry-semconv-version>
@@ -3495,6 +3496,11 @@
                     </exclusion>
                 </exclusions>
             </dependency>
+            <dependency>
+                <groupId>io.opentelemetry.proto</groupId>
+                <artifactId>opentelemetry-proto</artifactId>
+                <version>${opentelemetry-proto-version}</version>
+            </dependency>
             <dependency>
                 <groupId>com.openai</groupId>
                 <artifactId>openai-java</artifactId>

Reply via email to