关于python:loggingpython日志模块

3次阅读

共计 8822 个字符,预计需要花费 23 分钟才能阅读完成。

为何要应用日志?

  • 进行程序 (代码) 的调试
  • 程序运行过程中的问题定位和剖析
  • 收集程序运行的状况

logging 模块日志事件级别

默认的级别是 WARNING,意味着只会追踪该级别及以上的事件,除非更改日志配置。所追踪事件能够以不同模式解决。最简略的形式是输入到控制台。另一种罕用的形式是写入磁盘文件。

级别 数值 何时应用
DEBUG 10 细节信息,仅当诊断问题时实用。
INFO 20 确认程序按预期运行
WARNING 30 表明有曾经或行将产生的意外(例如:磁盘空间有余)。程序仍按预期进行
ERROR 40 因为重大的问题,程序的某些性能曾经不能失常执行
CRITICAL 50 重大的谬误,表明程序已不能继续执行
# -*- coding:utf-8 -*-

import logging

# 应用 basicConfig()来指定日志级别和相干信息

logging.basicConfig(
                level=logging.DEBUG  # 设置日志输入级别
           ,filename="demo.log"  # log 日志输入的文件地位和文件名
           ,filemode="w"  # 文件的写入格局,w 为从新写入文件,默认是追加
           # 日志输入的格局, - 8 示意占位符,让输入左对齐,输入长度都为 8 位
           ,format="%(asctime)s - %(name)s - %(levelname)-9s - %(filename)-8s : %(lineno)s line - %(message)s"
           ,datefmt="%Y-%m-%d %H:%M:%S"  # 工夫输入的格局
)

# 默认的 warning 级别,只输入 warning 以上的
logging.debug("This is  DEBUG !!")
logging.info("This is  INFO !!")
logging.warning("This is  WARNING !!")
logging.error("This is  ERROR !!")
logging.critical("This is  CRITICAL !!")

# 在理论我的项目中,捕捉异样的时候,如果应用 logging.error(e),只提醒指定的 logging 信息
# 不会呈现为什么会错的信息,所以要应用 logging.exception(e)去记录。try:
   3/0
except Exception as e:
    # logging.error(e)
    logging.exception(e)

日志输入后果如下:

2022-08-01 16:46:18 - root - DEBUG     - test.py  : 14 line - This is  DEBUG !!
2022-08-01 16:46:18 - root - INFO      - test.py  : 15 line - This is  INFO !!
2022-08-01 16:46:18 - root - WARNING   - test.py  : 16 line - This is  WARNING !!
2022-08-01 16:46:18 - root - ERROR     - test.py  : 17 line - This is  ERROR !!
2022-08-01 16:46:18 - root - CRITICAL  - test.py  : 18 line - This is  CRITICAL !!
2022-08-01 16:46:18 - root - ERROR     - test.py  : 27 line - division by zero
Traceback (most recent call last):
File "/Users/yg/Documents/test.py", line 24, in <module>
3/0
ZeroDivisionError: division by zero

日志组件

logging 采纳了模块化设计,次要蕴含四种组件:

组件 性能
Logger 记录器,提供利用程序代码能间接应用的接口。
Handler 处理器,将记录器产生的日志发送到目的地。(输入到文件或者控制台或者邮件等,一个记录器能够对应多个处理器。)
Filter 过滤器,提供更好的粒度管制,决定哪些日志会被输入。
Formatter 格式化器,设置日志内容的组成构造和音讯字段。

Loggers 记录器

  1. 提供应用程序的调用接口

    logger = logging.getLogger(__name__)
    # logger 是单例的,也就是__name__不变,获取到的 logger 都是同一个
  2. 设置日志记录的级别

    logger.setLevel()
  3. 将日志内容传递到相关联的 handlers 中

    logger.addHandler()
    logger.removeHandler()

Handler 处理器

将日志发送到不同的中央

# 常见的处理器
StreamHandler  # 屏幕输入
FileHandler  # 文件记录
BaseRotatingHandler  # 规范的宰割文件日志
RotatingFileHandler  # 按文件大小记录日志
TimeRotatingFileHandler  # 按工夫记录日志

