在多个模块中使用日志记录

414

我有一个小的Python项目,它具有以下结构 -

Project 
 -- pkg01
   -- test01.py
 -- pkg02
   -- test02.py
 -- logging.conf

我计划使用默认的日志记录模块将消息打印到标准输出和日志文件中。 要使用日志记录模块,需要进行一些初始化 -

import logging.config

logging.config.fileConfig('logging.conf')
logger = logging.getLogger('pyApp')

logger.info('testing')

目前,我在每个模块开始记录消息之前都执行此初始化。是否可能只在一个地方执行此初始化,以便所有项目中的日志记录都重用相同的设置?


5
关于你对我回答的评论:你不必在每个进行日志记录的模块中都调用 fileConfig,除非所有模块中都有 if __name__ == '__main__' 的逻辑。prost的回答对于库而言并不是最佳实践,尽管它可能适用于你——在库包中不应该配置日志记录,除非添加一个 NullHandler - Vinay Sajip
1
prost 暗示我们需要在每个模块中调用 import 和 logger 语句,并且只在主模块中调用 fileconfig 语句。这不是跟你说的很像吗? - Quest Monger
8
Prost 表示你应该将日志配置代码放在 package/__init__.py 文件中。这通常不是你放置 if __name__ == '__main__' 代码的位置。此外,Prost 的示例似乎会在导入时无条件地调用配置代码,这对我来说看起来不太对。通常,日志配置代码应该在一个地方完成,并且不应该作为导入的副作用发生,除非你正在导入 __main__ - Vinay Sajip
使用内置函数怎么样?https://stackoverflow.com/a/60232385/3404763? - fatih_dur
12个回答

2

有几种答案。我最终得出了一种类似但不同的解决方案,这对我来说是有意义的,也许对你也是如此。 我的主要目标是能够通过记录级别将日志传递给处理程序(将调试级别日志传递到控制台,将警告及以上级别日志传递到文件):

from flask import Flask
import logging
from logging.handlers import RotatingFileHandler

app = Flask(__name__)

# make default logger output everything to the console
logging.basicConfig(level=logging.DEBUG)

rotating_file_handler = RotatingFileHandler(filename="logs.log")
rotating_file_handler.setLevel(logging.INFO)

app.logger.addHandler(rotating_file_handler)

我创建了一个名为logger.py的实用文件:

import logging

def get_logger(name):
    return logging.getLogger("flask.app." + name)

flask.app是Flask中的硬编码值。应用程序记录器始终以flask.app作为模块名称启动。

现在,在每个模块中,我可以按以下方式使用它:

from logger import get_logger
logger = get_logger(__name__)

logger.info("new log")

这将以最小的工作量为“app.flask.MODULE_NAME”创建一个新的日志。

1
新手学习Python,不知道这是否可行,但它非常适合不重写样板文件。
你的项目必须有一个__init__.py文件,以便可以作为模块加载。
# Put this in your module's __init__.py
import logging.config
import sys

# I used this dictionary test, you would put:
# logging.config.fileConfig('logging.conf')
# The "" entry in loggers is the root logger, tutorials always 
# use "root" but I can't get that to work
logging.config.dictConfig({
    "version": 1,
    "formatters": {
        "default": {
            "format": "%(asctime)s %(levelname)s %(name)s %(message)s"
        },
    },
    "handlers": {
        "console": {
            "level": 'DEBUG',
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stdout"
        }
    },
    "loggers": {
        "": {
            "level": "DEBUG",
            "handlers": ["console"]
        }
    }
})

def logger():
    # Get the name from the caller of this function
    return logging.getLogger(sys._getframe(1).f_globals['__name__'])

sys._getframe(1) 的建议来自这里

然后在任何其他文件中使用您的日志记录器:

from [your module name here] import logger

logger().debug("FOOOOOOOOO!!!")

注意事项:

  1. 您必须将您的文件作为模块运行,否则import [your module]将无法工作:
    • python -m [your module name].[your filename without .py]
  2. 您的程序入口点的日志记录器名称将为__main__,但使用__name__的任何解决方案都会出现此问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接