日誌打印之logging.config.dictConfig使用總結python
By:授客 QQ:1033553122 app
#實踐環境socket
WIN 10函數
Python 3.6.5oop
#函數說明測試
logging.config.dictConfig(config) this
dictConfig函數位於logging.config模塊,該函數經過字典參數config對logging進行配置。3.2版本新增的函數spa
##參數說明debug
config 字典類型,包含如下key:rest
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
下同,再也不贅述.
# 上述的class配置項的值,可使用自定義Handler類,此時,若是自定義Handler類的__init__構造函數還須要其它參數來初始化類實例,能夠繼續添自定義參數,這些自定義參數被當作關鍵字參數會自動傳遞給構造函數。
一個例子:
"handlers": { "console":{ "class":"study.MyLogHandler", "formatter":"brief", "level":"INFO" }, "file": { "class": "logging.handlers.RotatingFileHandler", "formatter": "precise", "filename": "logconfig.log", "maxBytes": 1024, "backupCount": 3 } }
id爲console的日誌處理器被實例化爲一個logging.StreamHandler,使用sys.stout做爲基礎實例流。id爲file的日誌處理器則被實例化爲具備關鍵字參數filename ='logconfig.log',maxBytes = 1024,backupCount = 3的 logging.handlers.RotatingFileHandler
#代碼示例1
study.py
study.py #!/usr/bin/env python # -*- coding:utf-8 -*- ''' @CreateTime: 2020/12/29 14:08 @Author : shouke ''' import logging import logging.config LOGGING_CONFIG = { "version": 1, "formatters": { "default": { 'format':'%(asctime)s %(filename)s %(lineno)s %(levelname)s %(message)s', }, "plain": { "format": "%(message)s", }, }, "handlers": { "console": { "class": "logging.StreamHandler", "level": "INFO", "formatter": "default", }, "console_plain": { "class": "logging.StreamHandler", "level":logging.INFO, "formatter": "plain" }, "file":{ "class": "logging.FileHandler", "level":20, "filename": "./log.txt", "formatter": "default", } }, "loggers": { "console_logger": { "handlers": ["console"], "level": "INFO", "propagate": False, }, "console_plain_logger": { "handlers": ["console_plain"], "level": "DEBUG", "propagate": False, }, "file_logger":{ "handlers": ["file"], "level": "INFO", "propagate": False, } }, "disable_existing_loggers": True, } # 運行測試 logging.config.dictConfig(LOGGING_CONFIG) logger = logging.getLogger("console_logger") logger.debug('debug message') logger.info('info message') logger.warn('warning message') logger.error('error message') logger.critical('critical message')
運行study.py,結果輸出以下
2021-01-09 10:01:59,123 study.py 66 INFO info message
2021-01-09 10:01:59,123 study.py 67 WARNING warning message
2021-01-09 10:01:59,123 study.py 68 ERROR error message
2021-01-09 10:01:59,123 study.py 69 CRITICAL critical message
#代碼示例2
基於代碼示例1,修改LOGGING_CONFIG及getLogger函數參數
LOGGING_CONFIG = { "version": 1, "formatters": { "default": { 'format':'%(asctime)s %(filename)s %(lineno)s %(levelname)s %(message)s', } }, "handlers": { "console": { "class": "logging.StreamHandler", "level": "INFO", "formatter": "default", } }, "disable_existing_loggers": True, "root": { "handlers": ["console"], "level": "DEBUG" }, } # 運行測試 logging.config.dictConfig(LOGGING_CONFIG) logger = logging.getLogger("root") logger.debug('debug message') logger.info('info message') logger.warn('warning message') logger.error('error message') logger.critical('critical message')
運行study.py,結果輸出以下
2021-01-09 10:33:03,456 study.py 38 INFO info message
2021-01-09 10:33:03,456 study.py 39 WARNING warning message
2021-01-09 10:33:03,456 study.py 40 ERROR error message
2021-01-09 10:33:03,456 study.py 41 CRITICAL critical message
# 源碼的角度分析propagate配置項
Logger類,位於logging/__init__.py
class Logger(Filterer): #...略 def debug(self, msg, *args, **kwargs): """ Log 'msg % args' with severity 'DEBUG'. To pass exception information, use the keyword argument exc_info with a true value, e.g. logger.debug("Houston, we have a %s", "thorny problem", exc_info=1) """ if self.isEnabledFor(DEBUG): self._log(DEBUG, msg, args, **kwargs) def info(self, msg, *args, **kwargs): """ Log 'msg % args' with severity 'INFO'. To pass exception information, use the keyword argument exc_info with a true value, e.g. logger.info("Houston, we have a %s", "interesting problem", exc_info=1) """ if self.isEnabledFor(INFO): self._log(INFO, msg, args, **kwargs) #...略 def _log(self, level, msg, args, exc_info=None, extra=None, stack_info=False): """ Low-level logging routine which creates a LogRecord and then calls all the handlers of this logger to handle the record. """ sinfo = None if _srcfile: #IronPython doesn't track Python frames, so findCaller raises an #exception on some versions of IronPython. We trap it here so that #IronPython can use logging. try: fn, lno, func, sinfo = self.findCaller(stack_info) except ValueError: # pragma: no cover fn, lno, func = "(unknown file)", 0, "(unknown function)" else: # pragma: no cover fn, lno, func = "(unknown file)", 0, "(unknown function)" if exc_info: if isinstance(exc_info, BaseException): exc_info = (type(exc_info), exc_info, exc_info.__traceback__) elif not isinstance(exc_info, tuple): exc_info = sys.exc_info() record = self.makeRecord(self.name, level, fn, lno, msg, args, exc_info, func, extra, sinfo) self.handle(record) def handle(self, record): """ Call the handlers for the specified record. This method is used for unpickled records received from a socket, as well as those created locally. Logger-level filtering is applied. """ if (not self.disabled) and self.filter(record): self.callHandlers(record) def hasHandlers(self): """ See if this logger has any handlers configured. Loop through all handlers for this logger and its parents in the logger hierarchy. Return True if a handler was found, else False. Stop searching up the hierarchy whenever a logger with the "propagate" attribute set to zero is found - that will be the last logger which is checked for the existence of handlers. """ c = self rv = False while c: if c.handlers: rv = True break if not c.propagate: break else: c = c.parent return rv def callHandlers(self, record): """ Pass a record to all relevant handlers. Loop through all handlers for this logger and its parents in the logger hierarchy. If no handler was found, output a one-off error message to sys.stderr. Stop searching up the hierarchy whenever a logger with the "propagate" attribute set to zero is found - that will be the last logger whose handlers are called. """ c = self found = 0 while c: for hdlr in c.handlers: found = found + 1 if record.levelno >= hdlr.level: hdlr.handle(record) if not c.propagate: c = None #break out else: c = c.parent if (found == 0): if lastResort: if record.levelno >= lastResort.level: lastResort.handle(record) elif raiseExceptions and not self.manager.emittedNoHandlerWarning: sys.stderr.write("No handlers could be found for logger" " \"%s\"\n" % self.name) self.manager.emittedNoHandlerWarning = True
默認的,當經過logger.debug,logger.info的方式打印日誌時,會先判斷對應日誌級別是否開啓,若是開啓,則調用logger實例的_log方法,接着通過一連串的函數調用(self._log() -> self.handle -> self.callHandlers),如上,self.callHandlers中,會先遍歷當前日誌打印器自身的全部日誌處理器,處理日誌消息,而後判斷propagate屬性是否爲True,若是爲True,則獲取上級日誌打印器,繼續遍歷其日誌處理器,處理消息,不然不遍歷上級
另外,查看hasHandlers函數可知,判斷一個logger是否有日誌處理器,也用到了propagate,若是propagate爲True,則遍歷父級日誌打印器,看其是否存在日誌處理器,若是父級或者父輩日誌打印器存在日誌處理器,則判斷該logger擁有日誌處理器。
因而可知,propagate功能就是用於控制是否向上遍歷父輩日誌打印器,進而控制當前日誌打印器是否共享父輩打印器的日誌處理器。