StreamHandler

规范输入散发器,也就是屏幕显示

sh = logging.StreamHandler(stream=None)

FileHandler

将日志保留到文件中

fh = logging.FileHandler(filename,mode='a',encoding=None,delay=False)

setFormatter()

设置以后 Handler 对象应用的音讯格局

Filter 过滤器

Filter 能够被 Handler 和 Logger 用来做比之前设置的日志等级 level 更为细粒度的、更简单的相干过滤性能。

简略的说 Filter 是一个过滤器基类,它只容许某个 logger 层级下的日志事件通过过滤,保留下来。该类定义如下:

class logging.Filter(name='')
    filter(record)

过滤举例:

例如用‘A.B’初始化的 Filter,那么其容许 Logger‘A.B’,‘A.B.C’,‘A.B.C.D’,‘A.B.D’等日志记录的事件,logger‘A.BB’,‘B.A.B’等就不满足过滤的条件。

如果用空字符串来对 Filter 初始化,所有日志记录的事件都将不会被过滤。

Formatter 格式化器

formatter 对象用来最终设置日志信息的程序,构造和内容

ft = logging.Formatter.__init__(fmt=None,datafmt=None)
属性 格局 形容
asctime %(asctime)s 日志产生的工夫,默认格局为 msecs2003-07-08 16:49:45, 896
message %(message)s 具体的日志信息
filename %(filename)s 生成日志的程序名
name %(name)s 日志调用者
levelname %(levelname)s 日志级別(DEBUG, INFO, WARNING, ERROR, CRITICAL)
lineno %(lineno)d 日志所针对的代码行号(如果可用的话)
msecs %(msecs)d 日志生成工夫的亳秒局部
created %(created)f time.tme)生成的日志创立工夫戳
funcname %(funcname)s 调用日志的函数名
levene %(leveling)s 日志级别对应的数值
module %(module)s 生成日志的模块名
pathname %(pathname)s 生成日志的文件的残缺门路
process %(process)d 生成日志的过程 D(如果可用)
processname %(processname)s 过程名(如果可用)
thread %(thread)d 生成日志的线程 D(如果可用)
threadname %(threadname)s 线程名(如果可用)

logging 编程形式代码 demo

# -*- coding:utf-8 -*-

import logging

#编程的形式记录日志

#记录器
logger1 = logging.getLogger("logger1")
logger1.setLevel(logging.DEBUG)
print(logger1)
print(type(logger1))

logger2 = logging.getLogger("logger2")
logger2.setLevel(logging.INFO)
print(logger2)
print(type(logger2))

#处理器
#1. 规范输入
sh1 = logging.StreamHandler()

sh1.setLevel(logging.WARNING)

sh2 = logging.StreamHandler()

# 2. 文件输入
# 没有设置输入级别,将用 logger1 的输入级别(并且输入级别在设置的时候级别不能比 Logger 的低!!!),设置了就应用本人的输入级别
fh1 = logging.FileHandler(filename="fh.log",mode='w')

fh2 = logging.FileHandler(filename="fh.log",mode='a')
fh2.setLevel(logging.WARNING)

# 格局器
fmt1 = logging.Formatter(fmt="%(asctime)s - %(levelname)-9s - %(filename)-8s : %(lineno)s line - %(message)s")

fmt2 = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)-9s - %(filename)-8s : %(lineno)s line - %(message)s"
                        ,datefmt="%Y/%m/%d %H:%M:%S")

#给处理器设置格局
sh1.setFormatter(fmt1)
fh1.setFormatter(fmt2)
sh2.setFormatter(fmt2)
fh2.setFormatter(fmt1)

#记录器设置处理器
logger1.addHandler(sh1)
logger1.addHandler(fh1)
logger2.addHandler(sh2)
logger2.addHandler(fh2)

