logging

Page actions AI-ready formats and sharing
Open LLM text
Share with AI
Ask Claude Ask ChatGPT Ask Gemini Ask Copilot

Structured logging with request correlation.

Provides request_id propagation via ContextVar and a structured_log helper for JSON-formatted logs with request_id, user_id, path, etc.

WhenAppConfig.log_format == "json"the framework installs a crash-proof JSONFormatter…

Structured logging with request correlation.

Provides request_id propagation via ContextVar and a structured_log helper for JSON-formatted logs with request_id, user_id, path, etc.

WhenAppConfig.log_format == "json"the framework installs a crash-proof JSONFormatter on the "chirp"logger at freeze time (configure_json_logging()) so Chirp's own log lines share the same JSON envelope the server (Pounce) emits, instead of leaking the divergent ad-hoc json.dumpspayload as an unformatted line.

This module is internal — it is intentionally absent from chirp.__all__ / chirp._LAZY_IMPORTS and from docs/public-api.md.

logging

Name Type Default Description
type
qualified_name
element_type
description
source_file
line_number
is_autodoc
autodoc_element
_autodoc_template
_autodoc_url_path
_autodoc_page_type
title
doc_content_hash

Symbols on this page

get_request_id
function
def get_request_id() -> str | None

Return the current request ID, or None if outside a request context.

No parameters.

_current_trace_context
function
def _current_trace_context() -> tuple[str, str] | None

Best-effort (trace_id, span_id) hex pair from the active OTel span.

Chirp has no opentelemetry dependency — OTel is delegated to the server (Pounce) viaAppConfig.otel_endpoint. This reads the ambient span behind a guarded import so logs join the trace pillar when OTel is configured and are unchanged otherwise. ReturnsNonewhen opentelemetry is absent, no span is active, or the span context is invalid (the no-op default span).

SSE note: the SSE drain re-establishes request context from a captured snapshot and starts the producer inside acopy_context() snapshot so OTel span context survives intoEventStreamgenerators. Buffered responses and theSuspense / Streamdrains (which do copy_contexton worker threads) keep the span for free.

No parameters.

structured_log
function
def structured_log(level: int, message: str, *, request_id: str | None = None, user_id: str | None = None, path: str | None = None, method: str | None = None, **extra: Any) -> None

Log a structured JSON message with correlation fields.

Merges request_id from context if not provided. Use for audit trails and observability pipelines that expect JSON logs.

When an OpenTelemetry span is active (configured via AppConfig.otel_endpoint), trace_id and span_idare best-effort bound fromget_current_span() so logs join the trace pillar. The lookup is fully guarded — no opentelemetry dependency, no failure surface. See_current_trace_context() for the SSE blind spot: trace context survives buffered,Suspense, and Streamrenders and SSEEventStream generators (via a connect-time copy_context snapshot). See_current_trace_context() for historical context.

Parameters

Name Type Default Description
level int
message str
request_id str | None None
user_id str | None None
path str | None None
method str | None None
**extra Any
JSONFormatter
class

Crash-proof JSON log formatter matching the server (Pounce) envelope.

Produces{"ts", "level", "logger", "message"} (plus "exception"when the record carriesexc_info), the same shape Pounce's _JSONFormatter emits, so Chirp's own"chirp"logger lines and the server's request lines parse identically in a log pipeline.

Defensive by design: a record with a non-serializable extra, an exploding getMessage, or an unformattable exception must never raise out of format() (a logging handler that raises drops the log line and can surface the error at the call site). Every step degrades through a nested fallback to a minimal still-valid JSON object.

configure_json_logging
function
def configure_json_logging() -> None

InstallJSONFormatter on the "chirp"logger, idempotently.

Called once at app freeze whenAppConfig.log_format == "json"so the framework's own logs match the server JSON shape. Idempotent — a second call is a no-op (the marker handler is detected and reused), so repeated freeze()calls or test re-runs never stack handlers on the process-global logging.Logger.

Scope discipline (free-threading / shared-state safety):

  • Mutates the"chirp" logger only — never logging.basicConfig, which would clobber root configuration the server (Pounce) owns.
  • propagate = Falseso a chirp JSON line is not re-emitted through an ancestor handler (no double logging through Pounce's root handler).
  • Installs exactly oneStreamHandlertagged with a private marker; a foreign handler an app added to the"chirp"logger is left untouched.

No parameters.

View source · /home/runner/work/chirp/chirp/site/../src/chirp/logging.py:1