25
25
.. note::
26
26
27
27
This module has a few key differences compared to its CPython counterpart, notably
28
- that loggers can only be assigned one handler at a time. Calling ``addHander()``
29
- replaces the currently stored handler for that logger. Additionally, the default
30
- formatting for handlers is different.
28
+ that loggers do not form a hierarchy that allows record propagation.
29
+ Additionally, the default formatting for handlers is different.
31
30
32
31
Attributes
33
32
----------
@@ -147,7 +146,17 @@ def _logRecordFactory(name, level, msg, args):
147
146
148
147
149
148
class Handler :
150
- """Abstract logging message handler."""
149
+ """Base logging message handler."""
150
+
151
+ def __init__ (self , level : int = NOTSET ) -> None :
152
+ """Create Handler instance"""
153
+ self .level = level
154
+
155
+ def setLevel (self , level : int ) -> None :
156
+ """
157
+ Set the logging level of this handler.
158
+ """
159
+ self .level = level
151
160
152
161
# pylint: disable=no-self-use
153
162
def format (self , record : LogRecord ) -> str :
@@ -156,9 +165,7 @@ def format(self, record: LogRecord) -> str:
156
165
:param record: The record (message object) to be logged
157
166
"""
158
167
159
- return "{0:<0.3f}: {1} - {2}" .format (
160
- record .created , record .levelname , record .msg
161
- )
168
+ return f"{ record .created :<0.3f} : { record .levelname } - { record .msg } "
162
169
163
170
def emit (self , record : LogRecord ) -> None :
164
171
"""Send a message where it should go.
@@ -239,13 +246,13 @@ def emit(self, record: LogRecord) -> None:
239
246
240
247
241
248
logger_cache = {}
249
+ _default_handler = StreamHandler ()
242
250
243
251
244
252
def _addLogger (logger_name : Hashable ) -> None :
245
253
"""Adds the logger if it doesn't already exist"""
246
254
if logger_name not in logger_cache :
247
255
new_logger = Logger (logger_name )
248
- new_logger .addHandler (StreamHandler ())
249
256
logger_cache [logger_name ] = new_logger
250
257
251
258
@@ -277,7 +284,8 @@ def __init__(self, name: Hashable, level: int = WARNING) -> None:
277
284
self .name = name
278
285
"""The name of the logger, this should be unique for proper
279
286
functionality of `getLogger()`"""
280
- self ._handler = None
287
+ self ._handlers = []
288
+ self .emittedNoHandlerWarning = False
281
289
282
290
def setLevel (self , log_level : int ) -> None :
283
291
"""Set the logging cutoff level.
@@ -296,23 +304,56 @@ def getEffectiveLevel(self) -> int:
296
304
return self ._level
297
305
298
306
def addHandler (self , hdlr : Handler ) -> None :
299
- """Sets the handler of this logger to the specified handler.
300
-
301
- *NOTE* This is slightly different from the CPython equivalent
302
- which adds the handler rather than replacing it.
307
+ """Adds the handler to this logger.
303
308
304
309
:param Handler hdlr: The handler to add
305
310
"""
306
- self ._handler = hdlr
311
+ self ._handlers .append (hdlr )
312
+
313
+ def removeHandler (self , hdlr : Handler ) -> None :
314
+ """Remove handler from this logger.
315
+
316
+ :param Handler hdlr: The handler to remove
317
+ """
318
+ self ._handlers .remove (hdlr )
307
319
308
320
def hasHandlers (self ) -> bool :
309
321
"""Whether any handlers have been set for this logger"""
310
- return self ._handler is not None
322
+ return len ( self ._handlers ) > 0
311
323
312
324
def _log (self , level : int , msg : str , * args ) -> None :
313
325
record = _logRecordFactory (self .name , level , msg % args , args )
314
- if self ._handler and level >= self ._level :
315
- self ._handler .emit (record )
326
+ self .handle (record )
327
+
328
+ def handle (self , record : LogRecord ) -> None :
329
+ """Pass the record to all handlers registered with this logger.
330
+
331
+ :param LogRecord record: log record
332
+ """
333
+ if (
334
+ _default_handler is None
335
+ and not self .hasHandlers ()
336
+ and not self .emittedNoHandlerWarning
337
+ ):
338
+ sys .stderr .write (
339
+ f"Logger '{ self .name } ' has no handlers and default handler is None\n "
340
+ )
341
+ self .emittedNoHandlerWarning = True
342
+ return
343
+
344
+ emitted = False
345
+ if record .levelno >= self ._level :
346
+ for handler in self ._handlers :
347
+ if record .levelno >= handler .level :
348
+ handler .emit (record )
349
+ emitted = True
350
+
351
+ if (
352
+ not emitted
353
+ and _default_handler
354
+ and record .levelno >= _default_handler .level
355
+ ):
356
+ _default_handler .emit (record )
316
357
317
358
def log (self , level : int , msg : str , * args ) -> None :
318
359
"""Log a message.
0 commit comments