FemtoStreamHandler
FemtoStreamHandler.stderr()(default) and.stdout()log to the respective standard streams. Calls return immediately; the handler thread flushes the underlyingio::Write.handler.flush()waits (up to one second by default) for the worker to flush buffered writes and returnsTrueon success.handler.close()shuts down the worker thread and should be called before process exit.- To tune capacity, flush timeout, or formatters use
StreamHandlerBuilder. It provides.with_capacity(n),.with_flush_timeout_ms(ms), and.with_formatter(callable_or_id)fluent methods before calling.build().
FemtoFileHandler
- Constructor signature:
FemtoFileHandler(path, capacity=1024, flush_interval=1, policy="drop"). The flush interval counts records, not seconds. policycontrols queue overflow handling:"drop"(default) discards records and raisesRuntimeError."block"blocks the caller until the worker makes room."timeout:N"blocks forNmilliseconds before giving up.- Use
handler.flush()andhandler.close()to ensure on-disk consistency. Always close the handler when the application shuts down. FileHandlerBuildermirrors these options and also exposes.with_overflow_policy(OverflowPolicy.drop()/block()/timeout(ms))and.with_formatter(…). Formatter identifiers other than"default"are not wired up yet; pass a callable (taking a mapping and returning a string) to attach custom formatting logic.
FemtoRotatingFileHandler
- Wraps
FemtoFileHandlerwith size-based rotation. Instantiate viaFemtoRotatingFileHandler(path, options=HandlerOptions(…)). HandlerOptionsfields:capacity,flush_interval, andpolicymirrorFemtoFileHandler.rotation=(max_bytes, backup_count)enables rollover when both values are greater than zero. Set(0, 0)to disable rotation entirely.- Rotation renames the active log file to
.1, shifts older backups up tobackup_count, and truncates the live file. If opening a fresh file fails the implementation falls back to appending to the existing file and logs the reason. RotatingFileHandlerBuilderprovides the same fluent API as the file builder plus.with_max_bytes()and.with_backup_count().
FemtoSocketHandler
- Socket handlers must be built via
SocketHandlerBuilder. Typical usage:
from femtologging import SocketHandlerBuilder
socket_handler = (
SocketHandlerBuilder()
.with_tcp("127.0.0.1", 9020)
.with_capacity(2048)
.with_connect_timeout_ms(5000)
.with_write_timeout_ms(1000)
.with_tls("logs.example.com", insecure=False)
.with_backoff(base_ms=100, cap_ms=5000, reset_after_ms=30000, deadline_ms=120000)
.build()
)
- Default transport is TCP to
localhost:9020. Call.with_unix_path()to use Unix sockets on POSIX systems. TLS only works with TCP transports; attempting to combine TLS and Unix sockets raisesHandlerConfigError. - Records are serialized to MessagePack maps:
{logger, level, message, timestamp_ns, filename, line_number, module_path, thread_id, thread_name, key_values}and framed with a 4-byte big-endian length prefix. - The worker reconnects automatically using exponential backoff. Payloads that
exceed the configured
max_frame_sizeare dropped. handler.flush()forces the worker to flush the active socket. Always callhandler.close()to terminate the worker thread cleanly.
Custom Python handlers
class Collector:
def __init__(self) -> None:
self.records: list[tuple[str, str, str]] = []
def handle(self, logger: str, level: str, message: str) -> None:
# Runs inside the FemtoLogger worker thread
self.records.append((logger, level, message))
collector = Collector()
logger.add_handler(collector)
The handler’s handle method must be callable and thread-safe. Exceptions are
printed to stderr and counted as handler errors, so prefer defensive code and
avoid raising from handle.