logging: Logger.setLevel() and logging.disable() are O(number of loggers)

Offen
#160,936 2 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Anfängerfreundlichkeit
38/100
Issue-Typ
Bug
Klarheit
Größtenteils klar
Aktivitätsstatus
Aktiv
Tech-Stack
python
Bereich
backend, performance

Rechercherichtung

Start with Manager._clear_cache() and Logger.isEnabledFor() in CPython’s logging implementation, then inspect the logging tests that cover cache invalidation. The issue includes a benchmark reproducing quadratic behavior across thousands of loggers. Done means cache clearing scales with loggers that have cached values while preserving correct isEnabledFor() results after level changes.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

performance stdlib type-bug
Bug report

Every Logger.setLevel() and logging.disable() call goes through Manager._clear_cache(), which walks the whole loggerDict and clears each logger's isEnabledFor cache, even the ones that never cached anything. So setting the level on N loggers one by one is quadratic. That shows up in apps or test suites with thousands of loggers (one per module/plugin/connection) that get configured individually.

import logging, time

for n in (1000, 2000, 4000, 8000):
    logging.root.manager.loggerDict.clear()
    loggers = [logging.getLogger(f"app.mod{i}") for i in range(n)]
    for lg in loggers:
        lg.isEnabledFor(logging.DEBUG)
    t = time.perf_counter()
    for lg in loggers:
        lg.setLevel(logging.INFO)
    print(f"{n:5d} loggers: {time.perf_counter() - t:.3f} s")

On 3.14.7 this gives about 0.23 s at 2000 loggers, 0.89 s at 4000 and 4.4 s at 8000 (each doubling is about 4x).

A fix is to have the manager remember which loggers actually have something in their cache (a WeakSet filled on the isEnabledFor cache-miss path, which already holds the lock) and only clear those. The cache-hit path doesn't change. I have a patch ready and can open a PR.

CPython versions tested on:

3.14, CPython main branch

Operating systems tested on:

Linux

Linked PRs
  • gh-160937
Vorherrschende Sprache
Python
Sterne
77.8k
Forks
37.7k
Ø Merge
15 Std. 24 Min.
Gemergte PRs (30 T.)
728

Entwicklungsumgebung

In Codespaces öffnen

Startet den Dev-Container des Projekts im Browser, mit Ihrem eigenen GitHub-Konto.

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus python/cpython

Alle Issues in python/cpython

Ähnliche Issues

Weitere Issues zu Python

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.