Python logging模块:别再用print来打印啦~

软件开发中通过日志记录程序的运行情况是一个开发的好习惯,对于错误排查和系统运维都有很大帮助。Python标准库自带日志模块,程序的日志功能直接调用标准库的日志模块即可通过日志,开发者可以清楚的了解发生了哪些事件,包括出现了哪些错误。

日志记录是一种跟踪某些软件运行时发生的事件的方法。 该软件的开发人员在其代码中添加了日志记录调用,以指示发生了某些事件。 事件由描述性消息描述,该消息可以可选地包含变量数据。 事件也具有开发者认为该事件的重要性。 重要性也可以称为级别或严重性。

由标准库模块提供的日志记录API的主要好处是所有Python模块都可以参与日志记录,因此您的应用程序日志可以包括您自己的消息以及与第三方模块的消息集成的消息。

首先,需要知道日志是有等级的。下面列举了五个等级。

日志等级(level) 描述
DEBUG 调试信息,通常在诊断问题的时候用
INFO 普通信息,确认程序按照预期运行
WARNING 警告信息,表示发生意想不到的事,或者指示接下来可能会出现一些问题,但是程序还是继续运行
ERROR 错误信息,程序运行中出现了一些问题,程序某些功能不能执行
CRITICAL 危险信息,一个严重的错误,导致程序无法继续运行

注意:指定了日志等级后,只会显示大于等于所指定日志等级的日志信息!

logging中级别大小:

DEBUG < INFO < WARNING < ERROR < CRITICAL

日志内容是可以自己定制的,包括时间,记录内容等等。这些格式是由formater来定制。下面列举一些formater格式:(加粗的就是常用的)

%(asctime)s 日志时间发生的时间
%(levelname)s 该日志记录的日志级别
%(message)s 日志记录的文本内容
%(name)s 所使用的日志器名称,默认是“root”
%(filename)s 调用日志记录函数的文件
%(funcName)s 调用日志记录函数的函数名
%(lineno)d 调用日志记录函数的代码所在的行号
%(pathname)s 打印当前执行程序的路径,其实就是sys.argv[0]
%(thread)d 打印线程ID
%(process)d 打印进程ID

日常使用中,可以通过创建带有默认FormatterStreamHandler并将其添加到根记录器r,对记录系统进行基本配置。 如果没有为根记录器定义处理程序handler,则debug()info()warning()error()critical()函数将自动调用basicConfig()函数。如果根记录器已经配置了处理程序,则此功能将不执行任何操作,除非将关键字参数force设置为True

logging.basicConfig(**kwargs)

basicConfig()的相关参数列举如下:

Format Description
filename 使用指定文件名创建FileHandler
filemode 如果filename指定,使用filemode打开文件,默认是a,追加
format handler使用指定format string
datefmt 使用指定date/time格式
style 如果指定format,使用为format string使用该style。
level 将root logger级别设置为指定level,默认是logging.WARNING
stream 使用指定stream初始化StreamHandler。和filename不能同时指定
handlers 如果指定,应该是已经创建的可迭代的处理程序handler,并添加到根记录器。 任何尚未设置格式器的处理程序都将被分配此函数中创建的默认格式器。 请注意,此参数与filename或stream不兼容,如果同时存在,则会引发ValueError
force 如果将此关键字参数指定为True,则在执行其他参数指定的配置之前,将删除并关闭附加到根记录程序的所有现有处理程序。

这些都是碎片化的知识,下面直接列举一些实用的例子。

PS:日常使用中,只需要对logging进行一定的配置(根据需要),然后把程序中所有使用print()打印内容换成logging.warning()等函数打印即可。

简单使用

日志内容输出到控制台

import logging

# 设置输出的格式
LOG_FORMAT = "Time:%(asctime)s - Level:%(levelname)s - Message:%(message)s"
# 对logger进行配置——日志等级&输出格式
logging.basicConfig(level=logging.WARNING, format=LOG_FORMAT)

# logging.level(message)创建一条level级别的日志
logging.debug("This is a debug log")
logging.info("This is a info log")
logging.warning("This is a warning log")
logging.error("This is a error log")
logging.critical("This is a critical log")

运行结果如下:

在这里插入图片描述

