Skip to content

FastStream keeps its own stderr handler next to lite-bootstrap's, so every FastStream log line is written twice #336

Closed

Description

@lesnik512

FastStream installs a StreamHandler(sys.stderr) with its colourized text format on the faststream logger at import time (faststream/_internal/logger/logging.py:94-99 in faststream 0.7.4). FastStreamLoggingInstrument.bootstrap (lite_bootstrap/bootstrappers/faststream_bootstrapper.py:155-163) hands brokers structlog.get_logger("faststream"), and MemoryLoggerFactory adds its MemoryHandler to the same stdlib logger on first use (lite_bootstrap/instruments/logging_factory.py:120-133) without removing FastStream's. Every FastStream record is then written as lite-bootstrap JSON on stdout and again, in FastStream's text format, on stderr.

At the default faststream_log_level=logging.WARNING the happy path logs nothing, so this shows up on errors and for services that lower the level. Measured on 2026-10-24 at 705d8a3 on Linux with 2 CPUs (CPython 3.14.9, a real RedisBroker, the subscriber's process_message on a prebuilt message), with faststream_log_level=logging.INFO: removing FastStream's handler as a prototype takes the cost from +35.2 to +25.1 µs per message, 10 µs per message or 5 µs per record ("Received" and "Processed"). The tables and scripts are to be published with #335.

Workaround today: logging_unset_handlers=["faststream"].

Work

  • Test first: after bootstrapping a FastStreamBootstrapper with a broker, logging.getLogger("faststream").handlers holds no StreamHandler writing to sys.stderr, and one FastStream INFO record at faststream_log_level=logging.INFO produces one line. It fails today.
  • In FastStreamLoggingInstrument.bootstrap, remove the handlers already on the faststream stdlib logger before lite-bootstrap's is added, and put them back in teardown() so a torn-down process logs as it did before bootstrap.
  • Alternative to weigh: clear existing handlers in MemoryLoggerFactory.__call__ for every logger it creates. That covers other libraries with the same pattern, but it touches loggers lite-bootstrap does not own, so the FastStream-only fix is the safer default.
  • Docs: none; docs/integrations/faststream.md does not describe FastStream's own output.

Verify: the new test passes, and the existing FastStream logging tests in tests/test_faststream_bootstrap.py still pass.

Not breaking: the duplicate stderr line goes away.

Activity

  1. added
    bugSomething isn't working
    needs-triageMaintainer needs to evaluate this issue
    on Oct 24, 2026
  2. added a commit that references this issue on Oct 28, 2026
    8b12711
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingneeds-triageMaintainer needs to evaluate this issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions