|
| 1 | +# OTEL Logs Missing While Traces Work |
| 2 | + |
| 3 | +Use this runbook when traces are visible but application logs are missing in |
| 4 | +Grafana Loki. |
| 5 | + |
| 6 | +## Symptoms |
| 7 | + |
| 8 | +- Traces for a service are visible in Tempo/Grafana. |
| 9 | +- Loki mostly shows infrastructure logs (for example `traefik`). |
| 10 | +- Application logs for the same service are absent. |
| 11 | + |
| 12 | +## Decision Tree |
| 13 | + |
| 14 | +1. **Collector receives logs?** |
| 15 | + - If no: issue is app emission or app-to-collector transport. |
| 16 | + - If yes: continue. |
| 17 | +2. **Collector exports logs successfully?** |
| 18 | + - If no: issue is collector exporter config/connectivity. |
| 19 | + - If yes: continue. |
| 20 | +3. **Loki indexes expected service label?** |
| 21 | + - If no: issue is label/resource mapping. |
| 22 | + - If yes: continue. |
| 23 | +4. **Direct Loki `query_range` returns service logs?** |
| 24 | + - If no: issue is ingest/drop path or tenant mismatch. |
| 25 | + - If yes: issue is Grafana query/time range/datasource config. |
| 26 | + |
| 27 | +## Commands |
| 28 | + |
| 29 | +Run on the observability host (example machine: `pophub`). |
| 30 | + |
| 31 | +```bash |
| 32 | +docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}' \ |
| 33 | + | egrep -i 'loki|tempo|otel|collector|traefik|edge-graphql' |
| 34 | + |
| 35 | +docker logs --since 15m otel-collector 2>&1 \ |
| 36 | + | grep -Ei 'otlp|logs|export|loki|error|dropped|failed' |
| 37 | + |
| 38 | +docker logs --since 15m loki 2>&1 \ |
| 39 | + | grep -Ei 'error|warn|otlp|push|query' |
| 40 | +``` |
| 41 | + |
| 42 | +If Loki is not bound on host `localhost:3100`, run queries from a container on |
| 43 | +the same Docker network: |
| 44 | + |
| 45 | +```bash |
| 46 | +docker run --rm --network traefik curlimages/curl:8.10.1 \ |
| 47 | + -sG 'http://loki:3100/loki/api/v1/label/service_name/values' |
| 48 | +``` |
| 49 | + |
| 50 | +Use range queries for log streams: |
| 51 | + |
| 52 | +```bash |
| 53 | +START_NS=$(($(date -u +%s)-1800))000000000 |
| 54 | +END_NS=$(date -u +%s)000000000 |
| 55 | + |
| 56 | +docker run --rm --network traefik curlimages/curl:8.10.1 \ |
| 57 | + -sG 'http://loki:3100/loki/api/v1/query_range' \ |
| 58 | + --data-urlencode 'query={service_name="on-the-edge"}' \ |
| 59 | + --data-urlencode "start=${START_NS}" \ |
| 60 | + --data-urlencode "end=${END_NS}" \ |
| 61 | + --data-urlencode 'limit=100' |
| 62 | +``` |
| 63 | + |
| 64 | +## Application-Side Root Cause Seen In This Repo |
| 65 | + |
| 66 | +`OtelStream` emits logs through the global OpenTelemetry `LoggerProvider`. |
| 67 | +If that provider is created without processors, `emit()` calls do not export. |
| 68 | + |
| 69 | +Required provider wiring: |
| 70 | + |
| 71 | +- Create `BatchLogRecordProcessor` with `OTLPLogExporter`. |
| 72 | +- Pass it to `LoggerProvider` via `processors: [...]`. |
| 73 | +- Set the provider globally with `logs.setGlobalLoggerProvider(...)`. |
| 74 | +- Shutdown the provider on app close to flush batched records. |
| 75 | + |
| 76 | +## Remediation Checklist |
| 77 | + |
| 78 | +- Verify `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` is reachable from app runtime. |
| 79 | +- Verify collector logs pipeline has receiver + processors + Loki exporter. |
| 80 | +- Verify Loki label keys used in queries (`service_name` vs `service.name`). |
| 81 | +- Verify app logger provider includes processors. |
| 82 | +- Verify graceful shutdown flush for logger provider. |
0 commit comments