python日志处理 logging

一. 简介

logging模块是Python内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级、日志保存路径、日志文件回滚等。

二. 日志等级

  • CRITICAL: 50, 特别糟糕的事情,软件已不能继续运行了
  • ERROR:    40, 发生错误,不能执行一些功能时,如IO操作失败或者连接问题
  • WARNING:30, 发生很重要的事件,但是并不是错误时
  • INFO:         20, 处理请求或者状态变化等日常事务,按预期工作
  • DEBUG:     10, 调试过程中使用DEBUG等级,如算法中每个循环的中间状态

三. 基本使用

使用logging.basicConfig输出日志

# 输出日志到控制台
import logging
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')

logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
logger.info("Finish")

# 输出日志到文件
import logging
logger = logging.getLogger() 
logging.basicConfig(filename="xxx.log", level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') 

logger.info("Start print log") 
logger.debug("Do something") 
logger.warning("Something maybe fail.") 
logger.info("Finish")

basicConfig 参数:

  • filename    日志文件名
  • filemode    日志文件的打开模式,”w”(写)或”a”(追加),默认”a”
  • format        输出的格式和内容
  • datefmt      时间格式,与time.strftime()相同
  • level           设置日志级别
  • stream        日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,与filename参数不兼容
  • handlers     指定处理程序(详情见下文),此参数与 filename 或 stream 不兼容

format 占位符 :

  • args 不需要格式化。 合并到 msg 以产生 message 的包含参数的元组,或是其中的值将被用于合并的字典(当只有一个参数且其类型为字典时)。
    asctime %(asctime)s 表示 LogRecord 何时被创建的供人查看时间值。 默认形式为 ‘2003-07-08 16:49:45,896’ (逗号之后的数字为时间的毫秒部分)。
    created %(created)f LogRecord 被创建的时间(即 time.time() 的返回值)。
    exc_info 不需要格式化。 异常元组 (例如 sys.exc_info) 或者如未发生异常则为 None
    filename %(filename)s pathname 的文件名部分。
    funcName %(funcName)s 函数名包括调用日志记录.
    levelname %(levelname)s 消息文本记录级别 ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL').
    levelno %(levelno)s 消息数字记录级别 (DEBUG, INFO, WARNING, ERROR, CRITICAL).
    lineno %(lineno)d 发出日志记录调用所在的源行号(如果可用)。
    message %(message)s 记入日志的消息,即 msg % args 的结果。 这是在发起调用 Formatter.format() 时设置的。
    module 模块 %(module)s 模块 (filename 的名称部分)。
    msecs %(msecs)d LogRecord 被创建的时间的毫秒部分。
    msg 不需要格式化。 在原始日志记录调用中传入的格式字符串。 与 args 合并以产生 message,或是一个任意对象 (参见 使用任意对象作为消息)。
    名称 %(name)s 用于记录调用的日志记录器名称。
    pathname %(pathname)s 发出日志记录调用的源文件的完整路径名(如果可用)。
    process %(process)d 进程ID(如果可用)
    processName %(processName)s 进程名(如果可用)
    relativeCreated %(relativeCreated)d 以毫秒数表示的 LogRecord 被创建的时间,即相对于 logging 模块被加载时间的差值。
    stack_info 不需要格式化。 当前线程中从堆栈底部起向上直到包括日志记录调用并导致创建此记录的堆栈帧的堆栈帧信息(如果可用)。
    thread %(thread)d 线程ID(如果可用)
    threadName %(threadName)s 线程名(如果可用)

    四. Handlers

处理器负责将适当的日志消息(基于日志消息的严重性)分派到处理程序的指定目标。

Logger 对象可以通过addHandler()方法增加零个或多个handler对象。

# 同时输出到文件和控制台
import logging
logger = logging.getLogger()
logger.setLevel(level = logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler = logging.FileHandler("log.txt")# 文件处理器
handler.setLevel(logging.INFO)
handler.setFormatter(formatter)

console = logging.StreamHandler() # 控制台处理器
console.setLevel(logging.INFO)
handler.setFormatter(formatter)
logger.addHandler(handler) # 添加文件输出
logger.addHandler(console) # 添加控制台输出

logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
logger.info("Finish")

Handlers处理器常用的有四种:

  • logging.StreamHandler:     控制台输出 
  • logging.FileHandler:           文件输出
  • logging.handlers.RotatingFileHandler:    按照大小自动分割日志文件,一旦达到指定的大小重新生成文件

类似于上面的FileHandler,但是它可以管理文件大小。当日志文件大小超过设定值后,新建一个日志文件存储日志。

  • logging.handlers.TimedRotatingFileHandler:    按照时间自动分割日志文件

和RotatingFileHandler类似,但是通过间隔一定时间,然后自动创建新的日志文件。

RotatingFileHandler 参数:

class RotatingFileHandler(BaseRotatingHandler):
    def __init__(self, filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False):
        """

        :param filename:    日志文件名
        :param mode:        日志文件打开模式
        :param maxBytes:    最大Bytes数,1K=1024Bytes,为0时,日志可以无限大。
        :param backupCount: 回滚数量,日志总数不大于该数值,超过之后,删除旧日志
        :param encoding:    编码方式,'utf-8'
        :param delay:       
        """

TimedRotatingFileHandler 参数:

class TimedRotatingFileHandler(BaseRotatingHandler):
    def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False, atTime=None):
        """

        :param filename:    日志文件名
        :param when:        时间间隔的单位(S秒,M分,H小时,D天,W每星期(interval==0时代表星期一,midnight 每天凌晨)
        :param interval:    时间间隔
        :param backupCount: 回滚数量,日志总数不大于该数值,超过之后,删除旧日志
        :param encoding:    编码方式,'utf-8'
        :param delay:
        :param utc:
        :param atTime:
        """

五. 使用例子

def Logger():
    logger = logging.getLogger()
    format_str = '%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s' # 日志格式化样式
    logger.setLevel(logging.INFO)  # Log等级总开关
    logging.basicConfig(level=logging.INFO, format=format_str) # 这里使用basicConfig进行控制台输出,也可以通过StreamHandler进行设置

    log_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'logs', 'xxx.log') # 日志文件
    fh = handlers.TimedRotatingFileHandler(filename=log_path, when='D', backupCount=8, encoding='utf-8') # 按时间进行回滚
    fh.setFormatter(logging.Formatter(format_str)) # 设置文件处理器日志格式
    logger.addHandler(fh) # 添加日志文件处理器

    return logger