[
https://issues.apache.org/jira/browse/CAMEL-23709?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18086884#comment-18086884
]
Claus Ibsen commented on CAMEL-23709:
-------------------------------------
## Analysis & Implementation Plan
_Claude Code on behalf of Claus Ibsen_
### Problem
EIPs like `to`, `toD`, `wireTap`, and `enrich` create two spans: an
EVENT_PROCESS processor span and an EVENT_SENT event span, in a parent-child
relationship. The processor span adds no value because the event span already
captures the destination, timing, and status. This doubles the span tree depth
unnecessarily.
For example, when `to` sends to `kafka://orders`, the span tree shows:
{noformat}
to7 (EVENT_PROCESS) ← redundant wrapper
kafka://orders (EVENT_SENT) ← the useful one
{noformat}
The TUI SpansTab already works around this with client-side span collapsing
(merging EVENT_PROCESS with its single EVENT_SENT child), but the root cause is
that the instrumentation creates redundant spans.
### Proposed Solution: EndpointSpannable marker interface
Introduce a pure marker interface `EndpointSpannable` in `camel-api`.
Processors that implement it signal "I will produce my own endpoint span via
ExchangeSendingEvent — skip the processor span."
{code:java}
public interface EndpointSpannable {
}
{code}
The telemetry intercept strategy (`TraceProcessorsInterceptStrategy`) checks
`processor instanceof EndpointSpannable` and skips `beginProcessorSpan()` /
`endProcessorSpan()` for those processors.
### Processors to implement EndpointSpannable
|| Processor || EIP || Emits EVENT_SENT via ||
| `SendProcessor` | `to` | Direct `EventHelper.notifyExchangeSending()` |
| `SendDynamicProcessor` | `toD` | `DefaultProducerCache` |
| `WireTapProcessor` | `wireTap` | Delegates to `SendDynamicProcessor` |
| `Enricher` | `enrich` | `DefaultProducerCache` |
*Not included:* `PollEnricher` / `PollProcessor` — these use `ConsumerCache`
(poll/receive), not `ProducerCache` (send). They do NOT emit
`ExchangeSendingEvent`, so skipping their processor span would lose visibility
entirely.
### Why a marker interface (not hardcoded class names)
- All four processors extend `BaseProcessorSupport → AsyncProcessorSupport`
which implements `AsyncProcessor`, so the `instanceof` check works directly on
the `processor` field in `TraceProcessor` (no bridge wrapping)
- Clean API contract — third-party components can implement it too
- Follows existing Camel marker interface patterns (`Suspendable`,
`AsyncEndpoint`, `NonManagedService`)
- `TraceProcessorsOtelInterceptStrategy` is NOT modified — it handles OTel
scope/baggage propagation (not span creation) and should wrap all processors
unconditionally
### Files to modify
1. `core/camel-api` — new `EndpointSpannable.java` marker interface
2. `core/camel-core-processor` — add `EndpointSpannable` to `SendProcessor`,
`SendDynamicProcessor`, `WireTapProcessor`, `Enricher`
3. `components/camel-telemetry` — skip processor span for `EndpointSpannable`
in `TraceProcessorsInterceptStrategy`
> camel-opentelemtry2 - Span verbosity for core processors that also emit events
> ------------------------------------------------------------------------------
>
> Key: CAMEL-23709
> URL: https://issues.apache.org/jira/browse/CAMEL-23709
> Project: Camel
> Issue Type: Improvement
> Components: camel-opentelemetry
> Reporter: Claus Ibsen
> Priority: Major
>
> For EIPs such as to / wireTap / toD and others that emit events (send an
> outgoing message ) then you get double spans, one as a processor and one as
> the event, and they get into a parent/child relationship - which makes the
> span tree very deep.
> IMHO the processor spans should only be for EIPS that do not emit events such
> as split, aggregate, etc.
> The core span has no value for the to, as the value is the span about sending
> event, to capture where its being sent, etc.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)