Guide for retrofitting OpenTelemetry into an existing, uninstrumented application. Trigger phrases: "migrate existing app to OTel", "add OpenTelemetry to existing project", "retrofit OTel into my codebase", "thread context through my code", "context propagation", "bridge Prometheus metrics to OTel", "logging bridge", "migrate logging to OTel", "slog bridge", "logback bridge", "verify my instrumentation", "traces are disconnected", "orphaned spans", "migrate to OpenTelemetry", "OTel migration plan", "how do I sequence an OTel migration", "add tracing to existing code", "refactor for context propagation", "Fiber context gotcha", "keep existing logging working with OTel", "add OTel without breaking Prometheus", "bridge existing metrics", "coexist with existing monitoring", or any request about retrofitting OpenTelemetry into an existing application. This skill is for migrating existing codebases, NOT greenfield instrumentation (use otel-instrumentation) or Beeline-specific migration (use beeline-migration).
From honeycombnpx claudepluginhub honeycombio/agent-skill --plugin honeycombThis skill uses the workspace's default tool permissions.
references/bridge-libraries.mdreferences/context-propagation-patterns.mdreferences/framework-middleware.mdreferences/migration-pitfalls.mdreferences/verification-checklist.mdDispatches parallel agents to independently tackle 2+ tasks like separate test failures or subsystems without shared state or dependencies.
Executes pre-written implementation plans: critically reviews, follows bite-sized steps exactly, runs verifications, tracks progress with checkpoints, uses git worktrees, stops on blockers.
Guides idea refinement into designs: explores context, asks questions one-by-one, proposes approaches, presents sections for approval, writes/review specs before coding.
Guide for retrofitting OpenTelemetry into an existing, uninstrumented application. This covers the phased migration approach, context propagation refactoring, logging and metrics bridges, and verification. This is distinct from greenfield OTel setup (see otel-instrumentation skill) and Beeline-specific migration (see beeline-migration skill).
Use this skill when the user has an existing application that:
For greenfield OTel setup, use the otel-instrumentation skill instead.
For Beeline-to-OTel migration, use the beeline-migration skill instead.
For understanding why to instrument, see the observability-fundamentals skill.
The migration follows six phases in order. Each phase is independently deployable and verifiable. Context propagation (Phase 3) is typically ~60% of the effort.
Set up TracerProvider, MeterProvider, and LoggerProvider with OTLP exporters. Wire initialization early in the application's entry point and shutdown in signal handlers.
Key guidance:
${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/sdk-setup-by-language.mdAdd OTel middleware to your HTTP framework. This gives you automatic spans for every inbound request with zero code changes to handlers. This is the highest-ROI step.
Critical: Different frameworks expose the OTel-enriched context differently. This is the #1
source of silent trace breaks. Consult
${CLAUDE_PLUGIN_ROOT}/skills/otel-migration/references/framework-middleware.md for
framework-specific details.
| Framework | How to get OTel context | Common mistake |
|---|---|---|
| Go net/http | r.Context() | N/A (standard) |
| Go Fiber v2 | c.UserContext() | Using c.Context() (returns fasthttp context without OTel span) |
| Go Gin | c.Request.Context() | Using c directly |
| Go Echo | c.Request().Context() | N/A |
| Python Flask | Automatic (thread-local) | N/A with instrumentation library |
| Python Django | Automatic (thread-local) | N/A with instrumentation library |
| Node.js Express | Automatic (AsyncLocalStorage) | N/A with instrumentation library |
| Java Spring | Automatic (thread-local) | Thread pool context loss |
| .NET ASP.NET Core | Automatic (AsyncLocal) | N/A |
| Ruby Rails | Automatic (thread-local) | N/A with instrumentation library |
Thread trace context through your call chain from HTTP handlers (or entry points) down to I/O operations. This is the hardest phase — typically ~60% of migration effort.
The difficulty of this phase varies dramatically by language:
context.Context parameter to every function in the call chain.contextvars propagates automatically within a thread. Pain points are
thread pools and multiprocessing.AsyncLocalStorage propagates through async/await automatically.
Pain points are old callback-based code.Activity propagates through async/await via AsyncLocal<T> automatically.For language-specific patterns and code examples, consult
${CLAUDE_PLUGIN_ROOT}/skills/otel-migration/references/context-propagation-patterns.md.
Add spans to business logic operations that auto-instrumentation doesn't cover. Defer to the
otel-instrumentation skill for span creation mechanics. Migration-specific guidance:
For attribute naming and span creation patterns, consult
${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/custom-instrumentation.md.
Replace or bridge your existing logging library into OTel so logs correlate with traces.
Key guidance:
For language-specific logging bridges and the multi-handler pattern, consult
${CLAUDE_PLUGIN_ROOT}/skills/otel-migration/references/bridge-libraries.md.
If you already have Prometheus metrics (or another metrics library), bridge them to OTel rather than rewriting.
Key guidance:
prometheus.NewCounterVec(...) calls continue unchanged/metrics endpoint if you have existing scrapers. The bridge adds OTLP
export in addition to scraping.For language-specific metrics bridges, consult
${CLAUDE_PLUGIN_ROOT}/skills/otel-migration/references/bridge-libraries.md.
After each phase, verify that instrumentation is correct and complete. Consult
${CLAUDE_PLUGIN_ROOT}/skills/otel-migration/references/verification-checklist.md for the
full checklist and query patterns.
For Honeycomb-specific verification queries, also consult the query-patterns skill.
For a catalog of common mistakes and how to avoid them, consult
${CLAUDE_PLUGIN_ROOT}/skills/otel-migration/references/migration-pitfalls.md.
For reference, a real migration of Gatus (~30k LOC Go, Fiber v2, SQLite/Postgres, Prometheus):
c.Context() vs c.UserContext(), printf-style slog format strings,
missing span.End() calls, goroutine context reuse