Duplicate log output when using Python logging module
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
Duplicate log output in Python usually means the same LogRecord is being handled more than once. The common causes are attaching handlers at multiple levels in the logger hierarchy, reconfiguring logging repeatedly, or mixing application logging setup with library logging setup.
How Duplication Happens
Python logging is hierarchical. A logger named app.api is a child of app, which is a child of the root logger. By default, a child logger propagates records upward. If both the child and one of its ancestors have handlers, one log call can appear multiple times.
This example duplicates output:
The app logger handles the record once with its own handler, then propagates the same record to the root logger, which handles it again.
Fix 1: Configure Only One Layer
The cleanest approach is usually to attach handlers only once, often at the root logger, and let child loggers propagate naturally.
Here the child logger has no direct handler, so the record is emitted once by the root configuration.
Fix 2: Disable Propagation When You Intentionally Own the Handler
Sometimes a specific logger should write to its own destination and should not bubble upward. In that case, set propagate to False.
That stops the record at app and prevents a second emission by the root logger.
Fix 3: Avoid Adding Handlers Repeatedly
Another common duplication bug appears when setup code runs more than once. For example, a module import, test fixture, or web app reload may keep adding new handlers to the same logger.
Bad pattern:
If configure_logging() runs three times, the logger ends up with three handlers.
Safer version:
For applications that fully own logging, another option is to clear handlers before rebuilding the configuration.
Libraries Should Not Configure Global Logging Aggressively
If you are writing a library, do not call basicConfig() or attach global handlers as a side effect of import. Libraries should usually create loggers and let the application decide where records go.
That pattern avoids surprising duplicate or conflicting output in applications that already have a logging policy.
Inspect the Active Configuration
When duplication is confusing, print the relevant state:
This quickly reveals whether a logger has its own handler, whether propagation is still enabled, and whether the root logger is also emitting the same record.
Common Pitfalls
The most common mistake is attaching a handler to both a child logger and the root logger without disabling propagation. Another is calling configuration code multiple times in development servers, notebooks, or test runners.
Developers also sometimes use basicConfig() after custom handlers already exist and expect it to replace the old setup. It usually does not behave that way. Library code that configures root logging on import is another frequent source of duplicated or messy output.
Summary
- Duplicate log lines usually mean one record is being handled more than once.
- The usual cause is child logger propagation combined with handlers on multiple levels.
- Prefer one central logging configuration, often on the root logger.
- If a logger owns its own handler, set
propagate = False. - Guard against repeated handler registration when configuration code can run more than once.
Related reading
- Dynamic deployment of stateful applications in GKE
- Dynamic References to Specify Secret Manager Values in AWS Cloudformation
- Dynamically change log levels across all instances
- Dynamically changing log level without restarting the application
- Dynamic instantiation from string name of a class in dynamically imported module?
- Dynamic periodic tasks - alternatives to Celery beat
- Duplicate Symbols for Architecture arm64
- Duplicate symbols for architecture x86_64 under Xcode

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.