08 | 日志模块 logging

逸兴
逸兴
逸兴
57
文章
25
评论
2020-05-2622:53:03
评论
1 3912字阅读13分2秒

1.0 类

08 | 日志模块 logging

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
08 | 日志模块 logging

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表示未设置,有特殊意义。
级别用来表示日志消息级别记录器级别处理器级别

级别数值
CRITICAL50
ERROR40
WARNING30
INFO20
DEBUG10
NOTSET0

2.0 消息级别

每一条日志消息被封装成一个LogRecord实例,该实例包含消息本身、消息级别、记录器的name等信息。
消息级别只能说明消息的重要等级,但不一定能输出。

3.0 记录器级别

日志记录器 Logger 有自己的级别,这个级别意味着 消息能否通过 日志记录器输出,记录器级别默认为0。

只有 消息级别 大于等于 记录器级别,这个消息才有资格输出。

3.0.1 记录器有效级别

关于记录器级别,其实不能以表面的 级别 判断。因为记录器默认 0级别,0 代表 no set。但是它可以继承父类的,最近的父类的有效级别,也就是 RootLogger 的级别,也就是 30。

所有,准确的说,应该是“所有消息级别 大于等于 记录器有效级别 的消息,才有资格输出。”

08 | 日志模块 logging

3.0.2 设置级别

08 | 日志模块 logging
08 | 日志模块 logging

setLevel() 建议使用

4.0 处理器 Handle 级别

前面说道,只有消息级别大于等于记录器级别才有资格输出。因为每个记录器都由消息处理器进行消息处理,消息处理器自身也有级别,它控制消息能否通过该处理器 Handle 输出。

所以 消息级别还必须大于等于处理器级别,才可以输出。

5.0 根记录器使用

使用RootLogger 进行日志输出

08 | 日志模块 logging

logging模块提供了debug、info、warning、error、critical等快捷函数,可以快速产生相应级别消息。
本质上这些方法使用的都是根记录器对象。

5.0.1 日志格式处理 Formate

用来定义输出的日志的格式

logging.basicConfig() 对记录器进行全局的配置。
注意:只能配置一次。
08 | 日志模块 logging

5.0.1.1 日志格式:

属性名 格式 描述
日志消
息内容 
%(message)sThe 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 日志输出到文件

此外,basicConfig() 还可指定 filename ,用来指定将日志打印到文件中,而非标准错误输出。

如下:

08 | 日志模块 logging
08 | 日志模块 logging

使用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 日志流

日志处理流程:

  1. Logger产生了一个日志消息,这个Logger就是当前logger。然后比较消息级别和Logger的有效级别,如果低于有效级别,则流程结束。否则生成一个log记录;
  2. 日志记录会交给当前所有的Handle处理,记录还要和每一个Handle级别比较,低的不处理,否则按照Handle输出日志记录;
  3. 当前Logger的所有Handle处理完日志后,要看自己的propagate属性,如果为True,则会向父Logger传递这个日志记录,否则流程结束 默认传播是打开的;
  4. 父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))
08 | 日志模块 logging
08 | 日志模块 logging
08 | 日志模块 logging



https://www.hugbg.com/archives/2705.html
逸兴
  • 本文由 发表于 2020-05-2622:53:03
  • 除非特殊声明,本站文章均为原创,转载请务必保留本文链接
01-1 数据类型 基础语法

01-1 数据类型

第一章 数据类型 使用type() 函数可以查看数据类型 1.1 字符串 str 字符串是使用单引号或双引号括起来的任意文本。 比如'abc', '123'等 字符串类型 字符串类型用str表示 st...
09-5 | asyncio基本使用 并发编程

09-5 | asyncio基本使用

第一节 关于asyncio asyncio 在3.4 版本中加入到标准库, asyncio基于selector实现, 看似库, 其实是个框架, 包含异步IO, 事件循环, 协程, 任务等内容。 通过a...
09-4 | 全局解释器锁 & 多进程 & 池 并发编程

09-4 | 全局解释器锁 & 多进程 & 池

GIL CPython 在解释器进程级别有一把锁,叫做GIL,即全局解释器锁。 GIL 保证CPython进程中,只有一个线程执行字节码。甚至是在多核CPU的情况下,也只允许同时只能 有一个CPU核心...
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: