Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Observability patterns for Python applications. Triggers on: logging, metrics, tracing, opentelemetry, prometheus, observability, monitoring, structlog, correlation id.
.claude/skills/aiskillstore-python-observability-patterns/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-14 | ✗→✓ | ▲ Improved | 37% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 56% | 0% |
| case-10 | ✓→✓ | = Same ✓ | 61% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 79% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 64% | 0% |
Logging, metrics, and tracing for production applications.
pythonimport structlog # Configure structlog structlog.configure( processors=[ structlog.contextvars.merge_contextvars, structlog.processors.add_log_level, structlog.processors.TimeStamper(fmt="iso"), structlog.processors.JSONRenderer(), ], wrapper_class=structlog.make_filtering_bound_logger(logging.INFO), context_class=dict, logger_factory=structlog.PrintLoggerFactory(), ) logger = structlog.get_logger() # Usage logger.info("user_created", user_id=123, email="test@example.com") # Output: {"event": "user_created", "user_id": 123, "email": "test@example.com", "level": "info", "timestamp": "2024-01-15T10:00:00Z"}
pythonimport structlog from contextvars import ContextVar from uuid import uuid4 request_id_var: ContextVar[str] = ContextVar("request_id", default="") def bind_request_context(request_id: str | None = None): """Bind request ID to logging context.""" rid = request_id or str(uuid4()) request_id_var.set(rid) structlog.contextvars.bind_contextvars(request_id=rid) return rid # FastAPI middleware @app.middleware("http") async def request_context_middleware(request, call_next): request_id = request.headers.get("X-Request-ID") or str(uuid4()) bind_request_context(request_id) response = await call_next(request) response.headers["X-Request-ID"] = request_id structlog.contextvars.clear_contextvars() return response
pythonfrom prometheus_client import Counter, Histogram, Gauge, generate_latest from fastapi import FastAPI, Response # Define metrics REQUEST_COUNT = Counter( "http_requests_total", "Total HTTP requests", ["method", "endpoint", "status"] ) REQUEST_LATENCY = Histogram( "http_request_duration_seconds", "HTTP request latency", ["method", "endpoint"], buckets=[0.01, 0.05, 0.1, 0.5, 1.0, 5.0] ) ACTIVE_CONNECTIONS = Gauge( "active_connections", "Number of active connections" ) # Middleware to record metrics @app.middleware("http") async def metrics_middleware(request, call_next): ACTIVE_CONNECTIONS.inc() start = time.perf_counter() response = await call_next(request) duration = time.perf_counter() - start REQUEST_COUNT.labels( method=request.method, endpoint=request.url.path, status=response.status_code ).inc() REQUEST_LATENCY.labels( method=request.method, endpoint=request.url.path ).observe(duration) ACTIVE_CONNECTIONS.dec() return response # Metrics endpoint @app.get("/metrics") async def metrics(): return Response( content=generate_latest(), media_type="text/plain" )
pythonfrom opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter # Setup provider = TracerProvider() processor = BatchSpanProcessor(OTLPSpanExporter(endpoint="localhost:4317")) provider.add_span_processor(processor) trace.set_tracer_provider(provider) tracer = trace.get_tracer(__name__) # Manual instrumentation async def process_order(order_id: int): with tracer.start_as_current_span("process_order") as span: span.set_attribute("order_id", order_id) with tracer.start_as_current_span("validate_order"): await validate(order_id) with tracer.start_as_current_span("charge_payment"): await charge(order_id)
| Library | Purpose | |---------|---------| | structlog | Structured logging | | prometheus-client | Metrics collection | | opentelemetry | Distributed tracing |
| Metric Type | Use Case | |-------------|----------| | Counter | Total requests, errors | | Histogram | Latencies, sizes | | Gauge | Current connections, queue size |
./references/structured-logging.md - structlog configuration, formatters./references/metrics.md - Prometheus patterns, custom metrics./references/tracing.md - OpenTelemetry, distributed tracing./assets/logging-config.py - Production logging configurationPrerequisites:
python-async-patterns - Async context propagationRelated Skills:
python-fastapi-patterns - API middleware for metrics/tracingpython-cli-patterns - CLI logging patternsIntegration Skills:
python-database-patterns - Database query tracing| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-10 | pass→pass | 9,537 | 7,651 | -20% | 1 | 1 | 0% | 1,702 | 2,745 | +61% | 0 | 0 | — |
case-01 | fail→fail | 15,883 | 13,299 | -16% | 1 | 1 | 0% | 3,054 | 4,124 | +35% | 0 | 0 | — |
case-02 | fail→fail | 14,854 | 10,030 | -32% | 1 | 1 | 0% | 3,172 | 3,322 | +5% | 0 | 0 | — |
case-03 | pass→pass | 10,748 | 12,271 | +14% | 1 | 1 | 0% | 2,059 | 3,682 | +79% | 0 | 0 | — |
case-04 | pass→pass | 9,230 | 7,296 | -21% | 1 | 1 | 0% | 1,685 | 2,759 | +64% | 0 | 0 | — |
case-09 | pass→pass | 4,875 | 3,181 | -35% | 1 | 1 | 0% | 886 | 1,870 | +111% | 0 | 0 | — |
case-05 | pass→pass | 10,265 | 8,181 | -20% | 1 | 1 | 0% | 1,844 | 2,954 | +60% | 0 | 0 | — |
case-06 | pass→pass | 13,876 | 11,956 | -14% | 1 | 1 | 0% | 2,542 | 3,477 | +37% | 0 | 0 | — |
case-07 | pass→pass | 9,948 | 4,953 | -50% | 1 | 1 | 0% | 1,679 | 2,192 | +31% | 0 | 0 | — |
case-08 | pass→pass | 9,635 | 6,626 | -31% | 1 | 1 | 0% | 1,868 | 2,494 | +34% | 0 | 0 | — |
case-11 | fail→fail | 12,581 | 6,836 | -46% | 1 | 1 | 0% | 2,236 | 2,605 | +17% | 0 | 0 | — |
case-12 | pass→pass | 12,845 | 7,144 | -44% | 1 | 1 | 0% | 2,152 | 2,576 | +20% | 0 | 0 | — |
case-13 | fail→fail | 4,984 | 4,420 | -11% | 1 | 1 | 0% | 945 | 2,078 | +120% | 0 | 0 | — |
case-14 | fail→pass | 9,827 | 6,582 | -33% | 1 | 1 | 0% | 1,915 | 2,614 | +37% | 0 | 0 | — |
case-15 | pass→pass | 3,970 | 4,250 | +7% | 1 | 1 | 0% | 659 | 1,906 | +189% | 0 | 0 | — |
case-16 | pass→pass | 10,742 | 12,933 | +20% | 1 | 1 | 0% | 2,030 | 3,582 | +76% | 0 | 0 | — |
case-17 | fail→fail | 10,336 | 8,950 | -13% | 1 | 1 | 0% | 1,823 | 2,911 | +60% | 0 | 0 | — |
case-18 | pass→pass | 8,708 | 3,246 | -63% | 1 | 1 | 0% | 1,513 | 1,789 | +18% | 0 | 0 | — |
case-19 | pass→pass | 13,355 | 8,104 | -39% | 1 | 1 | 0% | 2,402 | 2,758 | +15% | 0 | 0 | — |
case-20 | fail→pass | 8,302 | 5,955 | -28% | 1 | 1 | 0% | 1,496 | 2,332 | +56% | 0 | 0 | — |
case-21 | pass→pass | 10,026 | 6,423 | -36% | 1 | 1 | 0% | 1,651 | 2,393 | +45% | 0 | 0 | — |
case-22 | pass→pass | 9,012 | 5,029 | -44% | 1 | 1 | 0% | 1,585 | 2,087 | +32% | 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 +9 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.