### 導航
- [索引](# "總目錄")
- [下一頁](# "配置處理") |
- [上一頁](# "測試 Flask 應用") |
- [Flask 0.10.1 文檔](#) ?
# 記錄應用錯誤
0.3 新版功能.
應用故障,服務器故障。早晚你會在產品中看見異常。即使你的代碼是 100% 正確的,你仍然會不時看見異常。為什么?因為涉及的所有一切都會出現故障。這里給出一些完美正確的代碼導致服務器錯誤的情況:
- 客戶端在應用讀取到達數據時,提前終止請求
- 數據庫服務器超載,并無法處理查詢
- 文件系統滿了
- 硬盤損壞
- 后端服務器超載
- 你所用的庫出現程序錯誤
- 服務器的網絡連接或其它系統故障
而且這只是你可能面對的問題的簡單情形。那么,我們應該怎么處理這一系列問題?默認情況下,如果你的應用在以生產模式運行, Flask 會顯示一個非常簡單的頁面并記錄異常到 [logger](# "flask.Flask.logger") 。
但是你還可以做些別的,我們會介紹一些更好的設置來應對錯誤。
### 錯誤郵件
如果你的應用在生產模式下運行(會在你的服務器上做),默認情況下,你不會看見任何日志消息。為什么會這樣?Flask 試圖實現一個零配置框架。如果沒有配置,日志會存放在哪?猜測不是個好主意,因為它猜測的位置可能不是一個用戶有權創建日志文件的地方。而且,對于大多數小型應用,不會有人關注日志。
事實上,我現在向你保證,如果你給應用錯誤配置一個日志文件,你將永遠不會去看它,除非在調試問題時用戶向你報告。你需要的應是異常發生時的郵件,然后你會得到一個警報,并做些什么。
Flask 使用 Python 內置的日志系統,而且它確實向你發送你可能需要的錯誤郵件。這里給出你如何配置 Flask 日志記錄器向你發送報告異常的郵件:
~~~
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)
~~~
那么剛剛發生了什么?我們創建了一個新的[SMTPHandler](http://docs.python.org/dev/library/logging.handlers.html#logging.handlers.SMTPHandler "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.handlers.html#logging.handlers.SMTPHandler] 來用監聽 127.0.0.1 的郵件服務器向所有的 ADMINS 發送發件人為 *server-error@example.com* ,主題為 “YourApplication Failed” 的郵件。如果你的郵件服務器需要憑證,這些功能也被提供了。詳情請見 [SMTPHandler](http://docs.python.org/dev/library/logging.handlers.html#logging.handlers.SMTPHandler "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.handlers.html#logging.handlers.SMTPHandler] 的文檔。
我們同樣告訴處理程序只發送錯誤和更重要的消息。因為我們的確不想收到警告或是其它沒用的,每次請求處理都會發生的日志郵件。
你在生產環境中運行它之前,請參閱 [*控制日志格式*](#) 來向錯誤郵件中置放更多的信息。這會讓你少走彎路。
### 記錄到文件
即便你收到了郵件,你可能還是想記錄警告。當調試問題的時候,收集更多的信息是個好主意。請注意 Flask 核心系統本身不會發出任何警告,所以在古怪的事情發生時發出警告是你的責任。
在日志系統的方框外提供了一些處理程序,但它們對記錄基本錯誤并不是都有用。最讓人感興趣的可能是下面的幾個:
- [FileHandler](http://docs.python.org/dev/library/logging.handlers.html#logging.FileHandler "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.handlers.html#logging.FileHandler] - 在文件系統上記錄日志
- [RotatingFileHandler](http://docs.python.org/dev/library/logging.handlers.html#logging.handlers.RotatingFileHandler "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.handlers.html#logging.handlers.RotatingFileHandler] - 在文件系統上記錄日志,并且當消息達到一定數目時,會滾動記錄
- [NTEventLogHandler](http://docs.python.org/dev/library/logging.handlers.html#logging.handlers.NTEventLogHandler "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.handlers.html#logging.handlers.NTEventLogHandler] - 記錄到 Windows 系統中的系統事件日志。如果你在 Windows 上做開發,這就是你想要用的。
- [SysLogHandler](http://docs.python.org/dev/library/logging.handlers.html#logging.handlers.SysLogHandler "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.handlers.html#logging.handlers.SysLogHandler] - 發送日志到 Unix 的系統日志
當你選擇了日志處理程序,像前面對 SMTP 處理程序做的那樣,只要確保使用一個低級的設置(我推薦 WARNING ):
~~~
if not app.debug:
import logging
from themodule import TheHandlerYouWant
file_handler = TheHandlerYouWant(...)
file_handler.setLevel(logging.WARNING)
app.logger.addHandler(file_handler)
~~~
### 控制日志格式
默認情況下,錯誤處理只會把消息字符串記錄到文件或郵件發送給你。一個日志記錄應存儲更多的信息,這使得配置你的日志記錄器包含那些信息很重要,如此你會對錯誤發生的原因,還有更重要的——錯誤在哪發生,有更好的了解。
格式可以從一個格式化字符串實例化。注意回溯(tracebacks)會被自動加入到日志條目后,你不需要在日志格式的格式化字符串中這么做。
這里有一些配置實例:
### 郵件
~~~
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](http://docs.python.org/dev/library/logging.html#module-logging "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.html#module-logging] 包的官方文檔。
| 格式 | 描述 |
|-----|-----|
| %(levelname)s | 消息文本的記錄等級('DEBUG', 'INFO', 'WARNING','ERROR', 'CRITICAL'). |
| %(pathname)s | 發起日志記錄調用的源文件的完整路徑(如果可用) |
| %(filename)s | 路徑中的文件名部分 |
| %(module)s | 模塊(文件名的名稱部分) |
| %(funcName)s | 包含日志調用的函數名 |
| %(lineno)d | 日志記錄調用所在的源文件行的行號(如果可用) |
| %(asctime)s | LogRecord 創建時的人類可讀的時間。默認情況下,格式為 "2003-07-0816:49:45,896" (逗號后的數字時間的毫秒部分)。這可以通過繼承:class:~logging.Formatter,并重載 [formatTime()](http://docs.python.org/dev/library/logging.html#logging.Formatter.formatTime "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.html#logging.Formatter.formatTime] 改變。 |
| %(message)s | 記錄的消息,視為 msg%args |
如果你想深度定制日志格式,你可以繼承 [Formatter](http://docs.python.org/dev/library/logging.html#logging.Formatter "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.html#logging.Formatter] 。[Formatter](http://docs.python.org/dev/library/logging.html#logging.Formatter "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.html#logging.Formatter] 有三個需要關注的方法:
[format()](http://docs.python.org/dev/library/logging.html#logging.Formatter.format "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.html#logging.Formatter.format]:處理實際上的格式。需要一個 [LogRecord](http://docs.python.org/dev/library/logging.html#logging.LogRecord "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.html#logging.LogRecord] 對象作為參數,并必須返回一個格式化字符串。[formatTime()](http://docs.python.org/dev/library/logging.html#logging.Formatter.formatTime "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.html#logging.Formatter.formatTime]:控制 asctime 格式。如果你需要不同的時間格式,可以重載這個函數。[formatException()](http://docs.python.org/dev/library/logging.html#logging.Formatter.formatException "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.html#logging.Formatter.formatException]控制異常的格式。需要一個 exc_info 元組作為參數,并必須返回一個字符串。默認的通常足夠好,你不需要重載它。
更多信息請見其官方文檔。
### 其它的庫
至此,我們只配置了應用自己建立的日志記錄器。其它的庫也可以記錄它們。例如,SQLAlchemy 在它的核心中大量地使用日志。而在 [logging](http://docs.python.org/dev/library/logging.html#module-logging "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.html#module-logging] 包中有一個方法可以一次性配置所有的日志記錄器,我不推薦使用它。可能存在一種情況,當你想要在同一個 Python 解釋器中并排運行多個獨立的應用時,則不可能對它們的日志記錄器做不同的設置。
作為替代,我推薦你找出你有興趣的日志記錄器,用 [getLogger()](http://docs.python.org/dev/library/logging.html#logging.getLogger "(在 Python v3.5)") [http://docs.python.org/dev/library/logging.html#logging.getLogger]函數來獲取日志記錄器,并且遍歷它們來附加處理程序:
~~~
from logging import getLogger
loggers = [app.logger, getLogger('sqlalchemy'),
getLogger('otherlibrary')]
for logger in loggers:
logger.addHandler(mail_handler)
logger.addHandler(file_handler)
~~~
# 調試應用錯誤
對于生產應用,按照 [*記錄應用錯誤*](#) 中的描述來配置你應用的日志記錄和通知。這個章節講述了調試部署配置和深入一個功能強大的 Python 調試器的要點。
### 有疑問時,手動運行
在配置你的應用到生產環境時時遇到了問題?如果你擁有主機的 shell 權限,驗證你是否可以在部署環境中手動用 shell 運行你的應用。確保在同一用戶賬戶下運行配置好的部署來解決權限問題。你可以使用 Flask 內置的開發服務器并設置 debug=True ,這在捕獲配置問題的時候非常有效,但是 **請確保在可控環境下臨時地這么做。** 不要在生產環境中使用 debug=True 運行。
### 調試器操作
為了深入跟蹤代碼的執行,Flask 提供了一個方框外的調試器(見 [*調試模式*](#) )。如果你想用其它的 Python 調試器,請注意相互的調試器接口。你需要設置下面的參數來使用你中意的調試器:
- debug - 是否開啟調試模式并捕獲異常
- use_debugger - 是否使用內部的 Flask 調試器
- use_reloader - 是否在異常時重新載入并創建子進程
debug 必須為 True (即異常必須被捕獲)來允許其它的兩個選項設置為任何值。
如果你使用 Aptana/Eclipse 來調試,你會需要把 use_debugger 和 user_reloader都設置為 False 。
一個可能有用的配置模式就是在你的 config.yaml 中設置為如下(當然,自行更改為適用你應用的):
~~~
FLASK:
DEBUG: True
DEBUG_WITH_APTANA: True
~~~
然后在你應用的入口( main.py ),你可以寫入下面的內容:
~~~
if __name__ == "__main__":
# To allow aptana to receive errors, set use_debugger=False
app = create_app(config="config.yaml")
if app.debug: use_debugger = True
try:
# Disable Flask's debugger if external debugger is requested
use_debugger = not(app.config.get('DEBUG_WITH_APTANA'))
except:
pass
app.run(use_debugger=use_debugger, debug=app.debug,
use_reloader=use_debugger, host='0.0.0.0')
~~~
? 版權所有 2013, Armin Ronacher.
- 歡迎使用 Flask
- 前言
- 給有經驗程序員的前言
- 安裝
- 快速入門
- 教程
- 介紹 Flaskr
- 步驟 0: 創建文件夾
- 步驟 1: 數據庫模式
- 步驟 2: 應用設置代碼
- 步驟 3: 創建數據庫
- 步驟 4: 請求數據庫連接
- 步驟 5: 視圖函數
- 步驟 6: 模板
- 步驟 7: 添加樣式
- 福利: 應用測試
- 模板
- 測試 Flask 應用
- 記錄應用錯誤
- 配置處理
- 信號
- 即插視圖
- 應用上下文
- 請求上下文
- 用藍圖實現模塊化的應用
- Flask 擴展
- 與 Shell 共舞
- Flask 代碼模式
- 大型應用
- 應用程序的工廠函數
- 應用調度
- 使用 URL 處理器
- 部署和分發
- 使用 Fabric 部署
- 在 Flask 中使用 SQLite 3
- 在 Flask 中使用 SQLAlchemy
- 上傳文件
- 緩存
- 視圖裝飾器
- 使用 WTForms 進行表單驗證
- 模板繼承
- 消息閃現
- 用 jQuery 實現 Ajax
- 自定義錯誤頁面
- 延遲加載視圖
- 在 Flask 中使用 MongoKit
- 添加 Favicon
- 數據流
- 延遲請求回調
- 添加 HTTP Method Overrides
- 請求內容校驗碼
- 基于 Celery 的后臺任務
- 部署選擇
- mod_wsgi (Apache)
- 獨立 WSGI 容器
- uWSGI
- FastCGI
- CGI
- 聚沙成塔
- API
- JSON 支持
- Flask 中的設計決策
- HTML/XHTML 常見問題
- 安全注意事項
- Flask 中的 Unicode
- Flask 擴展開發
- Pocoo 風格指引
- Python 3 支持
- 升級到最新版本
- Flask Changelog
- 許可證
- 術語表