Observability Best Practices
Instrumenting a Claude application well means a cost spike, a latency regression, or a cache regression surfaces on a dashboard or a page within the hour, not on next month's invoice.
Search across all documentation pages
Instrumenting a Claude application well means a cost spike, a latency regression, or a cache regression surfaces on a dashboard or a page within the hour, not on next month's invoice.
This checklist consolidates the practices covered across this section into rules you can check your own instrumentation against.
logging.Logger, not print. Structured output through a real logging framework integrates with log level filtering and most log aggregation agents out of the box.status field lets one query cover both outcomes instead of maintaining separate error logs.cache_read_input_tokens and similar fields with getattr(..., None) since they're only populated once prompt caching applies.gen_ai.* attribute naming convention on spans. Consistent naming keeps traces queryable the same way regardless of which service or model provider produced them.record_exception. A span without an explicit error status can still render as successful in some trace viewers.Structured logging (section A): a consistent schema capturing prompt, response, tokens, model, latency, and request ID for every call. It costs little to add, and every other practice on this list (tracing, dashboards, alerting) depends on this data existing in a queryable form.
Not necessarily. Tracing earns its cost once you have a multi-step agent loop where call ordering and nesting matter. A single-call integration can rely on structured logging alone until that changes.
A runaway agent loop is a reliability bug that happens to surface first as a spend anomaly. Treating cost as a first-class engineering signal, alongside latency and error rate, catches that bug the same day instead of at the end of a billing cycle.
Each service that adopts tracing independently tends to invent its own span names and attribute keys. Once that happens, cross-service trace queries and shared dashboards stop working, and fixing it later requires a migration instead of a one-time decision.
No. Run alert evaluation on a schedule, separate from the request path, whether as a cron job or a monitor evaluated by your metrics backend. Putting alert logic inline adds latency and a new failure mode to code already serving users.
A fixed threshold that fits your traffic today becomes either too sensitive or too late to catch a real spike as usage grows. A rolling baseline (a median of recent windows) adapts automatically, keeping the alert meaningful without manual retuning.
Write the ADR documenting span names, attributes, and sampling policy before that second service ships its instrumentation, not after. This is the point where inconsistency starts to compound, and it's much cheaper to prevent than to migrate away from later.
At low traffic volume, yes, since the cost and noise are negligible. As traffic grows, most teams shift to a lower sampling rate for routine successful spans while keeping error and cost-outlier spans at full sampling, which the ADR should document explicitly.
If you can't answer "what did this specific call cost, how long did it take, and what did it return" from your logs alone, without re-running the request, the schema is incomplete. The fields in section A (prompt, response, model, tokens, latency, request ID) are the minimum that makes that question answerable.
Compare the anomaly's start timestamp against your deploy log for the same window, and check Anthropic's status page to rule out a provider-side cause. This is the first step of the deploy-correlation checklist linked below, and it resolves most incidents faster than starting from scratch.
With your other infrastructure metrics. A dedicated LLM-only dashboard tends to get checked rarely, while spend sitting next to latency and error-rate graphs your team already watches daily gets noticed the day something goes wrong.
Stack versions: Written against the Claude model lineup current as of ~June 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (the default), and Claude Haiku 4.5 - and the official
anthropicPython SDK (latest 0.x release). Model names, pricing, and SDK versions move quickly - verify current specifics at platform.claude.com/docs before relying on them.
Reviewed by Chris St. John·Last updated Jul 13, 2026