Python 如何更优雅的记录日志(loguru)

一、背景

在使用Python 编写自动化脚本过程中,大多数情况下可能都是直接用 logging 模块来记录日志,在使用时需要配置一些 Handler、Formatter 来进行一些处理,比如把日志输出到不同的位置(控制台打印、文件记录等等),或者定义不同的输出格式、日志分块、备份。需要配置的内容较多且繁琐。然后直到发现了 loguru 之后,功能强大而且还很灵活,几乎不需要太多配置就可以使用。在了解之后果然投入 loguru 的怀抱


二、loguru

1.安装

>>> pip install loguru

2.入门操作

不需要配置什么东西,直接 improt logger,调用其对应日志 level 方法即可。logger 默认配置了基操信息,比如格式化输出、文本颜色区别、 时间日期记录、对应模块方法、代码行标识等等,尽可能的友好。值得点赞。

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')

上面的代码运行结果如下:

2021-11-25 15:23:58.507 | DEBUG    | __main__:<module>:53 - this is a debug message
2021-11-25 15:23:58.508 | INFO     | __main__:<module>:54 - this is a info message
2021-11-25 15:23:58.508 | WARNING  | __main__:<module>:55 - this is a warning message
2021-11-25 15:23:58.508 | ERROR    | __main__:<module>:56 - this is a error message

Process finished with exit code 0

以上的日志信息是默认输出到控制台打印的,如果想要将日志输出或者记录到其他的地方,需要使用 add() 来指定。 下面将仔细介绍常用基本参数的使用。

from loguru import logger

log_path = Path(Path.cwd().parent, "log")
logger.add(f"{log_path}/interface_log_{time.strftime('%Y-%m-%d')}.log", rotation="50MB", encoding="utf-8")
logger.debug('Enter into a log file.')

对应的日志就写入到对应项目路径下的 /log/interface_log_2021-11-25.log 看起来是不是 眼前一亮!

# interface_log_2021-11-25.log
2021-11-25 17:15:56.988 | DEBUG    | __main__:<module>:55 - Enter into a log file.

三、参数介绍

sink

一个对象,负责接收格式化的日志消息并将它们传播到适当的端点。
支持:file-like object pathlib.Path callable coroutine function logging.Handler 等等

