debug-missing-spans
Troubleshoot when expected OpenTelemetry spans don't reach the backend.
Skill by jagreehal
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/jagreehal-debug-missing-spans
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: backend, cloud, security
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/debug-missing-spans
What's inside
- Skill name
debug-missing-spans- Description
- Troubleshoot when expected OpenTelemetry spans don't reach the backend. Walks the chain top-to-bottom — code → SDK init → sampler → processor → exporter → network → backend ingest — with concrete tests at each step. Covers a missing endpoint, sampling drops, ctx.waitUntil drops on Cloudflare, init-order races, propagation breaks, exporter auth errors, and silent ratelimits.
- License
- Apache-2.0
- Instructions
- 259 lines in SKILL.md · view on GitHub
Before installing
- Instructions call the network
Files (1)
- SKILL.md
SKILL.md (first lines)
# Debug missing spans
When a span you expect isn't in the backend, the cause is somewhere in this chain:
```
code → SDK init → sampler → processor → exporter → network → backend ingest → backend index
```
This skill walks each link in order with a quick check you can run. Don't skip steps. The cause is rarely where you'd guess.
## Check these three first
1. **No endpoint, no export.** Node `init()` has no default endpoint and no
localhost fallback. Without `endpoint`, `destinations`, `spanExporters`,
`spanProcessors` or `OTEL_EXPORTER_OTLP_ENDPOINT`, no exporter is built and
every span is silently discarded. Set one:
```typescript
init({ service: 'my-app', endpoint: 'http://localhost:4318' });
```
`endpoint` is the base URL; autotel appends `/v1/traces`, `/v1/metrics`
and `/v1/logs`.
2. **Sampling.** With `sampling: 'production'` (or
`samplingPresets.production()`), about 90 % of fast, successful spans from
`trace()` / `withTracing()` / `instrument()` are dropped on export, and each
wrapped span decides on its own. Reproduce with `sampling: 'development'`.
See [`tune-sampling`](../tune-sampling/SKILL.md).
3. **Two copies of `@opentelemetry/api` (Next.js, bundlers).** An
instrumentation on a different API copy than autotel sends its spans to a
provider nobody exports from. `init()` warns and names it. Under Next.js,
use `withAutotelConfig` from `autotel-adapters/next-config` and add
`@opentelemetry/api` to the app's dependencies.
## Step 0: Reproduce locally with the pretty exporter
Before chasing remote backends, confirm the span exists at all:
```typescript
init({
service: 'my-app',
debug: 'pretty', // hierarchical colourised output to stdout
sampling: 'development', // keep everything while reproducing
});
```
The pretty exporter prints one tree per trace when the trace's root span ends; a trace whose root never exports prints after two idle seconds, and `flush()` prints anything still waiting. If you see the span in stdout, the code and sampler are fine. Skip to "exporter / network". If you don't, keep reading.
## Step 1: Is the SDK actually initialised?
Common failure: `init()` runs after the code you expect to trace, or after the
library you expect auto-instrumented was imported.
```typescript
import { isInitialized } from 'autotel';
console.log('[autotel-debug] initialised:', isInitialized());
```
If `false`, `init()` has not run. Move it to the very top of the entry file (or to `instrumentation.ts` for Next.js). Wrapping a function with `trace()` at module load is fine; calling it before `init()` is not.
Auto-instrumented spans (HTTP, pg, pino, …) need three things: the library
listed in `autoInstrumentations` (it is off by default), the
`@opentelemetry/auto-instrumentations-node` package installed, and `init()`
running before the library is imported. Under ESM, start node with
`--import autotel/register`. `init()` prints a console warning for a missing
loader hook or a logger loaded too early.
## Step 2: Sampler
- `sampling: 'production'` / `'errors-only'` drop fast, successful wrapped
spans; `'off'` drops all of them.
- A `sampler` passed to a single `trace()` / `withTracing()` / `instrument()`
overrides the one from `init()`.
- With neither `sampling` nor `sampler`, `OTEL_TRACES_SAMPLER` /
`OTEL_TRACES_SAMPLER_ARG` from the environment set the SDK head sampler.
To keep one request whatever the sampler says, call `forceKeep()` in its span,
or send `baggage: autotel.debug=1` (read where incoming context is extracted).
Edge (`autotel-edge` / `autotel-cloudflare`): check `sampling.headSampler`
(a `{ ratio }` stops spans being recorded) and `sampling.tailSampler`.
`getActiveConfig()` from `autotel-edge` returns the resolved edge config.
## Step 3: Cloudflare Workers: `ctx.waitUntil`
The single biggest cause of missing spans on the edge: **the response returned before the exporter flushed**.
If you're using `addEventListener('fetch', …)` or a hand-rolled `fetch` in a module worker without wiring `ctx.waitUntil(…)` to the export call, async drains drop silently. `autotel-edge` also warns once when the config has no `exporter` and no `spanProcessors`.
Fix. Switch to `defineWorkerFetch` or `wrapModule`, both of which wire `waitUntil` automatically:
```typescript
import { defineWorkerFetch } from 'autotel-cloudflare';
export default defineWorkerFetch(
{
service: { name: 'edge' },
exporter: { url: 'https://otlp.example.com/v1/traces' },
},
async (request, env, ctx, log) => {
// log.set / spans here all flush via ctx.waitUntil before response returns
return new Response('ok');
},
);
```
## Step 4: Processor pipeline
Read the `init()` call, not the provider internals. Common issues:
- **`spanFilter` returns `false` for your span.** It wraps every processor.
- **A `FilteringSpanProcessor` you added drops it.** Its `filter` must return `true` to keep.
- **`TailSamplingSpanProcessor` dropped it** (fast, successful, not force-kept).
- **`spanProcessors: []`** is an explicit off switch: nothing is exported.
- **Edge only: a `postProcessor` / `composePostProcessors` step returns `[]` for your span.**From jagreehal/autotel, Apache-2.0.
More from jagreehal/autotel
- 0.631score
find-observability-gaps
jagreehal
Scores the observability of every entry point in a codebase with `autotel map` and closes the gaps it reports.
SkillAFreshness: A★ 8Claude Code +9 - 0.631score
build-audit-trails
jagreehal
Build or review tamper-aware audit trails on top of OpenTelemetry spans using autotel and the autotel-audit package (`withAudit`, `setAuditAttributes`…
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-anti-patterns
jagreehal
Common autotel mistakes and how to fix them.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-testing
jagreehal
Test autotel instrumentation with createTraceCollector() and InMemorySpanExporter.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-core
jagreehal
Explains when to reach for trace vs span vs request logger vs events in Autotel, and the package exports each lives behind.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
migrate-to-autotel
jagreehal
Migrate an existing observability setup to autotel.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
production-observability
jagreehal
Takes a Node.js or TypeScript service to production-grade observability with autotel, in an existing codebase or a new one, and keeps it there.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
analyze-traces
jagreehal
Analyze OpenTelemetry traces and structured logs from a running autotel service to debug errors, investigate latency, follow requests across services, and…
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-investigate
jagreehal
Query OpenTelemetry telemetry (traces, metrics, logs, LLM analytics) via the autotel CLI.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-framework-setup
jagreehal
Set up autotel in Hono, Fastify, TanStack Start, Cloudflare Workers, Next.js, Express, MCP, and edge runtimes.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-request-logging
jagreehal
Accumulates request-scoped context and emits one wide-event snapshot per request with getRequestLogger(), set(), setLevel(), info/warn/error, and emitNow().
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-structured-errors
jagreehal
Throws and parses errors that explain themselves with message, why, fix, link, and status, including reusable catalogs via defineErrorCatalog.
SkillAFreshness: A★ 8Claude Code +9
Signals
- Stars
- 8
- Forks
- 3
- Open issues
- 0
- Last commit (this folder)
- Oct 20, 2026 (8 days ago)
- Last release
- Sep 27, 2026 (1 month ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- Apache-2.0
- Repository
- github.com/jagreehal/autotel
- Website
- jagreehal.github.io/autotel/
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from jagreehal
- 0.631score
find-observability-gaps
jagreehal
Scores the observability of every entry point in a codebase with `autotel map` and closes the gaps it reports.
SkillAFreshness: A★ 8Claude Code +9 - 0.631score
build-audit-trails
jagreehal
Build or review tamper-aware audit trails on top of OpenTelemetry spans using autotel and the autotel-audit package (`withAudit`, `setAuditAttributes`…
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-anti-patterns
jagreehal
Common autotel mistakes and how to fix them.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-testing
jagreehal
Test autotel instrumentation with createTraceCollector() and InMemorySpanExporter.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-core
jagreehal
Explains when to reach for trace vs span vs request logger vs events in Autotel, and the package exports each lives behind.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-investigate
jagreehal
Query OpenTelemetry telemetry (traces, metrics, logs, LLM analytics) via the autotel CLI.
SkillAFreshness: A★ 8Claude Code +9
Cite this page
debug-missing-spans skill. Agent Mart. https://agentmart.dev/skills/jagreehal-debug-missing-spans (last updated 2026-10-24)