#打印日志代码
logger1.debug("This is  DEBUG of logger1 !!")
logger1.info("This is  INFO of logger1 !!")
logger1.warning("This is  WARNING of logger1 !!")
logger1.error("This is  ERROR of logger1 !!")
logger1.critical("This is  CRITICAL of logger1 !!")

logger2.debug("This is  DEBUG of logger2 !!")
logger2.info("This is  INFO of logger2 !!")
logger2.warning("This is  WARNING of logger2 !!")
logger2.error("This is  ERROR of logger2 !!")
logger2.critical("This is  CRITICAL of logger2 !!")

控制台输入:

<Logger logger1 (DEBUG)>
<class 'logging.Logger'>
<Logger logger2 (INFO)>
<class 'logging.Logger'>
2022-08-01 18:04:28,160 - WARNING   - test.py  : 56 line - This is  WARNING of logger1 !!
2022-08-01 18:04:28,160 - ERROR     - test.py  : 57 line - This is  ERROR of logger1 !!
2022-08-01 18:04:28,160 - CRITICAL  - test.py  : 58 line - This is  CRITICAL of logger1 !!
2022/08/01 18:04:28 - logger2 - INFO      - test.py  : 61 line - This is  INFO of logger2 !!
2022/08/01 18:04:28 - logger2 - WARNING   - test.py  : 62 line - This is  WARNING of logger2 !!
2022/08/01 18:04:28 - logger2 - ERROR     - test.py  : 63 line - This is  ERROR of logger2 !!
2022/08/01 18:04:28 - logger2 - CRITICAL  - test.py  : 64 line - This is  CRITICAL of logger2 !!

文件 fh.log 输入:

2022/08/01 18:04:28 - logger1 - DEBUG     - test.py  : 54 line - This is  DEBUG of logger1 !!

2022/08/01 18:04:28 - logger1 - INFO      - test.py  : 55 line - This is  INFO of logger1 !!

2022/08/01 18:04:28 - logger1 - WARNING   - test.py  : 56 line - This is  WARNING of logger1 !!

2022/08/01 18:04:28 - logger1 - ERROR     - test.py  : 57 line - This is  ERROR of logger1 !!

2022/08/01 18:04:28 - logger1 - CRITICAL  - test.py  : 58 line - This is  CRITICAL of logger1 !!

2022-08-01 18:04:28,160 - WARNING   - test.py  : 62 line - This is  WARNING of logger2 !!

2022-08-01 18:04:28,160 - ERROR     - test.py  : 63 line - This is  ERROR of logger2 !!

