前言
线上的程序报错的时候, 使用 python 的标准库 logging 记录的日志 debug 问题, 是我们常用的操作, 但是 logging 没有直接提供给我们打印变量值的功能, 这个需要我们显性的写在日志中, 就像这样: logger.debug(f'error: {a}')
但是错误是一个链条, 不是一个点, 如果在每处都加上打印语句的话, 工作量太大了
python 的第三方日志库 loguru , 可以很好的帮助我们实现这个需求
效果展示
你想要实现下面的效果吗?
- 2022-01-09 15:59:52.058 | ERROR | __main__:func:32 - Expecting value: line 1 column 1 (char 0)
- Traceback (most recent call last):
- File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py", line 930, in _bootstrap
- self._bootstrap_inner()
│ └ <function Thread._bootstrap_inner at 0x10556dc10>
└ <Thread(ThreadPoolExecutor-0_14, started 6343241728)>
- File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py", line 973, in _bootstrap_inner
- self.run()
│ └ <function Thread.run at 0x10556d940>
└ <Thread(ThreadPoolExecutor-0_14, started 6343241728)>
- File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py", line 910, in run
- self._target(*self._args, **self._kwargs)
│ │ │ │ │ └ {}
│ │ │ │ └ <Thread(ThreadPoolExecutor-0_14, started 6343241728)>
│ │ │ └ (<weakref at 0x106459450; to 'ThreadPoolExecutor' at 0x105fafd30>, <_queue.SimpleQueue object at 0x1053e88b0>, None, ())
│ │ └ <Thread(ThreadPoolExecutor-0_14, started 6343241728)>
│ └ <function _worker at 0x105fd6d30>
└ <Thread(ThreadPoolExecutor-0_14, started 6343241728)>
- File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/concurrent/futures/thread.py", line 77, in _worker
- work_item.run()
│ └ <function _WorkItem.run at 0x105fd6e50>
└ <concurrent.futures.thread._WorkItem object at 0x106fbb4c0>
- File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/concurrent/futures/thread.py", line 52, in run
- result = self.fn(*self.args, **self.kwargs)
│ │ │ │ │ └ {}
│ │ │ │ └ <concurrent.futures.thread._WorkItem object at 0x106fbb4c0>
│ │ │ └ ()
│ │ └ <concurrent.futures.thread._WorkItem object at 0x106fbb4c0>
│ └ <function func at 0x104e58040>
└ <concurrent.futures.thread._WorkItem object at 0x106fbb4c0>
- > File "/Users/bot/Desktop/code/ideaboom/test_zjwt/test_api_copy.py", line 27, in func
- assert int(response.JSON().get('r')) == (a+b)
│ │ │ └ 54
│ │ └ 100
│ └ <function Response.JSON at 0x105fb40d0>
└ <Response [500]>
- File "/Users/bot/.local/share/virtualenvs/ideaboom-8ZWsq-JB/lib/python3.9/site-packages/requests/models.py", line 910, in JSON
- return complexjson.loads(self.text, **kwargs)
│ │ │ │ └ {}
│ │ │ └ <property object at 0x105fb24f0>
│ │ └ <Response [500]>
│ └ <function loads at 0x105c58a60>
└ <module 'json' from '/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/json/__init__.py'>
- File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/json/__init__.py", line 346, in loads
- return _default_decoder.decode(s)
│ │ └ '<!DOCTYPE html PUBLIC"-//W3C//DTD HTML 3.2 Final//EN">\n<title>500 Internal Server Error</title>\n<h1>Internal Server Error...
│ └ <function JSONDecoder.decode at 0x105c583a0>
└ <JSON.decoder.JSONDecoder object at 0x105c50130>
- File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/json/decoder.py", line 337, in decode
- obj, end = self.raw_decode(s, idx=_w(s, 0).end())
│ │ │ │ └ '<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 3.2 Final//EN">\n<title>500 Internal Server Error</title>\n<h1>Internal Server Error...
│ │ │ └ <built-in method match of re.Pattern object at 0x105c493f0>
│ │ └ '<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 3.2 Final//EN">\n<title>500 Internal Server Error</title>\n<h1>Internal Server Error...
│ └ <function JSONDecoder.raw_decode at 0x105c58430>
└ <JSON.decoder.JSONDecoder object at 0x105c50130>
- File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/json/decoder.py", line 355, in raw_decode
- raise JSONDecodeError("Expecting value", s, err.value) from None
│ └ '<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 3.2 Final//EN">\n<title>500 Internal Server Error</title>\n<h1>Internal Server Error...
└ <class 'json.decoder.JSONDecodeError'>
JSON.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
一个简单的例子
使用 loguru 吧!
loguru 提供了 exception 方法来打印异常
logger.exception() 需要一个参数, 随便填什么都可以, 我习惯用 error
logger.exception 和 logger.error 不一样. 前者会做变量跟踪, 但是后者不会
效果展示:
- from loguru import logger
- def func(a: int, b: int):
- a/b
- try:
- func(0, 0)
- except Exception as error:
- logger.exception(error)
─ python -u "/Users/bot/Desktop/code/ideaboom/test_logger/003.py"
- 2022-01-09 23:44:12.792 | ERROR | __main__:<module>:11 - division by zero
- Traceback (most recent call last):
- > File "/Users/bot/Desktop/code/ideaboom/test_logger/003.py", line 9, in <module>
- func(0, 0)
└ <function func at 0x104a4c040>
- File "/Users/bot/Desktop/code/ideaboom/test_logger/003.py", line 5, in func
- a/b
│ └ 0
└ 0
ZeroDivisionError: division by zero
从图中可以看到, 日志展示时候, 打印了变量 a 和 b 的值
链式异常
loguru 对链式异常 (raise ... from ...) 的支持也很好
如果你不知道什么是异常链, 可以看 Python 官方文档 -- 异常链
- from loguru import logger
- def func(a: int, b: int):
- try:
- a/b
- except Exception as error:
- raise Exception('计算错误') from error
- try:
- func(0, 0)
- except Exception as error:
- logger.exception(error)
─ python -u "/Users/bot/Desktop/code/ideaboom/test_logger/003.py"
2022-01-09 23:43:04.729 | ERROR | __main__:<module>:14 - 计算错误
- Traceback (most recent call last):
- File "/Users/bot/Desktop/code/ideaboom/test_logger/003.py", line 6, in func
- a/b
│ └ 0
└ 0
- ZeroDivisionError: division by zero
- The above exception was the direct cause of the following exception:
- Traceback (most recent call last):
- > File "/Users/bot/Desktop/code/ideaboom/test_logger/003.py", line 12, in <module>
- func(0, 0)
└ <function func at 0x1046e0040>
- File "/Users/bot/Desktop/code/ideaboom/test_logger/003.py", line 8, in func
- raise Exception('计算错误') from error
└ Exception('计算错误')
Exception: 计算错误
来源: https://segmentfault.com/a/1190000041251917