logger.add(sys.stderr")
level

( intor str, 可选) -- 记录的消息应该发送到接收器的最低严重性级别

logger.add(sys.stderr,  level='DEBUG')

format

(str或callable,可选)– 用于在发送到接收器之前格式化记录的消息的模板。

logger.add(sys.stderr, format="{message}", level='DEBUG')
filter

( callable, stror dict, optional) -- 一个可选的指令,用于决定每个记录的消息是否应该发送到接收器

logger.add(sys.stderr, format="{message}", level='DEBUG', filter="sub.module")

其他不太常用,默认设置即可.这里只做简单介绍不示例了
colorize
( bool, 可选) – 格式化消息中包含的颜色标记是否应转换为用于终端着色的 ansi 代码,或者以其他方式剥离。如果None,则根据接收器是否为 tty 自动做出选择
serialize
( bool, 可选) – 在发送到接收器之前,是否应首先将记录的消息及其记录转换为 JSON 字符串。
backtrace
( bool, 可选) – 格式化的异常跟踪是否应该向上扩展,超出捕获点,以显示生成错误的完整堆栈跟踪。
diagnose
(bool,可选)– 异常跟踪是否应显示变量值以简化调试。这应该False在生产中设置为避免泄露敏感数据。
enqueue
( bool, 可选) – 要记录的消息在到达接收器之前是否应首先通过多进程安全队列。这在通过多个进程记录到文件时很有用。这也具有使日志记录调用非阻塞的优点。可以理解为异步写入
catch
( bool, 可选) – 是否应自动捕获接收器处理日志消息时发生的错误。如果True,则显示异常消息,sys.stderr但异常不会传播到调用者,从而防止您的应用程序崩溃。

当且仅当接收器是文件路径时,以下参数适用:
rotation

( str, int, datetime.time, datetime.timedeltaor callable, 可选) – 指示何时应关闭当前记录的文件并启动新文件的条件。

from loguru import logger

# 根据指定 rotation 参数来自动分隔日志文件,可以根据文件大小,日期时间等
logger.add('runtime_{time}.log', rotation="500 MB")  # 文件超过500Mb就会生成一个新的日志文件
logger.add('runtime_{time}.log', rotation='00:00')  # 每天0点自动生成新的文件
logger.add('runtime_{time}.log', rotation='1 week')  # 每隔一周生成新的
retention

( str, int,datetime.timedelta或callable, 可选) – 过滤旧文件的指令,应在循环或程序结束期间删除。

# 可以配置日志文件数据的最长保留时间
logger.add('runtime.log', retention='10 days') 
compression

(str或callable,可选)– 日志文件在关闭时应转换为的压缩或存档格式。

# 配置文件的压缩格式
logger.add('runtime.log', retention='10 days', compression="zip")

delay ( bool, 可选) -- 是在配置接收器后立即创建文件,还是延迟到第一条记录的消息。它默认为False.
mode ( str, 可选) – 内置open()函数的打开模式。它默认为"a"(以追加模式打开文件)。
buffering (int,可选)– 内置open()函数的缓冲策略。它默认为1(行缓冲文件)。
encoding ( str, optional) – 内置open()函数的文件编码。如果None,则默认为 locale.getpreferredencoding()。
**kwargs – 其他参数传递给内置open()函数。


remove(handler_id=None)

删除先前添加的 sink 并停止向其接收器发送日志.

handler_id (int or None) – 要移除的接收器的 id,因为它是由add()方法返回的。如果None,则删除所有处理程序。其实实际并没有删除,只是没有将日志进行写入了而已。

sink = logger.add(sys.stderr, format="{message}")
logger.info("Logging")
logger.remove(sink)
logger.info("No longer logging")
@catch 使用

装饰器以自动记录包装函数中可能捕获的错误并将异常情况写入日志文件

@logger.catch
def catch_function(z):
# An error? It's caught anyway!
return 10 / z


if __name__ == '__main__':
catch_function(0)

上面抛出的zero异常由于函数上使用了 @catch 装饰器,不仅控制台会捕获异常信息,同事也将写入对应的日志文件中。

2021-11-25 17:09:04.852 | ERROR    | __main__:<module>:53 - An error has been caught in function '<module>', process 'MainProcess' (14380), thread 'MainThread' (22452):
Traceback (most recent call last):

> File "C:/Users/lenovo/PycharmProjects/job/httpRunner_demo/utils\loguruUtils.py", line 53, in <module>
    catch_function(0)
    └ <function catch_function at 0x0000025BF548F948>

  File "C:/Users/lenovo/PycharmProjects/job/httpRunner_demo/utils\loguruUtils.py", line 48, in catch_function
    return 10 / z
                └ 0

ZeroDivisionError: division by zero

Process finished with exit code 0

四、loguru封装

import time
from loguru import logger
from pathlib import Path


class Logger(object):
    log = logger

    def __init__(self):
        self.log_path = Path(Path.cwd().parent, "log")
        logger.add(f"{self.log_path}/interface_log_{time.strftime('%Y-%m-%d')}.log",
                   rotation="00:00",
                   encoding="utf-8",
                   enqueue=True,
                   retention="7 days")

    def trace(self, *args, **kwargs):
        return self.log.trace(*args, **kwargs)

    def debug(self, *args, **kwargs):
        return self.log.debug(*args, **kwargs)

    def info(self, *args, **kwargs):
        return self.log.info(*args, **kwargs)

    def warning(self, *args, **kwargs):
        return self.log.warning(*args, **kwargs)

    def error(self, *args, **kwargs):
        return self.log.error(*args, **kwargs)

    def critical(self, *args, **kwargs):
        return self.log.critical(*args, **kwargs)


if __name__ == '__main__':
    logger = Logger()
    logger.debug("Write anything down.")

可以进行简单的封装定制一下,就可以使用到项目当中去了。不需要改动太多地方。好东西啊!

2021-11-25 17:21:05.579 | DEBUG    | __main__:debug:30 - Write anything down.

Process finished with exit code 0

以上只是简单介绍了loguru的用法,感兴趣想深入了解其他的功能的,可以去查阅:
官方文档
官方github

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容