2022-08-01 18:04:28,160 - CRITICAL  - test.py  : 64 line - This is  CRITICAL of logger2 !!```

过滤器在代码里的利用

# 定义一个过滤器
flt1 = logging.Filter("logger1") #名字就是 logger 记录器的名字

# 关联过滤器
# 1.logger 关联过滤器
logger.addFilter(flt1)

# 2. 处理器关联过滤器
sh1.addFilter(flt1)
# fh1.addFilter(flt1)

# 过滤器定义在记录器上的时候,不论你设置了任何对于这个过滤器的任何设置,都不起作用。# 过滤器定义在哪个处理器上,哪个处理器就不起作用,也就能够管制日志的输入,想要还是不想要。# 特地是在我的项目调试的时候,不想让日志记录到文件里去,间接在屏幕显示,就过滤到 fh
# 代码上线后,日志记录到文件,不必在屏幕显示,就过滤掉 sh

文件配置 logging 编程


上述的办法都写的很死板,在小工程或者单个文件还能够,然而当我的项目大了,咱们就必须应用配置文件的形式配置 logging 的信息,从而来灵便应用,次要有两种形式去配置,一种是 conf 文件,一种是字典文件。

import logging.config
logging.config.fileConfig("/path/to/configfile")

logging.config.dictConfig("/path/to/configfile")

yaml 配置文件:

version: 1
# 是否笼罩掉曾经存在的 loggers
disable_existing_loggers: True

formatters:

  tostrout:
    format: "%(asctime)s - %(name)s - %(levelname)-9s - %(filename)-8s : %(lineno)s line - %(message)s"
    datefmt: "%Y/%m/%d %H:%M:%S"

  tofile:
    format: "%(asctime)s - %(name)s - %(levelname)-9s - %(filename)-8s : %(lineno)s line - %(message)s"

handlers:
  sh:
    class: logging.StreamHandler
    level: WARNING
    formatter: tostrout
    stream: ext://sys.stdout

  fh:
    class: logging.handlers.TimedRotatingFileHandler
    filename: info.log
    interval: 1
    backupCount: 2
    when: D
    level: INFO
    formatter: tofile

loggers:
  logger1:
    level: DEBUG
    handlers: [sh]
    # 是否往下级 Logger 传递,如果为 yes 的话,root 抉择了两个 logger,这里的日志也会在两个 logger 的配置中输入,会反复。所以选 No, 本人记录本人的日志。propagate: no

  logger2:
    level: INFO
    handlers: [fh]
    propagate: no

root:
  level: DEBUG
  handlers: [sh,fh]
  propagate: no

调用代码:

#  -*- coding:utf-8 -*-

import logging
import logging.config
import yaml

with open("logger_config.yaml", "r") as f:
    dict_conf = yaml.safe_load(f)

logging.config.dictConfig(dict_conf)
root = logging.getLogger()
logger1 = logging.getLogger('logger1')
logger2 = logging.getLogger('logger2')

# 打印日志代码

root.debug("This is  DEBUG of root !!")
root.info("This is  INFO of root !!")
root.warning("This is  WARNING of root !!")
root.error("This is  ERROR of root !!")
root.critical("This is  CRITICAL of root !!")

logger1.debug("This is  DEBUG of logger1 !!")
logger1.info("This is  INFO of logger1 !!")
logger1.warning("This is  WARNING of logger1 !!")
logger1.error("This is  ERROR of logger1 !!")
logger1.critical("This is  CRITICAL of logger1 !!")

logger2.debug("This is  DEBUG of logger2 !!")
logger2.info("This is  INFO of logger2 !!")
logger2.warning("This is  WARNING of logger2 !!")
logger2.error("This is  ERROR of logger2 !!")
logger2.critical("This is  CRITICAL of logger2 !!")

规范输入:

2022/08/02 01:23:05 - root - WARNING   - test.py  : 17 line - This is  WARNING of root !!
2022/08/02 01:23:05 - root - ERROR     - test.py  : 18 line - This is  ERROR of root !!
2022/08/02 01:23:05 - root - CRITICAL  - test.py  : 19 line - This is  CRITICAL of root !!
2022/08/02 01:23:05 - logger1 - WARNING   - test.py  : 23 line - This is  WARNING of logger1 !!
2022/08/02 01:23:05 - logger1 - ERROR     - test.py  : 24 line - This is  ERROR of logger1 !!
2022/08/02 01:23:05 - logger1 - CRITICAL  - test.py  : 25 line - This is  CRITICAL of logger1 !!

文件输入(info.log):

2022-08-02 01:23:05,688 - root - INFO      - test.py  : 16 line - This is  INFO of root !!

2022-08-02 01:23:05,688 - root - WARNING   - test.py  : 17 line - This is  WARNING of root !!

2022-08-02 01:23:05,688 - root - ERROR     - test.py  : 18 line - This is  ERROR of root !!

2022-08-02 01:23:05,688 - root - CRITICAL  - test.py  : 19 line - This is  CRITICAL of root !!

2022-08-02 01:23:05,688 - logger2 - INFO      - test.py  : 28 line - This is  INFO of logger2 !!

2022-08-02 01:23:05,688 - logger2 - WARNING   - test.py  : 29 line - This is  WARNING of logger2 !!

2022-08-02 01:23:05,688 - logger2 - ERROR     - test.py  : 30 line - This is  ERROR of logger2 !!

2022-08-02 01:23:05,688 - logger2 - CRITICAL  - test.py  : 31 line - This is  CRITICAL of logger2 !!
正文完
 0