Configuration options

Updated Jul 05, 2026

basicConfig

  • Accepts level, filename, stream (sys.stdout or sys.stderr), force, and handlers (an iterable of handler objects) either via keyword arguments or the BasicConfig dataclass.
  • filename and stream are mutually exclusive and cannot be combined with the handlers argument.
  • Passing force=True clears existing handlers on the root logger before installing the new one.
  • Formatting parameters (format, datefmt, and friends) are intentionally unsupported until formatter customization lands.

ConfigBuilder (imperative API)

from femtologging import (
    ConfigBuilder,
    LoggerConfigBuilder,
    StreamHandlerBuilder,
    FileHandlerBuilder,
    OverflowPolicy,
    LevelFilterBuilder,
    PythonCallbackFilterBuilder,
)


def add_request_id(record):
    record.request_id = "req-123"
    return True


builder = (
    ConfigBuilder()
    .with_handler("console", StreamHandlerBuilder.stderr())
    .with_handler(
        "audit",
        FileHandlerBuilder("/var/log/app.log").with_overflow_policy(
            OverflowPolicy.block()
        ),
    )
    .with_filter(
        "request_context",
        PythonCallbackFilterBuilder(add_request_id),
    )
    .with_filter("info_only", LevelFilterBuilder().with_max_level("INFO"))
    .with_logger(
        "app.audit",
        LoggerConfigBuilder()
        .with_level("INFO")
        .with_handlers(["audit"])
        .with_filters(["request_context", "info_only"])
        .with_propagate(False),
    )
    .with_root_logger(
        LoggerConfigBuilder().with_level("WARNING").with_handlers(["console"])
    )
)

builder.build_and_init()
  • with_default_level(level) sets a fallback for loggers that omit explicit levels. with_disable_existing_loggers(True) clears handlers and filters on previously created loggers that are not part of the new configuration (their ancestors are preserved automatically).
  • Available filter builders are LevelFilterBuilder, NameFilterBuilder, and PythonCallbackFilterBuilder. Callback filters run on the producer thread and may either return a truthy/falsy value directly or expose a stdlib-style filter(record) method. Filters are applied in the order they are declared in each LoggerConfigBuilder.
  • Formatter registration (with_formatter(id, FormatterBuilder)) is currently a placeholder. Registered formatters are stored in the serialized config, but handlers still treat any string other than "default" as unknown and raise HandlerConfigError.

dictConfig (restricted compatibility layer)

  • Supported handler classes: logging.StreamHandler, femtologging.StreamHandler, logging.FileHandler, femtologging.FileHandler, logging.handlers.RotatingFileHandler, logging.handlers.TimedRotatingFileHandler, and logging.handlers.SocketHandler (plus their femtologging equivalents).
  • Handler args are evaluated with ast.literal_eval, matching the stdlib behaviour for simple tuples. For socket handlers you can pass either (host, port) or a single Unix socket path; keyword arguments mirror the builder API (host, port, unix_path, capacity, connect_timeout_ms, write_timeout_ms, max_frame_size, tls, tls_domain, tls_insecure, backoff_* aliases).
  • Top-level filters sections are supported. Declarative mappings still use exactly one of level or name, while factory mappings use stdlib-style "()" syntax such as {"()": "pkg.module.FilterFactory", "prefix": "svc"}. The factory target may be a dotted path or a direct callable, and is instantiated with the remaining keys as keyword arguments. Mixing "()" with level or name is rejected. Loggers and the root logger accept a filters list of filter IDs.
  • Unsupported stdlib features raise ValueError: incremental updates, handler level, handler filters, and handler formatters. Although the schema accepts a formatters section, referencing a formatter from a handler currently results in ValueError("unknown formatter id").
  • A root section is mandatory. Named loggers support level, handlers, filters, and propagate (bool).

fileConfig (INI compatibility)

  • fileConfig(path, defaults=None, disable_existing_loggers=True, encoding=None) parses CPython-style INI files via the Rust extension and translates them to the restricted dictConfig schema.
  • Default substitutions (%(foo)s) work across the INI file and any mapping you pass via defaults.
  • Formatters and handler-level overrides are not supported. Including [formatter_*] sections or specifying level/formatter inside [handler_*] entries raises ValueError.