Working with loggers

Updated Nov 11, 2025

Creating and naming loggers

  • Use get_logger(name) to obtain a singleton FemtoLogger. Names must not be empty, start or end with ., or contain consecutive dots.
  • Logger parents are derived from dotted names. get_logger("api.v1") creates a parent api logger that ultimately propagates to root.
  • Call logger.set_propagate(False) to stop parent propagation. The default is to bubble records to ancestors, just like the stdlib.
  • reset_manager() clears all registered loggers. It is intended for tests and is not thread-safe.

Emitting records

  • logger.log(level, message) accepts the case-insensitive names "TRACE", "DEBUG", "INFO", "WARN", "WARNING", "ERROR", and "CRITICAL".
  • The method returns the formatted string when the record passes level checks (default format is "{logger} [LEVEL] message"), or None when the record is filtered out. This differs from logging.Logger.log(), which always returns None.
  • Convenience methods (logger.info, logger.warning, and so on) are not implemented yet; call log() directly or wrap it in a helper.
  • Currently, FemtoLogger sends only the text form of each record to handlers. There is no equivalent to extra, exc_info, stack_info, or lazy formatting. Build the final message string yourself before calling log().

Managing handlers and custom sinks

  • The built-in handlers implement the Rust-side FemtoHandlerTrait. Python handlers can be attached by supplying any object that exposes a callable handle(logger_name: str, level: str, message: str) method.
  • Python handlers run inside the logger’s worker thread. Ensure they are thread-safe and fast; slow handlers block the logger worker and can cause additional record drops.
  • logger.add_handler(handler) accepts either a Rust-backed handler or a Python handler as described above. Use logger.remove_handler(handler) or logger.clear_handlers() to detach them. Removals only affect records that are enqueued after the call because previously queued items already captured their handler list.
  • Use logger.get_dropped() to inspect how many records have been discarded because the logger queue was full or shutting down.