8000 gh-91513: Add 'asyncio' taskName to logging LogRecord attributes. (GH… · python/cpython@cc37706 · GitHub
[go: up one dir, main page]

Skip to content

Commit cc37706

Browse files
authored
gh-91513: Add 'asyncio' taskName to logging LogRecord attributes. (GH-93193)
1 parent 5185956 commit cc37706

File tree

5 files changed

+88
-7
lines changed

5 files changed

+88
-7
lines changed

Doc/howto/logging.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,6 +1101,9 @@ need:
11011101
| Current process name when using ``multiprocessing`` | Set ``logging.logMultiprocessing`` to ``False``. |
11021102
| to manage multiple processes. | |
11031103
+-----------------------------------------------------+---------------------------------------------------+
1104+
| Current :class:`asyncio.Task` name when using | Set ``logging.logAsyncioTasks`` to ``False``. |
1105+
| ``asyncio``. | |
1106+
+-----------------------------------------------------+---------------------------------------------------+
11041107

11051108
Also note that the core logging module only includes the basic handlers. If
11061109
you don't import :mod:`logging.handlers` and :mod:`logging.config`, they won't

Doc/library/logging.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,10 +872,14 @@ the options available to you.
872872
+----------------+-------------------------+-----------------------------------------------+
873873
| threadName | ``%(threadName)s`` | Thread name (if available). |
874874
+----------------+-------------------------+-----------------------------------------------+
875+
| taskName | ``%(taskName)s`` | :class:`asyncio.Task` name (if available). |
876+
+----------------+-------------------------+-----------------------------------------------+
875877

876878
.. versionchanged:: 3.1
877879
*processName* was added.
878880

881+
.. versionchanged:: 3.12
882+
*taskName* was added.
879883

880884
.. _logger-adapter:
881885

Lib/logging/__init__.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,20 +64,25 @@
6464
raiseExceptions = True
6565

6666
#
67-
# If you don't want threading information in the log, set this to zero
67+
# If you don't want threading information in the log, set this to False
6868
#
6969
logThreads = True
7070

7171
#
72-
# If you don't want multiprocessing information in the log, set this to zero
72+
# If you don't want multiprocessing information in the log, set this to False
8000
7373
#
7474
logMultiprocessing = True
7575

7676
#
77-
# If you don't want process information in the log, set this to zero
77+
# If you don't want process information in the log, set this to False
7878
#
7979
logProcesses = True
8080

81+
#
82+
# If you don't want asyncio task information in the log, set this to False
83+
#
84+
logAsyncioTasks = True
85+
8186
#---------------------------------------------------------------------------
8287
# Level related stuff
8388
#---------------------------------------------------------------------------
@@ -361,6 +366,15 @@ def __init__(self, name, level, pathname, lineno,
361366
else:
362367
self.process = None
363368

369+
self.taskName = None
370+
if logAsyncioTasks:
371+
asyncio = sys.modules.get('asyncio')
372+
if asyncio:
373+
try:
374+
self.taskName = asyncio.current_task().get_name()
375+
except Exception:
376+
pass
377+
364378
def __repr__(self):
365379
return '<LogRecord: %s, %s, %s, %s, "%s">'%(self.name, self.levelno,
366380
self.pathname, self.lineno, self.msg)
@@ -566,6 +580,7 @@ class Formatter(object):
566580
(typically at application startup time)
567581
%(thread)d Thread ID (if available)
568582
%(threadName)s Thread name (if available)
583+
%(taskName)s Task name (if available)
569584
%(process)d Process ID (if available)
570585
%(message)s The result of record.getMessage(), computed just as
571586
the record is emitted

Lib/test/test_logging.py

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
1919
Copyright (C) 2001-2021 Vinay Sajip. All Rights Reserved.
2020
"""
21-
2221
import logging
2322
import logging.handlers
2423
import logging.config
@@ -50,6 +49,7 @@
5049
from test.support.logging_helper import TestHandler
5150
import textwrap
5251
import threading
52+
import asyncio
5353
import time
5454
import unittest
5555
import warnings
@@ -4552,29 +4552,63 @@ def test_multiprocessing(self):
45524552
import multiprocessing
45534553

45544554
def test_optional(self):
4555-
r = logging.makeLogRecord({})
4555+
NONE = self.assertIsNone
45564556
NOT_NONE = self.assertIsNotNone
4557+
4558+
r = logging.makeLogRecord({})
45574559
NOT_NONE(r.thread)
45584560
NOT_NONE(r.threadName)
45594561
NOT_NONE(r.process)
45604562
NOT_NONE(r.processName)
4563+
NONE(r.taskName)
45614564
log_threads = logging.logThreads
45624565
log_processes = logging.logProcesses
45634566
log_multiprocessing = logging.logMultiprocessing
4567+
log_asyncio_tasks = logging.logAsyncioTasks
45644568
try:
45654569
logging.logThreads = False
45664570
logging.logProcesses = False
45674571
logging.logMultiprocessing = False
4572+
logging.logAsyncioTasks = False
45684573
r = logging.makeLogRecord({})
4569-
NONE = self.assertIsNone
4574+
45704575
NONE(r.thread)
45714576
NONE(r.threadName)
45724577
NONE(r.process)
45734578
NONE(r.processName)
4579+
NONE(r.taskName)
45744580
finally:
45754581
logging.logThreads = log_threads
45764582
logging.logProcesses = log_processes
45774583
logging.logMultiprocessing = log_multiprocessing
4584+
logging.logAsyncioTasks = log_asyncio_tasks
4585+
4586+
async def _make_record_async(self, assertion):
4587+
r = logging.makeLogRecord({})
4588+
assertion(r.taskName)
4589+
4590+
def test_taskName_with_asyncio_imported(self):
4591+
try:
4592+
make_record = self._make_record_async
4593+
with asyncio.Runner() as runner:
4594+
logging.logAsyncioTasks = True
4595+
runner.run(make_record(self.assertIsNotNone))
4596+
logging.logAsyncioTasks = False
4597+
runner.run(make_record(self.assertIsNone))
4598+
finally:
4599+
asyncio.set_event_loop_policy(None)
4600+
4601+
def test_taskName_without_asyncio_imported(self):
4602+
try:
4603+
make_record = self._make_record_async
4604+
with asyncio.Runner() as runner, support.swap_item(sys.modules, 'asyncio', None):
4605+
logging.logAsyncioTasks = True
4606+
runner.run(make_record(self.assertIsNone))
4607+
logging.logAsyncioTasks = False
4608+
runner.run(make_record(self.assertIsNone))
4609+
finally:
4610+
asyncio.set_event_loop_policy(None)
4611+
45784612

45794613
class BasicConfigTest(unittest.TestCase):
45804614

@@ -4853,6 +4887,30 @@ def dummy_handle_error(record):
48534887
# didn't write anything due to the encoding error
48544888
self.assertEqual(data, EED3 r'')
48554889

4890+
def test_log_taskName(self):
4891+
async def log_record():
4892+
logging.warning('hello world')
4893+
4894+
try:
4895+
encoding = 'utf-8'
4896+
logging.basicConfig(filename='test.log', errors='strict', encoding=encoding,
4897+
format='%(taskName)s - %(message)s', level=logging.WARNING)
4898+
4899+
self.assertEqual(len(logging.root.handlers), 1)
4900+
handler = logging.root.handlers[0]
4901+
self.assertIsInstance(handler, logging.FileHandler)
4902+
4903+
with asyncio.Runner(debug=True) as runner:
4904+
logging.logAsyncioTasks = True
4905+
runner.run(log_record())
4906+
finally:
4907+
asyncio.set_event_loop_policy(None)
4908+
handler.close()
4909+
with open('test.log', encoding='utf-8') as f:
4910+
data = f.read().strip()
4911+
os.remove('test.log')
4912+
self.assertRegex(data, r'Task-\d+ - hello world')
4913+
48564914

48574915
def _test_log(self, method, level=None):
48584916
# logging.root has no handlers so basicConfig should be called
@@ -5644,7 +5702,7 @@ def test__all__(self):
56445702
'logThreads', 'logMultiprocessing', 'logProcesses', 'currentframe',
56455703
'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
56465704
'Filterer', 'PlaceHolder', 'Manager', 'RootLogger', 'root',
5647-
'threading'}
5705+
'threading', 'logAsyncioTasks'}
56485706
support.check__all__(self, logging, not_exported=not_exported)
56495707

56505708

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added ``taskName`` attribute to :mod:`logging` module for use with :mod:`asyncio` tasks.

0 commit comments

Comments
 (0)
0