• 优雅高效的日志管理loguru MC


    前言

    在python中用到日志记录,早期接触的时候一直用的是内置的标准库logging。虽然logging库采用的是模块化设计,你可以设置不同的handler来进行组合,但是在配置上通常较为繁琐;而且如果不是特别处理,在一些多线程或多进程的场景下还需考虑各种异步处理情况,每一次应用得写个封装类来调。
    但有这么一个第三方库,它不仅能够减少繁琐的配置过程还能实现和logging类似的功能,同时还能保证日志记录的线程进程安全,又能够和logging相兼容,并进一步追踪异常也能进行详细的代码回溯。这个库叫loggur——旨在为 Python 带来愉快的日志记录。
    git地址:https://github.com/Delgan/loguru

    安装

    pip install loguru

    loguru

    1. 日志打印

    from loguru import logger
    logger.debug('this is a debug message')
    logger.info('this is a info message')
    logger.warning('this is a warning message')
    logger.error('this is a error message')
    logger.critical('this is a critical message')
    

    可以看到其默认的输出格式是上面的内容,有时间、级别、模块名、行号以及日志信息,不需要手动创建 logger,直接使用即可,另外其输出还是彩色的,看起来会更加友好。

    2. 文件配置

    以上的日志信息是直接输出到控制台的,并没有输出到其他的地方,如果想要输出到其他的位置,比如存为文件,我们只需要使用一行代码声明即可。 调用如下:

    from loguru import logger
    logger.add('./logs/file_{time}.log', encoding='utf-8')
    logger.debug('this is a debug message')
    

    我们再也不需要声明一个文件句柄了,就一行 add 语句搞定,运行之后会发现自动创建logs以及目录下 file_%Y-%m-%d_%H_%M_%S_%f.log 文件,文件记录了 DEBUG 信息。下面解下它的其他一些功能,包括留存、清理、压缩方法。

    from loguru import logger
    
    # 使用 format、filter、level 来规定输出的格式
    logger.add(sys.stderr, format="{time} {level} {message}", filter="my_module", level="INFO")
    # 每超过500M创建一个新文件输出保存
    logger.add("file_{time}.log", rotation="500 MB")
    # 每天12:00创建一个新文件输出保存
    logger.add("file_{time}.log", rotation="12:00")
    # 每隔一周创建一个新文件输出保存
    logger.add("file_{time}.log", rotation="1 week")
    # 设置日志文件最长保留 10 天
    logger.add("file_{time}.log", retention="10 days")
    # 使用 zip 文件格式保存
    logger.add("file_{time}.log", compression="zip")
    

    3. 字符串格式化

    loguru 在输出 log 的时候还提供了非常友好的字符串格式化功能,像这样:
    logger.info('If you are using Python {}, prefer {feature} of course!', 3.6, feature='f-strings')

    4. 异常捕获记录

    在很多情况下,如果遇到运行错误,而我们在打印输出 log 的时候万一不小心没有配置好 Traceback 的输出,很有可能我们就没法追踪错误所在了。 loguru可以直接用它提供的装饰器进行 Traceback 的记录,类似这样的配置即可:

    @logger.catch    # 装饰器捕获
    def my_function(x, y, z):
        # An error? It's caught anyway!
        return 1 / (x + y + z)
    
    
    def my_function2(x, y, z):
        try:
            return 1 / (x + y + z)
        except:
            logger.exception('what?')    # exception方法捕获
        
    my_function(0, 0, 0)    # 引发ZeroDivisionError异常通过装饰器捕获
    my_function2(0, 0, 0)    # 引发ZeroDivisionError异常通过exception方法捕获
    

    5. 序列化

    希望日志被序列化以便于解析或传递它们,可以使用该serialize参数,每条日志消息将在发送到配置的接收器之前转换为 JSON 字符串。

    from loguru import logger
    
    logger.add('./logs/file_{time}.log', encoding='utf-8', serialize=True)
    logger.debug('this is a debug message')
    logger.info('this is a info message')
    
    {"text": "2022-01-04 15:20:47.614 | DEBUG    | __main__:<module>:10 - this is a debug message\n", "record": {"elapsed": {"repr": "0:00:00.003996", "seconds": 0.003996}, "exception": null, "extra": {}, "file": {"name": "test.py", "path": "E:/code/small_project/test.py"}, "function": "<module>", "level": {"icon": "\ud83d\udc1e", "name": "DEBUG", "no": 10}, "line": 10, "message": "this is a debug message", "module": "test", "name": "__main__", "process": {"id": 13912, "name": "MainProcess"}, "thread": {"id": 11852, "name": "MainThread"}, "time": {"repr": "2022-01-04 15:20:47.614379+08:00", "timestamp": 1641280847.614379}}}
    {"text": "2022-01-04 15:20:47.614 | INFO     | __main__:<module>:11 - this is a info message\n", "record": {"elapsed": {"repr": "0:00:00.003996", "seconds": 0.003996}, "exception": null, "extra": {}, "file": {"name": "test.py", "path": "E:/code/small_project/test.py"}, "function": "<module>", "level": {"icon": "\u2139\ufe0f", "name": "INFO", "no": 20}, "line": 11, "message": "this is a info message", "module": "test", "name": "__main__", "process": {"id": 13912, "name": "MainProcess"}, "thread": {"id": 11852, "name": "MainThread"}, "time": {"repr": "2022-01-04 15:20:47.614379+08:00", "timestamp": 1641280847.614379}}}
    

    6. 多模块多线程应用

    在 loguru 中有且仅有一个对象:logger。所有添加至logger的sink默认都是线程安全的。
    所以loguru是可以在多模块多线程下使用的,只需要在对应模块下导入logger引用即可。
    from loguru import logger

    更多玩法

    飞书异常通知

    # _*_ coding:utf-8 _*_
    
    # @Time     : 2022/1/4 14:26
    # @Author   : mancheng
    # @File     : test.py
    
    from loguru import logger
    import requests
    import json
    
    
    def except_only(record):
        return record["level"].name == "ERROR" and record["exception"] is not None
    
    
    def except_sink(message):
        # print("The full exception message: ", message)
        # print("The record: ", message.record)
        # print("The message: ", message.record["message"])
        # print("The exception: ", message.record["exception"].value)
        webhook = 'https://open.feishu.cn/open-apis/bot/v2/hook/67097366-a3c8-4f1b-b17c-971be81e59dd'   # 飞书机器人webhook
        body = {"msg_type": "post",
                "content": {
                    "post": {
                        "zh_cn": {
                            "title": "Exception: {}".format(message.record["exception"].value),
                            "content": [
                                [{"tag": "text", "text": "报错内容信息如下:"}],
                                [{"tag": "text", "text": message}],
                            ],
                        }
                    }
                }}
        with requests.post(webhook, data=json.dumps(body)) as response:
            logger.info(response.content)
    
    
    @logger.catch
    def my_function(x, y, z):
        # An error? It's caught anyway!
        return 1 / (x + y + z)
    
    
    def run():
        my_function(0, 0, 0)
    
    
    logger.add('./logs/{time}.log', encoding='utf-8', backtrace=True, diagnose=True)
    logger.add(except_sink, filter=except_only, enqueue=True)   # 添加异常钩子
    run()
    

    再也不需要登录服务器去tail查看日志异常啦。

    欢迎更多玩法添加补充哦。

  • 相关阅读:
    变量1
    PHP 函数
    发送post请求
    XXE
    CSRF
    Html基础
    暴力破解
    Brup sute
    XSS
    URL 传参转义 (特殊符号转义)
  • 原文地址:https://www.cnblogs.com/mcboy/p/16248706.html
Copyright © 2020-2023  润新知