搞掂python日志的应用,同事面前装个13

# Python日志处理

日志是在软件开发中记录程序运行情况的一种重要方式,它对于错误排查和系统运维非常有帮助。Python标准库自带了强大的logging日志模块,被广泛应用于各种Python模块中。

## 1. 小试牛刀

### 1.1 简单使用

```python

import logging

# 默认的warning级别,只输出warning以上的

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

logging.basicConfig(

    level=logging.DEBUG,  # 设置级别,根据等级显示

    format='%(asctime)s-[%(filename)s-->line:%(lineno)d]-%(levelname)s:%(message)s',  # 设置输出格式

    datefmt="%Y-%m-%d %H:%M:%S"  # 时间输出的格式

)

logging.debug("This is a DEBUG message")

logging.info("This is an INFO message")

logging.warning("This is a WARNING message")

logging.error("This is an ERROR message")

logging.critical("This is a CRITICAL message")

```

输出结果:

```plaintext

2023-06-09 10:22:39-[ts.py-->line:11]-DEBUG:DEBUG

2023-06-09 10:22:39-[ts.py-->line:12]-INFO:INFO

2023-06-09 10:22:39-[ts.py-->line:13]-WARNING:WARNING

2023-06-09 10:22:39-[ts.py-->line:14]-ERROR:TERROR

2023-06-09 10:22:39-[ts.py-->line:15]-CRITICAL:CRITICAL

```

### 1.2 日志级别

五种日志等级,不同情况输出不同等级的日志。

| 日志等级(level) | 描述                                                                                    |

| ------------------- | ------------------------------------------------------------------------------------------ |

| DEBUG            | 调试信息,通常在诊断问题的时候用得着                                                    |

| INFO              | 普通信息,确认程序按照预期运行                                                          |

| WARNING          | 警告信息,表示发生意想不到的事情,或者指示接下来可能会出现一些问题,但是程序还是继续运行 |

| ERROR            | 错误信息,程序运行中出现了一些问题,程序某些功能不能执行                                |

| CRITICAL          | 危险信息,一个严重的错误,导致程序无法继续运行                                          |

过滤掉低于自定义设置的日志等级。

```python

import logging

# 默认的warning级别,只输出warning以上的

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

logging.basicConfig(

    level=logging.ERROR,  # 设置级别,根据等级显示

    format='%(asctime)s-[%(filename)s-->line:%(lineno)d]-%(levelname)s:%(message)s',  # 设置输出格式

    datefmt="%Y-%m-%d %H:%M:%S"  # 时间输出的格式

)

logging.debug("调试等级不输出")

logging.info("普通信息等级不会输出")

logging.warning("警告不会输出)

logging.error("输出错误等级")

logging.critical("输出崩溃等级")

```

输出结果:

```plaintext

2023-06-09 10:27:16-[ts.py-->line:13]-ERROR:输出错误等级

2023-06-09 10:27:16-[ts.py-->line:14]-CRITICAL:输出崩溃等级

```

在上面的示例中,我们将日志级别设置为`ERROR`,因此只有`ERROR`和`CRITICAL`级别的日志被输出,`DEBUG`、`INFO`和`WARNING`级别的日志被过滤掉。

### 1.3 日志格式

通过`format`参数可以自定义日志输出的格式。在格式字符串中,可以使用以下占位符来表示不同的日志信息:

* • `%(asctime)s`:日志记录的时间(默认格式为`YYYY-MM-DD HH:MM:SS`)

* • `%(levelname)s`:日志级别

* • `%(message)s`:日志消息

* • `%(name)s`:日志器的名称

* • `%(filename)s`:包含当前日志记录的源文件的文件名

* • `%(lineno)d`:当前日志记录所在的行号

设置自定义的日志格式:

```python

import logging

logging.basicConfig(

    level=logging.DEBUG, # 设置最低过滤级别

    format='%(asctime)s - %(levelname)s - %(message)s',

    datefmt='%Y-%m-%d %H:%M:%S' # 使用指定的日期/时间格式,与 time.strftime() 所接受的格式相同。

)

logging.debug('勇哥 debug ')

logging.info('勇哥 info')

logging.warning('勇哥 warning ')

logging.error('勇哥 error ')

logging.critical('勇哥 critical ')

```

输出结果:

