Logging是作為backend server必備的工具,透過log file,你可以知道程式執行了甚麼。如果你的server有unexpected error發生,最好的做法就是到server查看log file,找出發生甚麼事。
這篇就紀錄在Django設置logging的種種細節吧。
認識Python logging
為甚麼要用logging,不用print?
- Custom log format
- 不同程度的logging + custom handler
- 例如把
debug
和error
message log到不同的file - 用email匯報某個module的
error
- 例如把
- Custom filter
- Per-module level settings
print('Something happened!')
# Something happened!
logger.debug('Something happened!')
# [INFO] 2018-06-08 22:00:01,850 | module_a.function_b:26 | Something happened!
用法
可以直接logging.debug()
,但一般都會建立一個instance來使用:
# import the logging library
import logging
# Get an instance of a logger
logger = logging.getLogger(__name__)
logger.debug('')
logger.info('')
logger.warning('')
logger.error('')
logger.critical('')
logger.exception('')
__name__
用例子解釋:
Files
# b.py
def print_b_namespace():
print(__name__)
# c/d.py
def print_d_namespace():
print(__name__)
if __name__ == '__main__':
print(__name__)
# a.py
from b import print_b_namespace
from c.d import print_d_namespace
print(__name__)
print_b_namespace()
print_d_namespace()
延伸閱讀:理解Python的 relative 和 absolute import
執行
$ python a.py
__main__
b
c.d
$ python c/d.py
__main__
結論
- Entry point的
__name__
是__main__
- 所有被entry point "import"的module都會一層一層地命名下去
- 例如django中的
models.py
,__name__
就是some_app.models
- 例如django中的
好處
logger使用自己的__name__
來分類,可以:
- 在log file中分辨出這些log來自哪裡
- 可以逐個module決定如何log、log到哪裡等等這些設定
設置Django logging
Django支援python logging
的設定。
Sample config
# In settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'normal': {
'format': '[%(levelname)s] %(asctime)s | %(name)s:%(lineno)d | %(message)s'
},
'simple': {
'format': '[%(levelname)s] %(message)s'
},
},
# 'filters': {
# 'require_debug_true': {
# '()': 'django.utils.log.RequireDebugTrue',
# },
# },
'handlers': {
'console': {
'class': 'logging.StreamHandler', # Default logs to stderr
'formatter': 'normal', # use the above "normal" formatter
# 'filters': ['require_debug_true'], # add filters
},
},
'loggers': {
'': { # means "root logger"
'handlers': ['console'], # use the above "console" handler
'level': 'INFO', # logging level
},
'some_app.some_module': { # Modify logger in some modules
'handlers': ['console'],
'level': 'DEBUG',
'propagate': True,
},
},
}
詳細設定要同時查找Django doc和Python doc
Sentry
Sentry是一個error tracking工具,提供dashboard、email等功能,讓你可以即時查看server發生甚麼error。
Sentry支援各種語言和框架,官方也有django的整合教學,輕鬆設置後就可以隨時收到server的error消息,及早發現就能及早修復。
uWSGI
一般開發時,會使用manage.py runserver
啟動server,這時logs就會output到console (for StreamHandler
)。
但到實際production使用,多數會deploy到WSGI server,例如uWSGI,然後就不會再由console查看log訊息了。
延伸閱讀:入門理解WSGI
簡單教學:How To Serve Django Applications with uWSGI and Nginx on Ubuntu 16.04
此時Django有兩個做法:
- 在settings使用
FileHandler
等等,自行處理;或 - 在settings使用
StreamHandler
,把logs傳給uWSGI,然後uWSGI負責建立紀錄檔等等。
下面會講解如何使用第二種做法。
設定uWSGI
uWSGI的設定檔應該會在/etc/uwsgi/sites/your_project.ini
,在設定檔加入:
# logging
logto = /var/log/uwsgi/this_is_a_log.log
log-maxsize = 1000000 # 每到達1MB,就會自動split一個新檔案出來
然後準備logging用的directory
sudo mkdir -p /var/log/uwsgi
sudo chown -R user:user /var/log/uwsgi # 確保設定檔裡的user有權限
# 重啟uWSGI
sudo systemctl restart uwsgi
然後就可以查看/var/log/uwsgi/this_is_a_log.log
了!