python 日志输出变量_Python 日志打印之logging.config.dictConfig使用总结

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

By:授客 QQ:1033553122

#实践环境

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 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功能就是用于控制是否向上遍历父辈日志打印器,进而控制当前日志打印器是否共享父辈打印器的日志处理器。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值