```plaintext

2023-06-09 10:33:08 - DEBUG - 勇哥 debug 

2023-06-09 10:33:08 - INFO - 勇哥 info

2023-06-09 10:33:08 - WARNING - 勇哥 warning 

2023-06-09 10:33:08 - ERROR - 勇哥 error 

2023-06-09 10:33:08 - CRITICAL - 勇哥 critical

```

## 2. 磨磨牛刀

`日志处理器(Log Handlers)`用于指定日志的输出位置,例如控制台、文件或网络等。

### 2.1 控制台处理器

`StreamHandler`是一个将日志输出到控制台的处理器。它可以将日志消息打印到标准输出或标准错误。

将日志输出到控制台:

```python

import logging

logging.basicConfig(level=logging.DEBUG)

console_handler = logging.StreamHandler()

console_handler.setLevel(logging.DEBUG)

formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')

console_handler.setFormatter(formatter)

logger = logging.getLogger(__name__)

logger.addHandler(console_handler)

logger.debug('勇哥 debug ')

logger.info('勇哥 info ')

logger.warning('勇哥 warning')

logger.error('勇哥 error')

logger.critical('勇哥 critical')

```

输出结果:

```plaintext

2023-06-09 10:52:56,493 - DEBUG - 勇哥 debug 

DEBUG:__main__:勇哥 debug 

2023-06-09 10:52:56,493 - INFO - 勇哥 info 

INFO:__main__:勇哥 info 

2023-06-09 10:52:56,493 - WARNING - 勇哥 warning

WARNING:__main__:勇哥 warning

2023-06-09 10:52:56,494 - ERROR - 勇哥 error

ERROR:__main__:勇哥 error

2023-06-09 10:52:56,494 - CRITICAL - 勇哥 critical

CRITICAL:__main__:勇哥 critical

```

`StreamHandler`对象添加到日志器处理器中。设置处理器的级别和格式,控制输出的日志级别和格式。

### 2.2 文件处理器

`FileHandler`将日志输出到文件的处理器,将日志消息写入指定的文件。

将日志输出到文件:

```python

import logging

logging.basicConfig(level=logging.DEBUG)

file_handler = logging.FileHandler('app.log', encoding='utf8') # 不带编码会出现中文乱码

file_handler.setLevel(logging.DEBUG)

formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')

file_handler.setFormatter(formatter)

logger = logging.getLogger(__name__)

logger.addHandler(file_handler)

logger.debug('勇哥 debug ')

logger.info('勇哥 info ')

logger.warning('勇哥 warning')

logger.error('勇哥 error')

logger.critical('勇哥 critical')

```

