logging模块记日志
在python程序中,我们一般使用logging模块来记录日志。
简单模式: 我们可以直接使用logging.info()这种方式记日志。
import logging
# 如果不设置filename参数,则日志将默认输出到控制台。
logging.basicConfig(filename='execution.log', format='%(asctime)s - %(levelname)s - %(message)s', encoding='utf-8', level=logging.INFO)
logging.info('这是我写的日志')
常用模式: 通常我们可能需要日志在记录到文件的同时也输出到控制台。又或者,我们可能需要区别于日志的来源,即可能由不同的模块记录的,这时我们使用logger.info()来记日志。
多个logger可以是继承关系。 所以logger都会默认继承自root logger。 指定名称的logger会按照点分隔符来控制继承链。 名称举例: myproject.settings -> myproject。
logger可能通过setLevel()方法来控制记录的日志级别,达到级别的日志会传递给handler。logger的默认日志级别是logging.WARNING。 同时handler也可以设置自己的日志级别,达到级别的日志才会最终被记录。 handler默认的日志级别是logging.DEBUG。formatter是控制日志输出格式,它需要被添加到handler上才起作用。
前面讲的logging.basicConfig方法相当于给root logger做了配置。
import logging
# 为了将日志即能输出到日志文件,又能输出到控制台,采用单独创建logger,并附加handler的方式。
logger = logging.getLogger() # 不加参数,以获取root logger
logger.setLevel(LOG_LEVEL) # 设置日志级别。 默认是warning
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(process)d - %(message)s') # 设置日志输出格式, 增加进程id,为区分多进程并行处理
# handler不设置日志级别时,会将logger传给它的所有级别的日志都输出,而不是默认只输出warning级别
ch = logging.StreamHandler() # 创建控制台handler
ch.setFormatter(formatter)
fh = logging.FileHandler(filename=os.path.join(BASE_DIR, 'execution.log'), encoding='utf-8')
fh.setFormatter(formatter)
logger.addHandler(ch)
logger.addHandler(fh)
# 设置完root logger后,将logger变量指向当前模块名的logger,但其会自动继承root logger的配置
logger = logging.getLogger('main')
logger.info('这是main模块中的日志')
其他模块中
import logging
# logger会自动继承root logger中的配置,包括handler, formatter, log level等。
logger = logging.getLogger(__name__)
logger.info('这是其他模块中的日志')
logger.exception的特别之处
一般我们记录错误日志是都用logger.error 或 logger.critical(用于严重错误)。但还有一个叫logger.exception,它能记录错误时自动获取异常堆栈, 但是要用在异常处理部分才有效。
import logging
logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', encoding='utf-8', level=logging.INFO)
logger = logging.getLogger()
try:
raise Exception('人造异常')
except Exception as e:
logger.error(f"程序报错了,异常内容为: {e}")
logger.info('*******************************')
logger.exception(f"程序报错了,异常内容为:{e}")
> 输出内容如下:
> 2024-11-08 20:16:23,608 - ERROR - 程序报错了,异常内容为: 人造异常
> 2024-11-08 20:16:23,609 - INFO - *******************************
> 2024-11-08 20:16:23,609 - ERROR - 程序报错了,异常内容为:人造异常
> Traceback (most recent call last):
> File "F:\RolandWork\PythonProjects\excel_data_analysis\test.py", line 6, in <module>
> raise Exception('人造异常')
> Exception: 人造异常
其他类型的日志放在异常处理代码块时,同样可以记录traceback,只不过需要传递参数exec_info=True。 其实logger.exception函数相当于设置了exec_info的缺省值就是True。
RotatingFileHandler 和 TimedRotatingFileHandler: 这是两个特殊的handler。RotatingFileHandler用于控制当日志文件大小达到某个限定制时,就自动创建和写入到新的日志文件中。 TimedRotatingFileHandler用于控制当时间达到某个预设的间隔时间段时,就创建并写入到新的日志文件中。
过滤日志: handler.addFilter() 传入一个函数,该函数在运行时会接收实际的日志条目,是logging.LogRecord类型。logger在记录日志时,日志对象就会具有logger配置的属性。此函数需要返回bool型,也决定日志是否需要被过滤掉。
参考下面的用法:
import logging
def show_only_debug(record):
return record.levelname == "DEBUG"
logger = logging.getLogger(__name__)
logger.setLevel("DEBUG")
formatter = logging.Formatter("{levelname} - {message}", style="{")
console_handler = logging.StreamHandler()
console_handler.setLevel("DEBUG")
console_handler.setFormatter(formatter)
console_handler.addFilter(show_only_debug) # 使用 addFilter函数,传入参数为一个函数,该函数只有一个参数。运行时,该参数是logging.LogRecord类型。
logger.addHandler(console_handler)
file_handler = logging.FileHandler("app.log", mode="a", encoding="utf-8")
file_handler.setLevel("WARNING")
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.debug("Just checking in!")
logger.warning("Stay curious!")
logger.error("Stay put!")

浙公网安备 33010602011771号