Skip to content

Default logger is recreated from global config on every log call #60

@tylerbutler

Description

@tylerbutler

Problem

The default_logger() function reads the global config and constructs a new Logger value on every call to birch.info, birch.error, etc.:

fn default_logger() -> Logger {
  let cfg = get_config()
  logger.new("app")
  |> logger.with_level(cfg.level)
  |> logger.with_handlers(cfg.handlers)
  |> logger.with_context(cfg.context)
}

This means every log statement allocates a new Logger, reads from persistent storage, and chains multiple builder calls — even if the config hasn't changed.

Impact

For applications with sparse logging (like CLIs), this is negligible. But for hot paths or high-throughput services, this per-call overhead adds up unnecessarily.

Proposal

Cache the default logger and invalidate it only when birch.configure() is called:

  • Store the built logger alongside the config in global state
  • On configure(), rebuild and cache the logger
  • On default_logger(), return the cached logger directly

This is a pure internal optimization — no API changes needed.

Alternatives

  • Use a generation counter: bump on configure(), rebuild logger only when the counter changes
  • Accept the current behavior and document it as a tradeoff of the convenience API (users needing performance should use named loggers directly)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions