python 使用 loguru 輸出異常日誌同時列印變數值

ponponon發表於2022-01-12

前言

線上的程式報錯的時候,使用 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)

圖片.png

一個簡單的例子

使用 loguru 吧!

loguru 提供了 exception 方法來列印異常
logger.exception() 需要一個引數,隨便填什麼都可以,我習慣用 error

logger.exceptionlogger.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

從圖中可以看到,日誌展示時候,列印了變數 ab 的值
圖片.png

鏈式異常

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: 計算錯誤

圖片.png

相關文章