[英]What is the most pythonic way of logging for multiple modules and multiple handlers with specified encoding?
我正在尋找有關如何完成多模塊和多處理程序日志記錄的具體建議。 我在這里添加了我的簡化代碼,但我不想偏袒答案 - 告訴我最佳實踐是什么。
我想將所有內容記錄到一個文件中,然后向控制台發出警告。
這是我的level0.py
,我希望它能夠登錄到指定的文件:
import logging
from flask import Flask
from level1 import function1
app = Flask(__name__)
logger = logging.getLogger('logger0')
logger.setLevel(logging.DEBUG)
file_handler = logging.FileHandler('../logs/logger0','w','utf-8')
file_handler.setLevel(logging.DEBUG)
file_format = logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d in %(funcName)s]')
file_handler.setFormatter(file_format)
logger.addHandler(file_handler)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
console_format = logging.Formatter('%(message)s')
console_handler.setFormatter(console_format)
logger.addHandler(console_handler)
@app.route('/', methods=['GET', 'POST'])
def function0(foo):
bar = function1(foo)
logger.debug('function0')
...
此外,當作為腳本調用時, level1
可以是獨立模塊。 在那種情況下,我希望它記錄到另一個文件。 下面是level1.py
(有重復的日志記錄行):
import logging
logger = logging.getLogger('level0.level1')
from level2 import function2
def function1(foo):
bar = function2(foo)
logger.debug('function1')
...
if __name__ == "__main__":
logger = logging.getLogger('logger0')
logger.setLevel(logging.DEBUG)
file_handler = logging.FileHandler('../logs/logger1','w','utf-8')
file_handler.setLevel(logging.DEBUG)
file_format = logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d in %(funcName)s]')
file_handler.setFormatter(file_format)
logger.addHandler(file_handler)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
console_format = logging.Formatter('%(message)s')
console_handler.setFormatter(console_format)
logger.addHandler(console_handler)
bar = function1('foo')
logger.info('level1 main')
...
我已經從level0
復制了這個日志塊,因為我想要相同的日志記錄,將它放在main中似乎很直觀。 level2
不是獨立的,因此它只有:
import logging
logger = logging.getLogger('level0.level1.level2')
def function2(foo):
logger.info('function2')
....
我開始使用logging.basicSetup
,但無法為該文件設置編碼並在嘗試記錄非ascii字符串時不斷獲取UnicodeEncodeError
:
logger.warn(u'foo bar {}'.format(NON_ASCII_STR))
(當記錄器將消息傳遞給其父項時,我仍然收到錯誤)
那么,這個案例的最佳日志設計是什么,或者更普遍的 - 多個模塊(帶編碼選擇 - 我想要utf-8)
對於由許多部分組成的模塊,我使用文檔中推薦的方法,每個模塊只有一行, logger = logging.getLogger(__name__)
。 正如您所指出的,模塊不應該知道或關心其消息的方式或位置,它只是將其傳遞給應該由主程序設置的記錄器。
為了減少cut-n-paste,取決於你的主程序,確保你的模塊有一個有意義的層次結構,並且只有一個功能可以設置你的日志記錄,然后可以通過你想要的任何主要調用。
例如,創建一個logsetup.py:
import logging
def configure_log(level=None,name=None):
logger = logging.getLogger(name)
logger.setLevel(level)
file_handler = logging.FileHandler('../logs/%s' % name,'w','utf-8')
file_handler.setLevel(logging.DEBUG)
file_format = logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d in %(funcName)s]')
file_handler.setFormatter(file_format)
logger.addHandler(file_handler)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
console_format = logging.Formatter('%(message)s')
console_handler.setFormatter(console_format)
logger.addHandler(console_handler)
要使單個模塊具有其主要行為模式,請定義單獨的功能,例如main
。
在level0.py和/或level1.py中:
def main():
# do whatever
在最頂級的程序中,調用該函數:
import logging
from logsetup import configure_log
configure_log(logging.DEBUG,'level0') # or 'level1'
from level0 import main # or level1
if __name__ == "__main__"
main()
你應該仍然有__name__ == "__main__"
子句,一些模塊( 咳嗽多處理咳嗽 )具有不同的行為,具體取決於該子句是否存在。
有點包裝,這就是我所做的; 我在每個模塊/文件中放了以下兩行:
import logging
logger = logging.getLogger(__name__)
這會設置日志記錄,但不會添加任何處理程序。 然后我將處理程序添加到主文件中的根記錄器我正在運行導入的模塊,因此將它們的記錄傳遞給根記錄器,一切都得到保存和顯示。 我像CaptainMurphy建議的那樣做,但用logger = logging.getLogger('')
來處理根記錄器
為了解決編碼問題 - 我在將非ascii字符串保存到文件時遇到了問題。 所以我只是將FileHandler
添加到根記錄器中,可以指定編碼。 我無法用logging.basicConfig
做到這一點。
再次感謝@CaptainMurphy - 對不起,我不能以低聲望向你投票,但我已經勾選了答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.