instrumentation

Add Pydantic Logfire observability to applications. Use this skill whenever the user asks to "add logfire", "instrument with logfire", "add observability",…

INSTALLATION
npx skills add https://github.com/pydantic/skills --skill instrumentation
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

$28

Identify the project language and instrumentable libraries:

  • Python: Read pyproject.toml or requirements.txt. Common instrumentable libraries: FastAPI, httpx, asyncpg, SQLAlchemy, psycopg, Redis, Celery, Django, Flask, requests, PydanticAI.
  • JavaScript/TypeScript: Read package.json. Common frameworks: Express, Next.js, Fastify. Also check for Cloudflare Workers or Deno.
  • Rust: Read Cargo.toml.

Then follow the language-specific steps below.

Python

Install with Extras

Install logfire with extras matching the detected frameworks. Each instrumented library needs its corresponding extra - without it, the instrument_*() call will fail at runtime with a missing dependency error.

uv add 'logfire[fastapi,httpx,asyncpg]'

The full list of available extras: fastapi, starlette, django, flask, httpx, requests, asyncpg, psycopg, psycopg2, sqlalchemy, redis, pymongo, mysql, sqlite3, celery, aiohttp, aws-lambda, system-metrics, litellm, dspy, google-genai.

Configure and Instrument

This is where ordering matters. logfire.configure() initializes the SDK and must come before everything else. The instrument_*() calls register hooks into each library. If you call instrument_*() before configure(), the hooks register but traces go nowhere.

import logfire

# 1. Configure first - always

logfire.configure()

# 2. Instrument libraries - after configure, before app starts

logfire.instrument_fastapi(app)

logfire.instrument_httpx()

logfire.instrument_asyncpg()

Placement rules:

  • logfire.configure() goes in the application entry point (main.py, or the module that creates the app)
  • Call it once per process - not inside request handlers, not in library code
  • instrument_*() calls go right after configure()
  • Web framework instrumentors (instrument_fastapi, instrument_flask, instrument_django) need the app instance as an argument. HTTP client and database instrumentors (instrument_httpx, instrument_asyncpg) are global and take no arguments.
  • In Gunicorn deployments, call logfire.configure() inside the post_fork hook, not at module level - each worker is a separate process

Structured Logging

Replace print() and logging.*() calls with Logfire's structured logging. The key pattern: use {key} placeholders with keyword arguments, never f-strings.

# Correct - each {key} becomes a searchable attribute in the Logfire UI

logfire.info("Created user {user_id}", user_id=uid)

logfire.error("Payment failed {amount} {currency}", amount=100, currency="USD")

# Wrong - creates a flat string, nothing is searchable

logfire.info(f"Created user {uid}")

For grouping related operations and measuring duration, use spans:

with logfire.span("Processing order {order_id}", order_id=order_id):

    items = await fetch_items(order_id)

    total = calculate_total(items)

    logfire.info("Calculated total {total}", total=total)

For exceptions, use logfire.exception() which automatically captures the traceback:

try:

    await process_order(order_id)

except Exception:

    logfire.exception("Failed to process order {order_id}", order_id=order_id)

    raise

AI/LLM Instrumentation (Python)

Logfire auto-instruments AI libraries to capture LLM calls, token usage, tool invocations, and agent runs.

uv add 'logfire[pydantic-ai]'

# or: uv add 'logfire[openai]' / uv add 'logfire[anthropic]'

Available AI extras: pydantic-ai, openai, anthropic, litellm, dspy, google-genai.

logfire.configure()

logfire.instrument_pydantic_ai()  # captures agent runs, tool calls, LLM request/response

# or:

logfire.instrument_openai()       # captures chat completions, embeddings, token counts

logfire.instrument_anthropic()    # captures messages, token usage

For PydanticAI, each agent run becomes a parent span containing child spans for every tool call and LLM request.

JavaScript / TypeScript

Install

# Node.js

npm install @pydantic/logfire-node

# Cloudflare Workers

npm install @pydantic/logfire-cf-workers logfire

# Next.js / generic

npm install logfire

Configure

Node.js (Express, Fastify, etc.) - create an instrumentation.ts loaded before your app:

import * as logfire from '@pydantic/logfire-node'

logfire.configure()

Launch with: node --require ./instrumentation.js app.js

The SDK auto-instruments common libraries when loaded before the app. Set LOGFIRE_TOKEN in your environment or pass token to configure().

Cloudflare Workers - wrap your handler with instrument():

import { instrument } from '@pydantic/logfire-cf-workers'

export default instrument(handler, {

  service: { name: 'my-worker', version: '1.0.0' }

})

Next.js - set environment variables for OpenTelemetry export:

OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://logfire-api.pydantic.dev/v1/traces

OTEL_EXPORTER_OTLP_HEADERS=Authorization=<your-write-token>

Structured Logging (JS/TS)

// Structured attributes as second argument

logfire.info('Created user', { user_id: uid })

logfire.error('Payment failed', { amount: 100, currency: 'USD' })

// Spans

logfire.span('Processing order', { order_id }, {}, async () => {

  logfire.info('Processing step completed')

})

// Error reporting

logfire.reportError('order processing', error)

Log levels: trace, debug, info, notice, warn, error, fatal.

Rust

Install

[dependencies]

logfire = "0.6"

Configure

let shutdown_handler = logfire::configure()

    .install_panic_handler()

    .finish()?;

Set LOGFIRE_TOKEN in your environment or use the Logfire CLI to select a project.

Structured Logging (Rust)

The Rust SDK is built on tracing and opentelemetry - existing tracing macros work automatically.

// Spans

logfire::span!("processing order", order_id = order_id).in_scope(|| {

    // traced code

});

// Events

logfire::info!("Created user {user_id}", user_id = uid);

Always call shutdown_handler.shutdown() before program exit to flush data.

Verify

After instrumentation, verify the setup works:

  • Run logfire auth to check authentication (or set LOGFIRE_TOKEN)
  • Start the app and trigger a request

If traces aren't appearing: check that configure() is called before instrument_*() (Python), check that LOGFIRE_TOKEN is set, and check that the correct packages/extras are installed.

References

Detailed patterns and integration tables, organized by language:

  • Python: ${CLAUDE_PLUGIN_ROOT}/skills/instrumentation/references/python/logging-patterns.md (log levels, spans, stdlib integration, metrics, capfire testing) and ${CLAUDE_PLUGIN_ROOT}/skills/instrumentation/references/python/integrations.md (full instrumentor table with extras)
  • JavaScript/TypeScript: ${CLAUDE_PLUGIN_ROOT}/skills/instrumentation/references/javascript/patterns.md (log levels, spans, error handling, config) and ${CLAUDE_PLUGIN_ROOT}/skills/instrumentation/references/javascript/frameworks.md (Node.js, Cloudflare Workers, Next.js, Deno setup)
  • Rust: ${CLAUDE_PLUGIN_ROOT}/skills/instrumentation/references/rust/patterns.md (macros, spans, tracing/log crate integration, async, shutdown)
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card