介绍这个库前,我们先看一个简单的例子(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
,使用前需要执行:
pip install better_exceptions
export BETTER_EXCEPTIONS=1 # Linux / OSX
setx BETTER_EXCEPTIONS 1 # Windows
最好是加入到系统环境变量里
或者
import better_exceptions;
better_exceptions.hook()
再执行,输入如下:
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
时是这样对待异常的:
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 集成.
先简单说一下,:
handler
的formater
的formatException
函数来格式化异常.better_exceptions
有个format_exception
方法会将异常调用栈变量值输出,就是 上面例子的那种输出.看代码:
# -*- 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)
思路和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
两处修改:
增加一个fm.py
文件:
import logging
from better_exceptions import format_exception
class ExceptionFormatter(logging.Formatter):
def formatException(self, ei):
return format_exception(*ei)
修改settings.py
的 LOGGING 配置:
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'simple': {
'()': 'test_better_exceptions_django.fm.ExceptionFormatter',
'format': '%(levelname)s %(message)s'
},
},
'handlers': {
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
'file': {
'level': 'ERROR',
'class': 'logging.FileHandler',
'filename': os.path.join(BASE_DIR, "error.log"),
'formatter': 'simple'
}
},
'loggers': {
'django': {
'handlers': ['console', 'file'],
}
}
}
这里主要是自定义了一个formatters
.
我是在请求里故意出发了一个异常,代码如下:
from django.conf.urls import url
from django.contrib import admin
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
]
from django.http import HttpResponse
import logging
logger = logging.getLogger('django')
def index(request):
a, b = 2, 0
try:
a / b
except Exception as e:
logger.exception(e)
return HttpResponse("You have an excepion, see console and log")
接着打开浏览器,可以看到根目录下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
1
kevindu 2018-04-19 12:54:16 +08:00
好玩
|
2
ant2017 2018-04-19 12:57:48 +08:00 via Android
nice
|
3
junnplus 2018-04-19 13:08:35 +08:00
道理我都懂,为什么标题叫 加速 Python 异常处理
|
4
510908220 OP @junnplus 用普通方式,当出现一个异常,缺少上下文(各个变量值等)去排查不是很费时吗. 如果集成了类似这样的方式,遇到异常根据上下文基本上可以直接定位问题. 不是节约了很多时间吗
|
5
Mistwave 2018-04-19 13:19:56 +08:00 via iPhone
不错
|
6
nooper 2018-04-19 13:26:49 +08:00
我还以为作者写了 better exception 这个库
|
7
doubleflower 2018-04-19 14:13:28 +08:00
啥,不是作者本人?
|
8
seerhut 2018-04-19 14:25:49 +08:00
看标题我还以为是加速抛异常。。原来是加速看异常
|
9
Leigg 2018-04-19 14:54:52 +08:00 via iPhone
可以的,不过标题党了
|
10
est 2018-04-19 18:06:45 +08:00
不错不错。
不过我是推荐 python -m pdb 一把梭 |
11
Dillion 2018-04-19 18:09:32 +08:00
哈哈 我看标题也以为是加速异常处理速度
|
13
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' |
15
zqguo 2018-05-14 13:49:35 +08:00
flask 里面怎么用?
|