-
-
Notifications
You must be signed in to change notification settings - Fork 34.8k
Expand file tree
/
Copy path__init__.py
More file actions
2345 lines (2029 loc) · 81.5 KB
/
Copy path__init__.py
File metadata and controls
2345 lines (2029 loc) · 81.5 KB
Edit and raw actions
OlderNewer
1
# Copyright 2001-2022 by Vinay Sajip. All Rights Reserved.
2
#
3
# Permission to use, copy, modify, and distribute this software and its
4
# documentation for any purpose and without fee is hereby granted,
5
# provided that the above copyright notice appear in all copies and that
6
# both that copyright notice and this permission notice appear in
7
# supporting documentation, and that the name of Vinay Sajip
8
# not be used in advertising or publicity pertaining to distribution
9
# of the software without specific, written prior permission.
10
# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
11
# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12
# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
13
# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
14
# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
17
"""
18
Logging package for Python. Based on PEP 282 and comments thereto in
19
comp.lang.python.
20
21
Copyright (C) 2001-2022 Vinay Sajip. All Rights Reserved.
22
23
To use, simply 'import logging' and log away!
24
"""
25
26
import sys, os, time, io, re, traceback, warnings, weakref, collections.abc
27
28
from types import GenericAlias
29
from string import Template
30
from string import Formatter as StrFormatter
31
32
33
__all__ = ['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR',
34
'FATAL', 'FileHandler', 'Filter', 'Formatter', 'Handler', 'INFO',
35
'LogRecord', 'Logger', 'LoggerAdapter', 'NOTSET', 'NullHandler',
36
'StreamHandler', 'WARN', 'WARNING', 'addLevelName', 'basicConfig',
37
'captureWarnings', 'critical', 'debug', 'disable', 'error',
38
'exception', 'fatal', 'getLevelName', 'getLogger', 'getLoggerClass',
39
'info', 'log', 'makeLogRecord', 'setLoggerClass', 'shutdown',
40
'warn', 'warning', 'getLogRecordFactory', 'setLogRecordFactory',
41
'lastResort', 'raiseExceptions', 'getLevelNamesMapping',
42
'getHandlerByName', 'getHandlerNames']
43
44
import threading
45
46
__author__ = "Vinay Sajip <[email protected]>"
47
__status__ = "production"
48
# The following module attributes are no longer updated.
49
__version__ = "0.5.1.2"
50
__date__ = "07 February 2010"
51
52
#---------------------------------------------------------------------------
53
# Miscellaneous module data
54
#---------------------------------------------------------------------------
55
56
#
57
#_startTime is used as the base when calculating the relative time of events
58
#
59
_startTime = time.time()
60
61
#
62
#raiseExceptions is used to see if exceptions during handling should be
63
#propagated
64
#
65
raiseExceptions = True
66
67
#
68
# If you don't want threading information in the log, set this to False
69
#
70
logThreads = True
71
72
#
73
# If you don't want multiprocessing information in the log, set this to False
74
#
75
logMultiprocessing = True
76
77
#
78
# If you don't want process information in the log, set this to False
79
#
80
logProcesses = True
81
82
#
83
# If you don't want asyncio task information in the log, set this to False
84
#
85
logAsyncioTasks = True
86
87
#---------------------------------------------------------------------------
88
# Level related stuff
89
#---------------------------------------------------------------------------
90
#
91
# Default levels and level names, these can be replaced with any positive set
92
# of values having corresponding names. There is a pseudo-level, NOTSET, which
93
# is only really there as a lower limit for user-defined levels. Handlers and
94
# loggers are initialized with NOTSET so that they will log all messages, even
95
# at user-defined levels.
96
#
97
98
CRITICAL = 50
99
FATAL = CRITICAL
100
ERROR = 40
101
WARNING = 30
102
WARN = WARNING
103
INFO = 20
104
DEBUG = 10
105
NOTSET = 0
106
107
_levelToName = {
108
CRITICAL: 'CRITICAL',
109
ERROR: 'ERROR',
110
WARNING: 'WARNING',
111
INFO: 'INFO',
112
DEBUG: 'DEBUG',
113
NOTSET: 'NOTSET',
114
}
115
_nameToLevel = {
116
'CRITICAL': CRITICAL,
117
'FATAL': FATAL,
118
'ERROR': ERROR,
119
'WARN': WARNING,
120
'WARNING': WARNING,
121
'INFO': INFO,
122
'DEBUG': DEBUG,
123
'NOTSET': NOTSET,
124
}
125
126
def getLevelNamesMapping():
127
return _nameToLevel.copy()
128
129
def getLevelName(level):
130
"""
131
Return the textual or numeric representation of logging level 'level'.
132
133
If the level is one of the predefined levels (CRITICAL, ERROR, WARNING,
134
INFO, DEBUG) then you get the corresponding string. If you have
135
associated levels with names using addLevelName then the name you have
136
associated with 'level' is returned.
137
138
If a numeric value corresponding to one of the defined levels is passed
139
in, the corresponding string representation is returned.
140
141
If a string representation of the level is passed in, the corresponding
142
numeric value is returned.
143
144
If no matching numeric or string value is passed in, the string
145
'Level %s' % level is returned.
146
"""
147
# See Issues #22386, #27937 and #29220 for why it's this way
148
result = _levelToName.get(level)
149
if result is not None:
150
return result
151
result = _nameToLevel.get(level)
152
if result is not None:
153
return result
154
return "Level %s" % level
155
156
def addLevelName(level, levelName):
157
"""
158
Associate 'levelName' with 'level'.
159
160
This is used when converting levels to text during message formatting.
161
"""
162
_acquireLock()
163
try: #unlikely to cause an exception, but you never know...
164
_levelToName[level] = levelName
165
_nameToLevel[levelName] = level
166
finally:
167
_releaseLock()
168
169
if hasattr(sys, "_getframe"):
170
currentframe = lambda: sys._getframe(1)
171
else: #pragma: no cover
172
def currentframe():
173
"""Return the frame object for the caller's stack frame."""
174
try:
175
raise Exception
176
except Exception as exc:
177
return exc.__traceback__.tb_frame.f_back
178
179
#
180
# _srcfile is used when walking the stack to check when we've got the first
181
# caller stack frame, by skipping frames whose filename is that of this
182
# module's source. It therefore should contain the filename of this module's
183
# source file.
184
#
185
# Ordinarily we would use __file__ for this, but frozen modules don't always
186
# have __file__ set, for some reason (see Issue #21736). Thus, we get the
187
# filename from a handy code object from a function defined in this module.
188
# (There's no particular reason for picking addLevelName.)
189
#
190
191
_srcfile = os.path.normcase(addLevelName.__code__.co_filename)
192
193
# _srcfile is only used in conjunction with sys._getframe().
194
# Setting _srcfile to None will prevent findCaller() from being called. This
195
# way, you can avoid the overhead of fetching caller information.
196
197
# The following is based on warnings._is_internal_frame. It makes sure that
198
# frames of the import mechanism are skipped when logging at module level and
199
# using a stacklevel value greater than one.
200
def _is_internal_frame(frame):
201
"""Signal whether the frame is a CPython or logging module internal."""
202
filename = os.path.normcase(frame.f_code.co_filename)
203
return filename == _srcfile or (
204
"importlib" in filename and "_bootstrap" in filename
205
)
206
207
208
def _checkLevel(level):
209
if isinstance(level, int):
210
rv = level
211
elif str(level) == level:
212
if level not in _nameToLevel:
213
raise ValueError("Unknown level: %r" % level)
214
rv = _nameToLevel[level]
215
else:
216
raise TypeError("Level not an integer or a valid string: %r"
217
% (level,))
218
return rv
219
220
#---------------------------------------------------------------------------
221
# Thread-related stuff
222
#---------------------------------------------------------------------------
223
224
#
225
#_lock is used to serialize access to shared data structures in this module.
226
#This needs to be an RLock because fileConfig() creates and configures
227
#Handlers, and so might arbitrary user threads. Since Handler code updates the
228
#shared dictionary _handlers, it needs to acquire the lock. But if configuring,
229
#the lock would already have been acquired - so we need an RLock.
230
#The same argument applies to Loggers and Manager.loggerDict.
231
#
232
_lock = threading.RLock()
233
234
def _acquireLock():
235
"""
236
Acquire the module-level lock for serializing access to shared data.
237
238
This should be released with _releaseLock().
239
"""
240
if _lock:
241
_lock.acquire()
242
243
def _releaseLock():
244
"""
245
Release the module-level lock acquired by calling _acquireLock().
246
"""
247
if _lock:
248
_lock.release()
249
250
251
# Prevent a held logging lock from blocking a child from logging.
252
253
if not hasattr(os, 'register_at_fork'): # Windows and friends.
254
def _register_at_fork_reinit_lock(instance):
255
pass # no-op when os.register_at_fork does not exist.
256
else:
257
# A collection of instances with a _at_fork_reinit method (logging.Handler)
258
# to be called in the child after forking. The weakref avoids us keeping
259
# discarded Handler instances alive.
260
_at_fork_reinit_lock_weakset = weakref.WeakSet()
261
262
def _register_at_fork_reinit_lock(instance):
263
_acquireLock()
264
try:
265
_at_fork_reinit_lock_weakset.add(instance)
266
finally:
267
_releaseLock()
268
269
def _after_at_fork_child_reinit_locks():
270
for handler in _at_fork_reinit_lock_weakset:
271
handler._at_fork_reinit()
272
273
# _acquireLock() was called in the parent before forking.
274
# The lock is reinitialized to unlocked state.
275
_lock._at_fork_reinit()
276
277
os.register_at_fork(before=_acquireLock,
278
after_in_child=_after_at_fork_child_reinit_locks,
279
after_in_parent=_releaseLock)
280
281
282
#---------------------------------------------------------------------------
283
# The logging record
284
#---------------------------------------------------------------------------
285
286
class LogRecord(object):
287
"""
288
A LogRecord instance represents an event being logged.
289
290
LogRecord instances are created every time something is logged. They
291
contain all the information pertinent to the event being logged. The
292
main information passed in is in msg and args, which are combined
293
using str(msg) % args to create the message field of the record. The
294
record also includes information such as when the record was created,
295
the source line where the logging call was made, and any exception
296
information to be logged.
297
"""
298
def __init__(self, name, level, pathname, lineno,
299
msg, args, exc_info, func=None, sinfo=None, **kwargs):
300
"""
301
Initialize a logging record with interesting information.
302
"""
303
ct = time.time()
304
self.name = name
305
self.msg = msg
306
#
307
# The following statement allows passing of a dictionary as a sole
308
# argument, so that you can do something like
309
# logging.debug("a %(a)d b %(b)s", {'a':1, 'b':2})
310
# Suggested by Stefan Behnel.
311
# Note that without the test for args[0], we get a problem because
312
# during formatting, we test to see if the arg is present using
313
# 'if self.args:'. If the event being logged is e.g. 'Value is %d'
314
# and if the passed arg fails 'if self.args:' then no formatting
315
# is done. For example, logger.warning('Value is %d', 0) would log
316
# 'Value is %d' instead of 'Value is 0'.
317
# For the use case of passing a dictionary, this should not be a
318
# problem.
319
# Issue #21172: a request was made to relax the isinstance check
320
# to hasattr(args[0], '__getitem__'). However, the docs on string
321
# formatting still seem to suggest a mapping object is required.
322
# Thus, while not removing the isinstance check, it does now look
323
# for collections.abc.Mapping rather than, as before, dict.
324
if (args and len(args) == 1 and isinstance(args[0], collections.abc.Mapping)
325
and args[0]):
326
args = args[0]
327
self.args = args
328
self.levelname = getLevelName(level)
329
self.levelno = level
330
self.pathname = pathname
331
try:
332
self.filename = os.path.basename(pathname)
333
self.module = os.path.splitext(self.filename)[0]
334
except (TypeError, ValueError, AttributeError):
335
self.filename = pathname
336
self.module = "Unknown module"
337
self.exc_info = exc_info
338
self.exc_text = None # used to cache the traceback text
339
self.stack_info = sinfo
340
self.lineno = lineno
341
self.funcName = func
342
self.created = ct
343
self.msecs = int((ct - int(ct)) * 1000) + 0.0 # see gh-89047
344
self.relativeCreated = (self.created - _startTime) * 1000
345
if logThreads:
346
self.thread = threading.get_ident()
347
self.threadName = threading.current_thread().name
348
else: # pragma: no cover
349
self.thread = None
350
self.threadName = None
351
if not logMultiprocessing: # pragma: no cover
352
self.processName = None
353
else:
354
self.processName = 'MainProcess'
355
mp = sys.modules.get('multiprocessing')
356
if mp is not None:
357
# Errors may occur if multiprocessing has not finished loading
358
# yet - e.g. if a custom import hook causes third-party code
359
# to run when multiprocessing calls import. See issue 8200
360
# for an example
361
try:
362
self.processName = mp.current_process().name
363
except Exception: #pragma: no cover
364
pass
365
if logProcesses and hasattr(os, 'getpid'):
366
self.process = os.getpid()
367
else:
368
self.process = None
369
370
self.taskName = None
371
if logAsyncioTasks:
372
asyncio = sys.modules.get('asyncio')
373
if asyncio:
374
try:
375
self.taskName = asyncio.current_task().get_name()
376
except Exception:
377
pass
378
379
def __repr__(self):
380
return '<LogRecord: %s, %s, %s, %s, "%s">'%(self.name, self.levelno,
381
self.pathname, self.lineno, self.msg)
382
383
def getMessage(self):
384
"""
385
Return the message for this LogRecord.
386
387
Return the message for this LogRecord after merging any user-supplied
388
arguments with the message.
389
"""
390
msg = str(self.msg)
391
if self.args:
392
msg = msg % self.args
393
return msg
394
395
#
396
# Determine which class to use when instantiating log records.
397
#
398
_logRecordFactory = LogRecord
399
400
def setLogRecordFactory(factory):
401
"""
402
Set the factory to be used when instantiating a log record.
403
404
:param factory: A callable which will be called to instantiate
405
a log record.
406
"""
407
global _logRecordFactory
408
_logRecordFactory = factory
409
410
def getLogRecordFactory():
411
"""
412
Return the factory to be used when instantiating a log record.
413
"""
414
415
return _logRecordFactory
416
417
def makeLogRecord(dict):
418
"""
419
Make a LogRecord whose attributes are defined by the specified dictionary,
420
This function is useful for converting a logging event received over
421
a socket connection (which is sent as a dictionary) into a LogRecord
422
instance.
423
"""
424
rv = _logRecordFactory(None, None, "", 0, "", (), None, None)
425
rv.__dict__.update(dict)
426
return rv
427
428
429
#---------------------------------------------------------------------------
430
# Formatter classes and functions
431
#---------------------------------------------------------------------------
432
_str_formatter = StrFormatter()
433
del StrFormatter
434
435
436
class PercentStyle(object):
437
438
default_format = '%(message)s'
439
asctime_format = '%(asctime)s'
440
asctime_search = '%(asctime)'
441
validation_pattern = re.compile(r'%\(\w+\)[#0+ -]*(\*|\d+)?(\.(\*|\d+))?[diouxefgcrsa%]', re.I)
442
443
def __init__(self, fmt, *, defaults=None):
444
self._fmt = fmt or self.default_format
445
self._defaults = defaults
446
447
def usesTime(self):
448
return self._fmt.find(self.asctime_search) >= 0
449
450
def validate(self):
451
"""Validate the input format, ensure it matches the correct style"""
452
if not self.validation_pattern.search(self._fmt):
453
raise ValueError("Invalid format '%s' for '%s' style" % (self._fmt, self.default_format[0]))
454
455
def _format(self, record):
456
if defaults := self._defaults:
457
values = defaults | record.__dict__
458
else:
459
values = record.__dict__
460
return self._fmt % values
461
462
def format(self, record):
463
try:
464
return self._format(record)
465
except KeyError as e:
466
raise ValueError('Formatting field not found in record: %s' % e)
467
468
469
class StrFormatStyle(PercentStyle):
470
default_format = '{message}'
471
asctime_format = '{asctime}'
472
asctime_search = '{asctime'
473
474
fmt_spec = re.compile(r'^(.?[<>=^])?[+ -]?#?0?(\d+|{\w+})?[,_]?(\.(\d+|{\w+}))?[bcdefgnosx%]?$', re.I)
475
field_spec = re.compile(r'^(\d+|\w+)(\.\w+|\[[^]]+\])*$')
476
477
def _format(self, record):
478
if defaults := self._defaults:
479
values = defaults | record.__dict__
480
else:
481
values = record.__dict__
482
return self._fmt.format(**values)
483
484
def validate(self):
485
"""Validate the input format, ensure it is the correct string formatting style"""
486
fields = set()
487
try:
488
for _, fieldname, spec, conversion in _str_formatter.parse(self._fmt):
489
if fieldname:
490
if not self.field_spec.match(fieldname):
491
raise ValueError('invalid field name/expression: %r' % fieldname)
492
fields.add(fieldname)
493
if conversion and conversion not in 'rsa':
494
raise ValueError('invalid conversion: %r' % conversion)
495
if spec and not self.fmt_spec.match(spec):
496
raise ValueError('bad specifier: %r' % spec)
497
except ValueError as e:
498
raise ValueError('invalid format: %s' % e)
499
if not fields:
500
raise ValueError('invalid format: no fields')
501
502
503
class StringTemplateStyle(PercentStyle):
504
default_format = '${message}'
505
asctime_format = '${asctime}'
506
asctime_search = '${asctime}'
507
508
def __init__(self, *args, **kwargs):
509
super().__init__(*args, **kwargs)
510
self._tpl = Template(self._fmt)
511
512
def usesTime(self):
513
fmt = self._fmt
514
return fmt.find('$asctime') >= 0 or fmt.find(self.asctime_search) >= 0
515
516
def validate(self):
517
pattern = Template.pattern
518
fields = set()
519
for m in pattern.finditer(self._fmt):
520
d = m.groupdict()
521
if d['named']:
522
fields.add(d['named'])
523
elif d['braced']:
524
fields.add(d['braced'])
525
elif m.group(0) == '$':
526
raise ValueError('invalid format: bare \'$\' not allowed')
527
if not fields:
528
raise ValueError('invalid format: no fields')
529
530
def _format(self, record):
531
if defaults := self._defaults:
532
values = defaults | record.__dict__
533
else:
534
values = record.__dict__
535
return self._tpl.substitute(**values)
536
537
538
BASIC_FORMAT = "%(levelname)s:%(name)s:%(message)s"
539
540
_STYLES = {
541
'%': (PercentStyle, BASIC_FORMAT),
542
'{': (StrFormatStyle, '{levelname}:{name}:{message}'),
543
'$': (StringTemplateStyle, '${levelname}:${name}:${message}'),
544
}
545
546
class Formatter(object):
547
"""
548
Formatter instances are used to convert a LogRecord to text.
549
550
Formatters need to know how a LogRecord is constructed. They are
551
responsible for converting a LogRecord to (usually) a string which can
552
be interpreted by either a human or an external system. The base Formatter
553
allows a formatting string to be specified. If none is supplied, the
554
style-dependent default value, "%(message)s", "{message}", or
555
"${message}", is used.
556
557
The Formatter can be initialized with a format string which makes use of
558
knowledge of the LogRecord attributes - e.g. the default value mentioned
559
above makes use of the fact that the user's message and arguments are pre-
560
formatted into a LogRecord's message attribute. Currently, the useful
561
attributes in a LogRecord are described by:
562
563
%(name)s Name of the logger (logging channel)
564
%(levelno)s Numeric logging level for the message (DEBUG, INFO,
565
WARNING, ERROR, CRITICAL)
566
%(levelname)s Text logging level for the message ("DEBUG", "INFO",
567
"WARNING", "ERROR", "CRITICAL")
568
%(pathname)s Full pathname of the source file where the logging
569
call was issued (if available)
570
%(filename)s Filename portion of pathname
571
%(module)s Module (name portion of filename)
572
%(lineno)d Source line number where the logging call was issued
573
(if available)
574
%(funcName)s Function name
575
%(created)f Time when the LogRecord was created (time.time()
576
return value)
577
%(asctime)s Textual time when the LogRecord was created
578
%(msecs)d Millisecond portion of the creation time
579
%(relativeCreated)d Time in milliseconds when the LogRecord was created,
580
relative to the time the logging module was loaded
581
(typically at application startup time)
582
%(thread)d Thread ID (if available)
583
%(threadName)s Thread name (if available)
584
%(taskName)s Task name (if available)
585
%(process)d Process ID (if available)
586
%(message)s The result of record.getMessage(), computed just as
587
the record is emitted
588
"""
589
590
converter = time.localtime
591
592
def __init__(self, fmt=None, datefmt=None, style='%', validate=True, *,
593
defaults=None):
594
"""
595
Initialize the formatter with specified format strings.
596
597
Initialize the formatter either with the specified format string, or a
598
default as described above. Allow for specialized date formatting with
599
the optional datefmt argument. If datefmt is omitted, you get an
600
ISO8601-like (or RFC 3339-like) format.
601
602
Use a style parameter of '%', '{' or '$' to specify that you want to
603
use one of %-formatting, :meth:`str.format` (``{}``) formatting or
604
:class:`string.Template` formatting in your format string.
605
606
.. versionchanged:: 3.2
607
Added the ``style`` parameter.
608
"""
609
if style not in _STYLES:
610
raise ValueError('Style must be one of: %s' % ','.join(
611
_STYLES.keys()))
612
self._style = _STYLES[style][0](fmt, defaults=defaults)
613
if validate:
614
self._style.validate()
615
616
self._fmt = self._style._fmt
617
self.datefmt = datefmt
618
619
default_time_format = '%Y-%m-%d %H:%M:%S'
620
default_msec_format = '%s,%03d'
621
622
def formatTime(self, record, datefmt=None):
623
"""
624
Return the creation time of the specified LogRecord as formatted text.
625
626
This method should be called from format() by a formatter which
627
wants to make use of a formatted time. This method can be overridden
628
in formatters to provide for any specific requirement, but the
629
basic behaviour is as follows: if datefmt (a string) is specified,
630
it is used with time.strftime() to format the creation time of the
631
record. Otherwise, an ISO8601-like (or RFC 3339-like) format is used.
632
The resulting string is returned. This function uses a user-configurable
633
function to convert the creation time to a tuple. By default,
634
time.localtime() is used; to change this for a particular formatter
635
instance, set the 'converter' attribute to a function with the same
636
signature as time.localtime() or time.gmtime(). To change it for all
637
formatters, for example if you want all logging times to be shown in GMT,
638
set the 'converter' attribute in the Formatter class.
639
"""
640
ct = self.converter(record.created)
641
if datefmt:
642
s = time.strftime(datefmt, ct)
643
else:
644
s = time.strftime(self.default_time_format, ct)
645
if self.default_msec_format:
646
s = self.default_msec_format % (s, record.msecs)
647
return s
648
649
def formatException(self, ei):
650
"""
651
Format and return the specified exception information as a string.
652
653
This default implementation just uses
654
traceback.print_exception()
655
"""
656
sio = io.StringIO()
657
tb = ei[2]
658
# See issues #9427, #1553375. Commented out for now.
659
#if getattr(self, 'fullstack', False):
660
# traceback.print_stack(tb.tb_frame.f_back, file=sio)
661
traceback.print_exception(ei[0], ei[1], tb, None, sio)
662
s = sio.getvalue()
663
sio.close()
664
if s[-1:] == "\n":
665
s = s[:-1]
666
return s
667
668
def usesTime(self):
669
"""
670
Check if the format uses the creation time of the record.
671
"""
672
return self._style.usesTime()
673
674
def formatMessage(self, record):
675
return self._style.format(record)
676
677
def formatStack(self, stack_info):
678
"""
679
This method is provided as an extension point for specialized
680
formatting of stack information.
681
682
The input data is a string as returned from a call to
683
:func:`traceback.print_stack`, but with the last trailing newline
684
removed.
685
686
The base implementation just returns the value passed in.
687
"""
688
return stack_info
689
690
def format(self, record):
691
"""
692
Format the specified record as text.
693
694
The record's attribute dictionary is used as the operand to a
695
string formatting operation which yields the returned string.
696
Before formatting the dictionary, a couple of preparatory steps
697
are carried out. The message attribute of the record is computed
698
using LogRecord.getMessage(). If the formatting string uses the
699
time (as determined by a call to usesTime(), formatTime() is
700
called to format the event time. If there is exception information,
701
it is formatted using formatException() and appended to the message.
702
"""
703
record.message = record.getMessage()
704
if self.usesTime():
705
record.asctime = self.formatTime(record, self.datefmt)
706
s = self.formatMessage(record)
707
if record.exc_info:
708
# Cache the traceback text to avoid converting it multiple times
709
# (it's constant anyway)
710
if not record.exc_text:
711
record.exc_text = self.formatException(record.exc_info)
712
if record.exc_text:
713
if s[-1:] != "\n":
714
s = s + "\n"
715
s = s + record.exc_text
716
if record.stack_info:
717
if s[-1:] != "\n":
718
s = s + "\n"
719
s = s + self.formatStack(record.stack_info)
720
return s
721
722
#
723
# The default formatter to use when no other is specified
724
#
725
_defaultFormatter = Formatter()
726
727
class BufferingFormatter(object):
728
"""
729
A formatter suitable for formatting a number of records.
730
"""
731
def __init__(self, linefmt=None):
732
"""
733
Optionally specify a formatter which will be used to format each
734
individual record.
735
"""
736
if linefmt:
737
self.linefmt = linefmt
738
else:
739
self.linefmt = _defaultFormatter
740
741
def formatHeader(self, records):
742
"""
743
Return the header string for the specified records.
744
"""
745
return ""
746
747
def formatFooter(self, records):
748
"""
749
Return the footer string for the specified records.
750
"""
751
return ""
752
753
def format(self, records):
754
"""
755
Format the specified records and return the result as a string.
756
"""
757
rv = ""
758
if len(records) > 0:
759
rv = rv + self.formatHeader(records)
760
for record in records:
761
rv = rv + self.linefmt.format(record)
762
rv = rv + self.formatFooter(records)
763
return rv
764
765
#---------------------------------------------------------------------------
766
# Filter classes and functions
767
#---------------------------------------------------------------------------
768
769
class Filter(object):
770
"""
771
Filter instances are used to perform arbitrary filtering of LogRecords.
772
773
Loggers and Handlers can optionally use Filter instances to filter
774
records as desired. The base filter class only allows events which are
775
below a certain point in the logger hierarchy. For example, a filter
776
initialized with "A.B" will allow events logged by loggers "A.B",
777
"A.B.C", "A.B.C.D", "A.B.D" etc. but not "A.BB", "B.A.B" etc. If
778
initialized with the empty string, all events are passed.
779
"""
780
def __init__(self, name=''):
781
"""
782
Initialize a filter.
783
784
Initialize with the name of the logger which, together with its
785
children, will have its events allowed through the filter. If no
786
name is specified, allow every event.
787
"""
788
self.name = name
789
self.nlen = len(name)
790
791
def filter(self, record):
792
"""
793
Determine if the specified record is to be logged.
794
795
Returns True if the record should be logged, or False otherwise.
796
If deemed appropriate, the record may be modified in-place.
797
"""
798
if self.nlen == 0:
799
return True
800
elif self.name == record.name:
801
return True
802
elif record.name.find(self.name, 0, self.nlen) != 0:
803
return False
804
return (record.name[self.nlen] == ".")
805
806
class Filterer(object):
807
"""
808
A base class for loggers and handlers which allows them to share
809
common code.
810
"""
811
def __init__(self):
812
"""
813
Initialize the list of filters to be an empty list.
814
"""
815
self.filters = []
816
817
def addFilter(self, filter):
818
"""
819
Add the specified filter to this handler.
820
"""
821
if not (filter in self.filters):
822
self.filters.append(filter)
823
824
def removeFilter(self, filter):
825
"""
826
Remove the specified filter from this handler.
827
"""
828
if filter in self.filters:
829
self.filters.remove(filter)
830
831
def filter(self, record):
832
"""
833
Determine if a record is loggable by consulting all the filters.
834
835
The default is to allow the record to be logged; any filter can veto
836
this by returning a false value.
837
If a filter attached to a handler returns a log record instance,
838
then that instance is used in place of the original log record in
839
any further processing of the event by that handler.
840
If a filter returns any other true value, the original log record
841
is used in any further processing of the event by that handler.
842
843
If none of the filters return false values, this method returns
844
a log record.
845
If any of the filters return a false value, this method returns
846
a false value.
847
848
.. versionchanged:: 3.2
849
850
Allow filters to be just callables.
851
852
.. versionchanged:: 3.12
853
Allow filters to return a LogRecord instead of
854
modifying it in place.
855
"""
856
for f in self.filters:
857
if hasattr(f, 'filter'):
858
result = f.filter(record)
859
else:
860
result = f(record) # assume callable - will raise if not
861
if not result:
862
return False
863
if isinstance(result, LogRecord):
864
record = result
865
return record
866
867
#---------------------------------------------------------------------------
868
# Handler classes and functions
869
#---------------------------------------------------------------------------
870
871
_handlers = weakref.WeakValueDictionary() #map of handler names to handlers
872
_handlerList = [] # added to allow handlers to be removed in reverse of order initialized
873
874
def _removeHandlerRef(wr):
875
"""
876
Remove a handler reference from the internal cleanup list.
877
"""
878
# This function can be called during module teardown, when globals are
879
# set to None. It can also be called from another thread. So we need to
880
# pre-emptively grab the necessary globals and check if they're None,
881
# to prevent race conditions and failures during interpreter shutdown.
882
acquire, release, handlers = _acquireLock, _releaseLock, _handlerList
883
if acquire and release and handlers:
884
acquire()
885
try:
886
handlers.remove(wr)
887
except ValueError:
888
pass
889
finally:
890
release()
891
892
def _addHandlerRef(handler):
893
"""
894
Add a handler to the internal cleanup list using a weak reference.
895
"""
896
_acquireLock()
897
try:
898
_handlerList.append(weakref.ref(handler, _removeHandlerRef))
899
finally:
900
_releaseLock()
901
902
903
def getHandlerByName(name):
904
"""
905
Get a handler with the specified *name*, or None if there isn't one with
906
that name.
907
"""
908
return _handlers.get(name)
909
910
911
def getHandlerNames():
912
"""
913
Return all known handler names as an immutable set.
914
"""
915
result = set(_handlers.keys())
916
return frozenset(result)
917
918
919
class Handler(Filterer):
920
"""
921
Handler instances dispatch logging events to specific destinations.
922
923
The base handler class. Acts as a placeholder which defines the Handler
924
interface. Handlers can optionally use Formatter instances to format
925
records as desired. By default, no formatter is specified; in this case,
926
the 'raw' message as determined by record.message is logged.
927
"""
928
def __init__(self, level=NOTSET):
929
"""
930
Initializes the instance - basically setting the formatter to None
931
and the filter list to empty.
932
"""
933
Filterer.__init__(self)
934
self._name = None
935
self.level = _checkLevel(level)
936
self.formatter = None
937
self._closed = False
938
# Add the handler to the global _handlerList (for cleanup on shutdown)
939
_addHandlerRef(self)
940
self.createLock()
941
942
def get_name(self):
943
return self._name
944
945
def set_name(self, name):
946
_acquireLock()
947
try:
948
if self._name in _handlers:
949
del _handlers[self._name]
950
self._name = name
951
if name:
952
_handlers[name] = self
953
finally:
954
_releaseLock()
955
956
name = property(get_name, set_name)
957
958
def createLock(self):
959
"""
960
Acquire a thread lock for serializing access to the underlying I/O.
961
"""
962
self.lock = threading.RLock()
963
_register_at_fork_reinit_lock(self)
964
965
def _at_fork_reinit(self):
966
self.lock._at_fork_reinit()
967
968
def acquire(self):
969
"""
970
Acquire the I/O thread lock.
971
"""
972
if self.lock:
973
self.lock.acquire()
974
975
def release(self):
976
"""
977
Release the I/O thread lock.
978
"""
979
if self.lock:
980
self.lock.release()
981
982
def setLevel(self, level):
983
"""
984
Set the logging level of this handler. level must be an int or a str.
985
"""
986
self.level = _checkLevel(level)
987
988
def format(self, record):
989
"""
990
Format the specified record.
991
992
If a formatter is set, use it. Otherwise, use the default formatter
993
for the module.
994
"""
995
if self.formatter:
996
fmt = self.formatter
997
else:
998
fmt = _defaultFormatter
999
return fmt.format(record)
1000