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.
BasicConfig is a slotted dataclass: level, filename, stream, force,
and handlers are its complete supported surface, and instances cannot
accept arbitrary extra attributes. Assigning a mistyped field name raises
AttributeError immediately rather than silently creating a new attribute
that basicConfig never reads:
cfg = BasicConfig(level="INFO")
cfg.filenam = "/var/log/app.log" # AttributeError: no such field
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()
build_and_init() validates handler and filter references and prepares the
complete configuration before changing live logger state. If configuration
fails, the current logger configuration remains intact.
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).
- The parsed configuration is passed to
ConfigBuilder.build_and_init(), so
handler and filter validation completes before live logger state changes. A
failed configuration leaves the current logger configuration intact.
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.
- Because the resulting schema is delegated to
dictConfig and then
ConfigBuilder.build_and_init(), validation completes before live logger
state changes. A failed fileConfig call leaves the current logger
configuration intact.
- 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.