logging库的使用
| 级别 | 何时使用 |
|---|---|
| DEBUG | 详细信息,典型地调试问题时会感兴趣。 详细的debug信息。 |
| INFO | 证明事情按预期工作。 关键事件。 |
| WARNING | 表明发生了一些意外,或者不久的将来会发生问题(如‘磁盘满了’)。软件还是在正常工作。 |
| ERROR | 由于更严重的问题,软件已不能执行一些功能了。 一般错误消息。 |
| CRITICAL | 严重错误,表明软件已不能继续运行了。 |
| NOTICE | 不是错误,但是可能需要处理。普通但是重要的事件。 |
| ALERT | 需要立即修复,例如系统数据库损坏。 |
| EMERGENCY | 紧急情况,系统不可用(例如系统崩溃),一般会通知所有用户。 |
一、基本的使用方式
logging.basicConfig(
filename="test.log" # 设置日志的文件名
filemode="w" # 设置日志的写入方式
format="%(asctime)s|%(levelname)s|%(filename)s:%(lineno)s|%(message)s", # 设置输出格式
datefmt = "%Y-%m-%d %H:%M:%S",# 设置输出日期的格式
level=logging.DEBUG # 设置log等级
)
logging.debug("hahah") # 输出日志
并不推荐使用这种方式,这种方式操作的是整个logging库的底层默认值,既root用户的设置(这么说可能不是很准确,但我也没太弄明白),后续使用中可能会遇到继承相关的问题。
二、logging库中的组件
| 名称 | 作用 |
|---|---|
| Loggers | 记录器,提供应用程序代码直接使用的接口 |
| Handlers | 处理器,将记录器产生的日志发送至目的地 |
| Filters | 过滤器,提供更好的粒度控制,决定哪些日志会被输出 |
| Formatters | 格式化器,设置日志内容的组成结构和消息字段 |
2.1 loggers记录器
loggers(记录器)可以看成一种载体
<注:过滤器是否可以在loggers或handlers中同时存在多个,我暂时还没弄清楚,但1个是肯定可以的
import logging # 后续将不再重复声明
guo_logger = logging.getlogger("guo") # 创建一个记录器
guo_logger.addHandler(<处理器的变量名>) # 为记录器设置一个处理器
guo_logger.addFilter(<过滤器变量名>) # 为记录器设置一个过滤器
为什么用guo?因为我姓国  ̄▽ ̄
”guo”为此过滤器提供了唯一的标识,同时也定义了继承关系
例如:
guo_logger = logging.getLogger("guo")
guo_logger.setLevel(logging.DEBUG)
guo1_logger = logging.getLogger("guo.a")
那么,guo1_logger,将会继承guo_logger的全部设置,不仅包括日志等级
“."的作用就像电脑里文件路径"/"的作用一样,”guo”会包括“guo.a",也会包括“guo.a.b"
对于不希望guo1_logger继承的处理器(handlers),我们可以使用过滤器(filter)对处理器进行设置,详见后文
在logging.getlogger()生成的记录器中:
默认的日志等级为“warning”,记录器是各个处理器(handler)的载体,如果记录器中的处理器(handler)的日志等级低于记录器的日志等级,处理器(handler)将不会进行相应的写日志操作,可以理解为,记录器规定了记录时的最低等级,处理器规定了处理时的最低等级
默认的处理器(handler)是StreamHandler,只会向终端打印日志信息
2.2 Handlers 处理器
guo_consoleHandler = logging.StreamHandler() # 生成一个向stream(数据流)输出的处理器
# StreamHandler(stream),参数stream默认值为sys.stderr(通过查看源码可知)
guo_consoleHandler.setFormatter(<格式化器的变量名>) # 为处理器设置格式化器->设置处理器输出日志时的格式
guo_consoleHandler.addFilter(<过滤器变量名>) # 为处理器设置过滤器
2.2.1 Handlers 处理器种类
| 处理器名称 | 解释 | 使用提示 |
|---|---|---|
| Streamhandler | 将日志输出在终端(控制台)上的处理器 | logging.StreamHandler() |
| Filehandler | 将日志保存到磁盘文件的处理器 | logging.FileHandler(filename="") |
| BaseRotatingHandler | 基本的日志轮转方式 | logging.handlers.BaseRotatingHandler() 具体的参数没有找到 |
| RotatingHandler | 支持日志文件按大小轮转 | logging.handlers.RotatingHandler 是后面类的基础 |
| RotatingHandler | 按照日志文件大小轮转,继承自RotatingHandler | logging.handlers.RotatingHandler |
| TimeRotatingHandler | 按照时间轮转,继承自RotatingHandler | logging.handlers.TimeRotatingHandler |
| SMTPHandler | 远程输出日志到邮件地址 | logging.handlers.SMTPHandler() |
| HTTPHandler | 通过GET或POST远程输出到HTTP服务器 | logging.handlers.HTTPHandler() |
具体各个handlers控制器的使用细节,用的时候再查吧。。。
2.3 Formatters 格式化器
guo_formatter = logging.Formatter("%(asctime)s|%(levelname)8s|%(filename)10s|%(lineno)s|%(message)s") # 定义一个格式化器
guo_formatter.datafmt = '%Y-%m-%d %H:%M' # 定义#(asctime)s中,日期的显示格式
实际上,logging.Formatter()中的第二个参数就是datafmt,因此以上代码可简写为:
guo_formatter = logging.Formatter("%(asctime)s|%(levelname)8s|%(filename)10s|%(lineno)s|%(message)s",'%Y-%m-%d %H:%M')
2.3.1 Formatters中的格式
| 属性 | 格式 | 描述 |
|---|---|---|
| asctime | %(asctime)s | 日志产生的时间,默认格式为msecs2003-07-0816:49:45,896 |
| msecs | %(msecs)d | 日志生成时间的亳秒部分 |
| created | %(created)f | time.tme)生成的日志创建时间戳 |
| message | %(message)s | 具体的日志信息 |
| filename | %(filename)s | 生成日志的程序名 |
| name | %(name)s | 日志调用者 |
| funcname | %( funcname)s | 调用日志的函数名 |
| levelname | %(levelname)s | 日志级別( DEBUG,INFO, WARNING, 'ERRORCRITICAL) |
| levene | %( leveling)s | 日志级别对应的数值 |
| lineno | %(lineno)d | 日志所针对的代码行号(如果可用的话) |
| module | %( module)s | 生成日志的模块名 |
| pathname | %( pathname)s | 生成日志的文件的完整路径 |
| process | %( (process)d | 生成日志的进程D(如果可用) |
| processname | (processname)s | 进程名(如果可用) |
| thread | %(thread)d | 生成日志的线程D(如果可用) |
| threadname | %( threadname)s | 线程名(如果可用) |
2.4 Filter过滤器
guo_fit = logging.Filter("guo") # 定义一个过滤器
如果把过滤器(fliter)配置到记录器(loggers)中,那么只有名称中包括“guo”字段的记录器(loggers)才能进行记录操作
如果把过滤器(fliter)配置到处理器(handlers)中,那么只有名称中包括“guo”字段的处理器(handlers)才能进行处理操作
过滤器的参数“guo”是可以自定义的,它也遵守记录器(loggers)的命名规则
假设,有一个名字为”guo“的记录器、一个名字为“guo.a"的记录器和一个名字为”guo.b"的记录器。
“guo.a”和“guo.b"两个记录器中的处理器会继承记录器”guo“的
例子如下:
import logging
#创建记录器
logger_guo = logging.getLogger("guo")
logger_guo_a = logging.getLogger("guo.a")
logger_guo_b = logging.getLogger("guo.b")
#创建格式化器
formatter_0 = logging.Formatter("%(asctime)r|%(levelname)8r|%(name)r|%(message)r")
#创建处理器并为处理器设置格式化器
console_hander = logging.StreamHandler()
console_hander.setFormatter(formatter_0)
#为记录器设置处理器
logger_guo.addHandler(console_hander)
#创建并为处理器设置过滤器
# fit = logging.Filter("guo.a") #创建过滤器
# console_hander.addFilter(fit) #为处理器添加过滤器
# 测试各个记录器
logger_guo.warning("test")# 此处用warning是因为记录器默认的日志等级为warning
logger_guo_a.warning("test1")
logger_guo_b.warning("test2")
在未设置过滤器时,输出结果为:
'2022-08-03 13:31:28,758'|'WARNING'|'guo'|'test'
'2022-08-03 13:31:28,759'|'WARNING'|'guo.a'|'test1'
'2022-08-03 13:31:28,759'|'WARNING'|'guo.b'|'test2'
在设置过滤器后,输出结果为:
'2022-08-03 13:44:11,869'|'WARNING'|'guo.a'|'test1'
此时,虽然处理器是设置在“guo”中的,但是“guo”本身已经无法使用此处理器了,只有名称为“guo.a"的记录器才可以使用此处理器,不止”guo.a"可以使用,“guo.a.a"也可以使用
例子如下:
import logging
#创建记录器
logger_guo = logging.getLogger("guo")
logger_guo_a = logging.getLogger("guo.a")
logger_guo_a_a = logging.getLogger("guo.a.a")
logger_guo_b = logging.getLogger("guo.b")
#创建格式化器
formatter_0 = logging.Formatter("%(asctime)r|%(levelname)8r|%(name)r|%(message)r")
#创建处理器并为处理器设置格式化器
console_hander = logging.StreamHandler()
console_hander.setFormatter(formatter_0)
#为记录器设置处理器
logger_guo.addHandler(console_hander)
#创建并为处理器设置过滤器
# fit = logging.Filter("guo.a") #创建过滤器
# console_hander.addFilter(fit) #为处理器添加过滤器
# 测试各个记录器
logger_guo.warning("test")# 此处用warning是因为记录器默认的日志等级为warning
logger_guo_a.warning("test1")
logger_guo_a_a.warning("test1_0")
logger_guo_b.warning("test2")
输出结果为:
'2022-08-03 13:54:01,778'|'WARNING'|'guo.a'|'test1'
'2022-08-03 13:54:01,778'|'WARNING'|'guo.a.a'|'test1_0'
三、一些零碎的想法
没有太理解过滤器存在的意义,如果我希望一个处理器(handlers)只在记录器”guo.a"中生效,那我为什么不直接把处理器放到记录器”guo.a"中呢?如果是希望处理器可以复用(定义一个处理器,用在多个记录器上),那么我为处理器定义了过滤器,那这个处理器就和记录器彻底绑定了,而且过滤器只能过滤一种“guo.a",如果我想让”guo.b"也可以使用,但不想让”guo.c"使用,这种情况我就只能把处理器从“guo”中拿出来,分别放到“guo.a"和”guo.b"中,那我过滤器存在的意义是什么呢。。。
也许是我对过滤器的用法还不了解?但我一直没找到可以参考的例子,,,
参考教程:https://www.bilibili.com/video/BV1sK4y1x7e1
教程后半部分,利用配置文件进行设置的方法我并没有整理,因为我还没弄明白前半部分

浙公网安备 33010602011771号