Skip to main content
Logging utilities for the mellea core library. Provides 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

set_log_context(**fields: Any) -> None
Inject extra fields into every log record emitted from this coroutine or thread. Call this at the start of a request or task to attach identifiers such as 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.
Raises:
  • ValueError: If any key clashes with a standard logging.LogRecord attribute (e.g. levelname, module, thread).

FUNC clear_log_context

clear_log_context() -> None
Remove all context fields set by :func:set_log_context for this coroutine/thread.

FUNC log_context

log_context(**fields: Any) -> Generator[None, None, None]
Context manager that injects fields for the duration of the block. On exit — including on exceptions — the context is restored to its state before the block via a 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 — reserved LogRecord attribute names are rejected with ValueError.
Raises:
  • ValueError: If any key clashes with a reserved LogRecord attribute.

FUNC configure_logging

configure_logging(logger: logging.Logger) -> None
Attach log handlers to logger based on current environment variables. It always appends new handlers (the caller is responsible for clearing existing ones before re-configuring). It is invoked automatically on the first call to :meth: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.Logger to 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

filter(self, record: logging.LogRecord) -> bool
Attach async-safe ContextVar fields to record and allow it through. Args:
  • record: The log record being processed.
Returns:
  • 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

filter(self, record: logging.LogRecord) -> bool
Adds trace_id and span_id to the log record from the current OTel span. No-op when OpenTelemetry is not installed or when there is no active span. Args:
  • record: The log record to enrich.
Returns:
  • 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"\} when None.
Methods:

FUNC emit

emit(self, record: logging.LogRecord) -> None
Forward record to the configured REST endpoint. Silently suppresses any network or HTTP errors to avoid disrupting the application. Args:
  • 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: strftime format for the timestamp field. Defaults to ISO-8601 ("%Y-%m-%dT%H\:%M\:%S").
  • include_fields: Whitelist of core field names to keep. When None all core fields are included. Note: this filter applies only to the fields listed in _DEFAULT_FIELDS; extra_fields passed 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.
Attributes:
  • _DEFAULT_FIELDS: Canonical ordered list of core field names produced by this formatter.
Methods:

FUNC format_as_dict

format_as_dict(self, record: logging.LogRecord) -> dict[str, Any]
Return the log record as a dictionary (public API for external callers). Equivalent to :meth:_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.
Returns:
  • A dictionary ready for JSON serialisation.

FUNC format

format(self, record: logging.LogRecord) -> str
Formats a log record as a JSON string. Core fields are filtered by include_fields / exclude_fields. Static extra_fields and any per-task ContextVar fields (set via :func:set_log_context) are merged in after the core fields. Args:
  • record: The log record to format.
Returns:
  • 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.
Methods:

FUNC format

format(self, record: logging.LogRecord) -> str
Formats a log record using a colour-coded ANSI format string based on the record’s log level. Appends [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.
Returns:
  • 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 shared logging.Logger instance; None until first call to get_logger().
  • CRITICAL: Numeric level for critical log messages (50).
  • FATAL: Alias for CRITICAL (50).
  • ERROR: Numeric level for error log messages (40).
  • WARNING: Numeric level for warning log messages (30).
  • WARN: Alias for WARNING (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).
Methods:

FUNC get_logger

get_logger() -> logging.Logger
Return the shared :class: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.