0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

richのprettyな出力をstrにしてloggingに渡す方法(達成感なし)

Posted at

TL;DR

rich(https://rich.readthedocs.io/en/stable/index.html)で出力されたstack traceが見やすいので、雑にdebugログをlogging.FileHandler等で吐いたときにログでも見れるようにしたい。このため、prettyなTracebackをstrで取得したい。
調べてはみたが、Traceback含めprettyな出力をstrで返してくれる関数がみあたらなかったので試行錯誤してみたがいい方法が見つからず、結局io.StringIOに頼ったよ。

モチベーション

ほぼ上述の通りだが、端的にいうと、loggingのRotatingFileHandlerでファイルにdebug logをダダ流しできると不具合調査が楽だよな、と。
richはコンソールアプリでの出力をかなりきれいにしてくれる。ただ、サクッと書いたツール等を人に使ってもらうとき、「不具合が出たらこのログ送って」で済ませたく、色はつかなくていいからなんとかloggingのFileHandlerで出力できないかなと思った。

コード

結局いい方法が見つからず、io.StringIO()をrich.print()file引数に渡して出力をstrで取得することで期待した動作にはなった。
以下サンプルコード。

  • Python 3.11.4
  • rich==13.7.0
import traceback
import rich
import rich.traceback


def get_logger(name="main"):
    import logging
    logger = logging.getLogger(name)
    logger.setLevel(logging.DEBUG)
    handler = logging.StreamHandler()
    formatter = logging.Formatter(fmt='%(asctime)-15s [%(name)s] %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    return logger

def main():
    logger = get_logger()
    try:
        hoge=1/0
    except Exception as e:
        e_args={"exc_type":type(e), "exc_value":e, "traceback":e.__traceback__, "show_locals":True}
        tb = rich.traceback.Traceback.from_exception(**e_args)
        import io
        with io.StringIO() as s:
            rich.print(tb, file=s)
            c = "\n" + s.getvalue()
            logger.debug(c)


if __name__ == "__main__":
    main()

結果は以下。
これができるならFileHandler系に出力できるでしょう。

2024-01-05 04:11:58,060 [main]
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /home/bounoki/work/20231229_rich/test1.py:19 in main                                             │
│                                                                                                  │
│   16 def main():                                                                                 │
│   17 │   logger = get_logger()                                                                   │
│   18 │   try:                                                                                    │
│ ❱ 19 │   │   hoge=1/0                                                                            │
│   20 │   except Exception as e:                                                                  │
│   21 │   │   e_args={"exc_type":type(e), "exc_value":e, "traceback":e.__traceback__, "show_lo    │
│   22 │   │   tb = rich.traceback.Traceback.from_exception(**e_args)                              │
│                                                                                                  │
│ ╭───────────────────────────── locals ─────────────────────────────╮                             │
│ │      e = ZeroDivisionError('division by zero')                   │                             │
│ │ e_args = {                                                       │                             │
│ │          │   'exc_type': <class 'ZeroDivisionError'>,            │                             │
│ │          │   'exc_value': ZeroDivisionError('division by zero'), │                             │
│ │          │   'traceback': <traceback object at 0x7f0c7d28b040>,  │                             │
│ │          │   'show_locals': True                                 │                             │
│ │          }                                                       │                             │
│ │ logger = <Logger main (DEBUG)>                                   │                             │
│ ╰──────────────────────────────────────────────────────────────────╯                             │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
ZeroDivisionError: division by zero

サンプルはStreamHandlerでやってるけど、StreamHandlerで処理したいならrichに積まれてるrich.logging.RichHandlerを使えばいいと思う。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?