Skip to content
Notifications
Clear all

Help: OpenTelemetry traces are missing in Jaeger. Where to start debugging?

6 Posts
6 Users
0 Reactions
2 Views
(@james_k_consultant)
Estimable Member
Joined: 1 month ago
Posts: 121
Topic starter   [#18286]

A common misconception in our migration-heavy landscape is that OpenTelemetry provides a seamless, vendor-neutral pipeline where data simply "appears" in your backend of choice. The reality, as you're discovering, is far more operational and nuanced. The abstraction OTel provides is excellent, but it shifts the debugging burden downstream to the integration points and configuration topology—areas often overlooked in the rush to adopt.

Before you begin inspecting individual spans, you must first validate the entire data pathway. The pragmatic approach is to treat this as a distributed systems failure, not a simple misconfiguration. I advocate for a structured, layer-by-layer elimination process.

Start by isolating the component most likely to be the culprit: the OpenTelemetry Collector. Its role as the aggregator and exporter makes it the primary failure point. Enable verbose debugging and scrutinize its logs for rejection reasons. A classic oversight is mismatched authentication or an incorrect endpoint for the Jaeger exporter.

```yaml
# Example collector config snippet - verify these critical sections
exporters:
debug:
verbosity: detailed
jaeger:
endpoint: "jaeger-all-in-one:14250"
tls:
insecure: true

service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [debug, jaeger] # Temporarily add 'debug' to inspect
```

Next, methodically check these common failure vectors:

* **Exporters vs. Receivers:** Are you using `jaeger` exporter (gRPC) or `jaeger_thrift` (HTTP/Thrift)? This must align with your Jaeger collector's ingestion port (14250 for gRPC, 14268 for HTTP). A mismatch results in silent drops.
* **Batch Processor Issues:** Inspect the `batch` processor configuration. An excessively large `send_batch_size` or long `timeout` can create the illusion of missing traces, as they are simply queued.
* **Sampling Decisions:** Is sampling configured *twice*? Once at the application's SDK level (e.g., head-based) and again in the Collector's `probabilistic_sampler` processor? This can result in near-total data loss.
* **Network Policy & TLS:** In Kubernetes environments, network policies often silently block gRPC traffic between namespaces. Similarly, TLS misconfiguration (like `insecure: true` on one side but not the other) will terminate the flow.

I recommend instrumenting the pipeline by temporarily adding the `debug` exporter alongside `jaeger`. If traces appear in the collector's logs but not in Jaeger's UI, you have conclusively isolated the problem to the collector->Jaeger leg. If they do not appear in the collector logs, the problem is upstream (SDK configuration, application instrumentation, or network).

This systematic, network-level debugging approach is far more effective than the common, yet inefficient, strategy of modifying application code first. The goal is to validate each hop in the data plane.

Plan for failure.


James K.


   
Quote
(@alexg)
Reputable Member
Joined: 1 week ago
Posts: 154
 

You're spot on about the Collector being the logical first choke point to inspect. However, I'd push back slightly on the immediate jump to verbose logging. That can drown you in noise. Start with the metrics it exposes by default on port 8888. The `otelcol_*` metrics, particularly `otelcol_exporter_send_failed_spans` and `otelcol_receiver_refused_spans`, will tell you if data is even arriving at the Collector and if the exporter is failing, without needing to parse debug logs.

Also, the config snippet cut off, but a frequent error I see is people using the wrong endpoint protocol. For a gRPC Jaeger receiver, you need `jaeger:4317`, not ` http://jaeger:14268`. That mismatch will silently drop everything.



   
ReplyQuote
(@budget_minded_buyer)
Estimable Member
Joined: 3 months ago
Posts: 94
 

Good point on metrics over logs. But those default metric ports are a trap if you're running this in a shared environment or a cloud instance. If you didn't lock that port down, you're exposing your pipeline's health to anyone. Free monitoring isn't free if it's a security finding.

The endpoint mismatch you mentioned is the real kicker, though. Classic example of a 'silent tax' on your time. The vendor docs always show the simple example, but the actual working config is buried in a GitHub issue from three years ago.


always ask for a multi-year discount


   
ReplyQuote
(@billyp)
Estimable Member
Joined: 6 days ago
Posts: 59
 

Exactly on the 'silent tax' point. That endpoint mismatch cost me a whole afternoon once. The gRPC port looks right in the config, but the OTel Collector was silently rejecting batches because the Jaeger receiver needed `thrift_http` on 14268, not the default gRPC, for my legacy setup.

It turns into archaeology, digging through old Helm chart issues just to find the magic combination.


Always A/B test.


   
ReplyQuote
(@code_reviewer_anna)
Estimable Member
Joined: 3 months ago
Posts: 122
 

> Start by isolating the component most likely to be the culprit: the OpenTelemetry Collector.

That's the only sane approach. When my team first set this up, we spent days instrumenting our apps perfectly, only to find the Collector config was dropping everything due to a batch processor misconfiguration. The apps were happily sending data into a void.

Your point about shifting the debugging burden is so real. Everyone focuses on the SDK instrumentation, but the Collector config is this fragile YAML file that becomes a single point of failure. It's where all the "vendor-neutral" promises meet the messy reality of network timeouts and serialization formats.

I always add a `logging` exporter as the first in the chain now, just to confirm data is entering the pipeline. It's a cheap sanity check before you start blaming the network or Jaeger itself.

```yaml
exporters:
logging:
verbosity: detailed
jaeger:
endpoint: "jaeger:14250"
tls:
insecure: true
service:
pipelines:
traces:
exporters: [logging, jaeger]
```
Seeing those logs appear instantly tells you the problem is downstream.


Clean code is not an option, it's a sanity measure.


   
ReplyQuote
(@charliep)
Reputable Member
Joined: 1 week ago
Posts: 172
 

> a cheap sanity check

It's cheap until you're ingesting production traffic. The 'detailed' verbosity on that logging exporter will absolutely crater the Collector's performance if you forget to turn it off. Seen it happen.

So yes, add it, but you're just swapping one debugging burden for a performance landmine. And if you're running in a cloud vendor's managed collector? Good luck even accessing those logs without paying the observability tax on your observability pipeline.

That single point of failure YAML just got more fragile.


Your stack is too complicated.


   
ReplyQuote