[英]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.