loguru安装
pip install loguru
loguru简单使用方法
from loguru import logger logger.info('this is info message') logger.debug('this is debug message') logger.warning('this is warning message') logger.error('this is error message')
可以看出,logger.debug、logger.info、logger.warning、logger.critical
不仅可以代替print
,还为输出的日志信息带上了不同的颜色样式,使得结果更加美观,其中也包含了时间、级别、模块名、行号以及日志信息。
loguru 配置日志文件
logger 默认采用 sys.stderr 标准错误输出将日志输出到控制台中,假如想要将日志同时输出到其他的位置,比如日志文件,此时我们只需要使用一行代码即可实现。
from loguru import logger # 例如我们可以把文件保存在all.log中 logger.add("E:/PythonCode/MOC/all.log",rotation="500MB", encoding="utf-8", enqueue=True, retention="10 days") logger.info('This is info information')
1、只输出到文本,不在console输出
通过 logger.remove(handler_id=None) 删除以前添加的处理程序,并停止向其接收器发送日志。然后通过add 添加输出日志文件,即可 实现 只输出到文本,不在console输出,如下:
from loguru import logger # 清除之前的设置 logger.remove(handler_id=None) logger.add('all.log') logger.error('This is error message') logger.warning('This is warn messag')
2、format 配置日志记录格式化模板
import sys from loguru import logger my_log_file_path = "test_log" class MyLogger: def __init__(self, log_file_path=my_log_file_path): self._logger = logger # 清空所有设置 self.logger.remove() # 添加控制台输出的格式,sys.stdout为输出到屏幕;关于这些配置还需要自定义请移步官网查看相关参数说明 self._logger.add(
sys.stdout, format="<green>{time:YYYYMMDD HH:mm:ss}</green> | " # 颜色>时间 "{process.name} | " # 进程名 "{thread.name} | " # 进程名 "<cyan>{module}</cyan>.<cyan>{function}</cyan>" # 模块名.方法名 ":<cyan>{line}</cyan> | " # 行号 "<level>{level}</level>: " # 等级 "<level>{message}</level>", # 日志内容 ) # 输出到文件的格式,注释下面的add',则关闭日志写入 #self._logger.rome(handler_id=None) #只写入文件,不输入控制台 self._logger.add(
log_file_path,
level='DEBUG', format='{time:YYYYMMDD HH:mm:ss} - ' # 时间 "{process.name} | " # 进程名 "{thread.name} | " # 进程名 '{module}.{function}:{line} - {level} -{message}', # 模块名.方法名:行号 rotation="10 MB") def get_logger(self): return self._logger if __name__ == '__main__': my_logger = MyLogger().get_logger() my_logger.info("this is info message") my_logger.debug("this is debug message") my_logger.warning("this is warning messgae") my_logger.error("this is error message") my_logger.exception("this exception message")
其它的格式化模板属性 如下:
+------------+---------------------------------+----------------------------+ | Key | Description | Attributes | +============+=================================+============================+ | elapsed | The time elapsed since the | See |timedelta| | | | start of the program | | +------------+---------------------------------+----------------------------+ | exception | The formatted exception if any, | ``type``, ``value``, | | | ``None`` otherwise | ``traceback`` | +------------+---------------------------------+----------------------------+ | extra | The dict of attributes | None | | | bound by the user (see |bind|) | | +------------+---------------------------------+----------------------------+ | file | The file where the logging call | ``name`` (default), | | | was made | ``path`` | +------------+---------------------------------+----------------------------+ | function | The function from which the | None | | | logging call was made | | +------------+---------------------------------+----------------------------+ | level | The severity used to log the | ``name`` (default), | | | message | ``no``, ``icon`` | +------------+---------------------------------+----------------------------+ | line | The line number in the source | None | | | code | | +------------+---------------------------------+----------------------------+ | message | The logged message (not yet | None | | | formatted) | | +------------+---------------------------------+----------------------------+ | module | The module where the logging | None | | | call was made | | +------------+---------------------------------+----------------------------+ | name | The ``__name__`` where the | None | | | logging call was made | | +------------+---------------------------------+----------------------------+ | process | The process in which the | ``name``, ``id`` (default) | | | logging call was made | | +------------+---------------------------------+----------------------------+ | thread | The thread in which the | ``name``, ``id`` (default) | | | logging call was made | | +------------+---------------------------------+----------------------------+ | time | The aware local time when the | See |datetime| | | | logging call was made | | +------------+---------------------------------+----------------------------+ +------------------------------------+--------------------------------------+ | Color (abbr) | Styles (abbr) | +====================================+======================================+ | Black (k) | Bold (b) | +------------------------------------+--------------------------------------+ | Blue (e) | Dim (d) | +------------------------------------+--------------------------------------+ | Cyan (c) | Normal (n) | +------------------------------------+--------------------------------------+ | Green (g) | Italic (i) | +------------------------------------+--------------------------------------+ | Magenta (m) | Underline (u) | +------------------------------------+--------------------------------------+ | Red (r) | Strike (s) | +------------------------------------+--------------------------------------+ | White (w) | Reverse (v) | +------------------------------------+--------------------------------------+ | Yellow (y) | Blink (l) | +------------------------------------+--------------------------------------+ | | Hide (h) | +------------------------------------+--------------------------------------+
3、level 配置日志最低日志级别
from loguru import logger logger.add('all.log', level='ERROR')
4、rotation 配置日志滚动记录的机制
如果想周期性的创建日志文件,或者按照文件大小自动分隔日志文件,我们可以直接使用 add 方法的 rotation 参数进行配置。
例如,每 10MB 创建一个日志文件,避免每个 log 文件过大,如下:
from loguru import logger logger.add('all.log', rotation="10 MB")
例如,周期也可以是安时间,如每天6点 创建一个日志文件,如下:
from loguru import logger logger.add('all.log', rotation='06:00')
5、retention 配置日志保留机制
通常,一些久远的日志文件,需要周期性的去清除,避免日志堆积,浪费存储空间。我们可以通过add方法的 retention 参数可以配置日志的最长保留时间。
例如,设置日志文件最长保留 10天,如下:
from loguru import logger logger.add('all.log', retention='10 days')
6、compression 配置日志压缩格式
loguru 还可以配置文件的压缩格式,比如使用 zip 文件格式保存,压缩的文件名:文件名_年月日.zip,示例如下:
from loguru import logger logger.add('all.log', compression='zip')
7、serialize 日志序列化
如果我们希望输出类似于Json-line格式的结构化日志,我们可以通过 serialize 参数,将日志信息序列化的json格式写入log 文件,最后可以将日志文件导入类作后续的日志分析,代码示例如下:
from loguru import logger import platform logger.add('all.json', serialize=True) logger.info('If you are using Python {version}, prefer {feature} of course!', version=platform.python_version(), feature='f-strings')
执行结果如下;
{ "text": "2022-11-05 14:08:01.161 | INFO | __main__:<module>:117 - If you are using Python 3.7.8, prefer f-strings of course!\n", "record": { "elapsed": { "repr": "0:00:00.080004", "seconds": 0.080004 }, "exception": null, "extra": { "version": "3.7.8", "feature": "f-strings" }, "file": { "name": "mylogger.py", "path": "E:/PycharmScripts/test_loguru/mylogger.py" }, "function": "<module>", "level": { "icon": "ℹ️", "name": "INFO", "no": 20 }, "line": 117, "message": "If you are using Python 3.7.8, prefer f-strings of course!", "module": "mylogger", "name": "__main__", "process": { "id": 1504, "name": "MainProcess" }, "thread": { "id": 7012, "name": "MainThread" }, "time": { "repr": "2022-11-05 14:08:01.161283+08:00", "timestamp": 1667628481.161283 } } }
8、Traceback 记录(异常追溯)
loguru集成了一个名为 better_exceptions 的库,不仅能够将异常和错误记录,并且还能对异常进行追溯,如下,我们通过在遍历列表的过程中删除列表元素,以触发IndexError 异常,
通过catch装饰器的方式实现异常捕获,代码示例如下:
from loguru import logger @logger.catch def test_func(a,b): print(a/b) test_func(1/0)
运行上述代码,我们可以发现loguru输出的 Traceback 日志信息, Traceback 日志信息中同时输出了当时的变量值
除此之外,也可以通过 logger.exception 方法也可以实现异常的捕获与记录:
from loguru import logger def test_demo(a,b): try: return a/b except ZeroDivisionError as error_mesg: logger.exception(error_mesg) test_demo(1/0)
loguru二次封装,可以结合装饰器扑获日志
from loguru import logger import datetime import os,sys from functools import wraps class MyLoggers(object): def __init__(self,log_filename=None,is_stdout=True,need_write_log=True): self._logger = logger # 判断是否添加控制台输出的格式, sys.stdout为输出到屏幕; if is_stdout: # 清空所有设置 self._logger.remove() self._logger.add( sink=sys.stdout, format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | " # 颜色>时间 "{process.name} | " # 进程名 "{thread.name} | " # 线程名 "<cyan>{module}</cyan>.<cyan>{function}</cyan>" # 模块名.方法名 ":<cyan>{line}</cyan> | " # 行号 "<level>{level}</level>: " # 等级 "<level>{message}</level>", # 日志内容 ) # 判断是否需要写入logger日志文件 if need_write_log: # self._logger.remove(handler_id=None) #只写入文件中,不输入控制台 self._logger.add( # 水槽,分流器,可以用来输入路径 sink= self.get_log_path(log_filename=log_filename), # 日志创建周期 rotation='00:00', # 保存 retention='1 days', # 文件的压缩格式 compression='zip', # 编码格式 encoding="utf-8", # 具有使日志记录调用非阻塞的优点(适用于多线程) enqueue=True, # 日志级别 level='INFO', # 时间|进程名|线程名|模块|方法|行号|日志等级|日志信息 format="{time:YYYY-MM-DD HH:mm:ss} | {process.name} | {thread.name} | {module}.{function}:{line} | {level}:{message}" ) def get_log_path(self,log_filename=None): # 项目日志目录 project_log_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), 'log')) if not os.path.exists(project_log_dir): os.makedirs(project_log_dir) # 日志文件名 if log_filename is not None: project_log_filename = '{}.log'.format(log_filename) else: project_log_filename = 'runtime_{}.log'.format(datetime.date.today()) # 日志文件路径 project_log_path = os.path.join(project_log_dir, project_log_filename) return project_log_path def info(self,mesg): self._logger.info(mesg) def debug(self,mesg): self._logger.debug(mesg) def warning(self,mesg): self._logger.warning(mesg) def error(self,mesg): self._logger.error(mesg) def get_logger(self): return self._logger my_loger = MyLoggers(log_filename='mylog', need_write_log=True, is_stdout=True).get_logger() # 装饰器用来扑获日志(不带参数) def wrapper_log(func): @wraps(func) def inner(*args,**kwargs): my_loger.info(f'{func.__name__}') try: func(*args,**kwargs) except Exception as error_mesg: print(error_mesg) my_loger.exception(error_mesg) return inner() # 装饰器用来扑获日志(带参数) def loger(logger_object): def wrapper(func): def inner(*args,**kwargs): logger_object.info(f'{func.__name__}') try: func(*args,**kwargs) except Exception as error_mesg: logger_object.exception(error_mesg) return inner() return wrapper @wrapper_log def test_func(a,b): print(a/b) @loger(my_loger) def test_demo(a,b): return a/b test_func(1/0) test_demo(1/0)
在输出台上显示的结果,如下
另外 loguru 还有很多很多强大的功能,这里就不再一一展开讲解了,更多的内容大家可以看看 loguru 的官方文档详细了解一下:
https://loguru.readthedocs.io/en/stable/index.html
原文地址:http://www.cnblogs.com/hhaostudy/p/16860064.html