You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2026/07/11 20:45:39 UTC
(camel) 01/01: CAMEL-24003: Enrich activity data with span decorator attributes from camel-telemetry
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch feature/CAMEL-24003-activity-span-enrichment
in repository https://gitbox.apache.org/repos/asf/camel.git
commit 684b49dcda6ff3a27711c309288448ef89850b40
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sat Jul 11 22:45:24 2026 +0200
CAMEL-24003: Enrich activity data with span decorator attributes from camel-telemetry
Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
Signed-off-by: Claus Ibsen <cl...@gmail.com>
---
.../org/apache/camel/telemetry/RecordingSpan.java | 78 ++++++++++++++++++++++
.../java/org/apache/camel/telemetry/Tracer.java | 26 +++++++-
.../src/main/java/org/apache/camel/Exchange.java | 8 +++
.../java/org/apache/camel/ExchangePropertyKey.java | 5 +-
.../java/org/apache/camel/spi/BacklogTracer.java | 9 +++
5 files changed, 124 insertions(+), 2 deletions(-)
diff --git a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/RecordingSpan.java b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/RecordingSpan.java
new file mode 100644
index 000000000000..28f40223d963
--- /dev/null
+++ b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/RecordingSpan.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.telemetry;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * A {@link Span} wrapper that records all {@code setTag} and {@code setComponent} calls into a {@link Map} while
+ * delegating every operation to the underlying span. This is used to capture span decorator attributes for the
+ * BacklogTracer activity enrichment without running decorator logic twice.
+ * <p>
+ * The recording is only activated when the BacklogTracer activity feature is enabled, so in production there is no
+ * wrapping overhead.
+ */
+class RecordingSpan implements Span {
+
+ private final Span delegate;
+ private final Map<String, String> tags = new LinkedHashMap<>();
+
+ RecordingSpan(Span delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void setTag(String key, String value) {
+ delegate.setTag(key, value);
+ if (value != null) {
+ tags.put(key, value);
+ }
+ }
+
+ @Override
+ public void setComponent(String component) {
+ delegate.setComponent(component);
+ if (component != null) {
+ tags.put("component", component);
+ }
+ }
+
+ @Override
+ public void setError(boolean isError) {
+ delegate.setError(isError);
+ }
+
+ @Override
+ public void log(Map<String, String> fields) {
+ delegate.log(fields);
+ }
+
+ /**
+ * Returns the real span that this wrapper delegates to.
+ */
+ Span getDelegate() {
+ return delegate;
+ }
+
+ /**
+ * Returns the recorded tags as an unmodifiable snapshot.
+ */
+ Map<String, String> getRecordedTags() {
+ return Map.copyOf(tags);
+ }
+}
diff --git a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/Tracer.java b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/Tracer.java
index 40d148fd5c88..91806d3fd62c 100644
--- a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/Tracer.java
+++ b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/Tracer.java
@@ -24,11 +24,13 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePropertyKey;
import org.apache.camel.NamedNode;
import org.apache.camel.Route;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.StaticService;
import org.apache.camel.api.management.ManagedAttribute;
+import org.apache.camel.spi.BacklogTracer;
import org.apache.camel.spi.CamelEvent;
import org.apache.camel.spi.CamelLogger;
import org.apache.camel.spi.CamelTracingService;
@@ -68,6 +70,7 @@ public abstract class Tracer extends ServiceSupport implements CamelTracingServi
private final TracingEventNotifier eventNotifier = new TracingEventNotifier();
private final SpanStorageManager spanStorageManager = new SpanStorageManagerExchange();
private final SpanDecoratorManager spanDecoratorManager = new SpanDecoratorManagerImpl();
+ private boolean activityEnabled;
/*
* It has to be provided by the specific implementation
@@ -209,6 +212,13 @@ public abstract class Tracer extends ServiceSupport implements CamelTracingServi
InterceptStrategy interceptStrategy = new TraceProcessorsInterceptStrategy(this);
camelContext.getCamelContextExtension().addInterceptStrategy(interceptStrategy);
+ // check if BacklogTracer activity is enabled so we can enrich activity data with span attributes
+ BacklogTracer backlogTracer
+ = camelContext.getCamelContextExtension().getContextPlugin(BacklogTracer.class);
+ if (backlogTracer != null) {
+ activityEnabled = backlogTracer.isActivityEnabled();
+ }
+
initTracer();
ServiceHelper.startService(eventNotifier);
}
@@ -349,7 +359,21 @@ public abstract class Tracer extends ServiceSupport implements CamelTracingServi
Span span = spanLifecycleManager.create(spanName, spanKind, parentSpan,
spanDecorator.getExtractor(exchange));
span.setTag(TagConstants.OP, op.toString());
- spanDecorator.beforeTracingEvent(span, exchange, endpoint);
+
+ if (activityEnabled && op == Op.EVENT_SENT) {
+ // wrap with recording span to capture decorator attributes for activity enrichment
+ RecordingSpan recording = new RecordingSpan(span);
+ spanDecorator.beforeTracingEvent(recording, exchange, endpoint);
+ // store recorded tags on exchange for BacklogTracer activity to pick up
+ Map<String, String> tags = recording.getRecordedTags();
+ if (!tags.isEmpty()) {
+ exchange.setProperty(ExchangePropertyKey.ACTIVITY_SPAN_TAGS, tags);
+ }
+ // continue with the real span for activation/storage
+ } else {
+ spanDecorator.beforeTracingEvent(span, exchange, endpoint);
+ }
+
spanLifecycleManager.activate(span);
spanStorageManager.push(exchange, span);
spanLifecycleManager.inject(span, spanDecorator.getInjector(exchange), this.traceHeadersInclusion);
diff --git a/core/camel-api/src/main/java/org/apache/camel/Exchange.java b/core/camel-api/src/main/java/org/apache/camel/Exchange.java
index 27607438f0a8..ac8ec7044d75 100644
--- a/core/camel-api/src/main/java/org/apache/camel/Exchange.java
+++ b/core/camel-api/src/main/java/org/apache/camel/Exchange.java
@@ -327,6 +327,14 @@ public interface Exchange extends VariableAware {
String OTEL_ACTIVE_SPAN = "OpenTracing.activeSpan";
@Deprecated(since = "4.19.0")
String OTEL_CLOSE_CLIENT_SCOPE = "OpenTracing.closeClientScope";
+ /**
+ * Exchange property set by tracing implementations (e.g., camel-telemetry) containing span decorator attributes as a
+ * {@code Map<String, String>}. Used by the BacklogTracer activity feature to enrich endpoint send entries with
+ * component-specific details (e.g., Kafka topic, SQL query, HTTP method).
+ *
+ * @since 4.22
+ */
+ String ACTIVITY_SPAN_TAGS = "CamelActivitySpanTags";
/**
* Returns the {@link ExchangePattern} (MEP) of this exchange.
diff --git a/core/camel-api/src/main/java/org/apache/camel/ExchangePropertyKey.java b/core/camel-api/src/main/java/org/apache/camel/ExchangePropertyKey.java
index 8b4dd6415e0c..c3d9ed220f05 100644
--- a/core/camel-api/src/main/java/org/apache/camel/ExchangePropertyKey.java
+++ b/core/camel-api/src/main/java/org/apache/camel/ExchangePropertyKey.java
@@ -100,7 +100,8 @@ public enum ExchangePropertyKey {
@Deprecated(since = "4.19.0")
OTEL_ACTIVE_SPAN(Exchange.OTEL_ACTIVE_SPAN),
@Deprecated(since = "4.19.0")
- OTEL_CLOSE_CLIENT_SCOPE(Exchange.OTEL_CLOSE_CLIENT_SCOPE);
+ OTEL_CLOSE_CLIENT_SCOPE(Exchange.OTEL_CLOSE_CLIENT_SCOPE),
+ ACTIVITY_SPAN_TAGS(Exchange.ACTIVITY_SPAN_TAGS);
private final String name;
@@ -246,6 +247,8 @@ public enum ExchangePropertyKey {
// Deprecated since 4.19.0
case Exchange.OTEL_CLOSE_CLIENT_SCOPE:
return OTEL_CLOSE_CLIENT_SCOPE;
+ case Exchange.ACTIVITY_SPAN_TAGS:
+ return ACTIVITY_SPAN_TAGS;
default:
return null;
}
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/BacklogTracer.java b/core/camel-api/src/main/java/org/apache/camel/spi/BacklogTracer.java
index d56acdc2dde5..2596cd53ee3d 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/BacklogTracer.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/BacklogTracer.java
@@ -43,6 +43,15 @@ import org.jspecify.annotations.Nullable;
*/
public interface BacklogTracer {
+ /**
+ * Whether the activity tracking feature is enabled.
+ *
+ * @since 4.22
+ */
+ default boolean isActivityEnabled() {
+ return false;
+ }
+
/**
* Is the tracer enabled.
*/