redballoon 发表于 2023-3-29 18:02

纯净版 - python日志模块学习笔记

# logging模块的使用

这个模块为应用与库实现了灵活的事件日志系统的函数与类。

使用标准库提供的 logging API 最主要的好处是,所有的 Python 模块都可能参与日志输出,包括你自己的日志消息和第三方模块的日志消息。

## 导入模块

```python
import logging
```

不需要下载,是python的内置模块。

## 简单使用

简单使用可以代替print函数来进行代码的调试。据说日志输出要比print输出要快一些,而且还是线程安全的(即在使用多线程或线程池时输出的结果是有序的)。

```python
logging.debug('调试中...')
logging.info('输出的信息...')
logging.warning('warning!')
logging.error('出现错误!')
logging.critical('严重错误!')
```

运行结果:



只输出了三条信息,这是因为日志是有一个级别的,而默认是warning级别,而比warning级别低的语句就不会输出。

可以自己设置日志级别,来输出全部的日志结果。

```python
logging.basicConfig(level=logging.DEBUG)
```

+ 日志级别(由高到低)

```python
CRITICAL = 50
ERROR = 40
WARNING = 30
INFO = 20
DEBUG = 10
NOTSET = 0
```


需要使用 Logging 的原因各有不同。这些原因可以根据严重性的不同分为如下几类。



默认的级别时WARNING,意味默认的级别下,显示的日志信息必须时 `>=` WARNING的级别才会进行输出。
日志的记录可以由不同的方式,最简单的是把日志直接输出到console,另外一种就是可以把他们写到文件。

### 将日志输出到文件中

```python
# 输出到日志文件中
logging.basicConfig(level=logging.INFO,
                  filename='log.txt',
                  filemode='w')# 默认filemode 是追加写入的方式
logging.debug('调试中...')
logging.info('输出的信息...')
logging.warning('warning!')
logging.error('出现错误!')
logging.critical('严重错误!')
```

运行结果:



有没有发现输出到文件中是不是少了debug的信息😃,细心的朋友肯定能知道是因为设置的日志级别是info, debug级别比info低自然不会输出啦。

来继续学习,仅仅这样可不够😁

### 将日志输出到控制台

废话,不加filename不就好啦。🙄

### 日志输出格式美化

```python
# 美化日志输出
logging.basicConfig(level=logging.INFO,
                  format='%(asctime)s %(levelname)s %(lineno)s >>> %(message)s',# %()s 是固定格式
                  datefmt='%Y-%m-%d %H:%M:%S')
logging.info('这是一条正常信息')
logging.warning('这是一条警告信息')
logging.error('这是一条错误信息')
logging.critical('这是一条致命的错误信息')
```

运行结果:



更多的format参数:



## 高级应用

在官方文档中有4个重要的对象,分别是logger(记录器)、handler(处理器)、filter(过滤器)、formatter(格式器)。

+ 记录器对象

提供应用程序代码能直接使用的接口

+ 处理器对象

将记录器产生的日志发送到目的地(控制台或文件)

+ 过滤器对象

提供更好的粒度控制,决定哪些日志会被输出

+ 格式化器对象

设置日志内容的组成结构和消息字段



```python
# logger记录器
'''
1. 提供应用程序的调用接口
logger = logging.getLogger(__name__)默认是root, 也可以自定义其他
2. 决定日志记录的级别
logger.setLevel()
3. 将日志内容传递到相关联的handler中
logger.addHandler() 和 logger.removeHandler()
'''

# handler处理器
'''
# 最常用的两个 StreamHandler 和 FileHandler
# 所有的Handler处理器都可以使用 setFormatter() 来设置当前Handler对象的消息格式
'''

# formatter格式器
'''
ft = logging.Formatter(fmt=None, datefmt=None, style='%')
style参数默认为%, 这表示 %(<dictionary key>)s 格式的字符串
'''
```

需求:我们即想在控制台输出日志,也想在文件中输出日志时,高级的做法

```python
# 记录器
logger = logging.getLogger('redballoon')
logger.setLevel(level=logging.INFO)
# print(logger)

# 处理器
# 定义StreamHandler输出到控制台
console_handler = logging.StreamHandler()
#定义FileHandler输出到日志文件
file_handler = logging.FileHandler(filename='2023-3-18-log.txt')

console_handler.setLevel(level=logging.DEBUG)
# 如果没有给handler设置日志级别,将使用logger的日志级别
# file_handler.setLevel(level=logging.INFO)
# * 若是设置了logger记录器的日志级别,又设置了console_handler的日志级别,则会以logger的级别为准。

# 格式化器
fmt = logging.Formatter('%(asctime)s %(levelname)s %(filename)s:%(lineno)s >>> %(message)s')

# 给处理器添加格式
console_handler.setFormatter(fmt)
file_handler.setFormatter(fmt)

# 给记录器添加处理器
logger.addHandler(console_handler)
logger.addHandler(file_handler)

logger.debug('这是调试的信息')
logger.info('这是一条正常信息')
logger.warning('这是一条警告信息')
logger.error('这是一条错误信息')
logger.critical('这是一条致命的错误信息')
```

