Python logging模块基础与进阶使用指南

Nora
Nora
发布时间:2026-10-13 | 4人浏览过
原创

本文详细解析Python标准库logging模块的基础与进阶用法。涵盖日志级别设置、Logger/Handler/Formatter配置、日志格式化字符串及日期格式控制。深入讲解Filter过滤器的两种实现方式,以及通过配置文件和basicConfig进行日志管理的最佳实践,帮助开发者构建规范的日志系统。

本文介绍Python标准库logging模块的功能与具体用法,供开发者参考学习。

  • logging模块概述
  • logging模块基础用法
  • logging模块进阶用法
  • 日志过滤器(Filter)应用
  • 通过配置文件配置logging与Logger
  • 实用技巧
  • 如需深入了解,建议查阅官方文档。

首发日期:2018-07-05


  • 作为Python标准库,logging具有极高的通用性,所有Python模块均可利用它进行日志记录。

日志级别说明

基本 中文意义 触发情况
DEBUG 调试 调试时期
INFO 提示 正常运行时
WARINING 警告 现在可运行,但未来可能发生错误时(例如未来存储空间可能不足)
ERROR 错误 当程序发生错误,无法执行某些功能时
CRITICAL 严重的、致命的 当程序发生严重错误,无法继续运行时

默认级别为WARNING。。

核心类介绍

  • Loggers(日志器):提供调用接口,负责添加Handlers和Filters。系统存在默认的Logger对象。
  • Handlers(处理器):决定日志输出的目的地,例如FileHandler(输出至文件)和StreamHandler(输出至流,默认为标准输出流)。
  • Filters(过滤器):用于筛选需要输出的日志信息。
  • Formatters(格式化器):负责定义日志输出的具体格式。

  • 基础用法即直接使用默认的Logger对象进行日志记录。
  1. 设置logging,调用logging.basicConfig()来配置日志信息。【由此可知,它是“通用型的,只能设置一次的”,若不同部分需使用不同的日志记录,需使用logger对象(见下文扩展使用)】。
    • 可配置参数包括:filename(日志文件名)、filemode(文件打开模式)、format(日志输出格式)、datefmt(日期格式)、style(format类型,默认为'%')、level(最低记录级别)、stream(输出流,若指定filename则忽略此参数)、handlers(日志处理对象,默认为根处理器)。
    • 一般使用的参数:filename日志文件名,format日志的输出格式,level日志记录的最低级别,stream设置输出流。
      • filename指定日志文件名,为普通字符串。
      • format定义日志输出格式,具体设置方法见下文。
      • level参数值对应debug等枚举,使用方式为logging.DEBUG、logging.INFO、logging.WARNING、logging.ERROR、logging.CRITICAL。
      • style影响format类型,可选值有'%','{','$',默认是'%'。不同style识别不同的message标识符:%(message)s、{message}、$message。
  2. 输出日志信息:
    • 调试级别日志:logging.debug(信息)。
    • 提示级别信息:logging.info(信息)。
    • 警告级别信息:logging.warning(信息)。
    • 错误级别信息:logging.error(信息)。
    • 严重级别信息:logging.critical(信息)。

日志信息格式化(指logging.info等函数中的信息):

此概念类似程序报错信息。普通异常可能仅有一个原因,但为方便查看,还需错误地点、事件等附加信息。这些信息不应由产生错误的各模块添加,而应交由专门处理格式化的部分(Formatter)统一处理。

1. 支持普通字符串%格式化,例如:


logging.info('Started %s'%tag) 

2. 支持普通字符串format格式化,例如:


logging.info('{} started '.format(tag)) 

3. logging内置格式化方式,例如:


logging.info('%s start in', tag) logging.info('%s start in %s',tag,address)

format设置方法:

  • 常用特殊字符:
    • message为日志信息。
    • levelname为日志信息等级。
    • asctime为字符串形式的日期时间。
    • name为logger的名称。
    • levelno为数字形式的日志信息等级。
    • module为调用日志输出函数的模块名。
    • funcName为调用日志输出函数的函数名。
    • lineno为调用日志输出函数的代码行数。

根据style不同,可使用%(message)s、{message}或$message等格式标注指定位置,以指定信息替换。

  • 默认格式:
    • asctime使用%(asctime)s。
    • funcName使用%(funcName)s。
    • levelname使用%(levelname)s。
    • message使用%(message)s。
    • lineno使用%(lineno)d。
    • module使用%(module)s。
    • name使用%(name)s。

