您的位置:首页 > 编程语言 > Python开发

python模块:logging

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


python:logging
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: