通常亩鬼,我們的日志是這樣寫的:
_code_log_file = os.path.join(BASE_DIR, 'logs', 'code.log')
_code_log_handler = TimedRotatingFileHandler(_code_log_file, when="D")
_code_log_formatter = logging.Formatter('%(levelname)s %(pathname)s->func:%(funcName)s line:%(lineno)d %(message)s %(asctime)s')
_code_log_handler.setFormatter(_code_log_formatter)# 此處設(shè)置logger名稱,否則默認(rèn)的會和tornado的logger相同而使得下方設(shè)置的錯(cuò)誤等級被輕質(zhì)更新為info
code_log = logging.getLogger('code-log')
code_log.setLevel(logging.INFO)
code_log.addHandler(_code_log_handler)
這樣寫阿蝶,一般情況下不會有問題雳锋,即使程序中使用了多線程寫日志也不會導(dǎo)致日志丟失。(logging是線程安全的)
但是羡洁,實(shí)際項(xiàng)目中玷过,為了最大量的利用CPU,我們需要啟動多個(gè)python進(jìn)程筑煮,這個(gè)時(shí)候辛蚊,這樣寫日志就會出問題了。當(dāng)有多個(gè)進(jìn)程同時(shí)寫同一個(gè)日志文件時(shí)真仲,就會出現(xiàn)覆蓋而導(dǎo)致日志信息丟失的問題袋马。
對于這樣的問題,通常有兩種方案:
一. 為每個(gè)進(jìn)程分配不同的文件
原理:規(guī)避了多個(gè)進(jìn)程寫同一個(gè)文件的情境秸应。問題自然解決虑凛。
優(yōu)點(diǎn):不用寫額外代碼或第三方包的引用。
缺點(diǎn):日志分散软啼,不利于日志查看和監(jiān)測桑谍。
二. 重寫handler,用方法解決多進(jìn)程寫文件的問題
原理:就像同一時(shí)間多個(gè)客戶買火車票的問題一樣祸挪,加入鎖機(jī)制锣披。
優(yōu)點(diǎn):日志集中,方便查看與監(jiān)測贿条。
缺點(diǎn):需要自行解決鎖的相關(guān)算法或引入第三方包雹仿。
多進(jìn)程寫日志的第三方包ConcurrentLogHandler
詳細(xì)介紹:https://pypi.python.org/pypi/ConcurrentLogHandler/0.9.1
具體使用如下:
_code_log_file = os.path.join(BASE_DIR, 'logs', 'code.log')
# 對應(yīng)三個(gè)參數(shù)為:文件名,寫入模式(a表示追加)整以,文件大须柿伞(2M),最多保存5個(gè)文件
_code_log_handler = ConcurrentRotatingFileHandler(_code_log_file, "a", 2*1024*1024, 5)
_code_log_formatter = logging.Formatter('%(levelname)s %(pathname)s->func:%(funcName)s '
'line:%(lineno)d %(message)s %(asctime)s')
_code_log_handler.setFormatter(_code_log_formatter)
# 此處設(shè)置logger名稱悄蕾,否則默認(rèn)的會和tornado的logger相同而使得下方設(shè)置的錯(cuò)誤等級被輕質(zhì)更新為info
code_log = logging.getLogger('code-log')
code_log.setLevel(logging.INFO)
code_log.addHandler(_code_log_handler)
code_log.info("balabala")
在windows上使用ConcurrentLogHandler的問題
暫不知什么原因票顾,windows上使用該handler會出錯(cuò),程序卡死在寫日志的地方帆调。調(diào)試跟蹤到該Handler內(nèi)部奠骄,是某個(gè)鎖的問題。但該問題在正式環(huán)境Linux中不會存在番刊,也沒去深究含鳞。臨時(shí)的解決方法是在日志初始化的地方判斷當(dāng)前系統(tǒng),是windows則使用傳統(tǒng)的日志handler芹务。
代碼如下:
import logging
from setting import BASE_DIR
import os
from cloghandler import ConcurrentRotatingFileHandler as LogHandler
import platform
import json
# 不知道為毛windows上ConcurrentRotatingFileHandler這個(gè)handler會有導(dǎo)致程序卡死蝉绷,linux上無問題
# 暫時(shí)采用這種方法解決windows上因卡死導(dǎo)致的調(diào)試不方便問題
if str(platform.system()) == "Windows":
from logging.handlers import RotatingFileHandler as LogHandler
# -------------------------------運(yùn)行日志(代碼運(yùn)行記錄)-------------------------------
_code_log_file = os.path.join(BASE_DIR, 'logs', 'code.log')
_code_log_handler = LogHandler(_code_log_file, "a", 20*1024*1024, 50)
_code_log_formatter = logging.Formatter('%(levelname)s %(pathname)s->func:%(funcName)s '
'line:%(lineno)d %(message)s %(asctime)s')
_code_log_handler.setFormatter(_code_log_formatter)
# 此處設(shè)置logger名稱鸭廷,否則默認(rèn)的會和tornado的logger相同而使得下方設(shè)置的錯(cuò)誤等級被更新為info
code_log = logging.getLogger('code-log')
code_log.setLevel(logging.INFO)
code_log.addHandler(_code_log_handler)
更新
- 用concurrent-log-handler替換ConcurrentLogHandler可解決windows因鎖機(jī)制導(dǎo)致的卡死問題。即pip install ConcurrentLogHandler 改為pip install concurrent-log-handler.