Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Monitoring, logging, and tracing implementation using OpenTelemetry as the unified standard. Use when building production systems requiring visibility into performance, errors, and behavior. Covers OpenTelemetry (metrics, logs, traces), Prometheus, Grafana, Loki, Jaeger, Tempo, structured logging (structlog, tracing, slog, pino), and alerting.
.claude/skills/ancoleman-implementing-observability/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✗→✓ | ▲ Improved | 101% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 200% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 496% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 125% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 129% | 0% |
Implement production-grade observability using OpenTelemetry as the 2025 industry standard. Covers the three pillars (metrics, logs, traces), LGTM stack deployment, and critical log-trace correlation patterns.
Use when:
Skip if:
OpenTelemetry is the CNCF graduated project unifying observability:
┌────────────────────────────────────────────────────────┐
│ OpenTelemetry: The Unified Standard │
├────────────────────────────────────────────────────────┤
│ │
│ ONE SDK for ALL signals: │
│ ├── Metrics (Prometheus-compatible) │
│ ├── Logs (structured, correlated) │
│ ├── Traces (distributed, standardized) │
│ └── Context (propagates across services) │
│ │
│ Language SDKs: │
│ ├── Python: opentelemetry-api, opentelemetry-sdk │
│ ├── Rust: opentelemetry, tracing-opentelemetry │
│ ├── Go: go.opentelemetry.io/otel │
│ └── TypeScript: @opentelemetry/api │
│ │
│ Export to ANY backend: │
│ ├── LGTM Stack (Loki, Grafana, Tempo, Mimir) │
│ ├── Prometheus + Jaeger │
│ ├── Datadog, New Relic, Honeycomb (SaaS) │
│ └── Custom backends via OTLP protocol │
│ │
└────────────────────────────────────────────────────────┘Context7 Reference: /websites/opentelemetry_io (Trust: High, Snippets: 5,888, Score: 85.9)
Track system health and performance over time.
Metric Types: Counters (always increase), Gauges (up/down), Histograms (distributions), Summaries (percentiles).
Brief Example (Python):
pythonfrom opentelemetry import metrics meter = metrics.get_meter(__name__) http_requests = meter.create_counter("http.server.requests") http_requests.add(1, {"method": "GET", "status": 200})
Record discrete events with context.
CRITICAL: Always inject trace_id/span_id for log-trace correlation.
Brief Example (Python + structlog):
pythonimport structlog from opentelemetry import trace logger = structlog.get_logger() span = trace.get_current_span() ctx = span.get_span_context() logger.info( "processing_request", trace_id=format(ctx.trace_id, '032x'), span_id=format(ctx.span_id, '016x'), user_id=user_id )
See: references/structured-logging.md for complete configuration.
Track request flow across distributed services.
Key Concepts: Trace (end-to-end journey), Span (individual operation), Parent-Child (nested operations).
Brief Example (Python + FastAPI):
pythonfrom opentelemetry.instrumentation.fastapi import FastAPIInstrumentor app = FastAPI() FastAPIInstrumentor.instrument_app(app) # Auto-traces all HTTP requests
See: references/opentelemetry-setup.md for SDK installation by language.
LGTM = Loki (Logs) + Grafana (Visualization) + Tempo (Traces) + Mimir (Metrics)
┌────────────────────────────────────────────────────────┐
│ LGTM Architecture │
├────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Grafana Dashboard (Port 3000) │ │
│ │ Unified UI for Logs, Metrics, Traces │ │
│ └──────┬──────────────┬─────────────┬─────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Loki │ │ Tempo │ │ Mimir │ │
│ │ (Logs) │ │ (Traces) │ │(Metrics) │ │
│ │Port 3100 │ │Port 3200 │ │Port 9009 │ │
│ └────▲─────┘ └────▲─────┘ └────▲─────┘ │
│ │ │ │ │
│ └──────────────┴─────────────┘ │
│ │ │
│ ┌───────▼────────┐ │
│ │ Grafana Alloy │ │
│ │ (Collector) │ │
│ │ Port 4317/8 │ ← OTLP gRPC/HTTP │
│ └───────▲────────┘ │
│ │ │
│ OpenTelemetry Instrumented Apps │
│ │
└────────────────────────────────────────────────────────┘Quick Start: Run examples/lgtm-docker-compose/docker-compose.yml for a complete LGTM stack.
See: references/lgtm-stack.md for production deployment guide.
The Problem: Logs and traces live in separate systems. You see an error log but can't find the related trace.
The Solution: Inject trace_id and span_id into every log record.
pythonimport structlog from opentelemetry import trace logger = structlog.get_logger() span = trace.get_current_span() ctx = span.get_span_context() logger.info( "request_processed", trace_id=format(ctx.trace_id, '032x'), # 32-char hex span_id=format(ctx.span_id, '016x'), # 16-char hex user_id=user_id )
rustuse tracing::{info, instrument}; #[instrument(fields(user_id = %user_id))] async fn process_request(user_id: u64) -> Result<Response> { // trace_id/span_id automatically included info!(user_id = user_id, "processing request"); Ok(result) }
See: references/trace-context.md for Go and TypeScript patterns.
logql{job="api-service"} |= "trace_id=4bf92f3577b34da6a3ce929d0e0e4736"
Decision Tree:
Bootstrap Script:
bashpython scripts/setup_otel.py --language python --framework fastapi
Manual (Python):
bashpip install opentelemetry-api opentelemetry-sdk \ opentelemetry-instrumentation-fastapi \ opentelemetry-exporter-otlp
See: references/opentelemetry-setup.md for Rust, Go, TypeScript installation.
Docker Compose (development):
bashcd examples/lgtm-docker-compose docker-compose up -d # Grafana: http://localhost:3000 (admin/admin) # OTLP: localhost:4317 (gRPC), localhost:4318 (HTTP)
See: references/lgtm-stack.md for production Kubernetes deployment.
See: references/structured-logging.md for complete setup (Python, Rust, Go, TypeScript).
See: references/alerting-rules.md for Prometheus and Loki alert patterns.
OpenTelemetry auto-instruments popular frameworks:
pythonfrom opentelemetry.instrumentation.fastapi import FastAPIInstrumentor app = FastAPI() FastAPIInstrumentor.instrument_app(app) # Auto-trace all HTTP requests
Supported: FastAPI, Flask, Django, Express, Gin, Echo, Nest.js
See: references/opentelemetry-setup.md for framework-specific setup.
pythonfrom opentelemetry import trace tracer = trace.get_tracer(__name__) with tracer.start_as_current_span("fetch_user_details") as span: span.set_attribute("user_id", user_id) user = await db.fetch_user(user_id) span.set_attribute("user_found", user is not None)
pythonfrom opentelemetry.trace import Status, StatusCode with tracer.start_as_current_span("process_payment") as span: try: result = process_payment(amount, card_token) span.set_status(Status(StatusCode.OK)) except PaymentError as e: span.set_status(Status(StatusCode.ERROR, str(e))) span.record_exception(e) raise
See: references/trace-context.md for background job tracing and context propagation.
bash# Test log-trace correlation # 1. Make request to your app # 2. Copy trace_id from logs # 3. Query in Grafana: {job="myapp"} |= "trace_id=<TRACE_ID>" # Validate metrics python scripts/validate_metrics.py
See: examples/fastapi-otel/ for complete integration.
Setup Guides:
references/opentelemetry-setup.md - SDK installation (Python, Rust, Go, TypeScript)references/structured-logging.md - structlog, tracing, slog, pino configurationreferences/lgtm-stack.md - LGTM deployment (Docker, Kubernetes)references/trace-context.md - Log-trace correlation patternsreferences/alerting-rules.md - Prometheus and Loki alert templatesExamples:
examples/fastapi-otel/ - FastAPI + OpenTelemetry + LGTMexamples/axum-tracing/ - Rust Axum + tracing + LGTMexamples/lgtm-docker-compose/ - Production-ready LGTM stackScripts:
scripts/setup_otel.py - Bootstrap OpenTelemetry SDKscripts/generate_dashboards.py - Generate Grafana dashboardsscripts/validate_metrics.py - Validate metric namingDon't:
Do:
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-02 | pass→pass | 13,851 | 11,893 | -14% | 1 | 1 | 0% | 2,139 | 4,898 | +129% | 0 | 0 | — |
case-01 | pass→pass | 19,877 | 14,776 | -26% | 1 | 1 | 0% | 3,000 | 5,471 | +82% | 0 | 0 | — |
case-03 | fail→pass | 20,400 | 20,547 | +1% | 1 | 1 | 0% | 2,981 | 5,995 | +101% | 0 | 0 | — |
case-04 | pass→pass | 18,279 | 13,641 | -25% | 1 | 1 | 0% | 2,943 | 5,404 | +84% | 0 | 0 | — |
case-05 | pass→pass | 11,829 | 9,262 | -22% | 1 | 1 | 0% | 1,953 | 4,626 | +137% | 0 | 0 | — |
case-06 | pass→pass | 11,808 | 9,426 | -20% | 1 | 1 | 0% | 2,145 | 4,888 | +128% | 0 | 0 | — |
case-07 | pass→pass | 13,334 | 13,809 | +4% | 1 | 1 | 0% | 2,087 | 5,496 | +163% | 0 | 0 | — |
case-08 | pass→pass | 11,003 | 7,564 | -31% | 1 | 1 | 0% | 1,730 | 4,347 | +151% | 0 | 0 | — |
case-09 | pass→pass | 10,991 | 6,040 | -45% | 1 | 1 | 0% | 1,999 | 4,281 | +114% | 0 | 0 | — |
case-10 | pass→pass | 9,431 | 7,630 | -19% | 1 | 1 | 0% | 1,589 | 4,474 | +182% | 0 | 0 | — |
case-11 | fail→pass | 7,426 | 5,326 | -28% | 1 | 1 | 0% | 1,371 | 4,114 | +200% | 0 | 0 | — |
case-12 | pass→pass | 5,483 | 6,058 | +10% | 1 | 1 | 0% | 869 | 4,131 | +375% | 0 | 0 | — |
case-13 | fail→pass | 5,186 | 9,364 | +81% | 1 | 1 | 0% | 760 | 4,533 | +496% | 0 | 0 | — |
case-14 | pass→pass | 14,944 | 10,006 | -33% | 1 | 1 | 0% | 2,446 | 4,774 | +95% | 0 | 0 | — |
case-15 | pass→pass | 12,865 | 9,232 | -28% | 1 | 1 | 0% | 2,121 | 4,622 | +118% | 0 | 0 | — |
case-16 | fail→pass | 12,163 | 8,406 | -31% | 1 | 1 | 0% | 1,973 | 4,435 | +125% | 0 | 0 | — |
case-17 | pass→pass | 20,547 | 20,606 | +0% | 1 | 1 | 0% | 3,610 | 7,032 | +95% | 0 | 0 | — |
case-18 | fail→fail | 12,884 | 10,888 | -15% | 1 | 1 | 0% | 2,544 | 5,152 | +103% | 0 | 0 | — |
case-19 | pass→pass | 13,660 | 13,140 | -4% | 1 | 1 | 0% | 2,037 | 5,400 | +165% | 0 | 0 | — |
case-20 | pass→pass | 2,794 | 2,945 | +5% | 1 | 1 | 0% | 431 | 3,682 | +754% | 0 | 0 | — |
case-21 | pass→pass | 16,466 | 14,792 | -10% | 1 | 1 | 0% | 3,051 | 5,650 | +85% | 0 | 0 | — |
case-22 | pass→pass | 16,334 | 14,951 | -8% | 1 | 1 | 0% | 2,498 | 5,775 | +131% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +18 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.