From 4a907d8a732ed23bf8631e4aa4167a6fc04fdf07 Mon Sep 17 00:00:00 2001 From: Charles Machalow Date: Sat, 12 Apr 2025 09:22:22 -0700 Subject: [PATCH 1/2] gh-132106 - Make it so start can't be called again while running Prevents a thread leak --- Doc/library/logging.handlers.rst | 4 ++++ Doc/whatsnew/3.14.rst | 4 ++++ Lib/logging/handlers.py | 3 +++ Lib/test/test_logging.py | 11 +++++++++++ .../2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst | 2 ++ 5 files changed, 24 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst index b737fe311dfb6e..72312b512a5884 100644 --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -1186,6 +1186,10 @@ possible, while any potentially slow operations (such as sending an email via This starts up a background thread to monitor the queue for LogRecords to process. + .. versionchanged:: next + Raises :exc:`RuntimeError` if called and the listener is already + running. + .. method:: stop() Stops the listener. diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 762d53eeb2df1a..d961ec41bc816b 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -819,6 +819,10 @@ logging.handlers manager protocol, allowing it to be used in a :keyword:`with` statement. (Contributed by Charles Machalow in :gh:`132106`.) +* :meth:`~logging.handlers.QueueListener.start` will raise a :exc:`RuntimeError` + if the listener is already started. + (Contributed by Charles Machalow in :gh:`132106`.) + mimetypes --------- diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 0571ed2356345a..2748b5941eade2 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -1561,6 +1561,9 @@ def start(self): This starts up a background thread to monitor the queue for LogRecords to process. """ + if self._thread is not None: + raise RuntimeError("Listener already started") + self._thread = t = threading.Thread(target=self._monitor) t.daemon = True t.start() diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 11f6b64abe28fb..9305844829a500 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4356,6 +4356,17 @@ def test_queue_listener_context_manager(self): listener.stop() self.assertIsNone(listener._thread) + def test_queue_listener_multi_start(self): + handler = TestHandler(support.Matcher()) + with logging.handlers.QueueListener(self.queue, handler) as listener: + self.assertRaises(RuntimeError, listener.start) + + with listener: + self.assertRaises(RuntimeError, listener.start) + + listener.start() + listener.stop() + def test_queue_listener_with_StreamHandler(self): # Test that traceback and stack-info only appends once (bpo-34334, bpo-46755). listener = logging.handlers.QueueListener(self.queue, self.root_hdlr) diff --git a/Misc/NEWS.d/next/Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst b/Misc/NEWS.d/next/Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst new file mode 100644 index 00000000000000..4ebcbdbe919da2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst @@ -0,0 +1,2 @@ +:meth:`~logging.handlers.QueueListener.start` will raise a +:exc:`RuntimeError` if the listener is already started. From b40c1fd0e6deda55869c261c97e0971d97e89c51 Mon Sep 17 00:00:00 2001 From: Charles Machalow Date: Sat, 12 Apr 2025 10:02:05 -0700 Subject: [PATCH 2/2] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/whatsnew/3.14.rst | 4 ++-- .../Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index d961ec41bc816b..421d12660b7956 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -819,8 +819,8 @@ logging.handlers manager protocol, allowing it to be used in a :keyword:`with` statement. (Contributed by Charles Machalow in :gh:`132106`.) -* :meth:`~logging.handlers.QueueListener.start` will raise a :exc:`RuntimeError` - if the listener is already started. +* :meth:`QueueListener.start ` now + raises a :exc:`RuntimeError` if the listener is already started. (Contributed by Charles Machalow in :gh:`132106`.) diff --git a/Misc/NEWS.d/next/Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst b/Misc/NEWS.d/next/Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst index 4ebcbdbe919da2..b6d58a29f9b42f 100644 --- a/Misc/NEWS.d/next/Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst +++ b/Misc/NEWS.d/next/Library/2025-04-12-09-30-24.gh-issue-132106.OxUds3.rst @@ -1,2 +1,2 @@ -:meth:`~logging.handlers.QueueListener.start` will raise a -:exc:`RuntimeError` if the listener is already started. +:meth:`QueueListener.start ` now +raises a :exc:`RuntimeError` if the listener is already started.