New in version 0.3.
應(yīng)用出錯(cuò),服務(wù)器出錯(cuò)。或早或晚,你會(huì)遇到產(chǎn)品出錯(cuò)。即使你的代碼是百分百正確, 還是會(huì)時(shí)??匆姵鲥e(cuò)。為什么?因?yàn)槠渌嚓P(guān)東西會(huì)出錯(cuò)。以下是一些在代碼完全正確的條件下服務(wù)器出錯(cuò)的情況:
以上只是你會(huì)遇到的問題的一小部分。那么如果處理這些問題呢?如果你的應(yīng)用運(yùn)行在生產(chǎn)環(huán)境下,那么缺省情況下 Flask 會(huì)顯示一個(gè)簡(jiǎn)單的出錯(cuò)頁面,并把出錯(cuò)情況記錄到 logger 。
但要做得還不只這些,下面介紹一些更好的出錯(cuò)處理方法。
如果應(yīng)用在生產(chǎn)環(huán)境(在你的服務(wù)器中一般使用生產(chǎn)環(huán)境)下運(yùn)行,那么缺省情況下不會(huì) 看到任何日志信息。為什么?因?yàn)?Flask 是一個(gè)零配置的框架。既然沒有配置,那么日志 放在哪里呢?顯然, Flask 不能來隨便找一個(gè)地放給用戶存放日志,因?yàn)槿绻脩粼谶@個(gè) 位置沒有創(chuàng)建文件的權(quán)限就糟了。同時(shí),對(duì)于大多數(shù)小應(yīng)用來說,沒人會(huì)去看日志。
事實(shí)上,我現(xiàn)在可以負(fù)責(zé)任地說除非調(diào)試一個(gè)用戶向你報(bào)告的錯(cuò)誤,你是不會(huì)去看應(yīng)用的 日志文件的。你真下需要的是出錯(cuò)的時(shí)候馬上給你發(fā)封電子郵件,及時(shí)提醒你,以便于進(jìn)行處理。
Flask 使用 Python 內(nèi)置的日志系統(tǒng),它可以發(fā)送你需要的錯(cuò)誤報(bào)告電子郵件。以下是 如何配置 Flask 日志記錄器發(fā)送錯(cuò)誤報(bào)告電子郵件的例子:
ADMINS = ['yourname@example.com']
if not app.debug:
import logging
from logging.handlers import SMTPHandler
mail_handler = SMTPHandler('127.0.0.1',
'server-error@example.com',
ADMINS, 'YourApplication Failed')
mail_handler.setLevel(logging.ERROR)
app.logger.addHandler(mail_handler)
這個(gè)例子是什么意思?我們創(chuàng)建了一個(gè)新的 SMTPHandler 類。這個(gè)類會(huì)使用郵件服務(wù)器 127.0.0.1 向 server-error@example.com 的 ADMINS 發(fā)送主題為 “YourApplication Failed” 的 電子郵件。如果你的郵件服務(wù)器需要認(rèn)證,這是可行的,詳見 SMTPHandler 的文檔。
我們還定義了只報(bào)送錯(cuò)誤及錯(cuò)誤以上級(jí)別的信息。因?yàn)槲覀儾幌氲玫骄婊蚱渌麤]用的 日志,比如請(qǐng)求處理日志。
在你的產(chǎn)品中使用它們前,請(qǐng)查看一下控制日志格式 ,以了解錯(cuò)誤報(bào)告郵件的更多 信息,磨刀不誤砍柴功。
報(bào)錯(cuò)郵件有了,可能還需要記錄警告信息。這是一個(gè)好習(xí)慣,有利于除錯(cuò)。請(qǐng)注意,在 核心系統(tǒng)中 Flask 本身不會(huì)發(fā)出任何警告。因此,在有問題時(shí)發(fā)出警告只能自力更生了。
雖然有許多日志記錄系統(tǒng),但不是每個(gè)系統(tǒng)都能做好基本日志記錄的。以下可能是最值得關(guān)注的:
if not app.debug:
import logging
from themodule import TheHandlerYouWant
file_handler = TheHandlerYouWant(...)
file_handler.setLevel(logging.WARNING)
app.logger.addHandler(file_handler)
缺省情況下一個(gè)處理器只會(huì)把信息字符串寫入一個(gè)文件或把信息作為電子郵件發(fā)送給你。 但是一個(gè)日志應(yīng)當(dāng)記錄更多的信息,因些應(yīng)該認(rèn)真地配置日志記錄器。一個(gè)好的日志不光 記錄為什么會(huì)出錯(cuò),更重要的是記錄錯(cuò)在哪里。
格式化器使用一個(gè)格式化字符串作為實(shí)例化時(shí)的構(gòu)造參數(shù),這個(gè)字符串中的格式變量會(huì)在日志記錄時(shí)自動(dòng)轉(zhuǎn)化。
舉例:
from logging import Formatter
mail_handler.setFormatter(Formatter('''
Message type: %(levelname)s
Location: %(pathname)s:%(lineno)d
Module: %(module)s
Function: %(funcName)s
Time: %(asctime)s
Message:
%(message)s
'''))
from logging import Formatter
file_handler.setFormatter(Formatter(
'%(asctime)s %(levelname)s: %(message)s '
'[in %(pathname)s:%(lineno)d]'
))
以下是格式化字符串中一種重要的格式變量。注意,這并不包括全部格式變量,更多變更參見 logging 包的官方文檔。
| 格式變量 | 說明 |
|---|---|
| %(levelname)s | 文字形式的日志等級(jí) ( 'DEBUG' 、 'INFO' 、 'WARNING' 、 'ERROR' 和 'CRITICAL' )。 |
| %(pathname)s | 調(diào)用日志的源文件的完整路徑(如果可用)。 |
| %(filename)s | 調(diào)用日志的源文件文件名。 |
| %(module)s | 調(diào)用日志的模塊名。 |
| %(funcName)s | 調(diào)用日志的函數(shù)名。 |
| %(lineno)d | 調(diào)用日志的代碼的行號(hào)(如果可用)。 |
| %(asctime)s | 調(diào)用日志的時(shí)間,缺省格式為 "2003-07-08 16:49:45,896" (逗號(hào)后面的數(shù)字為 毫秒)。通過重載 formatTime() 方法可以改變格式。 |
| %(message)s | 日志記錄的消息,同 msg % args 。 |
如果要進(jìn)一步定制格式,可以使用格式化器的子類。格式化器有三個(gè)有趣的方法:
format(): 處理實(shí)際的格式化。它接收一個(gè) LogRecord 對(duì)象,返回格式化后 的字符串。 formatTime(): 它用于 asctime 格式變量。重載它可以改變時(shí)間格式。 formatException() 它用于異常格式化。接收一個(gè) exc_info 元組并且必須返回一個(gè)字符串。缺省情況下它夠用了,不必重載。 更多信息參見官方文檔。
至此,我們只配置了應(yīng)用本身的日志記錄器。其他庫可能同樣需要記錄日志。例如, SQLAlchemy 在其核心中大量使用日志。在 logging 包中有一個(gè)方法可以一次性 地配置所有日志記錄器,但我不推薦這么做。因?yàn)楫?dāng)你在同一個(gè) Python 解釋器中同時(shí)運(yùn)行兩個(gè)獨(dú)立的應(yīng)用時(shí)就無法使用不同的日志設(shè)置了。
相反,我建議使用 getLogger() 函數(shù)來鑒別是哪個(gè)日志記錄器,并獲取相應(yīng)的處理器:
from logging import getLogger
loggers = [app.logger, getLogger('sqlalchemy'),
getLogger('otherlibrary')]
for logger in loggers:
logger.addHandler(mail_handler)
logger.addHandler(file_handler)
? Copyright 2013, Armin Ronacher. Created using Sphinx.