官方文档:

https://docs.python.org/3.6/library/logging.html

datefmt日期输出格式设置方法:

用于设置format中特殊字符asctime(日期时间)的输出格式。

  • 特殊字符:
    • %y 两位数的年份表示(00-99)。
    • %Y 四位数的年份表示(000-9999)。
    • %m 月份(01-12)。
    • %d 月内中的一天(0-31)。
    • %H 24小时制小时数(0-23)。
    • %I 12小时制小时数(01-12)。
    • %M 分钟数(00-59)。
    • %S 秒(00-59)。

使用自定义分隔符和顺序定义日期时间格式,例如:

datefmt='%m/%d/%Y %I:%M:%S %p'。

使用小例子:

不使用format的情况:


import
logging def show(): print("wechat running...") return "wechat" def main(): logging.basicConfig(filename='myapp.log', level=logging.INFO) tag=show() logging.info('Started %s'%tag) logging.info('Finished %s'%tag) if __name__ == '__main__'
:
  main()

使用format和datefmt的情况:


import
logging def show(): print("wechat running...") return "wechat" def main(): logging.basicConfig(filename='myapp.log', format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p',level=logging.INFO) tag=show() logging.info('%s start in', tag) logging.info('%s Finished',tag) if __name__ == '__main__'
:
  main()

注意:虽然上述示例未显式创建logger、handler(默认输出至标准输出流)和formatter对象,但系统默认存在这些对象。为避免混淆,不建议混合使用基础版和扩展版用法。


1. 导入模块:


import logging

2. 获取logger对象:


logger = logging.getLogger("AppName")

【此处可根据不同名称定义不同的logger对象,默认为root。】

在模块中使用时,官方文档提供了一个示例代码:


logger = logging.getLogger(__name__)

3. 设置最低日志输出级别:


logger.setlevel()

例如:


logger.setLevel(logging.INFO)

4. 创建并绑定handler:

handler用于处理日志信息的输出方向,可添加多个handler以同时向多个方向输出信息。

  • 创建handler:

输出方向为文件,使用FileHandler,例如:


logging.FileHandler("test.log")

输出方向为流,使用StreamHandler,例如:


logging.StreamHandler(sys.stdout)

欲了解更多Handler类型,请查阅官方文档https://docs.python.org/3.6/howto/logging.html。

  • 绑定handler,使用addHandler():

例如:


logger.addHandler(handler)
  • 绑定后如需解绑handler,使用removeHandler():

例如:


logger.removeHandler(handler)

5. 定义handler的输出格式formatter并绑定到handler上,formatter设置方法类似基础使用中的format:

  • 创建:

例如:


formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')
  • 绑定:

handler.setFormatter(formatter) 或 handler.formatter=formatter。

6. 将handler绑定到logger对象上。


logger.addHandler(file_handler)

logger.addHandler(console_handler)

7. 输出日志:

调试级别:logger.debug(信息)。

提示级别:logger.info(信息)。

警告级别:logger.warn(信息)。

错误级别:

logger.error(信息)。

logger.exception(信息)【与error不同,附带堆栈信息,通常用于发生异常时】。

严重级别:

logger.fatal(信息) 【fatal是critical的别名】。

logger.critical(信息)。

使用示例:


import
logging def demo(): #获取logger对象 logger=logging.getLogger("WeChat") #设置日志等级 logger.setLevel(logging.DEBUG) #创建绑定handler handler=logging.FileHandler('wechat.log') logger.addHandler(handler) # 创建绑定formatter formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s') formatter.datefmt = '%m/%d/%Y %I:%M:%S %p' #可选的 handler.setFormatter(formatter) #尝试输出错误信息 logger.debug("debug message") logger.info("info message") logger.warning("warining message") logger.error("error message") logger.critical("critical message") if __name__=="__main__"
:
  demo()

补充:

  • 若不想新建handler和formatter,可使用basicConfig方式(可配置所有logger对象的handler和formatter),但需注意混杂风险。【basicConfig和handler必须至少存在一个,因为默认logger对象需要初始化】。
  • logging模块中还有一个filter,因涉及内容较多,单独列在下面讲解。

  • Filter用于过滤日志信息,例如想输出A类信息但不想输出C类信息,即可进行过滤。
  • 由于所有信息均经过过滤器,也可利用过滤器增加一些信息。

使用方法1:建立子类

以下示例可能不完全符合实际应用,仅用于举例:

过滤非允许用户的日志信息:


import
logging import sys class ContextFilter(logging.Filter): def filter(self, record): if record.role=="admin" : return True else: return False if __name__ == '__main__': logger=logging.getLogger("Wechat") logger.setLevel(logging.DEBUG) handler=logging.StreamHandler(sys.stdout) formatter=logging.Formatter('%(asctime)s %(levelname)s: %(message)s Role: %(role)s') handler.setFormatter(formatter) logger.addHandler(handler) #创建绑定fiter f = ContextFilter() logger.addFilter(f) logger.info('An info message with %s', 'some parameters',extra={"role":"admin"}) logger.info('An info message with %s', 'some parameters',extra={"role":"hacker"})#hacker的被过滤掉了

官网版的加信息版本:


import
logging from random import choice class ContextFilter(logging.Filter): """

  This is a filter which injects contextual information into the log.

  Rather than use actual contextual information, we just use random
  data in this demo.
  """

  USERS 
= ['jim', 'fred', 'sheila'] IPS = ['123.231.231.123', '127.0.0.1', '192.168.0.1'] def filter(self, record): record.ip = choice(ContextFilter.IPS) record.user = choice(ContextFilter.USERS) return True if __name__ == '__main__': levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL) logging.basicConfig(level=logging.DEBUG, format='%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s') a1 = logging.getLogger('a.b.c') a2 = logging.getLogger('d.e.f') f = ContextFilter() a1.addFilter(f) a2.addFilter(f) a1.debug('A debug message') a1.info('An info message with %s', 'some parameters') for x in range(10): lvl = choice(levels) lvlname = logging.getLevelName(lvl) a2.log(lvl, 'A message at %s level with %d %s', lvlname, 2, 'parameters')

