Python 日志打印之logging.config.dictConfig使用总结

#实践环境

WIN 10

Python 3.6.5

#函数说明

logging.config.dictConfig(config)

dictConfig函数位于logging.config模块,该函数通过字典参数config对logging进行配置。3.2版本新增的函数

##参数说明

config 字典类型,包含以下key:

  • version - 表示版本,该键值为从1开始的整数。该key必选,除此之外,其它key都是可选。

  • formatters - 日志格式化器,其value值为一个字典,该字典的每个键值对都代表一个Formatter,键值对中,key代表Formatter ID(自定义ID),value为字典,描述如何配置相应的Formatter实例。默认格式为 '%(message)s’

  • filters - 日志过滤器,其value值为一个字典,该字典的每个键值对都代表一个Filter,键值对中,key代表Filter ID(自定义ID),value为字典,描述如何配置相应的Filter实例。

  • handlers - 日志处理器,其value值为一个字典,该字典的每个键值对都代表一个Handler,键值对中,key代表Handler ID(自定义ID),value为字典,描述如何配置相应的Handler实例,包含以下配置key:

  • class (必选). 日志处理器类全称

  • level (可选). 指定该日志处理器需要处理哪些级别的日志,低于该级别的日志将不被该handler处理。level可以为代表日志级别的整数或者表大写字符串,字符串日志级别和数字日志级别对应关系如下:

    CRITICAL = 50

    FATAL = CRITICAL

    ERROR = 40

    WARNING = 30

    WARN = WARNING

    INFO = 20

    DEBUG = 10

    NOTSET = 0

    下同,不再赘述.

  • formatter (可选). 指定该日志处理器使用的日志格式化器

  • filters (可选). 制定该日志处理器使用的日志过滤器

# 上述的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

  • loggers - 日志记录器,其value值为一个字典,该字典的每个键值对都代表一个Handler,键值对中,key代表Handler ID,value为字典,描述如何配置相应的Logger实例,包含以下配置key:

  • level (可选). 指定该日志记录器需要记录哪些级别的日志,低于该级别的日志将不被该logger记录。

  • propagate (可选). 指定该日志记录器的propagation配置,为布尔值,即True 或 False,用于控制是否向上遍历父辈日志打印器,进而控制当前日志打印器是否共享父辈打印器的日志处理器。True,向上遍历,否则不向上遍历。

  • filters (可选). 指定该日志记录器使用的日志过滤器

  • handlers (可选). 制定该日志记录器使用的日志处理器

  • root - root logger配置。除了不支持propagate配置项以外,该配置的处理过程同处理其它logger的配置一样,配置规则也一样

  • incremental - 用于判断该config配置是否解释为现有配置的增量配置,还是覆盖原有配置。默认为False,即使用现有fileConfig()API使用的相同语义替换现有配置

  • disable_existing_loggers - 其value为布尔值,表示是否禁用现有日志记录器(root logger除外),默认值为True,即禁用。如果incremental 键值为True,则忽略该配置项

#代码示例1

study.py

study.py#!/usr/bin/env python# -*- coding:utf-8 -*-'''@CreateTime: 2020/12/29 14:08@Author : shouke'''import loggingimport logging.configLOGGING_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功能就是用于控制是否向上遍历父辈日志打印器,进而控制当前日志打印器是否共享父辈打印器的日志处理器。

(0)

相关推荐

  • python笔记46-史上最强大最好用的python日志模块nb_log

    前言 python的日志模块如何封装一值都是一个头疼的问题,封装的不好总是会出现重复打印等头疼问题. 现在终于找到一个最好用的日志模块nb_log,此日志模块由这位大佬开发的https://www.c ...

  • Selenium2+python自动化72-logging日志使用

    前言 脚本运行的时候,有时候不知道用例的执行情况,这时候可以加入日志,这样出现问题后方便查阅,也容易排查哪些用例执行了,哪些没有执行. 一.封装logging模块 1.关于logging日志的介绍,我 ...

  • 应用程序Python的日志记录模板 | 区块链研究实验室

    原创 链三丰 区块链研究实验室 4天前 通过定义明确,信息量大且结构方便的日志,调试和跟踪应用程序执行的理想方式. 它们是任何编程语言(不仅仅是Python)中任何大型,中型或大型项目必不可少的组成部 ...

  • 使用Python的logging.config.fileConfig配置日志

    文件 logglogging.conf 配置如下: [loggers] keys=root,fileLogger,rotatingFileLogger [handlers] keys=consoleH ...

  • Python之日志处理(logging模块)

    本节内容 日志相关概念 logging模块简介 使用logging提供的模块级别的函数记录日志 logging模块日志流处理流程 使用logging四大组件记录日志 配置logging的几种方式 向日 ...

  • python日志系统-logging

    时间主题12.25(周三)20:00 自动化运维工具-Ansible 在之前测试运维试听课程中,芒果给大家介绍了python日志系统-logging的使用,这里我们来做个小总结.日志相关概念介绍日志是 ...

  • python 日志 按日期或大小归档

    随着回调的事件与越来越多,如果每个事件都写一个方法,这就显得代码的冗余,所以,今天将日志都归档,分类 事件日志,看情况,我们一般保留10天,至于错误日志,一般不会报错,所以我们按文件的大小进行分类 # ...

  • 弃繁就简!一行代码搞定 Python 日志!

    来源:Python 技术「ID: pythonall」 写了这么多年的 Python ,我一直都是使用 Python 自带的 logging 模块来记录日志,每次需要写一些配置将日志输出到不同的位置, ...

  • python日志输出你会想到啥?不妨来看看这几个模块的用法

    日志可以说是每个开发人员必备的功能 ,通过它可以方便的帮我们找出程序中的一些错误 ,因此要使用到一个好的日志模块或方法对我们来说,也是比较重要的 .接下来我们就介绍python中支持输出日志的4个方法 ...

  • Python语言学习之字母L开头函数使用集锦:logging日志用法之详细攻略

    Python语言学习之字母L开头函数使用集锦:logging日志用法之详细攻略 logging日志用法之详细攻略 K Llogging.basicConfig(level=logging.ERROR, ...