观察可知,只有大于等于WARNING日志等级的日志信息才进行输出!

注意:logging.basicConfig()只能有一个哦!如果写多条——只有第一条会生效!!!

日志信息保存为文件

上述使用最终日志信息都是在终端输出——电脑一关/程序一关/编辑器一关,日志信息就丢失了! 而且我们实际使用中也不会那样做,所以下面就来来看看如何写入文件!
方法很简单,直接再basicConfig()函数中加入filename参数即可。(这里添加filename参数之后,日志不会输出到控制台,而是只输出到log文件)

import logging

# 设置输出的格式
LOG_FORMAT = "Time:%(asctime)s - Level:%(levelname)s - Message:%(message)s"
# 对logger进行配置——日志等级&输出格式
logging.basicConfig(level=logging.WARNING, format=LOG_FORMAT, filename="train.log")

# logging.level(message)创建一条level级别的日志
logging.debug("This is a debug log")
logging.info("This is a info log")
logging.warning("This is a warning log")
logging.error("This is a error log")
logging.critical("This is a critical log")

运行结果如下:

在这里插入图片描述

basicConfig的调用应先于对debuginfo等的任何调用。由于它是一次性的简单配置工具,因此实际上只有第一个调用会做任何事情:后续调用实际上是无操作。如果您多次运行上述脚本,则连续运行的消息将附加到文件train.log中。 如果您希望每个运行重新开始,而不记得先前运行的消息,则可以通过将上述示例中的调用更改为以下方式来指定filemode参数:

logging.basicConfig(filename='example.log', filemode='w', level=logging.WARNING)

输出将与以前相同,但是不再将日志文件附加到该文件,因此先前运行的消息将丢失。

进阶操作:模块化组件

如果只是简单的使用logging,那么使用上面介绍的方法就可以了,如果要深度定制logging,那么就需要对它有更深的了解!

logging模块提供了模块化组件的方法:

组件 说明
Loggers(日志记录器) 提供程序直接使用的接口
(基操中的logging.basicConfig()就是配置了此组件)
Handlers(日志处理器) 将记录的日志发送到指定的位置(终端打印/保存为文件)
Filters(日志过滤器) 用于过滤特定的日志记录
Formatters(日志格式器) 用于控制日志信息的输出格式

模块化组件的使用步骤:

  1. 创建一个logger(日志记录器)对象;
  2. 定义handler(日志处理器),决定把日志发到哪里;常用的是:
    1. StreamHandler——>输出到控制台;
    2. FileHandler——>输出到文件;
  3. 设置日志级别(level)和输出格式Formatters(日志格式器);
  4. 把handler添加到对应的logger中去。

下面列举两个例子,也即是上面例子的升级版。

日志信息保存为文件

import logging

# 1.创建一个logger(日志记录器)对象;
my_logger = logging.Logger("first_logger")

# 2.定义handler(日志处理器),决定把日志发到哪里;
my_handler = logging.FileHandler('test.log')

# 3.设置日志级别(level)和输出格式Formatters(日志格式器);
my_handler.setLevel(logging.INFO)
my_format = logging.Formatter("时间:%(asctime)s 日志信息:%(message)s 行号:%(lineno)d")

# 把handler添加到对应的logger中去。
my_handler.setFormatter(my_format)
my_logger.addHandler(my_handler)


# 使用:
my_logger.info("我是日志组件")

同时写入文件和控制台

在日常使用中,一般我的习惯是同时写入文件和控制台,这样有两个好处:

  • 写入文件避免因为停电或者一些原因导致输出的信息丢失
  • 写入控制台方便查看日志信息
import logging

logger = logging.getLogger("train")

handler = logging.FileHandler('train.log')
handler.setLevel(logging.INFO)
formatter_handler = logging.Formatter("时间:%(asctime)s 日志信息:%(message)s")
handler.setFormatter(formatter_handler)
logger.addHandler(handler)

console = logging.StreamHandler()
console.setLevel(logging.INFO)
format_console = logging.Formatter("时间:%(asctime)s 日志信息:%(message)s 行号:%(lineno)d")
console.setFormatter(format_console)
logger.addHandler(console)

logger.warning("~~~~~哦豁~~~~~")

运行结果如下:

在这里插入图片描述


相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...