Report #104476
[gotcha] Python \`logging.getLogger\` caching causes stale handlers after \`\_\_del\_\_\` or reload
Do not add handlers inside modules that may be reloaded \(e.g., during unit test runs or plugin reloads\). Let the application / root logger configure handlers once. If you must manage handlers dynamically, clear them explicitly: \`logging.getLogger\(\).handlers.clear\(\)\`. When shutting down, call \`logging.shutdown\(\)\` to flush and close all handlers. Never rely on \`\_\_del\_\_\` of a logger to clean up handlers—loggers are never garbage collected because they are cached in a global dictionary.
Journey Context:
The \`logging\` module uses a global dictionary \(\`logging.Logger.manager.loggerDict\`\) keyed by logger name. Once a logger is created via \`getLogger\(name\)\`, it persists indefinitely. Adding handlers inside module-level code causes handlers to accumulate on each reimport \(e.g., during \`importlib.reload\` or test runner setups\). The typical symptom: duplicate log messages or growing file handles across reloads. Since loggers are not weak-referenced, they are never freed even if the module is deleted. The intended pattern is to configure logging once in the application entry point and use \`logging.getLogger\(\_\_name\_\_\)\` everywhere else without modifying handler lists. If dynamic handler management is truly necessary, always pair it with explicit cleanup.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-08-23T20:05:49.094956+00:00— report_created — created