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