使用方法2:使用filter函数

python3.2后,可使用filter函数实现上述方法1的效果。

例子1:


import
logging import sys def myfilter(record): if record.role == "admin": return True else: return False if __name__ == '__main__': logger=logging.getLogger("Wechat") logger.setLevel(logging.DEBUG) handler=logging.StreamHandler(sys.stdout) formatter=logging.Formatter('%(asctime)s %(levelname)s: %(message)s Role: %(role)s') handler.setFormatter(formatter) logger.addHandler(handler) #创建绑定fiter f = logging.Filter() f.filter=myfilter logger.addFilter(f) logger.info('An info message with %s', 'some parameters',extra={"role":"admin"}) logger.info('An info message with %s', 'some parameters',extra={"role":"hacker"})#hacker的被过滤掉了

例子2,利用lambda:


logger=logging.getLogger("Wechat") logger.setLevel(logging.DEBUG) handler=logging.StreamHandler(sys.stdout) formatter=logging.Formatter('%(asctime)s %(levelname)s: %(message)s Role: %(role)s') handler.setFormatter(formatter) logger.addHandler(handler) #创建绑定fiter

#
f = ContextFilter() f = logging.Filter() f.filter=lambda record: record.role=="admin"

logger.addFilter(f)

logger.info(
'An info message with %s', 'some parameters',extra={"role":"admin"}) logger.info('An info message with %s', 'some parameters',extra={"role":"hacker"})#hacker的被过滤掉了

注意:logging默认使用的logger对象名为root。

config文件配置方式:

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')

文件内容:

[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=

注意:也支持YAML方式,此处不展开讲述。


若留意到过滤器示例,可以发现

在formatter内可以附加参数:

输出信息时,附加一个参数extra,附加的参数可被formatter使用。


import
logging import sys class ContextFilter(logging.Filter): def filter(self, record): if record.role=="admin" : return True else: return False if __name__ == '__main__': logger=logging.getLogger("Wechat") logger.setLevel(logging.DEBUG) handler=logging.StreamHandler(sys.stdout) formatter=logging.Formatter('%(asctime)s %(levelname)s: %(message)s Role: %(role)s') handler.setFormatter(formatter) logger.addHandler(handler) #创建绑定fiter f = ContextFilter() logger.addFilter(f) logger.info('An info message with %s', 'some parameters',extra={"role":"admin"}) logger.info('An info message with %s', 'some parameters',extra={"role":"hacker"})#hacker的被过滤掉了

https://docs.python.org/3.6/library/logging.html

更多关于Python相关内容感兴趣的读者可查看本站专题:《Python日志操作技巧总结》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》及《Python文件与目录操作技巧汇总》。

希望本文所述对大家Python程序设计有所帮助。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表