Python logging模块核心机制与实战配置指南
本文深入解析Python logging模块的核心组件,包括Logger、Formatter、Handler及Filter的作用与配置方法。详细阐述日志等级数值与名称映射机制,演示如何通过配置文件实现个性化日志输出,并提供封装好的Logger工具类代码。同时指出logging模块在多线程环境下的安全性及多进程写日志的潜在风险,帮助开发者构建稳定可靠的日志系统。
1. logging 简介
Python内置的logging包提供了一套通用的日志记录系统,便于第三方模块或应用程序集成使用。该模块支持多种日志级别,并允许通过文件、HTTP GET/POST请求、SMTP邮件、Socket连接等多种方式记录日志,甚至支持用户自定义日志记录后端。
logging包内部定义了Logger、Formatter、Handler和Filter等核心类,此外还包含用于配置管理的config模块。
Logger是日志记录的核心对象,直接提供记录日志的操作接口。
Formatter负责定义日志输出的格式及具体内容。
Handler决定日志写入的目标位置,例如保存为本地文件、按小时分割生成新日志文件,或通过Socket传输至其他服务器。Python提供了十几种实用的Handler,常用的包括StreamHandler、BaseRotatingHandler、SocketHandler、DatagramHandler和SMTPHandler等。通过Logger对象的addHandler()方法,可以将日志输出到多个不同的目的地。
2. Logging package
在Python编程中引入Logging package后,系统中会存在一个名为root的Logging对象,以及众多其他命名的Logging对象。不同Logger对象的Handler和Formatter配置是相互独立的。
(1)logging.getLogger():若调用getLogger()时不带参数,则返回名为root的Logger对象;若传入参数,则返回以该参数为名称的Logger对象。相同名称的Logger对象指向同一实例。
(2)logging.basicConfig():此方法专门用于配置名为root的Logger对象。
(3)logging.info()、logging.debug()等方法默认使用root Logger对象进行信息输出。若需使用其他命名的Logging对象输出日志,可通过logging.getLogger(name).info()来实现。
(4)日志的等级
CRITICAL = 50 ERROR = 40 WARNING = 30 INFO = 20 DEBUG = 10 NOTSET = 0
Python中定义了0、10、20、30、40、50这6个等级数值,分别对应一个字符串常量作为等级名称(如上述代码所示)。但可以通过logging.addLevelName(20, "NOTICE:")方法修改这种映射关系,从而定制化日志等级名称。
通过Logger对象的setLevel()方法,可以配置Logging对象的默认日志等级。只有当一条日志的等级数值大于或等于该默认等级时,才会被输出到日志文件中。
当使用logging.info(msg)输出日志时,内部封装会使用数字20作为日志等级数值。默认情况下,20对应的是INFO,但如果通过addLevelName()修改了20对应的等级名称,那么日志中打印的将是个性化的等级名称。
3. logging包使用配置文件
在1~2节描述的案例中,对Logger对象的Handler、Formatter等配置均在程序中定义或绑定。实际上,Logging的个性化配置可以移至配置文件中,以实现更灵活的管理。
logging的配置文件举例如下:
[loggers] keys=root,simpleExample [handlers] keys=consoleHandler [formatters] keys=simpleFormatter [logger_root] level=DEBUG handlers=consoleHandler [logger_simpleExample] level=DEBUG handlers=consoleHandler qualname=simpleExample propagate=0 [handler_consoleHandler] class=StreamHandler level=DEBUG formatter=simpleFormatter args=(sys.stdout,) [formatter_simpleFormatter] format=%(asctime)s - %(name)s - %(levelname)s - %(message)s datefmt=
对应程序为:
import logging
import logging.config
logging.config.fileConfig("logging.conf") # 采用配置文件
# create logger
logger = logging.getLogger("simpleExample")
# "application" code
logger.debug("debug message")
logger.info("info message")
logger.warn("warn message")
logger.error("error message")
logger.critical("critical message")
4.一个常用的Logging封装工具
#!/usr/bin/env python
#-*- coding:utf-8 -*-
#coding=utf-8
import logging
import os
class Logger(object):
"""
封装好的Logger工具
"""
def __init__(self, logPath):
"""
initial
"""
log_path = logPath
logging.addLevelName(20, "NOTICE:")
logging.addLevelName(30, "WARNING:")
logging.addLevelName(40, "FATAL:")
logging.addLevelName(50, "FATAL:")
logging.basicConfig(level=logging.DEBUG,
format="%(levelname)s %(asctime)s [pid:%(process)s] %(filename)s %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
filename=log_path,
filemode="a")
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(levelname)s [pid:%(process)s] %(message)s")
console.setFormatter(formatter)
logging.getLogger("").addHandler(console)
def debug(self, msg=""):
"""
output DEBUG level LOG
"""
logging.debug(str(msg))
def info(self, msg=""):
"""
output INFO level LOG
"""
logging.info(str(msg))
def warning(self, msg=""):
"""
output WARN level LOG
"""
logging.warning(str(msg))
def exception(self, msg=""):
"""
output Exception stack LOG
"""
logging.exception(str(msg))
def error(self, msg=""):
"""
output ERROR level LOG
"""
logging.error(str(msg))
def critical(self, msg=""):
"""
output FATAL level LOG
"""
logging.critical(str(msg))
if __name__ == "__main__":
testlog = Logger("oupput.log")
testlog.info("info....")
testlog.warning("warning....")
testlog.critical("critical....")
try:
lists = []
print lists[1]
except Exception as ex:
"""logging.exception()输出格式:
FATAL: [pid:7776] execute task failed. the exception as follows:
Traceback (most recent call last):
File "logtool.py", line 86, in <module>
print lists[1]
IndexError: list index out of range
"""
testlog.exception("execute task failed. the exception as follows:")
testlog.info("++++++++++++++++++++++++++++++++++++++++++++++")
"""logging.error()输出格式:
FATAL: [pid:7776] execute task failed. the exception as follows:
"""
testlog.error("execute task failed. the exception as follows:")
exit(1)
备注:exception()方法能够完整打印异常的堆栈信息。而error()方法仅打印参数传入的信息。
备注:
按照官方文档介绍,logging是线程安全的,即在一个进程内的多个线程同时向同一个文件写入日志是安全的。但是,多个进程向同一个文件写入日志是不安全的。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













