Text logs and structured logs
This text log has the same facts as the structured log below it.message and order_id. The message stays the same for every order, so you
can also count it.
Choose a log format
Use JSON, with 1 object on each line. Use the same field names in all services. This table lists the base fields and the matching names in the OpenTelemetry log data model and in LogBrew.
OpenTelemetry severity numbers go from 1 to 24.
INFO starts at 9, WARN at
13, ERROR at 17, and FATAL at 21. LogBrew accepts OTLP logs directly. See
Send OpenTelemetry data.
Logging best practices
Keep the message fixed
Write"payment failed" and put the order ID in a field. A fixed message lets
you group, count, and alert on 1 event type.
Use 1 name for each field
Selectorder_id or orderId once, and use it in all services. Use the
OpenTelemetry semantic convention names for common fields, such as
http.response.status_code.
Select the level by the action that it needs
error means that an operation failed. warning means that the program
recovered. info confirms normal work. Use debug only while you find a
problem.
Write time in UTC
Use RFC 3339 with milliseconds and an offset, such as2026-11-07T14:21:19.773+00:00. Without UTC and milliseconds, records from
different time zones, or records in the same second, sort in the wrong order.
Add the trace ID and span ID
With these IDs, you can read all logs of 1 request across services.Set the service, environment, and release once
Configure them at startup, not in each call. A missing release hides which deploy caused a change.Log an error once, where you handle it
Add the error type and message. Do not log the same error again at each layer.Keep secrets and personal data out
Do not log passwords, tokens, cookies, request bodies, or full URLs with query strings. Use the redaction feature of your logger. See Safe capture.Use fixed field names
Do not use values as field names, such as{"ord_1001": "failed"}. Each new
value then adds a new field, and 1 filter cannot find all orders.
Write JSON to standard output in production
Use a readable format only in development.Structured logging in Python
The standardlogging module has no JSON formatter. This formatter writes the
base fields and the values from extra={"fields": {...}}.
LogBrewLoggingHandler. It sends the
message, level, and logger as fields, and primitive extra values as
metadata. See Python logging.
Structured logging in Node.js
Pino writes 1 JSON line for each record by default. Winston writes JSON withwinston.format.json(). Both keep fields from the call and from child
loggers. See Node.js logging for both setups and for
the trace ID in Express logs.