![](https://gitee.com/chenyongzhiaaron_admin/image/raw/master/img/log.png)

`FileHandler`对象添加到日志器中。日志消息写入名为`app.log`的文件中。

### 2.3 其他处理器

除了控制台处理器和文件处理器,`logging`模块还提供了其他处理器,例如:

* • `SMTPHandler`:将日志消息通过电子邮件发送。

* • `SocketHandler`:将日志消息发送到网络套接字。

* • `SysLogHandler`:将日志消息发送到系统日志。

* • 等等。

你可以根据需要选择适合的处理器,并根据需要配置其级别、格式和其他属性。

## 3. 镀膜牛刀

`日志过滤器(Log Filters)`用于对日志进行过滤,只输出满足特定条件的日志消息。通过添加日志过滤器,我们可以进一步控制哪些日志消息应该被处理器处理。

使用过滤器将日志消息限制在特定级别的范围内:

```python

import logging

class LevelFilter(logging.Filter):

    def __init__(self, level):

        super().__init__()

        self.level = level

    def filter(self, record):

        return record.levelno >= self.level

logging.basicConfig(level=logging.DEBUG)

console_handler = logging.StreamHandler()

console_handler.setLevel(logging.DEBUG)

formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')

console_handler.setFormatter(formatter)

logger = logging.getLogger(__name__)

logger.addHandler(console_handler)

level_filter = LevelFilter(logging.WARNING)

logger.addFilter(level_filter)

logger.debug('勇哥 debug')

logger.info('勇哥 info')

logger.warning('勇哥 warning')

logger.error('勇哥 error')

logger.critical('勇哥 critical')

```

`LevelFilter`自定义过滤器。该过滤器接受一个日志级别作为参数,在`filter`方法中根据日志记录的级别判断是否应该处理该日志记录。然后,我们将过滤器添加到控制台处理器中,从而限制了只输出`WARNING`级别及以上的日志消息。

输出结果:

```plaintext

2023-06-09 11:17:16,546 - WARNING - 勇哥 warning

WARNING:__main__:勇哥 warning

2023-06-09 11:17:16,546 - ERROR - 勇哥 error

ERROR:__main__:勇哥 error

2023-06-09 11:17:16,546 - CRITICAL - 勇哥 critical

CRITICAL:__main__:勇哥 critical

```

`DEBUG`和`INFO`级别的日志消息被过滤掉了。

## 牛刀装鞘

封装日志功能来提供更方便和可复用的日志记录接口

```python

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

# @Time : 2019/11/18 10:17

# @Author : 勇哥

# @Email : 262667641@qq.com

# @File : logger.py.py

# @Project : risk_api_project

import logging

import time

from logging import handlers

from common.base_datas import BaseDates

class MyLog:

    level_relations = {

        "debug": logging.DEBUG,

        "info": logging.INFO,

        "warning": logging.WARNING,

        "error": logging.ERROR,

        "critic": logging.CRITICAL

    }  # 日志级别关系映射

    def my_log(self, msg, level="error", when="D", back_count=10):

        """

        实例化 TimeRotatingFileHandler

        interval 是时间间隔, backupCount 是备份文件的个数,如果超过这个个数,就会自动删除,when 是间隔的时间单位,单位有以下几种

        S 秒

        M 分

        H 小时

        D 天

        每星期(interval == 0 时代表星期一

        midnight 每天凌晨

        """

        file_name = BaseDates.log_path

        my_logger = logging.getLogger()  # 定义日志收集器 my_logger

        my_logger.setLevel(self.level_relations.get(level))  # 设置日志级别

        format_str = logging.Formatter(

            "%(asctime)s-%(levelname)s-%(filename)s-[ line:%(lineno)d ] - 日志信息:%(message)s")  # 设置日志格式

        # 创建输出渠道

        sh = logging.StreamHandler()  # 往屏幕输出

        sh.setFormatter(format_str)  # 设置屏幕上显示的格式

        current = time.strftime("%Y-%m-%d", time.localtime())  # 设置当前日期

        if level == "error":

            th = handlers.TimedRotatingFileHandler(filename=f'{file_name}/{current}_{level}.log', when=when,

                                                   backupCount=back_count, encoding="utf-8")

        else:

            th = handlers.TimedRotatingFileHandler(filename=file_name + "/{}_info.log".format(current), when=when,

                                                   backupCount=back_count,

                                                   encoding="utf-8")  # 往文件里写日志

        th.setFormatter(format_str)  # 设置文件里写入的格式

        my_logger.addHandler(sh)  # 将对象加入logger里

        my_logger.addHandler(th)

        if level == "debug":

            my_logger.debug(msg)

        elif level == "error":

            my_logger.error(msg)

        elif level == "info":

            my_logger.info(msg)

        elif level == "warning":

            my_logger.warning(msg)

        else:

            my_logger.critical(msg)

        my_logger.removeHandler(sh)

        my_logger.removeHandler(th)

        logging.shutdown()

    def decorator_log(self, msg=None):

        def warp(fun):

            def inner(*args, **kwargs):

                try:

                    return fun(*args, **kwargs)

                except Exception as e:

                    self.my_log(f"{msg}: {e}", "error")

            return inner

        return warp

if __name__ == '__main__':

    # for i in range(2):

    #     MyLog().my_log("hhhh{}".format(i), "info")

    #     time.sleep(0.04)

    @MyLog().decorator_log(“”知错了嘛?)

    def add():

        print("试一下")

        raise "不好使,异常了。"

```

输出:

![](https://gitee.com/chenyongzhiaaron_admin/image/raw/master/img/Snipaste_2023-06-09_11-28-54.png)

## 总结

以上就是勇哥今天为各位小伙伴准备的内容,如果你想了解更多关于Python自动化测试的知识和技巧,欢迎关注我: 公众号\博客\CSDN\B站:测试玩家勇哥;我会不定期地分享更多的精彩内容。感谢你的阅读和支持!

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容