MelleaLogger, a singleton logger with colour-coded console output,
an optional rotating file handler, and optional OTLP / webhook forwarding.
All internal mellea modules obtain their logger via MelleaLogger.get_logger().
Handler setup is performed by :func:configure_logging, which is called
automatically on the first :meth:MelleaLogger.get_logger invocation.
Environment variables
MELLEA_LOG_ENABLED
Master switch for all logging handlers. Set to false / 0 / no to
suppress all handlers (useful in test environments). Defaults to true.
MELLEA_LOG_LEVEL
Minimum log level name (e.g. DEBUG, INFO, WARNING). Defaults to
INFO.
MELLEA_LOG_JSON
Set to any truthy value (1, true, yes) to emit structured JSON
instead of colour-coded human-readable text. Applies to both the console and
file handlers.
MELLEA_LOG_CONSOLE
Set to false / 0 / no to disable the console (stdout) handler.
Defaults to true.
MELLEA_LOG_FILE
Absolute or relative path for rotating file output (e.g.
/var/log/mellea.log). When unset no file handler is attached.
MELLEA_LOG_FILE_MAX_BYTES
Maximum size in bytes before the log file is rotated. Defaults to
10485760 (10 MB).
MELLEA_LOG_FILE_BACKUP_COUNT
Number of rotated backup files to keep. Defaults to 5.
MELLEA_LOG_OTLP
Set to true / 1 / yes to export logs via OpenTelemetry Logs
Protocol. Requires opentelemetry-sdk and an OTLP endpoint configured
via OTEL_EXPORTER_OTLP_LOG_ENDPOINT or OTEL_EXPORTER_OTLP_ENDPOINT.
MELLEA_LOG_WEBHOOK
HTTP(S) URL to forward log records to via HTTP POST. When set a
:class:RESTHandler is attached. Supersedes the deprecated MELLEA_FLOG
and FLOG variables.
MELLEA_FLOG
Deprecated alias for MELLEA_LOG_WEBHOOK. Activates a RESTHandler
pointed at http://localhost:8000/api/receive.
Functions
FUNC set_log_context
trace_id or request_id without modifying individual log calls.
.. note::
Prefer :func:log_context as the primary API — it guarantees cleanup
(including restoring outer values on same-key nesting) even on
exceptions.
Args:
**fields: Arbitrary key-value pairs to include in log records.
ValueError: If any key clashes with a standardlogging.LogRecordattribute (e.g.levelname,module,thread).
FUNC clear_log_context
set_log_context for this coroutine/thread.
FUNC log_context
ContextVar token. This is safe for both nested
usage and concurrent asyncio tasks: each asyncio.Task owns an isolated
copy of the context variable, so coroutines running on the same event-loop
thread cannot overwrite each other’s fields.
Example::
with log_context(request_id=“req-1”, user_id=“u-42”):
logger.info(“Handling request”) # both IDs appear here
logger.info(“After request”) # IDs are gone
Args:
**fields: Key-value pairs to inject. Same restrictions as :func:set_log_context— reservedLogRecordattribute names are rejected withValueError.
ValueError: If any key clashes with a reservedLogRecordattribute.
FUNC configure_logging
MelleaLogger.get_logger; subsequent calls return the
same singleton logger with its handlers already in place. It is also
available for programmatic use when you need to attach handlers to a custom
logger.
When MELLEA_LOG_ENABLED is falsy no handlers are attached; the logger
still exists and accepts records, but they are silently discarded.
If MELLEA_LOG_FILE is set but the path cannot be opened (e.g. due to a
permissions error), a :class:UserWarning is emitted and file logging is
skipped. The remaining handlers are still attached and the application
continues normally.
Args:
logger: The :class:logging.Loggerto configure.
Classes
CLASS ContextFilter
Logging filter that injects async-safe ContextVar fields into every record.
Fields registered via :func:set_log_context are copied onto the
logging.LogRecord before formatters see it, enabling trace/request IDs
to appear in structured output without touching call sites.
Methods:
FUNC filter
record: The log record being processed.
- Always
True— the record is never suppressed.
CLASS OtelTraceFilter
Logging filter that injects the current OpenTelemetry trace context into log records.
Adds trace_id and span_id attributes (hex strings) to every
LogRecord when an active span exists. When OpenTelemetry is not
installed the filter is a true no-op: it adds no attributes and takes no
branches, so there is zero overhead on the hot logging path. Formatters
use hasattr / getattr to handle the absent attributes gracefully.
Methods:
FUNC filter
record: The log record to enrich.
- Always
True— the record is never suppressed.
CLASS RESTHandler
Logging handler that forwards records to an HTTP endpoint unconditionally.
Attach this handler only when a webhook URL is configured; it sends every
record it receives. Use :func:configure_logging or
:meth:MelleaLogger.get_logger to obtain a pre-configured instance.
Failures are silently suppressed to avoid disrupting the application.
Args:
api_url: The URL of the REST endpoint that receives log records.method: HTTP method to use when sending records (default"POST").headers: HTTP headers to send; defaults to\{"Content-Type"\: "application/json"\}whenNone.
FUNC emit
record: The log record to forward.
CLASS JsonFormatter
Logging formatter that serialises log records as structured JSON strings.
Produces a consistent JSON schema with a fixed set of core fields.
Additional fields can be injected at construction time (extra_fields) or
dynamically per-thread via :func:set_log_context / :class:ContextFilter.
Includes trace_id and span_id when OpenTelemetry tracing is active.
Args:
timestamp_format:strftimeformat for thetimestampfield. Defaults to ISO-8601 ("%Y-%m-%dT%H\:%M\:%S").include_fields: Whitelist of core field names to keep. WhenNoneall core fields are included. Note: this filter applies only to the fields listed in_DEFAULT_FIELDS;extra_fieldspassed to the constructor and dynamic context fields (set via :func:set_log_context) are always included regardless of this setting.exclude_fields: Set of core field names to drop. Applied after include_fields.extra_fields: Static key-value pairs merged into every log record.
_DEFAULT_FIELDS: Canonical ordered list of core field names produced by this formatter.
FUNC format_as_dict
_build_log_dict but part of the public interface so
handlers and other callers do not need to reach into private methods.
Includes trace_id and span_id when OpenTelemetry tracing is active.
Args:
record: The log record to convert.
- A dictionary ready for JSON serialisation.
FUNC format
set_log_context) are merged in after the core fields.
Args:
record: The log record to format.
- A JSON-serialised log record.
CLASS CustomFormatter
A nice custom formatter copied from Sergey Pleshakov’s post on StackOverflow.
Attributes:
cyan: ANSI escape code for cyan text, used for DEBUG messages.grey: ANSI escape code for grey text, used for INFO messages.yellow: ANSI escape code for yellow text, used for WARNING messages.red: ANSI escape code for red text, used for ERROR messages.bold_red: ANSI escape code for bold red text, used for CRITICAL messages.reset: ANSI escape code to reset text colour.FORMATS: Mapping from logging level integer to the colour-formatted format string.
FUNC format
[trace_id=… span_id=…] when OtelTraceFilter has
populated those fields on the record and a trace is active.
Args:
record: The log record to format.
- The formatted log record string with ANSI colour codes applied.
CLASS MelleaLogger
Singleton logger with colour-coded console output and configurable handlers.
Obtain the shared logger instance via MelleaLogger.get_logger(). Log level
defaults to INFO but can be overridden via MELLEA_LOG_LEVEL. Handler
setup is delegated to :func:configure_logging.
Attributes:
logger: The sharedlogging.Loggerinstance;Noneuntil first call toget_logger().CRITICAL: Numeric level for critical log messages (50).FATAL: Alias forCRITICAL(50).ERROR: Numeric level for error log messages (40).WARNING: Numeric level for warning log messages (30).WARN: Alias forWARNING(30).INFO: Numeric level for informational log messages (20).DEBUG: Numeric level for debug log messages (10).NOTSET: Numeric level meaning no level is set (0).
FUNC get_logger
logging.Logger, creating it on first call.
The logger is created once (singleton). Subsequent calls return the
cached instance. Initialisation is protected by a module-level lock so
concurrent callers at startup cannot create duplicate handlers.
When MELLEA_LOG_ENABLED is falsy :func:configure_logging attaches
no handlers — the logger still exists, but records are silently
discarded (useful for tests or environments that must produce no output).
Returns:
- Configured logger instance.