summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjackh-ncl <1750152+jackh-ncl@users.noreply.github.com>2022-05-26 08:30:51 (GMT)
committerGitHub <noreply@github.com>2022-05-26 08:30:51 (GMT)
commitcc377063ef3ef99edce00e0c706809d9510e2bed (patch)
tree79b7df791bf0f18724d2f2fd078f4ca7ca426250
parent518595652759462b13904df767f69b8cc2c61143 (diff)
downloadcpython-cc377063ef3ef99edce00e0c706809d9510e2bed.zip
cpython-cc377063ef3ef99edce00e0c706809d9510e2bed.tar.gz
cpython-cc377063ef3ef99edce00e0c706809d9510e2bed.tar.bz2
gh-91513: Add 'asyncio' taskName to logging LogRecord attributes. (GH-93193)
-rw-r--r--Doc/howto/logging.rst3
-rw-r--r--Doc/library/logging.rst4
-rw-r--r--Lib/logging/__init__.py21
-rw-r--r--Lib/test/test_logging.py66
-rw-r--r--Misc/NEWS.d/next/Library/2022-05-25-00-21-28.gh-issue-91513.9VyCT4.rst1
5 files changed, 88 insertions, 7 deletions
diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst
index 9340062..125bde2 100644
--- a/Doc/howto/logging.rst
+++ b/Doc/howto/logging.rst
@@ -1101,6 +1101,9 @@ need:
| Current process name when using ``multiprocessing`` | Set ``logging.logMultiprocessing`` to ``False``. |
| to manage multiple processes. | |
+-----------------------------------------------------+---------------------------------------------------+
+| Current :class:`asyncio.Task` name when using | Set ``logging.logAsyncioTasks`` to ``False``. |
+| ``asyncio``. | |
++-----------------------------------------------------+---------------------------------------------------+
Also note that the core logging module only includes the basic handlers. If
you don't import :mod:`logging.handlers` and :mod:`logging.config`, they won't
diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst
index 3310c73..ac86bc8 100644
--- a/Doc/library/logging.rst
+++ b/Doc/library/logging.rst
@@ -872,10 +872,14 @@ the options available to you.
+----------------+-------------------------+-----------------------------------------------+
| threadName | ``%(threadName)s`` | Thread name (if available). |
+----------------+-------------------------+-----------------------------------------------+
+| taskName | ``%(taskName)s`` | :class:`asyncio.Task` name (if available). |
++----------------+-------------------------+-----------------------------------------------+
.. versionchanged:: 3.1
*processName* was added.
+.. versionchanged:: 3.12
+ *taskName* was added.
.. _logger-adapter:
diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py
index 79e4b7d..e7636e1 100644
--- a/Lib/logging/__init__.py
+++ b/Lib/logging/__init__.py
@@ -64,20 +64,25 @@ _startTime = time.time()
raiseExceptions = True
#
-# If you don't want threading information in the log, set this to zero
+# If you don't want threading information in the log, set this to False
#
logThreads = True
#
-# If you don't want multiprocessing information in the log, set this to zero
+# If you don't want multiprocessing information in the log, set this to False
#
logMultiprocessing = True
#
-# If you don't want process information in the log, set this to zero
+# If you don't want process information in the log, set this to False
#
logProcesses = True
+#
+# If you don't want asyncio task information in the log, set this to False
+#
+logAsyncioTasks = True
+
#---------------------------------------------------------------------------
# Level related stuff
#---------------------------------------------------------------------------
@@ -361,6 +366,15 @@ class LogRecord(object):
else:
self.process = None
+ self.taskName = None
+ if logAsyncioTasks:
+ asyncio = sys.modules.get('asyncio')
+ if asyncio:
+ try:
+ self.taskName = asyncio.current_task().get_name()
+ except Exception:
+ pass
+
def __repr__(self):
return '<LogRecord: %s, %s, %s, %s, "%s">'%(self.name, self.levelno,
self.pathname, self.lineno, self.msg)
@@ -566,6 +580,7 @@ class Formatter(object):
(typically at application startup time)
%(thread)d Thread ID (if available)
%(threadName)s Thread name (if available)
+ %(taskName)s Task name (if available)
%(process)d Process ID (if available)
%(message)s The result of record.getMessage(), computed just as
the record is emitted
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index fd56232..07804a2 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -18,7 +18,6 @@
Copyright (C) 2001-2021 Vinay Sajip. All Rights Reserved.
"""
-
import logging
import logging.handlers
import logging.config
@@ -50,6 +49,7 @@ from test.support import warnings_helper
from test.support.logging_helper import TestHandler
import textwrap
import threading
+import asyncio
import time
import unittest
import warnings
@@ -4552,29 +4552,63 @@ class LogRecordTest(BaseTest):
import multiprocessing
def test_optional(self):
- r = logging.makeLogRecord({})
+ NONE = self.assertIsNone
NOT_NONE = self.assertIsNotNone
+
+ r = logging.makeLogRecord({})
NOT_NONE(r.thread)
NOT_NONE(r.threadName)
NOT_NONE(r.process)
NOT_NONE(r.processName)
+ NONE(r.taskName)
log_threads = logging.logThreads
log_processes = logging.logProcesses
log_multiprocessing = logging.logMultiprocessing
+ log_asyncio_tasks = logging.logAsyncioTasks
try:
logging.logThreads = False
logging.logProcesses = False
logging.logMultiprocessing = False
+ logging.logAsyncioTasks = False
r = logging.makeLogRecord({})
- NONE = self.assertIsNone
+
NONE(r.thread)
NONE(r.threadName)
NONE(r.process)
NONE(r.processName)
+ NONE(r.taskName)
finally:
logging.logThreads = log_threads
logging.logProcesses = log_processes
logging.logMultiprocessing = log_multiprocessing
+ logging.logAsyncioTasks = log_asyncio_tasks
+
+ async def _make_record_async(self, assertion):
+ r = logging.makeLogRecord({})
+ assertion(r.taskName)
+
+ def test_taskName_with_asyncio_imported(self):
+ try:
+ make_record = self._make_record_async
+ with asyncio.Runner() as runner:
+ logging.logAsyncioTasks = True
+ runner.run(make_record(self.assertIsNotNone))
+ logging.logAsyncioTasks = False
+ runner.run(make_record(self.assertIsNone))
+ finally:
+ asyncio.set_event_loop_policy(None)
+
+ def test_taskName_without_asyncio_imported(self):
+ try:
+ make_record = self._make_record_async
+ with asyncio.Runner() as runner, support.swap_item(sys.modules, 'asyncio', None):
+ logging.logAsyncioTasks = True
+ runner.run(make_record(self.assertIsNone))
+ logging.logAsyncioTasks = False
+ runner.run(make_record(self.assertIsNone))
+ finally:
+ asyncio.set_event_loop_policy(None)
+
class BasicConfigTest(unittest.TestCase):
@@ -4853,6 +4887,30 @@ class BasicConfigTest(unittest.TestCase):
# didn't write anything due to the encoding error
self.assertEqual(data, r'')
+ def test_log_taskName(self):
+ async def log_record():
+ logging.warning('hello world')
+
+ try:
+ encoding = 'utf-8'
+ logging.basicConfig(filename='test.log', errors='strict', encoding=encoding,
+ format='%(taskName)s - %(message)s', level=logging.WARNING)
+
+ self.assertEqual(len(logging.root.handlers), 1)
+ handler = logging.root.handlers[0]
+ self.assertIsInstance(handler, logging.FileHandler)
+
+ with asyncio.Runner(debug=True) as runner:
+ logging.logAsyncioTasks = True
+ runner.run(log_record())
+ finally:
+ asyncio.set_event_loop_policy(None)
+ handler.close()
+ with open('test.log', encoding='utf-8') as f:
+ data = f.read().strip()
+ os.remove('test.log')
+ self.assertRegex(data, r'Task-\d+ - hello world')
+
def _test_log(self, method, level=None):
# logging.root has no handlers so basicConfig should be called
@@ -5644,7 +5702,7 @@ class MiscTestCase(unittest.TestCase):
'logThreads', 'logMultiprocessing', 'logProcesses', 'currentframe',
'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
'Filterer', 'PlaceHolder', 'Manager', 'RootLogger', 'root',
- 'threading'}
+ 'threading', 'logAsyncioTasks'}
support.check__all__(self, logging, not_exported=not_exported)
diff --git a/Misc/NEWS.d/next/Library/2022-05-25-00-21-28.gh-issue-91513.9VyCT4.rst b/Misc/NEWS.d/next/Library/2022-05-25-00-21-28.gh-issue-91513.9VyCT4.rst
new file mode 100644
index 0000000..f9f9376
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-05-25-00-21-28.gh-issue-91513.9VyCT4.rst
@@ -0,0 +1 @@
+Added ``taskName`` attribute to :mod:`logging` module for use with :mod:`asyncio` tasks.