xref: /third_party/python/Lib/logging/__init__.py (revision 7db96d56)
1# Copyright 2001-2019 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"""
18Logging package for Python. Based on PEP 282 and comments thereto in
19comp.lang.python.
20
21Copyright (C) 2001-2019 Vinay Sajip. All Rights Reserved.
22
23To use, simply 'import logging' and log away!
24"""
25
26import sys, os, time, io, re, traceback, warnings, weakref, collections.abc
27
28from types import GenericAlias
29from string import Template
30from 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
43import threading
44
45__author__  = "Vinay Sajip <vinay_sajip@red-dove.com>"
46__status__  = "production"
47# The following module attributes are no longer updated.
48__version__ = "0.5.1.2"
49__date__    = "07 February 2010"
50
51#---------------------------------------------------------------------------
52#   Miscellaneous module data
53#---------------------------------------------------------------------------
54
55#
56#_startTime is used as the base when calculating the relative time of events
57#
58_startTime = time.time()
59
60#
61#raiseExceptions is used to see if exceptions during handling should be
62#propagated
63#
64raiseExceptions = True
65
66#
67# If you don't want threading information in the log, set this to zero
68#
69logThreads = True
70
71#
72# If you don't want multiprocessing information in the log, set this to zero
73#
74logMultiprocessing = True
75
76#
77# If you don't want process information in the log, set this to zero
78#
79logProcesses = True
80
81#---------------------------------------------------------------------------
82#   Level related stuff
83#---------------------------------------------------------------------------
84#
85# Default levels and level names, these can be replaced with any positive set
86# of values having corresponding names. There is a pseudo-level, NOTSET, which
87# is only really there as a lower limit for user-defined levels. Handlers and
88# loggers are initialized with NOTSET so that they will log all messages, even
89# at user-defined levels.
90#
91
92CRITICAL = 50
93FATAL = CRITICAL
94ERROR = 40
95WARNING = 30
96WARN = WARNING
97INFO = 20
98DEBUG = 10
99NOTSET = 0
100
101_levelToName = {
102    CRITICAL: 'CRITICAL',
103    ERROR: 'ERROR',
104    WARNING: 'WARNING',
105    INFO: 'INFO',
106    DEBUG: 'DEBUG',
107    NOTSET: 'NOTSET',
108}
109_nameToLevel = {
110    'CRITICAL': CRITICAL,
111    'FATAL': FATAL,
112    'ERROR': ERROR,
113    'WARN': WARNING,
114    'WARNING': WARNING,
115    'INFO': INFO,
116    'DEBUG': DEBUG,
117    'NOTSET': NOTSET,
118}
119
120def getLevelNamesMapping():
121    return _nameToLevel.copy()
122
123def getLevelName(level):
124    """
125    Return the textual or numeric representation of logging level 'level'.
126
127    If the level is one of the predefined levels (CRITICAL, ERROR, WARNING,
128    INFO, DEBUG) then you get the corresponding string. If you have
129    associated levels with names using addLevelName then the name you have
130    associated with 'level' is returned.
131
132    If a numeric value corresponding to one of the defined levels is passed
133    in, the corresponding string representation is returned.
134
135    If a string representation of the level is passed in, the corresponding
136    numeric value is returned.
137
138    If no matching numeric or string value is passed in, the string
139    'Level %s' % level is returned.
140    """
141    # See Issues #22386, #27937 and #29220 for why it's this way
142    result = _levelToName.get(level)
143    if result is not None:
144        return result
145    result = _nameToLevel.get(level)
146    if result is not None:
147        return result
148    return "Level %s" % level
149
150def addLevelName(level, levelName):
151    """
152    Associate 'levelName' with 'level'.
153
154    This is used when converting levels to text during message formatting.
155    """
156    _acquireLock()
157    try:    #unlikely to cause an exception, but you never know...
158        _levelToName[level] = levelName
159        _nameToLevel[levelName] = level
160    finally:
161        _releaseLock()
162
163if hasattr(sys, "_getframe"):
164    currentframe = lambda: sys._getframe(1)
165else: #pragma: no cover
166    def currentframe():
167        """Return the frame object for the caller's stack frame."""
168        try:
169            raise Exception
170        except Exception:
171            return sys.exc_info()[2].tb_frame.f_back
172
173#
174# _srcfile is used when walking the stack to check when we've got the first
175# caller stack frame, by skipping frames whose filename is that of this
176# module's source. It therefore should contain the filename of this module's
177# source file.
178#
179# Ordinarily we would use __file__ for this, but frozen modules don't always
180# have __file__ set, for some reason (see Issue #21736). Thus, we get the
181# filename from a handy code object from a function defined in this module.
182# (There's no particular reason for picking addLevelName.)
183#
184
185_srcfile = os.path.normcase(addLevelName.__code__.co_filename)
186
187# _srcfile is only used in conjunction with sys._getframe().
188# Setting _srcfile to None will prevent findCaller() from being called. This
189# way, you can avoid the overhead of fetching caller information.
190
191# The following is based on warnings._is_internal_frame. It makes sure that
192# frames of the import mechanism are skipped when logging at module level and
193# using a stacklevel value greater than one.
194def _is_internal_frame(frame):
195    """Signal whether the frame is a CPython or logging module internal."""
196    filename = os.path.normcase(frame.f_code.co_filename)
197    return filename == _srcfile or (
198        "importlib" in filename and "_bootstrap" in filename
199    )
200
201
202def _checkLevel(level):
203    if isinstance(level, int):
204        rv = level
205    elif str(level) == level:
206        if level not in _nameToLevel:
207            raise ValueError("Unknown level: %r" % level)
208        rv = _nameToLevel[level]
209    else:
210        raise TypeError("Level not an integer or a valid string: %r"
211                        % (level,))
212    return rv
213
214#---------------------------------------------------------------------------
215#   Thread-related stuff
216#---------------------------------------------------------------------------
217
218#
219#_lock is used to serialize access to shared data structures in this module.
220#This needs to be an RLock because fileConfig() creates and configures
221#Handlers, and so might arbitrary user threads. Since Handler code updates the
222#shared dictionary _handlers, it needs to acquire the lock. But if configuring,
223#the lock would already have been acquired - so we need an RLock.
224#The same argument applies to Loggers and Manager.loggerDict.
225#
226_lock = threading.RLock()
227
228def _acquireLock():
229    """
230    Acquire the module-level lock for serializing access to shared data.
231
232    This should be released with _releaseLock().
233    """
234    if _lock:
235        _lock.acquire()
236
237def _releaseLock():
238    """
239    Release the module-level lock acquired by calling _acquireLock().
240    """
241    if _lock:
242        _lock.release()
243
244
245# Prevent a held logging lock from blocking a child from logging.
246
247if not hasattr(os, 'register_at_fork'):  # Windows and friends.
248    def _register_at_fork_reinit_lock(instance):
249        pass  # no-op when os.register_at_fork does not exist.
250else:
251    # A collection of instances with a _at_fork_reinit method (logging.Handler)
252    # to be called in the child after forking.  The weakref avoids us keeping
253    # discarded Handler instances alive.
254    _at_fork_reinit_lock_weakset = weakref.WeakSet()
255
256    def _register_at_fork_reinit_lock(instance):
257        _acquireLock()
258        try:
259            _at_fork_reinit_lock_weakset.add(instance)
260        finally:
261            _releaseLock()
262
263    def _after_at_fork_child_reinit_locks():
264        for handler in _at_fork_reinit_lock_weakset:
265            handler._at_fork_reinit()
266
267        # _acquireLock() was called in the parent before forking.
268        # The lock is reinitialized to unlocked state.
269        _lock._at_fork_reinit()
270
271    os.register_at_fork(before=_acquireLock,
272                        after_in_child=_after_at_fork_child_reinit_locks,
273                        after_in_parent=_releaseLock)
274
275
276#---------------------------------------------------------------------------
277#   The logging record
278#---------------------------------------------------------------------------
279
280class LogRecord(object):
281    """
282    A LogRecord instance represents an event being logged.
283
284    LogRecord instances are created every time something is logged. They
285    contain all the information pertinent to the event being logged. The
286    main information passed in is in msg and args, which are combined
287    using str(msg) % args to create the message field of the record. The
288    record also includes information such as when the record was created,
289    the source line where the logging call was made, and any exception
290    information to be logged.
291    """
292    def __init__(self, name, level, pathname, lineno,
293                 msg, args, exc_info, func=None, sinfo=None, **kwargs):
294        """
295        Initialize a logging record with interesting information.
296        """
297        ct = time.time()
298        self.name = name
299        self.msg = msg
300        #
301        # The following statement allows passing of a dictionary as a sole
302        # argument, so that you can do something like
303        #  logging.debug("a %(a)d b %(b)s", {'a':1, 'b':2})
304        # Suggested by Stefan Behnel.
305        # Note that without the test for args[0], we get a problem because
306        # during formatting, we test to see if the arg is present using
307        # 'if self.args:'. If the event being logged is e.g. 'Value is %d'
308        # and if the passed arg fails 'if self.args:' then no formatting
309        # is done. For example, logger.warning('Value is %d', 0) would log
310        # 'Value is %d' instead of 'Value is 0'.
311        # For the use case of passing a dictionary, this should not be a
312        # problem.
313        # Issue #21172: a request was made to relax the isinstance check
314        # to hasattr(args[0], '__getitem__'). However, the docs on string
315        # formatting still seem to suggest a mapping object is required.
316        # Thus, while not removing the isinstance check, it does now look
317        # for collections.abc.Mapping rather than, as before, dict.
318        if (args and len(args) == 1 and isinstance(args[0], collections.abc.Mapping)
319            and args[0]):
320            args = args[0]
321        self.args = args
322        self.levelname = getLevelName(level)
323        self.levelno = level
324        self.pathname = pathname
325        try:
326            self.filename = os.path.basename(pathname)
327            self.module = os.path.splitext(self.filename)[0]
328        except (TypeError, ValueError, AttributeError):
329            self.filename = pathname
330            self.module = "Unknown module"
331        self.exc_info = exc_info
332        self.exc_text = None      # used to cache the traceback text
333        self.stack_info = sinfo
334        self.lineno = lineno
335        self.funcName = func
336        self.created = ct
337        self.msecs = int((ct - int(ct)) * 1000) + 0.0  # see gh-89047
338        self.relativeCreated = (self.created - _startTime) * 1000
339        if logThreads:
340            self.thread = threading.get_ident()
341            self.threadName = threading.current_thread().name
342        else: # pragma: no cover
343            self.thread = None
344            self.threadName = None
345        if not logMultiprocessing: # pragma: no cover
346            self.processName = None
347        else:
348            self.processName = 'MainProcess'
349            mp = sys.modules.get('multiprocessing')
350            if mp is not None:
351                # Errors may occur if multiprocessing has not finished loading
352                # yet - e.g. if a custom import hook causes third-party code
353                # to run when multiprocessing calls import. See issue 8200
354                # for an example
355                try:
356                    self.processName = mp.current_process().name
357                except Exception: #pragma: no cover
358                    pass
359        if logProcesses and hasattr(os, 'getpid'):
360            self.process = os.getpid()
361        else:
362            self.process = None
363
364    def __repr__(self):
365        return '<LogRecord: %s, %s, %s, %s, "%s">'%(self.name, self.levelno,
366            self.pathname, self.lineno, self.msg)
367
368    def getMessage(self):
369        """
370        Return the message for this LogRecord.
371
372        Return the message for this LogRecord after merging any user-supplied
373        arguments with the message.
374        """
375        msg = str(self.msg)
376        if self.args:
377            msg = msg % self.args
378        return msg
379
380#
381#   Determine which class to use when instantiating log records.
382#
383_logRecordFactory = LogRecord
384
385def setLogRecordFactory(factory):
386    """
387    Set the factory to be used when instantiating a log record.
388
389    :param factory: A callable which will be called to instantiate
390    a log record.
391    """
392    global _logRecordFactory
393    _logRecordFactory = factory
394
395def getLogRecordFactory():
396    """
397    Return the factory to be used when instantiating a log record.
398    """
399
400    return _logRecordFactory
401
402def makeLogRecord(dict):
403    """
404    Make a LogRecord whose attributes are defined by the specified dictionary,
405    This function is useful for converting a logging event received over
406    a socket connection (which is sent as a dictionary) into a LogRecord
407    instance.
408    """
409    rv = _logRecordFactory(None, None, "", 0, "", (), None, None)
410    rv.__dict__.update(dict)
411    return rv
412
413
414#---------------------------------------------------------------------------
415#   Formatter classes and functions
416#---------------------------------------------------------------------------
417_str_formatter = StrFormatter()
418del StrFormatter
419
420
421class PercentStyle(object):
422
423    default_format = '%(message)s'
424    asctime_format = '%(asctime)s'
425    asctime_search = '%(asctime)'
426    validation_pattern = re.compile(r'%\(\w+\)[#0+ -]*(\*|\d+)?(\.(\*|\d+))?[diouxefgcrsa%]', re.I)
427
428    def __init__(self, fmt, *, defaults=None):
429        self._fmt = fmt or self.default_format
430        self._defaults = defaults
431
432    def usesTime(self):
433        return self._fmt.find(self.asctime_search) >= 0
434
435    def validate(self):
436        """Validate the input format, ensure it matches the correct style"""
437        if not self.validation_pattern.search(self._fmt):
438            raise ValueError("Invalid format '%s' for '%s' style" % (self._fmt, self.default_format[0]))
439
440    def _format(self, record):
441        if defaults := self._defaults:
442            values = defaults | record.__dict__
443        else:
444            values = record.__dict__
445        return self._fmt % values
446
447    def format(self, record):
448        try:
449            return self._format(record)
450        except KeyError as e:
451            raise ValueError('Formatting field not found in record: %s' % e)
452
453
454class StrFormatStyle(PercentStyle):
455    default_format = '{message}'
456    asctime_format = '{asctime}'
457    asctime_search = '{asctime'
458
459    fmt_spec = re.compile(r'^(.?[<>=^])?[+ -]?#?0?(\d+|{\w+})?[,_]?(\.(\d+|{\w+}))?[bcdefgnosx%]?$', re.I)
460    field_spec = re.compile(r'^(\d+|\w+)(\.\w+|\[[^]]+\])*$')
461
462    def _format(self, record):
463        if defaults := self._defaults:
464            values = defaults | record.__dict__
465        else:
466            values = record.__dict__
467        return self._fmt.format(**values)
468
469    def validate(self):
470        """Validate the input format, ensure it is the correct string formatting style"""
471        fields = set()
472        try:
473            for _, fieldname, spec, conversion in _str_formatter.parse(self._fmt):
474                if fieldname:
475                    if not self.field_spec.match(fieldname):
476                        raise ValueError('invalid field name/expression: %r' % fieldname)
477                    fields.add(fieldname)
478                if conversion and conversion not in 'rsa':
479                    raise ValueError('invalid conversion: %r' % conversion)
480                if spec and not self.fmt_spec.match(spec):
481                    raise ValueError('bad specifier: %r' % spec)
482        except ValueError as e:
483            raise ValueError('invalid format: %s' % e)
484        if not fields:
485            raise ValueError('invalid format: no fields')
486
487
488class StringTemplateStyle(PercentStyle):
489    default_format = '${message}'
490    asctime_format = '${asctime}'
491    asctime_search = '${asctime}'
492
493    def __init__(self, *args, **kwargs):
494        super().__init__(*args, **kwargs)
495        self._tpl = Template(self._fmt)
496
497    def usesTime(self):
498        fmt = self._fmt
499        return fmt.find('$asctime') >= 0 or fmt.find(self.asctime_search) >= 0
500
501    def validate(self):
502        pattern = Template.pattern
503        fields = set()
504        for m in pattern.finditer(self._fmt):
505            d = m.groupdict()
506            if d['named']:
507                fields.add(d['named'])
508            elif d['braced']:
509                fields.add(d['braced'])
510            elif m.group(0) == '$':
511                raise ValueError('invalid format: bare \'$\' not allowed')
512        if not fields:
513            raise ValueError('invalid format: no fields')
514
515    def _format(self, record):
516        if defaults := self._defaults:
517            values = defaults | record.__dict__
518        else:
519            values = record.__dict__
520        return self._tpl.substitute(**values)
521
522
523BASIC_FORMAT = "%(levelname)s:%(name)s:%(message)s"
524
525_STYLES = {
526    '%': (PercentStyle, BASIC_FORMAT),
527    '{': (StrFormatStyle, '{levelname}:{name}:{message}'),
528    '$': (StringTemplateStyle, '${levelname}:${name}:${message}'),
529}
530
531class Formatter(object):
532    """
533    Formatter instances are used to convert a LogRecord to text.
534
535    Formatters need to know how a LogRecord is constructed. They are
536    responsible for converting a LogRecord to (usually) a string which can
537    be interpreted by either a human or an external system. The base Formatter
538    allows a formatting string to be specified. If none is supplied, the
539    style-dependent default value, "%(message)s", "{message}", or
540    "${message}", is used.
541
542    The Formatter can be initialized with a format string which makes use of
543    knowledge of the LogRecord attributes - e.g. the default value mentioned
544    above makes use of the fact that the user's message and arguments are pre-
545    formatted into a LogRecord's message attribute. Currently, the useful
546    attributes in a LogRecord are described by:
547
548    %(name)s            Name of the logger (logging channel)
549    %(levelno)s         Numeric logging level for the message (DEBUG, INFO,
550                        WARNING, ERROR, CRITICAL)
551    %(levelname)s       Text logging level for the message ("DEBUG", "INFO",
552                        "WARNING", "ERROR", "CRITICAL")
553    %(pathname)s        Full pathname of the source file where the logging
554                        call was issued (if available)
555    %(filename)s        Filename portion of pathname
556    %(module)s          Module (name portion of filename)
557    %(lineno)d          Source line number where the logging call was issued
558                        (if available)
559    %(funcName)s        Function name
560    %(created)f         Time when the LogRecord was created (time.time()
561                        return value)
562    %(asctime)s         Textual time when the LogRecord was created
563    %(msecs)d           Millisecond portion of the creation time
564    %(relativeCreated)d Time in milliseconds when the LogRecord was created,
565                        relative to the time the logging module was loaded
566                        (typically at application startup time)
567    %(thread)d          Thread ID (if available)
568    %(threadName)s      Thread name (if available)
569    %(process)d         Process ID (if available)
570    %(message)s         The result of record.getMessage(), computed just as
571                        the record is emitted
572    """
573
574    converter = time.localtime
575
576    def __init__(self, fmt=None, datefmt=None, style='%', validate=True, *,
577                 defaults=None):
578        """
579        Initialize the formatter with specified format strings.
580
581        Initialize the formatter either with the specified format string, or a
582        default as described above. Allow for specialized date formatting with
583        the optional datefmt argument. If datefmt is omitted, you get an
584        ISO8601-like (or RFC 3339-like) format.
585
586        Use a style parameter of '%', '{' or '$' to specify that you want to
587        use one of %-formatting, :meth:`str.format` (``{}``) formatting or
588        :class:`string.Template` formatting in your format string.
589
590        .. versionchanged:: 3.2
591           Added the ``style`` parameter.
592        """
593        if style not in _STYLES:
594            raise ValueError('Style must be one of: %s' % ','.join(
595                             _STYLES.keys()))
596        self._style = _STYLES[style][0](fmt, defaults=defaults)
597        if validate:
598            self._style.validate()
599
600        self._fmt = self._style._fmt
601        self.datefmt = datefmt
602
603    default_time_format = '%Y-%m-%d %H:%M:%S'
604    default_msec_format = '%s,%03d'
605
606    def formatTime(self, record, datefmt=None):
607        """
608        Return the creation time of the specified LogRecord as formatted text.
609
610        This method should be called from format() by a formatter which
611        wants to make use of a formatted time. This method can be overridden
612        in formatters to provide for any specific requirement, but the
613        basic behaviour is as follows: if datefmt (a string) is specified,
614        it is used with time.strftime() to format the creation time of the
615        record. Otherwise, an ISO8601-like (or RFC 3339-like) format is used.
616        The resulting string is returned. This function uses a user-configurable
617        function to convert the creation time to a tuple. By default,
618        time.localtime() is used; to change this for a particular formatter
619        instance, set the 'converter' attribute to a function with the same
620        signature as time.localtime() or time.gmtime(). To change it for all
621        formatters, for example if you want all logging times to be shown in GMT,
622        set the 'converter' attribute in the Formatter class.
623        """
624        ct = self.converter(record.created)
625        if datefmt:
626            s = time.strftime(datefmt, ct)
627        else:
628            s = time.strftime(self.default_time_format, ct)
629            if self.default_msec_format:
630                s = self.default_msec_format % (s, record.msecs)
631        return s
632
633    def formatException(self, ei):
634        """
635        Format and return the specified exception information as a string.
636
637        This default implementation just uses
638        traceback.print_exception()
639        """
640        sio = io.StringIO()
641        tb = ei[2]
642        # See issues #9427, #1553375. Commented out for now.
643        #if getattr(self, 'fullstack', False):
644        #    traceback.print_stack(tb.tb_frame.f_back, file=sio)
645        traceback.print_exception(ei[0], ei[1], tb, None, sio)
646        s = sio.getvalue()
647        sio.close()
648        if s[-1:] == "\n":
649            s = s[:-1]
650        return s
651
652    def usesTime(self):
653        """
654        Check if the format uses the creation time of the record.
655        """
656        return self._style.usesTime()
657
658    def formatMessage(self, record):
659        return self._style.format(record)
660
661    def formatStack(self, stack_info):
662        """
663        This method is provided as an extension point for specialized
664        formatting of stack information.
665
666        The input data is a string as returned from a call to
667        :func:`traceback.print_stack`, but with the last trailing newline
668        removed.
669
670        The base implementation just returns the value passed in.
671        """
672        return stack_info
673
674    def format(self, record):
675        """
676        Format the specified record as text.
677
678        The record's attribute dictionary is used as the operand to a
679        string formatting operation which yields the returned string.
680        Before formatting the dictionary, a couple of preparatory steps
681        are carried out. The message attribute of the record is computed
682        using LogRecord.getMessage(). If the formatting string uses the
683        time (as determined by a call to usesTime(), formatTime() is
684        called to format the event time. If there is exception information,
685        it is formatted using formatException() and appended to the message.
686        """
687        record.message = record.getMessage()
688        if self.usesTime():
689            record.asctime = self.formatTime(record, self.datefmt)
690        s = self.formatMessage(record)
691        if record.exc_info:
692            # Cache the traceback text to avoid converting it multiple times
693            # (it's constant anyway)
694            if not record.exc_text:
695                record.exc_text = self.formatException(record.exc_info)
696        if record.exc_text:
697            if s[-1:] != "\n":
698                s = s + "\n"
699            s = s + record.exc_text
700        if record.stack_info:
701            if s[-1:] != "\n":
702                s = s + "\n"
703            s = s + self.formatStack(record.stack_info)
704        return s
705
706#
707#   The default formatter to use when no other is specified
708#
709_defaultFormatter = Formatter()
710
711class BufferingFormatter(object):
712    """
713    A formatter suitable for formatting a number of records.
714    """
715    def __init__(self, linefmt=None):
716        """
717        Optionally specify a formatter which will be used to format each
718        individual record.
719        """
720        if linefmt:
721            self.linefmt = linefmt
722        else:
723            self.linefmt = _defaultFormatter
724
725    def formatHeader(self, records):
726        """
727        Return the header string for the specified records.
728        """
729        return ""
730
731    def formatFooter(self, records):
732        """
733        Return the footer string for the specified records.
734        """
735        return ""
736
737    def format(self, records):
738        """
739        Format the specified records and return the result as a string.
740        """
741        rv = ""
742        if len(records) > 0:
743            rv = rv + self.formatHeader(records)
744            for record in records:
745                rv = rv + self.linefmt.format(record)
746            rv = rv + self.formatFooter(records)
747        return rv
748
749#---------------------------------------------------------------------------
750#   Filter classes and functions
751#---------------------------------------------------------------------------
752
753class Filter(object):
754    """
755    Filter instances are used to perform arbitrary filtering of LogRecords.
756
757    Loggers and Handlers can optionally use Filter instances to filter
758    records as desired. The base filter class only allows events which are
759    below a certain point in the logger hierarchy. For example, a filter
760    initialized with "A.B" will allow events logged by loggers "A.B",
761    "A.B.C", "A.B.C.D", "A.B.D" etc. but not "A.BB", "B.A.B" etc. If
762    initialized with the empty string, all events are passed.
763    """
764    def __init__(self, name=''):
765        """
766        Initialize a filter.
767
768        Initialize with the name of the logger which, together with its
769        children, will have its events allowed through the filter. If no
770        name is specified, allow every event.
771        """
772        self.name = name
773        self.nlen = len(name)
774
775    def filter(self, record):
776        """
777        Determine if the specified record is to be logged.
778
779        Returns True if the record should be logged, or False otherwise.
780        If deemed appropriate, the record may be modified in-place.
781        """
782        if self.nlen == 0:
783            return True
784        elif self.name == record.name:
785            return True
786        elif record.name.find(self.name, 0, self.nlen) != 0:
787            return False
788        return (record.name[self.nlen] == ".")
789
790class Filterer(object):
791    """
792    A base class for loggers and handlers which allows them to share
793    common code.
794    """
795    def __init__(self):
796        """
797        Initialize the list of filters to be an empty list.
798        """
799        self.filters = []
800
801    def addFilter(self, filter):
802        """
803        Add the specified filter to this handler.
804        """
805        if not (filter in self.filters):
806            self.filters.append(filter)
807
808    def removeFilter(self, filter):
809        """
810        Remove the specified filter from this handler.
811        """
812        if filter in self.filters:
813            self.filters.remove(filter)
814
815    def filter(self, record):
816        """
817        Determine if a record is loggable by consulting all the filters.
818
819        The default is to allow the record to be logged; any filter can veto
820        this and the record is then dropped. Returns a zero value if a record
821        is to be dropped, else non-zero.
822
823        .. versionchanged:: 3.2
824
825           Allow filters to be just callables.
826        """
827        rv = True
828        for f in self.filters:
829            if hasattr(f, 'filter'):
830                result = f.filter(record)
831            else:
832                result = f(record) # assume callable - will raise if not
833            if not result:
834                rv = False
835                break
836        return rv
837
838#---------------------------------------------------------------------------
839#   Handler classes and functions
840#---------------------------------------------------------------------------
841
842_handlers = weakref.WeakValueDictionary()  #map of handler names to handlers
843_handlerList = [] # added to allow handlers to be removed in reverse of order initialized
844
845def _removeHandlerRef(wr):
846    """
847    Remove a handler reference from the internal cleanup list.
848    """
849    # This function can be called during module teardown, when globals are
850    # set to None. It can also be called from another thread. So we need to
851    # pre-emptively grab the necessary globals and check if they're None,
852    # to prevent race conditions and failures during interpreter shutdown.
853    acquire, release, handlers = _acquireLock, _releaseLock, _handlerList
854    if acquire and release and handlers:
855        acquire()
856        try:
857            handlers.remove(wr)
858        except ValueError:
859            pass
860        finally:
861            release()
862
863def _addHandlerRef(handler):
864    """
865    Add a handler to the internal cleanup list using a weak reference.
866    """
867    _acquireLock()
868    try:
869        _handlerList.append(weakref.ref(handler, _removeHandlerRef))
870    finally:
871        _releaseLock()
872
873class Handler(Filterer):
874    """
875    Handler instances dispatch logging events to specific destinations.
876
877    The base handler class. Acts as a placeholder which defines the Handler
878    interface. Handlers can optionally use Formatter instances to format
879    records as desired. By default, no formatter is specified; in this case,
880    the 'raw' message as determined by record.message is logged.
881    """
882    def __init__(self, level=NOTSET):
883        """
884        Initializes the instance - basically setting the formatter to None
885        and the filter list to empty.
886        """
887        Filterer.__init__(self)
888        self._name = None
889        self.level = _checkLevel(level)
890        self.formatter = None
891        self._closed = False
892        # Add the handler to the global _handlerList (for cleanup on shutdown)
893        _addHandlerRef(self)
894        self.createLock()
895
896    def get_name(self):
897        return self._name
898
899    def set_name(self, name):
900        _acquireLock()
901        try:
902            if self._name in _handlers:
903                del _handlers[self._name]
904            self._name = name
905            if name:
906                _handlers[name] = self
907        finally:
908            _releaseLock()
909
910    name = property(get_name, set_name)
911
912    def createLock(self):
913        """
914        Acquire a thread lock for serializing access to the underlying I/O.
915        """
916        self.lock = threading.RLock()
917        _register_at_fork_reinit_lock(self)
918
919    def _at_fork_reinit(self):
920        self.lock._at_fork_reinit()
921
922    def acquire(self):
923        """
924        Acquire the I/O thread lock.
925        """
926        if self.lock:
927            self.lock.acquire()
928
929    def release(self):
930        """
931        Release the I/O thread lock.
932        """
933        if self.lock:
934            self.lock.release()
935
936    def setLevel(self, level):
937        """
938        Set the logging level of this handler.  level must be an int or a str.
939        """
940        self.level = _checkLevel(level)
941
942    def format(self, record):
943        """
944        Format the specified record.
945
946        If a formatter is set, use it. Otherwise, use the default formatter
947        for the module.
948        """
949        if self.formatter:
950            fmt = self.formatter
951        else:
952            fmt = _defaultFormatter
953        return fmt.format(record)
954
955    def emit(self, record):
956        """
957        Do whatever it takes to actually log the specified logging record.
958
959        This version is intended to be implemented by subclasses and so
960        raises a NotImplementedError.
961        """
962        raise NotImplementedError('emit must be implemented '
963                                  'by Handler subclasses')
964
965    def handle(self, record):
966        """
967        Conditionally emit the specified logging record.
968
969        Emission depends on filters which may have been added to the handler.
970        Wrap the actual emission of the record with acquisition/release of
971        the I/O thread lock. Returns whether the filter passed the record for
972        emission.
973        """
974        rv = self.filter(record)
975        if rv:
976            self.acquire()
977            try:
978                self.emit(record)
979            finally:
980                self.release()
981        return rv
982
983    def setFormatter(self, fmt):
984        """
985        Set the formatter for this handler.
986        """
987        self.formatter = fmt
988
989    def flush(self):
990        """
991        Ensure all logging output has been flushed.
992
993        This version does nothing and is intended to be implemented by
994        subclasses.
995        """
996        pass
997
998    def close(self):
999        """
1000        Tidy up any resources used by the handler.
1001
1002        This version removes the handler from an internal map of handlers,
1003        _handlers, which is used for handler lookup by name. Subclasses
1004        should ensure that this gets called from overridden close()
1005        methods.
1006        """
1007        #get the module data lock, as we're updating a shared structure.
1008        _acquireLock()
1009        try:    #unlikely to raise an exception, but you never know...
1010            self._closed = True
1011            if self._name and self._name in _handlers:
1012                del _handlers[self._name]
1013        finally:
1014            _releaseLock()
1015
1016    def handleError(self, record):
1017        """
1018        Handle errors which occur during an emit() call.
1019
1020        This method should be called from handlers when an exception is
1021        encountered during an emit() call. If raiseExceptions is false,
1022        exceptions get silently ignored. This is what is mostly wanted
1023        for a logging system - most users will not care about errors in
1024        the logging system, they are more interested in application errors.
1025        You could, however, replace this with a custom handler if you wish.
1026        The record which was being processed is passed in to this method.
1027        """
1028        if raiseExceptions and sys.stderr:  # see issue 13807
1029            t, v, tb = sys.exc_info()
1030            try:
1031                sys.stderr.write('--- Logging error ---\n')
1032                traceback.print_exception(t, v, tb, None, sys.stderr)
1033                sys.stderr.write('Call stack:\n')
1034                # Walk the stack frame up until we're out of logging,
1035                # so as to print the calling context.
1036                frame = tb.tb_frame
1037                while (frame and os.path.dirname(frame.f_code.co_filename) ==
1038                       __path__[0]):
1039                    frame = frame.f_back
1040                if frame:
1041                    traceback.print_stack(frame, file=sys.stderr)
1042                else:
1043                    # couldn't find the right stack frame, for some reason
1044                    sys.stderr.write('Logged from file %s, line %s\n' % (
1045                                     record.filename, record.lineno))
1046                # Issue 18671: output logging message and arguments
1047                try:
1048                    sys.stderr.write('Message: %r\n'
1049                                     'Arguments: %s\n' % (record.msg,
1050                                                          record.args))
1051                except RecursionError:  # See issue 36272
1052                    raise
1053                except Exception:
1054                    sys.stderr.write('Unable to print the message and arguments'
1055                                     ' - possible formatting error.\nUse the'
1056                                     ' traceback above to help find the error.\n'
1057                                    )
1058            except OSError: #pragma: no cover
1059                pass    # see issue 5971
1060            finally:
1061                del t, v, tb
1062
1063    def __repr__(self):
1064        level = getLevelName(self.level)
1065        return '<%s (%s)>' % (self.__class__.__name__, level)
1066
1067class StreamHandler(Handler):
1068    """
1069    A handler class which writes logging records, appropriately formatted,
1070    to a stream. Note that this class does not close the stream, as
1071    sys.stdout or sys.stderr may be used.
1072    """
1073
1074    terminator = '\n'
1075
1076    def __init__(self, stream=None):
1077        """
1078        Initialize the handler.
1079
1080        If stream is not specified, sys.stderr is used.
1081        """
1082        Handler.__init__(self)
1083        if stream is None:
1084            stream = sys.stderr
1085        self.stream = stream
1086
1087    def flush(self):
1088        """
1089        Flushes the stream.
1090        """
1091        self.acquire()
1092        try:
1093            if self.stream and hasattr(self.stream, "flush"):
1094                self.stream.flush()
1095        finally:
1096            self.release()
1097
1098    def emit(self, record):
1099        """
1100        Emit a record.
1101
1102        If a formatter is specified, it is used to format the record.
1103        The record is then written to the stream with a trailing newline.  If
1104        exception information is present, it is formatted using
1105        traceback.print_exception and appended to the stream.  If the stream
1106        has an 'encoding' attribute, it is used to determine how to do the
1107        output to the stream.
1108        """
1109        try:
1110            msg = self.format(record)
1111            stream = self.stream
1112            # issue 35046: merged two stream.writes into one.
1113            stream.write(msg + self.terminator)
1114            self.flush()
1115        except RecursionError:  # See issue 36272
1116            raise
1117        except Exception:
1118            self.handleError(record)
1119
1120    def setStream(self, stream):
1121        """
1122        Sets the StreamHandler's stream to the specified value,
1123        if it is different.
1124
1125        Returns the old stream, if the stream was changed, or None
1126        if it wasn't.
1127        """
1128        if stream is self.stream:
1129            result = None
1130        else:
1131            result = self.stream
1132            self.acquire()
1133            try:
1134                self.flush()
1135                self.stream = stream
1136            finally:
1137                self.release()
1138        return result
1139
1140    def __repr__(self):
1141        level = getLevelName(self.level)
1142        name = getattr(self.stream, 'name', '')
1143        #  bpo-36015: name can be an int
1144        name = str(name)
1145        if name:
1146            name += ' '
1147        return '<%s %s(%s)>' % (self.__class__.__name__, name, level)
1148
1149    __class_getitem__ = classmethod(GenericAlias)
1150
1151
1152class FileHandler(StreamHandler):
1153    """
1154    A handler class which writes formatted logging records to disk files.
1155    """
1156    def __init__(self, filename, mode='a', encoding=None, delay=False, errors=None):
1157        """
1158        Open the specified file and use it as the stream for logging.
1159        """
1160        # Issue #27493: add support for Path objects to be passed in
1161        filename = os.fspath(filename)
1162        #keep the absolute path, otherwise derived classes which use this
1163        #may come a cropper when the current directory changes
1164        self.baseFilename = os.path.abspath(filename)
1165        self.mode = mode
1166        self.encoding = encoding
1167        if "b" not in mode:
1168            self.encoding = io.text_encoding(encoding)
1169        self.errors = errors
1170        self.delay = delay
1171        # bpo-26789: FileHandler keeps a reference to the builtin open()
1172        # function to be able to open or reopen the file during Python
1173        # finalization.
1174        self._builtin_open = open
1175        if delay:
1176            #We don't open the stream, but we still need to call the
1177            #Handler constructor to set level, formatter, lock etc.
1178            Handler.__init__(self)
1179            self.stream = None
1180        else:
1181            StreamHandler.__init__(self, self._open())
1182
1183    def close(self):
1184        """
1185        Closes the stream.
1186        """
1187        self.acquire()
1188        try:
1189            try:
1190                if self.stream:
1191                    try:
1192                        self.flush()
1193                    finally:
1194                        stream = self.stream
1195                        self.stream = None
1196                        if hasattr(stream, "close"):
1197                            stream.close()
1198            finally:
1199                # Issue #19523: call unconditionally to
1200                # prevent a handler leak when delay is set
1201                # Also see Issue #42378: we also rely on
1202                # self._closed being set to True there
1203                StreamHandler.close(self)
1204        finally:
1205            self.release()
1206
1207    def _open(self):
1208        """
1209        Open the current base file with the (original) mode and encoding.
1210        Return the resulting stream.
1211        """
1212        open_func = self._builtin_open
1213        return open_func(self.baseFilename, self.mode,
1214                         encoding=self.encoding, errors=self.errors)
1215
1216    def emit(self, record):
1217        """
1218        Emit a record.
1219
1220        If the stream was not opened because 'delay' was specified in the
1221        constructor, open it before calling the superclass's emit.
1222
1223        If stream is not open, current mode is 'w' and `_closed=True`, record
1224        will not be emitted (see Issue #42378).
1225        """
1226        if self.stream is None:
1227            if self.mode != 'w' or not self._closed:
1228                self.stream = self._open()
1229        if self.stream:
1230            StreamHandler.emit(self, record)
1231
1232    def __repr__(self):
1233        level = getLevelName(self.level)
1234        return '<%s %s (%s)>' % (self.__class__.__name__, self.baseFilename, level)
1235
1236
1237class _StderrHandler(StreamHandler):
1238    """
1239    This class is like a StreamHandler using sys.stderr, but always uses
1240    whatever sys.stderr is currently set to rather than the value of
1241    sys.stderr at handler construction time.
1242    """
1243    def __init__(self, level=NOTSET):
1244        """
1245        Initialize the handler.
1246        """
1247        Handler.__init__(self, level)
1248
1249    @property
1250    def stream(self):
1251        return sys.stderr
1252
1253
1254_defaultLastResort = _StderrHandler(WARNING)
1255lastResort = _defaultLastResort
1256
1257#---------------------------------------------------------------------------
1258#   Manager classes and functions
1259#---------------------------------------------------------------------------
1260
1261class PlaceHolder(object):
1262    """
1263    PlaceHolder instances are used in the Manager logger hierarchy to take
1264    the place of nodes for which no loggers have been defined. This class is
1265    intended for internal use only and not as part of the public API.
1266    """
1267    def __init__(self, alogger):
1268        """
1269        Initialize with the specified logger being a child of this placeholder.
1270        """
1271        self.loggerMap = { alogger : None }
1272
1273    def append(self, alogger):
1274        """
1275        Add the specified logger as a child of this placeholder.
1276        """
1277        if alogger not in self.loggerMap:
1278            self.loggerMap[alogger] = None
1279
1280#
1281#   Determine which class to use when instantiating loggers.
1282#
1283
1284def setLoggerClass(klass):
1285    """
1286    Set the class to be used when instantiating a logger. The class should
1287    define __init__() such that only a name argument is required, and the
1288    __init__() should call Logger.__init__()
1289    """
1290    if klass != Logger:
1291        if not issubclass(klass, Logger):
1292            raise TypeError("logger not derived from logging.Logger: "
1293                            + klass.__name__)
1294    global _loggerClass
1295    _loggerClass = klass
1296
1297def getLoggerClass():
1298    """
1299    Return the class to be used when instantiating a logger.
1300    """
1301    return _loggerClass
1302
1303class Manager(object):
1304    """
1305    There is [under normal circumstances] just one Manager instance, which
1306    holds the hierarchy of loggers.
1307    """
1308    def __init__(self, rootnode):
1309        """
1310        Initialize the manager with the root node of the logger hierarchy.
1311        """
1312        self.root = rootnode
1313        self.disable = 0
1314        self.emittedNoHandlerWarning = False
1315        self.loggerDict = {}
1316        self.loggerClass = None
1317        self.logRecordFactory = None
1318
1319    @property
1320    def disable(self):
1321        return self._disable
1322
1323    @disable.setter
1324    def disable(self, value):
1325        self._disable = _checkLevel(value)
1326
1327    def getLogger(self, name):
1328        """
1329        Get a logger with the specified name (channel name), creating it
1330        if it doesn't yet exist. This name is a dot-separated hierarchical
1331        name, such as "a", "a.b", "a.b.c" or similar.
1332
1333        If a PlaceHolder existed for the specified name [i.e. the logger
1334        didn't exist but a child of it did], replace it with the created
1335        logger and fix up the parent/child references which pointed to the
1336        placeholder to now point to the logger.
1337        """
1338        rv = None
1339        if not isinstance(name, str):
1340            raise TypeError('A logger name must be a string')
1341        _acquireLock()
1342        try:
1343            if name in self.loggerDict:
1344                rv = self.loggerDict[name]
1345                if isinstance(rv, PlaceHolder):
1346                    ph = rv
1347                    rv = (self.loggerClass or _loggerClass)(name)
1348                    rv.manager = self
1349                    self.loggerDict[name] = rv
1350                    self._fixupChildren(ph, rv)
1351                    self._fixupParents(rv)
1352            else:
1353                rv = (self.loggerClass or _loggerClass)(name)
1354                rv.manager = self
1355                self.loggerDict[name] = rv
1356                self._fixupParents(rv)
1357        finally:
1358            _releaseLock()
1359        return rv
1360
1361    def setLoggerClass(self, klass):
1362        """
1363        Set the class to be used when instantiating a logger with this Manager.
1364        """
1365        if klass != Logger:
1366            if not issubclass(klass, Logger):
1367                raise TypeError("logger not derived from logging.Logger: "
1368                                + klass.__name__)
1369        self.loggerClass = klass
1370
1371    def setLogRecordFactory(self, factory):
1372        """
1373        Set the factory to be used when instantiating a log record with this
1374        Manager.
1375        """
1376        self.logRecordFactory = factory
1377
1378    def _fixupParents(self, alogger):
1379        """
1380        Ensure that there are either loggers or placeholders all the way
1381        from the specified logger to the root of the logger hierarchy.
1382        """
1383        name = alogger.name
1384        i = name.rfind(".")
1385        rv = None
1386        while (i > 0) and not rv:
1387            substr = name[:i]
1388            if substr not in self.loggerDict:
1389                self.loggerDict[substr] = PlaceHolder(alogger)
1390            else:
1391                obj = self.loggerDict[substr]
1392                if isinstance(obj, Logger):
1393                    rv = obj
1394                else:
1395                    assert isinstance(obj, PlaceHolder)
1396                    obj.append(alogger)
1397            i = name.rfind(".", 0, i - 1)
1398        if not rv:
1399            rv = self.root
1400        alogger.parent = rv
1401
1402    def _fixupChildren(self, ph, alogger):
1403        """
1404        Ensure that children of the placeholder ph are connected to the
1405        specified logger.
1406        """
1407        name = alogger.name
1408        namelen = len(name)
1409        for c in ph.loggerMap.keys():
1410            #The if means ... if not c.parent.name.startswith(nm)
1411            if c.parent.name[:namelen] != name:
1412                alogger.parent = c.parent
1413                c.parent = alogger
1414
1415    def _clear_cache(self):
1416        """
1417        Clear the cache for all loggers in loggerDict
1418        Called when level changes are made
1419        """
1420
1421        _acquireLock()
1422        for logger in self.loggerDict.values():
1423            if isinstance(logger, Logger):
1424                logger._cache.clear()
1425        self.root._cache.clear()
1426        _releaseLock()
1427
1428#---------------------------------------------------------------------------
1429#   Logger classes and functions
1430#---------------------------------------------------------------------------
1431
1432class Logger(Filterer):
1433    """
1434    Instances of the Logger class represent a single logging channel. A
1435    "logging channel" indicates an area of an application. Exactly how an
1436    "area" is defined is up to the application developer. Since an
1437    application can have any number of areas, logging channels are identified
1438    by a unique string. Application areas can be nested (e.g. an area
1439    of "input processing" might include sub-areas "read CSV files", "read
1440    XLS files" and "read Gnumeric files"). To cater for this natural nesting,
1441    channel names are organized into a namespace hierarchy where levels are
1442    separated by periods, much like the Java or Python package namespace. So
1443    in the instance given above, channel names might be "input" for the upper
1444    level, and "input.csv", "input.xls" and "input.gnu" for the sub-levels.
1445    There is no arbitrary limit to the depth of nesting.
1446    """
1447    def __init__(self, name, level=NOTSET):
1448        """
1449        Initialize the logger with a name and an optional level.
1450        """
1451        Filterer.__init__(self)
1452        self.name = name
1453        self.level = _checkLevel(level)
1454        self.parent = None
1455        self.propagate = True
1456        self.handlers = []
1457        self.disabled = False
1458        self._cache = {}
1459
1460    def setLevel(self, level):
1461        """
1462        Set the logging level of this logger.  level must be an int or a str.
1463        """
1464        self.level = _checkLevel(level)
1465        self.manager._clear_cache()
1466
1467    def debug(self, msg, *args, **kwargs):
1468        """
1469        Log 'msg % args' with severity 'DEBUG'.
1470
1471        To pass exception information, use the keyword argument exc_info with
1472        a true value, e.g.
1473
1474        logger.debug("Houston, we have a %s", "thorny problem", exc_info=1)
1475        """
1476        if self.isEnabledFor(DEBUG):
1477            self._log(DEBUG, msg, args, **kwargs)
1478
1479    def info(self, msg, *args, **kwargs):
1480        """
1481        Log 'msg % args' with severity 'INFO'.
1482
1483        To pass exception information, use the keyword argument exc_info with
1484        a true value, e.g.
1485
1486        logger.info("Houston, we have a %s", "interesting problem", exc_info=1)
1487        """
1488        if self.isEnabledFor(INFO):
1489            self._log(INFO, msg, args, **kwargs)
1490
1491    def warning(self, msg, *args, **kwargs):
1492        """
1493        Log 'msg % args' with severity 'WARNING'.
1494
1495        To pass exception information, use the keyword argument exc_info with
1496        a true value, e.g.
1497
1498        logger.warning("Houston, we have a %s", "bit of a problem", exc_info=1)
1499        """
1500        if self.isEnabledFor(WARNING):
1501            self._log(WARNING, msg, args, **kwargs)
1502
1503    def warn(self, msg, *args, **kwargs):
1504        warnings.warn("The 'warn' method is deprecated, "
1505            "use 'warning' instead", DeprecationWarning, 2)
1506        self.warning(msg, *args, **kwargs)
1507
1508    def error(self, msg, *args, **kwargs):
1509        """
1510        Log 'msg % args' with severity 'ERROR'.
1511
1512        To pass exception information, use the keyword argument exc_info with
1513        a true value, e.g.
1514
1515        logger.error("Houston, we have a %s", "major problem", exc_info=1)
1516        """
1517        if self.isEnabledFor(ERROR):
1518            self._log(ERROR, msg, args, **kwargs)
1519
1520    def exception(self, msg, *args, exc_info=True, **kwargs):
1521        """
1522        Convenience method for logging an ERROR with exception information.
1523        """
1524        self.error(msg, *args, exc_info=exc_info, **kwargs)
1525
1526    def critical(self, msg, *args, **kwargs):
1527        """
1528        Log 'msg % args' with severity 'CRITICAL'.
1529
1530        To pass exception information, use the keyword argument exc_info with
1531        a true value, e.g.
1532
1533        logger.critical("Houston, we have a %s", "major disaster", exc_info=1)
1534        """
1535        if self.isEnabledFor(CRITICAL):
1536            self._log(CRITICAL, msg, args, **kwargs)
1537
1538    def fatal(self, msg, *args, **kwargs):
1539        """
1540        Don't use this method, use critical() instead.
1541        """
1542        self.critical(msg, *args, **kwargs)
1543
1544    def log(self, level, msg, *args, **kwargs):
1545        """
1546        Log 'msg % args' with the integer severity 'level'.
1547
1548        To pass exception information, use the keyword argument exc_info with
1549        a true value, e.g.
1550
1551        logger.log(level, "We have a %s", "mysterious problem", exc_info=1)
1552        """
1553        if not isinstance(level, int):
1554            if raiseExceptions:
1555                raise TypeError("level must be an integer")
1556            else:
1557                return
1558        if self.isEnabledFor(level):
1559            self._log(level, msg, args, **kwargs)
1560
1561    def findCaller(self, stack_info=False, stacklevel=1):
1562        """
1563        Find the stack frame of the caller so that we can note the source
1564        file name, line number and function name.
1565        """
1566        f = currentframe()
1567        #On some versions of IronPython, currentframe() returns None if
1568        #IronPython isn't run with -X:Frames.
1569        if f is None:
1570            return "(unknown file)", 0, "(unknown function)", None
1571        while stacklevel > 0:
1572            next_f = f.f_back
1573            if next_f is None:
1574                ## We've got options here.
1575                ## If we want to use the last (deepest) frame:
1576                break
1577                ## If we want to mimic the warnings module:
1578                #return ("sys", 1, "(unknown function)", None)
1579                ## If we want to be pedantic:
1580                #raise ValueError("call stack is not deep enough")
1581            f = next_f
1582            if not _is_internal_frame(f):
1583                stacklevel -= 1
1584        co = f.f_code
1585        sinfo = None
1586        if stack_info:
1587            with io.StringIO() as sio:
1588                sio.write("Stack (most recent call last):\n")
1589                traceback.print_stack(f, file=sio)
1590                sinfo = sio.getvalue()
1591                if sinfo[-1] == '\n':
1592                    sinfo = sinfo[:-1]
1593        return co.co_filename, f.f_lineno, co.co_name, sinfo
1594
1595    def makeRecord(self, name, level, fn, lno, msg, args, exc_info,
1596                   func=None, extra=None, sinfo=None):
1597        """
1598        A factory method which can be overridden in subclasses to create
1599        specialized LogRecords.
1600        """
1601        rv = _logRecordFactory(name, level, fn, lno, msg, args, exc_info, func,
1602                             sinfo)
1603        if extra is not None:
1604            for key in extra:
1605                if (key in ["message", "asctime"]) or (key in rv.__dict__):
1606                    raise KeyError("Attempt to overwrite %r in LogRecord" % key)
1607                rv.__dict__[key] = extra[key]
1608        return rv
1609
1610    def _log(self, level, msg, args, exc_info=None, extra=None, stack_info=False,
1611             stacklevel=1):
1612        """
1613        Low-level logging routine which creates a LogRecord and then calls
1614        all the handlers of this logger to handle the record.
1615        """
1616        sinfo = None
1617        if _srcfile:
1618            #IronPython doesn't track Python frames, so findCaller raises an
1619            #exception on some versions of IronPython. We trap it here so that
1620            #IronPython can use logging.
1621            try:
1622                fn, lno, func, sinfo = self.findCaller(stack_info, stacklevel)
1623            except ValueError: # pragma: no cover
1624                fn, lno, func = "(unknown file)", 0, "(unknown function)"
1625        else: # pragma: no cover
1626            fn, lno, func = "(unknown file)", 0, "(unknown function)"
1627        if exc_info:
1628            if isinstance(exc_info, BaseException):
1629                exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1630            elif not isinstance(exc_info, tuple):
1631                exc_info = sys.exc_info()
1632        record = self.makeRecord(self.name, level, fn, lno, msg, args,
1633                                 exc_info, func, extra, sinfo)
1634        self.handle(record)
1635
1636    def handle(self, record):
1637        """
1638        Call the handlers for the specified record.
1639
1640        This method is used for unpickled records received from a socket, as
1641        well as those created locally. Logger-level filtering is applied.
1642        """
1643        if (not self.disabled) and self.filter(record):
1644            self.callHandlers(record)
1645
1646    def addHandler(self, hdlr):
1647        """
1648        Add the specified handler to this logger.
1649        """
1650        _acquireLock()
1651        try:
1652            if not (hdlr in self.handlers):
1653                self.handlers.append(hdlr)
1654        finally:
1655            _releaseLock()
1656
1657    def removeHandler(self, hdlr):
1658        """
1659        Remove the specified handler from this logger.
1660        """
1661        _acquireLock()
1662        try:
1663            if hdlr in self.handlers:
1664                self.handlers.remove(hdlr)
1665        finally:
1666            _releaseLock()
1667
1668    def hasHandlers(self):
1669        """
1670        See if this logger has any handlers configured.
1671
1672        Loop through all handlers for this logger and its parents in the
1673        logger hierarchy. Return True if a handler was found, else False.
1674        Stop searching up the hierarchy whenever a logger with the "propagate"
1675        attribute set to zero is found - that will be the last logger which
1676        is checked for the existence of handlers.
1677        """
1678        c = self
1679        rv = False
1680        while c:
1681            if c.handlers:
1682                rv = True
1683                break
1684            if not c.propagate:
1685                break
1686            else:
1687                c = c.parent
1688        return rv
1689
1690    def callHandlers(self, record):
1691        """
1692        Pass a record to all relevant handlers.
1693
1694        Loop through all handlers for this logger and its parents in the
1695        logger hierarchy. If no handler was found, output a one-off error
1696        message to sys.stderr. Stop searching up the hierarchy whenever a
1697        logger with the "propagate" attribute set to zero is found - that
1698        will be the last logger whose handlers are called.
1699        """
1700        c = self
1701        found = 0
1702        while c:
1703            for hdlr in c.handlers:
1704                found = found + 1
1705                if record.levelno >= hdlr.level:
1706                    hdlr.handle(record)
1707            if not c.propagate:
1708                c = None    #break out
1709            else:
1710                c = c.parent
1711        if (found == 0):
1712            if lastResort:
1713                if record.levelno >= lastResort.level:
1714                    lastResort.handle(record)
1715            elif raiseExceptions and not self.manager.emittedNoHandlerWarning:
1716                sys.stderr.write("No handlers could be found for logger"
1717                                 " \"%s\"\n" % self.name)
1718                self.manager.emittedNoHandlerWarning = True
1719
1720    def getEffectiveLevel(self):
1721        """
1722        Get the effective level for this logger.
1723
1724        Loop through this logger and its parents in the logger hierarchy,
1725        looking for a non-zero logging level. Return the first one found.
1726        """
1727        logger = self
1728        while logger:
1729            if logger.level:
1730                return logger.level
1731            logger = logger.parent
1732        return NOTSET
1733
1734    def isEnabledFor(self, level):
1735        """
1736        Is this logger enabled for level 'level'?
1737        """
1738        if self.disabled:
1739            return False
1740
1741        try:
1742            return self._cache[level]
1743        except KeyError:
1744            _acquireLock()
1745            try:
1746                if self.manager.disable >= level:
1747                    is_enabled = self._cache[level] = False
1748                else:
1749                    is_enabled = self._cache[level] = (
1750                        level >= self.getEffectiveLevel()
1751                    )
1752            finally:
1753                _releaseLock()
1754            return is_enabled
1755
1756    def getChild(self, suffix):
1757        """
1758        Get a logger which is a descendant to this one.
1759
1760        This is a convenience method, such that
1761
1762        logging.getLogger('abc').getChild('def.ghi')
1763
1764        is the same as
1765
1766        logging.getLogger('abc.def.ghi')
1767
1768        It's useful, for example, when the parent logger is named using
1769        __name__ rather than a literal string.
1770        """
1771        if self.root is not self:
1772            suffix = '.'.join((self.name, suffix))
1773        return self.manager.getLogger(suffix)
1774
1775    def __repr__(self):
1776        level = getLevelName(self.getEffectiveLevel())
1777        return '<%s %s (%s)>' % (self.__class__.__name__, self.name, level)
1778
1779    def __reduce__(self):
1780        if getLogger(self.name) is not self:
1781            import pickle
1782            raise pickle.PicklingError('logger cannot be pickled')
1783        return getLogger, (self.name,)
1784
1785
1786class RootLogger(Logger):
1787    """
1788    A root logger is not that different to any other logger, except that
1789    it must have a logging level and there is only one instance of it in
1790    the hierarchy.
1791    """
1792    def __init__(self, level):
1793        """
1794        Initialize the logger with the name "root".
1795        """
1796        Logger.__init__(self, "root", level)
1797
1798    def __reduce__(self):
1799        return getLogger, ()
1800
1801_loggerClass = Logger
1802
1803class LoggerAdapter(object):
1804    """
1805    An adapter for loggers which makes it easier to specify contextual
1806    information in logging output.
1807    """
1808
1809    def __init__(self, logger, extra=None):
1810        """
1811        Initialize the adapter with a logger and a dict-like object which
1812        provides contextual information. This constructor signature allows
1813        easy stacking of LoggerAdapters, if so desired.
1814
1815        You can effectively pass keyword arguments as shown in the
1816        following example:
1817
1818        adapter = LoggerAdapter(someLogger, dict(p1=v1, p2="v2"))
1819        """
1820        self.logger = logger
1821        self.extra = extra
1822
1823    def process(self, msg, kwargs):
1824        """
1825        Process the logging message and keyword arguments passed in to
1826        a logging call to insert contextual information. You can either
1827        manipulate the message itself, the keyword args or both. Return
1828        the message and kwargs modified (or not) to suit your needs.
1829
1830        Normally, you'll only need to override this one method in a
1831        LoggerAdapter subclass for your specific needs.
1832        """
1833        kwargs["extra"] = self.extra
1834        return msg, kwargs
1835
1836    #
1837    # Boilerplate convenience methods
1838    #
1839    def debug(self, msg, *args, **kwargs):
1840        """
1841        Delegate a debug call to the underlying logger.
1842        """
1843        self.log(DEBUG, msg, *args, **kwargs)
1844
1845    def info(self, msg, *args, **kwargs):
1846        """
1847        Delegate an info call to the underlying logger.
1848        """
1849        self.log(INFO, msg, *args, **kwargs)
1850
1851    def warning(self, msg, *args, **kwargs):
1852        """
1853        Delegate a warning call to the underlying logger.
1854        """
1855        self.log(WARNING, msg, *args, **kwargs)
1856
1857    def warn(self, msg, *args, **kwargs):
1858        warnings.warn("The 'warn' method is deprecated, "
1859            "use 'warning' instead", DeprecationWarning, 2)
1860        self.warning(msg, *args, **kwargs)
1861
1862    def error(self, msg, *args, **kwargs):
1863        """
1864        Delegate an error call to the underlying logger.
1865        """
1866        self.log(ERROR, msg, *args, **kwargs)
1867
1868    def exception(self, msg, *args, exc_info=True, **kwargs):
1869        """
1870        Delegate an exception call to the underlying logger.
1871        """
1872        self.log(ERROR, msg, *args, exc_info=exc_info, **kwargs)
1873
1874    def critical(self, msg, *args, **kwargs):
1875        """
1876        Delegate a critical call to the underlying logger.
1877        """
1878        self.log(CRITICAL, msg, *args, **kwargs)
1879
1880    def log(self, level, msg, *args, **kwargs):
1881        """
1882        Delegate a log call to the underlying logger, after adding
1883        contextual information from this adapter instance.
1884        """
1885        if self.isEnabledFor(level):
1886            msg, kwargs = self.process(msg, kwargs)
1887            self.logger.log(level, msg, *args, **kwargs)
1888
1889    def isEnabledFor(self, level):
1890        """
1891        Is this logger enabled for level 'level'?
1892        """
1893        return self.logger.isEnabledFor(level)
1894
1895    def setLevel(self, level):
1896        """
1897        Set the specified level on the underlying logger.
1898        """
1899        self.logger.setLevel(level)
1900
1901    def getEffectiveLevel(self):
1902        """
1903        Get the effective level for the underlying logger.
1904        """
1905        return self.logger.getEffectiveLevel()
1906
1907    def hasHandlers(self):
1908        """
1909        See if the underlying logger has any handlers.
1910        """
1911        return self.logger.hasHandlers()
1912
1913    def _log(self, level, msg, args, exc_info=None, extra=None, stack_info=False):
1914        """
1915        Low-level log implementation, proxied to allow nested logger adapters.
1916        """
1917        return self.logger._log(
1918            level,
1919            msg,
1920            args,
1921            exc_info=exc_info,
1922            extra=extra,
1923            stack_info=stack_info,
1924        )
1925
1926    @property
1927    def manager(self):
1928        return self.logger.manager
1929
1930    @manager.setter
1931    def manager(self, value):
1932        self.logger.manager = value
1933
1934    @property
1935    def name(self):
1936        return self.logger.name
1937
1938    def __repr__(self):
1939        logger = self.logger
1940        level = getLevelName(logger.getEffectiveLevel())
1941        return '<%s %s (%s)>' % (self.__class__.__name__, logger.name, level)
1942
1943    __class_getitem__ = classmethod(GenericAlias)
1944
1945root = RootLogger(WARNING)
1946Logger.root = root
1947Logger.manager = Manager(Logger.root)
1948
1949#---------------------------------------------------------------------------
1950# Configuration classes and functions
1951#---------------------------------------------------------------------------
1952
1953def basicConfig(**kwargs):
1954    """
1955    Do basic configuration for the logging system.
1956
1957    This function does nothing if the root logger already has handlers
1958    configured, unless the keyword argument *force* is set to ``True``.
1959    It is a convenience method intended for use by simple scripts
1960    to do one-shot configuration of the logging package.
1961
1962    The default behaviour is to create a StreamHandler which writes to
1963    sys.stderr, set a formatter using the BASIC_FORMAT format string, and
1964    add the handler to the root logger.
1965
1966    A number of optional keyword arguments may be specified, which can alter
1967    the default behaviour.
1968
1969    filename  Specifies that a FileHandler be created, using the specified
1970              filename, rather than a StreamHandler.
1971    filemode  Specifies the mode to open the file, if filename is specified
1972              (if filemode is unspecified, it defaults to 'a').
1973    format    Use the specified format string for the handler.
1974    datefmt   Use the specified date/time format.
1975    style     If a format string is specified, use this to specify the
1976              type of format string (possible values '%', '{', '$', for
1977              %-formatting, :meth:`str.format` and :class:`string.Template`
1978              - defaults to '%').
1979    level     Set the root logger level to the specified level.
1980    stream    Use the specified stream to initialize the StreamHandler. Note
1981              that this argument is incompatible with 'filename' - if both
1982              are present, 'stream' is ignored.
1983    handlers  If specified, this should be an iterable of already created
1984              handlers, which will be added to the root handler. Any handler
1985              in the list which does not have a formatter assigned will be
1986              assigned the formatter created in this function.
1987    force     If this keyword  is specified as true, any existing handlers
1988              attached to the root logger are removed and closed, before
1989              carrying out the configuration as specified by the other
1990              arguments.
1991    encoding  If specified together with a filename, this encoding is passed to
1992              the created FileHandler, causing it to be used when the file is
1993              opened.
1994    errors    If specified together with a filename, this value is passed to the
1995              created FileHandler, causing it to be used when the file is
1996              opened in text mode. If not specified, the default value is
1997              `backslashreplace`.
1998
1999    Note that you could specify a stream created using open(filename, mode)
2000    rather than passing the filename and mode in. However, it should be
2001    remembered that StreamHandler does not close its stream (since it may be
2002    using sys.stdout or sys.stderr), whereas FileHandler closes its stream
2003    when the handler is closed.
2004
2005    .. versionchanged:: 3.2
2006       Added the ``style`` parameter.
2007
2008    .. versionchanged:: 3.3
2009       Added the ``handlers`` parameter. A ``ValueError`` is now thrown for
2010       incompatible arguments (e.g. ``handlers`` specified together with
2011       ``filename``/``filemode``, or ``filename``/``filemode`` specified
2012       together with ``stream``, or ``handlers`` specified together with
2013       ``stream``.
2014
2015    .. versionchanged:: 3.8
2016       Added the ``force`` parameter.
2017
2018    .. versionchanged:: 3.9
2019       Added the ``encoding`` and ``errors`` parameters.
2020    """
2021    # Add thread safety in case someone mistakenly calls
2022    # basicConfig() from multiple threads
2023    _acquireLock()
2024    try:
2025        force = kwargs.pop('force', False)
2026        encoding = kwargs.pop('encoding', None)
2027        errors = kwargs.pop('errors', 'backslashreplace')
2028        if force:
2029            for h in root.handlers[:]:
2030                root.removeHandler(h)
2031                h.close()
2032        if len(root.handlers) == 0:
2033            handlers = kwargs.pop("handlers", None)
2034            if handlers is None:
2035                if "stream" in kwargs and "filename" in kwargs:
2036                    raise ValueError("'stream' and 'filename' should not be "
2037                                     "specified together")
2038            else:
2039                if "stream" in kwargs or "filename" in kwargs:
2040                    raise ValueError("'stream' or 'filename' should not be "
2041                                     "specified together with 'handlers'")
2042            if handlers is None:
2043                filename = kwargs.pop("filename", None)
2044                mode = kwargs.pop("filemode", 'a')
2045                if filename:
2046                    if 'b' in mode:
2047                        errors = None
2048                    else:
2049                        encoding = io.text_encoding(encoding)
2050                    h = FileHandler(filename, mode,
2051                                    encoding=encoding, errors=errors)
2052                else:
2053                    stream = kwargs.pop("stream", None)
2054                    h = StreamHandler(stream)
2055                handlers = [h]
2056            dfs = kwargs.pop("datefmt", None)
2057            style = kwargs.pop("style", '%')
2058            if style not in _STYLES:
2059                raise ValueError('Style must be one of: %s' % ','.join(
2060                                 _STYLES.keys()))
2061            fs = kwargs.pop("format", _STYLES[style][1])
2062            fmt = Formatter(fs, dfs, style)
2063            for h in handlers:
2064                if h.formatter is None:
2065                    h.setFormatter(fmt)
2066                root.addHandler(h)
2067            level = kwargs.pop("level", None)
2068            if level is not None:
2069                root.setLevel(level)
2070            if kwargs:
2071                keys = ', '.join(kwargs.keys())
2072                raise ValueError('Unrecognised argument(s): %s' % keys)
2073    finally:
2074        _releaseLock()
2075
2076#---------------------------------------------------------------------------
2077# Utility functions at module level.
2078# Basically delegate everything to the root logger.
2079#---------------------------------------------------------------------------
2080
2081def getLogger(name=None):
2082    """
2083    Return a logger with the specified name, creating it if necessary.
2084
2085    If no name is specified, return the root logger.
2086    """
2087    if not name or isinstance(name, str) and name == root.name:
2088        return root
2089    return Logger.manager.getLogger(name)
2090
2091def critical(msg, *args, **kwargs):
2092    """
2093    Log a message with severity 'CRITICAL' on the root logger. If the logger
2094    has no handlers, call basicConfig() to add a console handler with a
2095    pre-defined format.
2096    """
2097    if len(root.handlers) == 0:
2098        basicConfig()
2099    root.critical(msg, *args, **kwargs)
2100
2101def fatal(msg, *args, **kwargs):
2102    """
2103    Don't use this function, use critical() instead.
2104    """
2105    critical(msg, *args, **kwargs)
2106
2107def error(msg, *args, **kwargs):
2108    """
2109    Log a message with severity 'ERROR' on the root logger. If the logger has
2110    no handlers, call basicConfig() to add a console handler with a pre-defined
2111    format.
2112    """
2113    if len(root.handlers) == 0:
2114        basicConfig()
2115    root.error(msg, *args, **kwargs)
2116
2117def exception(msg, *args, exc_info=True, **kwargs):
2118    """
2119    Log a message with severity 'ERROR' on the root logger, with exception
2120    information. If the logger has no handlers, basicConfig() is called to add
2121    a console handler with a pre-defined format.
2122    """
2123    error(msg, *args, exc_info=exc_info, **kwargs)
2124
2125def warning(msg, *args, **kwargs):
2126    """
2127    Log a message with severity 'WARNING' on the root logger. If the logger has
2128    no handlers, call basicConfig() to add a console handler with a pre-defined
2129    format.
2130    """
2131    if len(root.handlers) == 0:
2132        basicConfig()
2133    root.warning(msg, *args, **kwargs)
2134
2135def warn(msg, *args, **kwargs):
2136    warnings.warn("The 'warn' function is deprecated, "
2137        "use 'warning' instead", DeprecationWarning, 2)
2138    warning(msg, *args, **kwargs)
2139
2140def info(msg, *args, **kwargs):
2141    """
2142    Log a message with severity 'INFO' on the root logger. If the logger has
2143    no handlers, call basicConfig() to add a console handler with a pre-defined
2144    format.
2145    """
2146    if len(root.handlers) == 0:
2147        basicConfig()
2148    root.info(msg, *args, **kwargs)
2149
2150def debug(msg, *args, **kwargs):
2151    """
2152    Log a message with severity 'DEBUG' on the root logger. If the logger has
2153    no handlers, call basicConfig() to add a console handler with a pre-defined
2154    format.
2155    """
2156    if len(root.handlers) == 0:
2157        basicConfig()
2158    root.debug(msg, *args, **kwargs)
2159
2160def log(level, msg, *args, **kwargs):
2161    """
2162    Log 'msg % args' with the integer severity 'level' on the root logger. If
2163    the logger has no handlers, call basicConfig() to add a console handler
2164    with a pre-defined format.
2165    """
2166    if len(root.handlers) == 0:
2167        basicConfig()
2168    root.log(level, msg, *args, **kwargs)
2169
2170def disable(level=CRITICAL):
2171    """
2172    Disable all logging calls of severity 'level' and below.
2173    """
2174    root.manager.disable = level
2175    root.manager._clear_cache()
2176
2177def shutdown(handlerList=_handlerList):
2178    """
2179    Perform any cleanup actions in the logging system (e.g. flushing
2180    buffers).
2181
2182    Should be called at application exit.
2183    """
2184    for wr in reversed(handlerList[:]):
2185        #errors might occur, for example, if files are locked
2186        #we just ignore them if raiseExceptions is not set
2187        try:
2188            h = wr()
2189            if h:
2190                try:
2191                    h.acquire()
2192                    h.flush()
2193                    h.close()
2194                except (OSError, ValueError):
2195                    # Ignore errors which might be caused
2196                    # because handlers have been closed but
2197                    # references to them are still around at
2198                    # application exit.
2199                    pass
2200                finally:
2201                    h.release()
2202        except: # ignore everything, as we're shutting down
2203            if raiseExceptions:
2204                raise
2205            #else, swallow
2206
2207#Let's try and shutdown automatically on application exit...
2208import atexit
2209atexit.register(shutdown)
2210
2211# Null handler
2212
2213class NullHandler(Handler):
2214    """
2215    This handler does nothing. It's intended to be used to avoid the
2216    "No handlers could be found for logger XXX" one-off warning. This is
2217    important for library code, which may contain code to log events. If a user
2218    of the library does not configure logging, the one-off warning might be
2219    produced; to avoid this, the library developer simply needs to instantiate
2220    a NullHandler and add it to the top-level logger of the library module or
2221    package.
2222    """
2223    def handle(self, record):
2224        """Stub."""
2225
2226    def emit(self, record):
2227        """Stub."""
2228
2229    def createLock(self):
2230        self.lock = None
2231
2232    def _at_fork_reinit(self):
2233        pass
2234
2235# Warnings integration
2236
2237_warnings_showwarning = None
2238
2239def _showwarning(message, category, filename, lineno, file=None, line=None):
2240    """
2241    Implementation of showwarnings which redirects to logging, which will first
2242    check to see if the file parameter is None. If a file is specified, it will
2243    delegate to the original warnings implementation of showwarning. Otherwise,
2244    it will call warnings.formatwarning and will log the resulting string to a
2245    warnings logger named "py.warnings" with level logging.WARNING.
2246    """
2247    if file is not None:
2248        if _warnings_showwarning is not None:
2249            _warnings_showwarning(message, category, filename, lineno, file, line)
2250    else:
2251        s = warnings.formatwarning(message, category, filename, lineno, line)
2252        logger = getLogger("py.warnings")
2253        if not logger.handlers:
2254            logger.addHandler(NullHandler())
2255        # bpo-46557: Log str(s) as msg instead of logger.warning("%s", s)
2256        # since some log aggregation tools group logs by the msg arg
2257        logger.warning(str(s))
2258
2259def captureWarnings(capture):
2260    """
2261    If capture is true, redirect all warnings to the logging package.
2262    If capture is False, ensure that warnings are not redirected to logging
2263    but to their original destinations.
2264    """
2265    global _warnings_showwarning
2266    if capture:
2267        if _warnings_showwarning is None:
2268            _warnings_showwarning = warnings.showwarning
2269            warnings.showwarning = _showwarning
2270    else:
2271        if _warnings_showwarning is not None:
2272            warnings.showwarning = _warnings_showwarning
2273            _warnings_showwarning = None
2274