1.0 类
logger:可以有多个实例,每个实例记录一些日志
RootLogger:根记录器,也是所有记录器实例的父类,默认级别为 30 warning。
Handler:logger中真正处理日志信息的,每个logger实例都会有一个handler
Formater:每个handler设置的固定输出的日志格式
Filter:handler中做日志信息过滤的
关于Logger
logger日志记录器可以通过实例化logger类,直接获得,有几种方式:
import logging l1 = logging.Logger('t1') l3 = logging.getLogger('t4') # 推荐使用,如果不指定name,返回的是RootLogger print([l3, type(l3), l3.name, l3.level, l3.parent, l3.parent.name]) # 父类是root
1.0.1 层次结构
记录器的名称另一个作用就是表示Logger实例的层次关系。
Logger是层次结构的,使用 . 点号分割,如'a'、'a.b'或'a.b.c.d',a是a.b的父parent,a.b是a的子child。
对于foo来说,名字为foo.bar、foo.bar.baz、foo.bam都是 foo的后代。
1.0.2 级别
级别可以是一个整数。0表示未设置,有特殊意义。
级别用来表示日志消息级别、记录器级别、处理器级别。
级别 | 数值 |
CRITICAL | 50 |
ERROR | 40 |
WARNING | 30 |
INFO | 20 |
DEBUG | 10 |
NOTSET | 0 |
2.0 消息级别
每一条日志消息被封装成一个LogRecord实例,该实例包含消息本身、消息级别、记录器的name等信息。
消息级别只能说明消息的重要等级,但不一定能输出。
3.0 记录器级别
日志记录器 Logger 有自己的级别,这个级别意味着 消息能否通过 日志记录器输出,记录器级别默认为0。
只有 消息级别 大于等于 记录器级别,这个消息才有资格输出。
3.0.1 记录器有效级别
关于记录器级别,其实不能以表面的 级别 判断。因为记录器默认 0级别,0 代表 no set。但是它可以继承父类的,最近的父类的有效级别,也就是 RootLogger 的级别,也就是 30。
所有,准确的说,应该是“所有消息级别 大于等于 记录器有效级别 的消息,才有资格输出。”
3.0.2 设置级别
setLevel() 建议使用
4.0 处理器 Handle 级别
前面说道,只有消息级别大于等于记录器级别才有资格输出。因为每个记录器都由消息处理器进行消息处理,消息处理器自身也有级别,它控制消息能否通过该处理器 Handle 输出。
所以 消息级别还必须大于等于处理器级别,才可以输出。
5.0 根记录器使用
使用RootLogger 进行日志输出
logging模块提供了debug、info、warning、error、critical等快捷函数,可以快速产生相应级别消息。
本质上这些方法使用的都是根记录器对象。
5.0.1 日志格式处理 Formate
用来定义输出的日志的格式
logging.basicConfig() 对记录器进行全局的配置。 注意:只能配置一次。
5.0.1.1 日志格式:
属性名 | 格式 | 描述 |
日志消 息内容 | %(message)s | The logged message, computed as msg % args. 当调用 Formatter.format()时设置 |
asctime | %(asctime)s | 创建LogRecord时的可读时间。默认情况下,它的格式为'2003- 07-08 16:49:45,896'(逗号后面的数字是毫秒部分的时间) |
函数名 | %(funcName)s | 日志调用所在的函数名 |
日志级 别名称 | %(levelname)s | 消息的级别名称 'CRITICAL' 'DEBUG', 'INFO', 'WARNING', 'ERROR', |
日记级 别数值 | %(levelno)s | 消息的级别数字 CRITICAL ,对应DEBUG, INFO, WARNING, ERROR, |
行号 | %(lineno)d | 日志调用所在的源码行号 |
模块 | %(module)s | 模块(filename的名字部分) |
进程ID | %(process)d | 进程 ID |
线程ID | %(thread)d | 线程 ID |
进程名 称 | % (processName)s | 进程名 |
线程名 称 | % (threadName)s | 线程名字 |
logger 名称 | %(name)s | logger名字 |
5.0.1.2 日志输出到文件
如下:
使用filemode配置文件模式,覆盖或者追加。
默认追加,覆盖--w
6.0 Handle 日志处理器
每个Logger可以有多个 Handle,进行日志处理。
Handler 控制日志信息的输出目的地,可以是控制台、文件。
- 可以单独设置level
- 可以单独设置格式
- 可以设置过滤器
Handler类层次:
- Handle
- StreamHandler # 不指定使用sys.stderr
- FileHandler # 文件
- _StderrHandler # 标准输出
handle = logging.StreamHandler() # 定义一个Handle logging.root.addHandler(handle) # 添加到 logger handle.setLevel(logging.DEBUG) # 设置handler级别
7.0 Format 格式处理器
每个Handle 都有一个Format, 用来进行输出格式处理。
basicConfig函数执行后,默认会生成一个StreamHandler实例,如果设置了filename,则只会生成一个FileHandler实例。
每一个记录器实例可以设置多个Handler实例
# 定义处理器 handler = logging.FileHandler('o:/test.log', 'w', 'utf-8') handler.setLevel(logging.WARNING) # 设置处理器级别
8.0 日志流
日志处理流程:
- Logger产生了一个日志消息,这个Logger就是当前logger。然后比较消息级别和Logger的有效级别,如果低于有效级别,则流程结束。否则生成一个log记录;
- 日志记录会交给当前所有的Handle处理,记录还要和每一个Handle级别比较,低的不处理,否则按照Handle输出日志记录;
- 当前Logger的所有Handle处理完日志后,要看自己的propagate属性,如果为True,则会向父Logger传递这个日志记录,否则流程结束 默认传播是打开的;
- 父Logger收到日志后,不会比较有效级别,而是直接交给所有的Handle处理日志,然后每个Handle重复 2,3步骤,直到父Logger为None结束。
9.0 关于logging.basicConfig函数
如果root没有handler,就默认创建一个StreamHandler,如果设置了filename,就创建一个FileHandler。如果设置了format参数,就会用它生成一个Formatter对象,否则会生成缺省Formatter,并把这个formatter加入到刚才创建的handler上,然后把这些handler加入到root.handlers列表上。level是设置给root logger的。
如果root.handlers列表不为空,logging.basicConfig的调用什么都不做。
10.0 日志处理示例
# encoding = utf-8 __author__ = "www.mcabana.com" import time import logging import os from logging.handlers import TimedRotatingFileHandler BASE_DIR = os.path.dirname(os.path.abspath(__file__)) log_file = os.path.join(BASE_DIR, "test.log") # 日志文件路径 # 日志文件格式 FORMAT = "%(asctime)s %(processName)s %(levelname)s: %(message)s" # 日志同时打印到屏幕 --- 利用了Handler的传播属性 logging.basicConfig(format=FORMAT) # 实例化Logger 级别为 DEBUG,这些是写入文件的日志 log = logging.getLogger('debug') log.setLevel(logging.DEBUG) # 定义handler , 文件模式,追加写入, 使用TimedRotatingFileHandler 按时间轮询, 也可以按大小轮询 handler = TimedRotatingFileHandler(log_file, 's', 10, encoding='utf-8') log.addHandler(handler) # 添加到 logger # 开启 传播,用来将warning日志打印到标准输出 log.propagate = True # 定义一个格式化器 formater = logging.Formatter(FORMAT) # 调用 FORMAT 格式 # 将格式化器添加到 Handle handler.setFormatter(formater) # 日志轮询切割测试 for i in range(20): time.sleep(3) log.debug('test in debug {:03}'.format(i)) log.info('test in info {:03}'.format(i))
https://www.hugbg.com/archives/2705.html
评论