加速 Python 异常处理

2018-04-19 12:37:40 +08:00
 510908220

better-exceptions使用简介

介绍这个库前,我们先看一个简单的例子(example.py),代码如下:

# -*- encoding: utf-8 -*-

def get_student_infos(logs):
    student_infos = []
    for log in logs:
        name, catgory, grade = log.split(' ')
        student_infos.append({
            'name': name,
            'catgory': catgory,
            'grade': grade,

        })
    return student_infos

if __name__ == '__main__':
    exam_logs = [
        'zhangsan math 60',
        'lisi english 80',
        'wangwu chinese 90',
        'qianliu music'
    ]
    get_student_infos(exam_logs)

运行输出:

Traceback (most recent call last):
  File "example.py", line 24, in <module>
    get_student_infos(exam_logs)
  File "example.py", line 7, in get_student_infos
    name, catgory, grade = log.split(' ')
ValueError: not enough values to unpack (expected 3, got 2)

如果我们给example.py增加一行代码import better_exceptions,使用前需要执行:

再执行,输入如下:

Traceback (most recent call last):
  File "example_with_better_exceptions.py", line 25, in <module>
    get_student_infos(exam_logs)
    │                 └ ['zhangsan math 60', 'lisi english 80', 'wangwu chinese 90', 'qianliu music']
    └ <function get_student_infos at 0x7fa594d1fe18>
  File "example_with_better_exceptions.py", line 8, in get_student_infos
    name, catgory, grade = log.split(' ')
    │     │        │       └ 'qianliu music'
    │     │        └ '90'
    │     └ 'chinese'
    └ 'wangwu'
ValueError: not enough values to unpack (expected 3, got 2)

看到了吗,加上import better_exceptions后, 异常时会将调用栈每一层用的变量值打印出来, 和普通异常时输出有比有什么好处呢,然我们来回忆一下,

是不是有小伙伴会想, 要是某些变量特别大(比如有几万个元素的列表),这样会造成日志很大的.确实存在这样的问题,不过这个库的作者已经够给解决方案了: 加上这句better_exceptions.MAX_LENGTH = 字符数控制字符的个数, 对于上面的例子加上better_exceptions.MAX_LENGTH = 20这句输出如下:

Traceback (most recent call last):
  File "example_with_better_exceptions_limit_length.py", line 25, in <module>
    get_student_infos(exam_logs)
    │                 └ ['zha...
    └ <func...
  File "example_with_better_exceptions_limit_length.py", line 8, in get_student_infos
    name, catgory, grade = log.split(' ')
    │     │        │       └ 'qian...
    │     │        └ '90'
    │     └ 'chin...
    └ 'wang...
ValueError: not enough values to unpack (expected 3, got 2)

看到了吗,只是简单的再代码上加上一句import better_exceptions就有如此神奇的效果. 但是, 这个库目前只会在控制台打印出这样的错误信息, 下面说一下怎么与 logging、django 集成.

logging 接入

先简单说一下,:

看代码:

# -*- encoding: utf-8 -*-
import logging
from better_exceptions import format_exception

logger = logging.getLogger()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
formatter.formatException = lambda exc_info: format_exception(*exc_info)

file_handler = logging.FileHandler("example.log")
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
def get_student_infos(logs):
    student_infos = []
    for log in logs:
        name, catgory, grade = log.split(' ')
        student_infos.append({
            'name': name,
            'catgory': catgory,
            'grade': grade,

        })
    return student_infos

if __name__ == '__main__':
    exam_logs = [
        'zhangsan math 60',
        'lisi english 80',
        'wangwu chinese 90',
        'qianliu music'
    ]
    try:
        get_student_infos(exam_logs)
    except Exception as e:
        logger.exception(e)

查看example.log文件输出:

2018-04-18 14:12:17,751 - root - ERROR - not enough values to unpack (expected 3, got 2)
Traceback (most recent call last):
  File "better_exceptions_with_logging.py", line 36, in <module>
    get_student_infos(exam_logs)
    │                 └ ['zhangsan math 60', 'lisi english 80', 'wangwu chinese 90', 'qianliu music']
    └ <function get_student_infos at 0x7f5c28d088c8>
  File "better_exceptions_with_logging.py", line 18, in get_student_infos
    name, catgory, grade = log.split(' ')
    │     │        │       └ 'qianliu music'
    │     │        └ '90'
    │     └ 'chinese'
    └ 'wangwu'
ValueError: not enough values to unpack (expected 3, got 2)

django 接入

思路和logging 接入一样的. 例如有如下django项目:

☁  test_better_exceptions_django  tree
.
├── db.sqlite3
├── manage.py
└── test_better_exceptions_django
    ├── fm.py
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    ├── views.py
    └── wsgi.py

两处修改:

我是在请求里故意出发了一个异常,代码如下:

接着打开浏览器,可以看到根目录下error.log文件内容:

Traceback (most recent call last):
  File "/opt/github/better-exceptions-example/test_better_exceptions_django/test_better_exceptions_django/views.py", line 7, in index
    a / b
    │   └ 0
    └ 2
ZeroDivisionError: division by zero

说明

所有的例子都在examples目录下. 可以在这里查看 https://github.com/510908220/better-exceptions-examples

3815 次点击
所在节点    Python
17 条回复
kevindu
2018-04-19 12:54:16 +08:00
好玩
ant2017
2018-04-19 12:57:48 +08:00
nice
junnplus
2018-04-19 13:08:35 +08:00
道理我都懂,为什么标题叫 加速 Python 异常处理
510908220
2018-04-19 13:18:07 +08:00
@junnplus 用普通方式,当出现一个异常,缺少上下文(各个变量值等)去排查不是很费时吗. 如果集成了类似这样的方式,遇到异常根据上下文基本上可以直接定位问题. 不是节约了很多时间吗
Mistwave
2018-04-19 13:19:56 +08:00
不错
nooper
2018-04-19 13:26:49 +08:00
我还以为作者写了 better exception 这个库
doubleflower
2018-04-19 14:13:28 +08:00
啥,不是作者本人?
seerhut
2018-04-19 14:25:49 +08:00
看标题我还以为是加速抛异常。。原来是加速看异常
Leigg
2018-04-19 14:54:52 +08:00
可以的,不过标题党了
est
2018-04-19 18:06:45 +08:00
不错不错。

不过我是推荐 python -m pdb 一把梭
Dillion
2018-04-19 18:09:32 +08:00
哈哈 我看标题也以为是加速异常处理速度
Anybfans
2018-04-20 09:07:17 +08:00
@est 你这方法适合脚步。有些 web 框架并不能这样运行吧?
Yycreater
2018-04-24 17:43:07 +08:00
难道,我的 django 是假的?还是,ta 自己生产错误?我是不添加环境变量的方式复制进去的啊
ValueError: Unable to configure formatter 'simple': Cannot resolve 'test_better_exceptions_django.fm.ExceptionFormatter': No module named 'test_better_exceptions_django'
510908220
2018-04-24 18:16:49 +08:00
@Yycreater 你这是模块导入的有问题. 你可以把你的目录结构贴出来看看.
zqguo
2018-05-14 13:49:35 +08:00
flask 里面怎么用?
510908220
2018-05-14 22:14:57 +08:00
@zqguo 一样的。日志 format 使用自定义类。这个只 logging 相关,实际和具 web 框架没多大关系
zqguo
2018-05-14 23:17:25 +08:00
@510908220 好的,我试试看

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/448096

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX