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