控制台运行结果:



日志文件结果:



哎,有问题呀,我想要的是控制台输出dubug的级别,日志文件输出info的级别。现在这咋都一样啊。

> 1.这是因为我前面说过,如果同时设置了console_handler的级别和logger的日志级别,则会以logger的级别为准。
>
> 2.而如果不设置logger的日志级别,则会是默认的warning级别。

想要解决,就设置logger的日志级别为最低的debug级别,再分别设置console_handler 和 file_handler的日志级别就好啦。

修改后代码如下:

```python
# 记录器
logger = logging.getLogger('redballoon')
logger.setLevel(level=logging.DEBUG)

# 处理器
console_handler = logging.StreamHandler()
file_handler = logging.FileHandler(filename='2023-3-18-log.txt')

console_handler.setLevel(level=logging.DEBUG)
# 如果没有给handler设置日志级别,将使用logger的日志级别
file_handler.setLevel(level=logging.INFO)
# * 若是设置了logger记录器的日志级别,又设置了console_handler的日志级别,则会以logger的级别为准。

# 格式化器
fmt = logging.Formatter('%(asctime)s %(levelname)s %(filename)s:%(lineno)s >>> %(message)s')

# 给处理器添加格式
console_handler.setFormatter(fmt)
file_handler.setFormatter(fmt)

# 给记录器添加处理器
logger.addHandler(console_handler)
logger.addHandler(file_handler)

logger.debug('这是调试的信息')
logger.info('这是一条正常信息')
logger.warning('这是一条警告信息')
logger.error('这是一条错误信息')
logger.critical('这是一条致命的错误信息')
```

+ 过滤器的使用

`Filters` 可被 `Handlers` 和 `Loggers` 用来实现比按层级提供更复杂的过滤操作。

使用场景,在有多个记录器时,如果想指定输出某一个的信息可使用过滤器。

通过记录器名称来设置过滤器,满足我们设置的名称便会被输出

```python
# 记录器
logger1 = logging.getLogger('redballoon')
logger2 = logging.getLogger('blueballoon')
logger1.setLevel(level=logging.DEBUG)
# logger2.setLevel(level=logging.DEBUG)不设置让他为默认级别

# 处理器
console_handler = logging.StreamHandler()
console_handler.setLevel(level=logging.DEBUG)

# 过滤器满足过滤器设置的记录器名称便会被输出
# 定义一个过滤器
flt = logging.Filter('blueballoon')
# 关联过滤器
console_handler.addFilter(flt)

# 格式化器
fmt = logging.Formatter('%(name)-12s | %(asctime)s %(levelname)s %(filename)s:%(lineno)s >>> %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S',)

# 给处理器添加格式
console_handler.setFormatter(fmt)

# 给记录器添加处理器
logger1.addHandler(console_handler)
logger2.addHandler(console_handler)

logger1.debug('这是调试的信息')
logger1.info('这是一条正常信息')
logger1.warning('这是一条警告信息')
logger1.error('这是一条错误信息')
logger1.critical('这是一条致命的错误信息')
print('=========================================')
logger2.debug('这是调试的信息')
logger2.info('这是一条正常信息')
logger2.warning('这是一条警告信息')
logger2.error('这是一条错误信息')
logger2.critical('这是一条致命的错误信息')
```

运行结果:



可以看到只输出了记录器为 blueballoon 的日志信息。

以上就是本菜鸟的学习笔记和理解,希望对你们有用。

johnversion 发表于 2023-3-29 18:08

楼主加油~~~~

yitiaocaoyu 发表于 2023-3-29 18:29

学一下看看怎么样

flyikun 发表于 2023-3-29 18:33

写的很详细

aceronethree 发表于 2023-3-29 18:38

可以可以,楼主加油

cxx0515 发表于 2023-3-29 18:45

怎么应用到代码中,有例子没?

redballoon 发表于 2023-3-29 19:05

cxx0515 发表于 2023-3-29 18:45
怎么应用到代码中,有例子没?

配置好直接就用啦,logging.info('这是输出的内容')跟print一样

brooks 发表于 2023-3-29 19:33

非常详细,清晰明了,谢谢分享!

xiaoyaowolf 发表于 2023-3-29 19:37

学习了,我的思路还好……………………

t5656 发表于 2023-3-29 20:15

先摩拜一下,做个记号
页: [1] 2
查看完整版本: 纯净版 - python日志模块学习笔记