Skip to content

API

Every exported function and class, the redaction rules, and the limits.

Updated View as Markdown

Everything below is exported from widelog.

Configuration

init(**config)

Call once at startup. Later calls update only the keys you pass.

Option Type Default Notes
service str $SERVICE_NAME or "app" Stamped on every event.
environment str $ENVIRONMENT or "development" Stamped on every event.
redact iterable of str see Redaction Replaces the default name list.
sink Callable[[dict], None] None Where events go. Unset writes NDJSON to stdout. OTLPSink sends to a collector, see OTLP.
stack_depth int 5 Frames kept per traceback, counted from the innermost.

Recording

use_logger()

Returns the event for the current operation. Outside one, returns a standalone logger that emits on every call, so nothing is silently dropped.

wide_event(**fields)

Context manager that scopes one event. Emits exactly once when the block exits, including when the block raises. An exception is attached to the event and then re-raised untouched.

WideEvent

Method Notes
set(dict) or set(**kw) Attach context. Dicts merge, lists concatenate, anything else overwrites.
info(msg, ctx=None) Record a message. Appends to messages.
warn(msg, ctx=None) Same, and raises the level to warn.
debug(msg, ctx=None) Same, at debug.
error(exc_or_str, ctx=None) Attach an error and raise the level to error.
set_level(level) Pin the level so later error() and warn() calls cannot raise it.
emit(**overrides) Emit and seal. Idempotent, and never raises.

The level of an event is the most severe thing recorded on it, unless set_level() pinned it.

Errors

status defaults to 500. to_dict() returns every field that is set except internal.

One error declared once. message is a string, or a function whose parameters become required keyword arguments at the call site. status defaults to 500, tags never reaches the wire.

ErrorCatalog

Subclass with prefix=. Every ErrorSpec in the body becomes a factory whose code is prefix.ATTRIBUTE_NAME. codes() returns them all in declaration order.

ErrorFactory(code, spec)

A spec bound to a code, for an error with no catalog. Reads spec fields off the factory: factory.status, factory.tags.

Adapters

WidelogMiddleware(app)

ASGI. Records method, path, status, and duration_ms. A 5xx raises the level to error. Non-HTTP scopes such as lifespan and websocket pass through untouched.

lambda_wide_event(handler)

Decorator. Adds request_id, cold_start, function, remaining_ms, and trace_id, reads method and path from all three payload shapes, and emits early with "timed_out": true 500ms before the deadline. See AWS Lambda.

Event shape

Every event carries these, then your fields:

Field Notes
timestamp UTC, millisecond precision, so a backend can order same-second events.
level debug, info, warn, or error.
service, environment From init().
duration_ms Absent on standalone one-off lines, which measure nothing.

Errors on an event

log.error(exc) and an exception that ends a wide_event() both write an error object:

Field Notes
message, type str(exc) and the exception class name.
status, code, why, fix, link From WidelogError, when set.
stack The innermost frames, path:line in function. widelog’s own frames are filtered out, so the first entry is your code.
causes The chain behind this error, outermost first, each with its own type, message, and stack.

The chain follows __cause__ first, so raise X from Y and WidelogError(cause=Y) win over an incidental __context__. raise X from None ends it, and the chain stops after five links or on a cycle.

{
  "message": "Payment failed",
  "status": 402,
  "type": "WidelogError",
  "stack": ["app/checkout.py:41 in checkout"],
  "causes": [
    {
      "type": "ValueError",
      "message": "connection reset by peer",
      "stack": ["app/gateway.py:12 in charge", "app/gateway.py:6 in post"]
    }
  ]
}

to_dict() carries none of this. The stack and the chain stay in your logs and never reach the client.

Redaction

Keys ending in password, token, secret, authorization, apikey, or cookie are replaced with [REDACTED] at any depth, in dicts and inside lists.

Matching ignores case, underscores, and hyphens, and looks at the end of the key:

Redacted Not redacted
password, user_password tokens_used
token, refresh_token, access_token token_count
api_key, x-api-key, apiKey secretary
cookie, set-cookie cookies_accepted
authorization, proxy-authorization
secret, client_secret

Suffix matching is why refresh_token is caught and tokens_used is not. Pass init(redact={...}) to replace the list with your own names, which are normalized the same way.

WidelogError(internal=...) is never serialized, into the event or into to_dict().

Limits

Values are copied as they enter the event, so widelog never writes back into the dicts and lists you passed to set(). Nesting is kept to 32 levels, and anything deeper becomes [TRUNCATED], which also makes a self-referential payload safe to log.

Failure

emit() never raises. If the sink is down, or a field cannot be serialized, widelog reports the dropped event on stderr and returns None. Logging is not allowed to fail the request it is describing, or to replace the exception the application is already handling.

Mutating a sealed event prints a warning to stderr and drops the data.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close