logging日志功能主要涉及到以下几个对象类型:
Logger:日志类,提供了应用程序可以直接调用的接口方法。程序代码通过调用Logger对象的相关方法来打印日志。Logger类包含level(日志级别)、handlers(处理器)、filters(过滤器)等属性,可通过设置其属性来定制Logger对象,指定日志的输出级别、输出格式、输出位置等信息。
Handler :处理器,
负责将(日志记录器产生的)日志记录输出到合适位置。
Filter :过滤器, 提供了更好的粒度控制,它可以决定输出哪些日志记录。
Formatter:格式器, 指明了最终输出的日志记录的格式。
LogRecord :日志记录器,将日志传到相应的处理器处理。
使用logging打印日志的具体代码如下:
import logging
# 1.创建logger对象
logger = logging.getLogger(__name__)
# 2.设置logger对象的相关参数
# 2.1 设置日志处理级别
logger.setLevel(logging.DEBUG)
# 2.2 指定logger对象的处理器
# 2.2.1 创建Handler对象
# 创建一个输出到控制台的Handler
console = logging.StreamHandler()
console.setLevel(logging.ERROR) # 设置handler的日志处理级别
# 创建一个输出到log文件的Handler.
logfile = logging.FileHandler('test_log.log')
logfile.setLevel(logging.DEBUG) # 设置handler的日志处理级别
file_format = logging.Formatter('%(asctime)s – %(name)s – %(levelname)s – %(message)s')
logfile.setFormatter(file_format) # 设置日志输出格式
# 2.2.2 将handler绑定到logger
logger.addHandler(logfile)
logger.addHandler(console)
# 3.调用logger对象打印不同级别的日志
logger.error('this is error ')
logger.info('this is info ')
logger.debug('this is debug ')
通过调用logging.getLogger方法创建logger对象,该方法需传入一个参数,用来指定logger对象的名称。建议传入__name__,以模块名为日志对象的名称,使得能直观的根据名称知道日志记录事件发生的位置。
1.设置日志级别
通过logger对象的setLevel方法可设置日志处理级别,低于设置级别的日志不会处理。
若没有给logger设置日志级别,则使用父logger的日志级别(若父logger也没有设置,继续找上一层logger的配置,直到root logger,root logger的默认日志处理级别为WARNING)。
2.指定logger对象的处理器
logging提供了多种类型的处理器,来处理日志并输出到指定位置。
StreamHandler:将日志记录输出发送到流,例如sys.stdout,sys.stderr或任何支持write()和flush()方法的对象。
FileHandler:将日志记录输出发送到磁盘文件。它继承了StreamHandler的输出功能。
Logger对象支持添加多个处理器。日志记录会被绑定的多个处理器处理,输出到不同位置。如上述代码示例中,日志会同时输出到控制台和文件。可根据实际情况选择需要的处理器类型及处理器的个数。
处理器支持日志级别,日志格式属性的设置。通过给不同的处理器设置不同的配置,来实现针对不同位置输出不同级别和格式的日志。当处理器未进行日志级别或格式的配置时,默认使用logger对象的配置。
logger对象和处理器都可设置日志处理级别,处理日志时,会先使用logger的日志处理级别配置去判断日志是否要处理,若需要处理,将日志记录传给handle对象,handle对象再根据其配置的日志处理级别判断是否对日志做处理。
所以如果handle对象的日志处理级别设置为DEBUG,低于logger对象的日志处理级别,DEBUG的日志不会输出。
logger是通过名字来决定继承关系。比如你在设置logger时,将一个logger命名为logging.getLogger(‘log‘),另一个命名为logging.getLogger(‘log.test‘),那么前者就是后者的父logger。并且存在根logger(RootLogger实例),logging.getLogger(‘log‘)这个对象的父logger就是根logger。
logger对象有一个propagate属性,当该属性为true时(默认值就是ture),会在当前logger对象的所有handles处理完日志记录之后,将日志记录传给父logger的handles处理,父logger若propagate也是ture,也会传递给其父logger处理器处理,循环往复,最终到root logger。
因而会出现以下情况,如果当前logger设置了输出到控制台的handle,其父辈logger也设置了输出到控制台的handle,这就会导致同一条日志记录会在控制台输出多次。
import logging.handlers
formatter = logging.Formatter("%(asctime)s %(name)s %(levelname)s %(message)s")
# 定义父logger
father_logger = logging.getLogger("log")
father_logger.setLevel(logging.WARNING)
handler = logging.StreamHandler()
# handler.setLevel(logging.WARNING)
handler.setFormatter(formatter)
father_logger.addHandler(handler)
# 定义子logger
logger = logging.getLogger("log.test")
logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)
# 使用子logger 打印日志
logger.debug('This is a customer debug message')
logger.info('This is a customer info message')
logger.warning('This is a customer warning message')
上述代码中,每条日志记录会由logger对象的handle以及父logger对象的handle依次处理,控制台输出内容如下:
2019-11-22 15:09:40,949 log.test INFO This is a customer info message
2019-11-22 15:09:40,949 log.test INFO This is a customer info message
2019-11-22 15:09:40,949 log.test WARNING This is a customer warning message
2019-11-22 15:09:40,949 log.test WARNING This is a customer warning message
上述代码父辈logger设置为Warning级别,依然打印了两条INFO级别的记录。日志记录传递给父logger的handle对象做处理,会依据父logger的handle对象的级别设置判断是否输出日志,而与父logger的设置无关。
若想避免日志重复输出的情况,有两种方式:
(1)确保同一类型handler只对父辈logger或子logger其中一个对象进行设置。
(2)将propagate设置为False,不受传递记录给父辈logger。
可以通过logger.parent.handlers查看父logger的handle
logging模块提供了一种简洁的打印日志的方法,供简单的程序使用。
import logging
logging.warning('this is warning')
logging.error('this is error')
上述打印日志的方法实际上就是调用的root logger的方法。root logger为RootLogger实例,日志处理级别为WARNING。
# /logging/__init__.py
root = RootLogger(WARNING)
...
def warning(msg, *args, **kwargs):
"""
Log a message with severity 'WARNING' on the root logger. If the logger has
no handlers, call basicConfig() to add a console handler with a pre-defined
format.
"""
if len(root.handlers) == 0:
basicConfig()
root.warning(msg, *args, **kwargs)
logging.warning方法先判断root对象是否添加了handles对象,如果没有,调用basicConfig()添加一个控制台输出的handle对象给root,再调用root的warning方法。
当需要自定义配置root logger时,同样可以调用basicConfig()方法进行配置。函数的参数如下:
import logging
logging.basicConfig(
filename='log_root',
filemode='a',
format='%(asctime)s – %(name)s – %(levelname)s – %(message)s',
datefmt='%m/%d/%Y %I:%M:%S',
level=logging.DEBUG)
logging.info('this is info in root logger')
Python logging模块介绍
Python logging
Python日志库logging总结
Python root logger解密
原文:https://www.cnblogs.com/anew/p/11984648.html