根目录下和我的项目记录器之上的层次结构中的 Python 记录器?

标签 python python-3.x logging

首先,我已经阅读了real python article on the subject .

了解到记录器具有层次结构后,我想在这样的层次结构中创建一个名为 MyProjectLogger 的新记录器:

Root logger
    · MyProjectLogger
         · File logger 1
         · File logger 2
         · ... and so on with all the loggers in my project...

以便 MyProjectLogger 用于所有后代记录器,因为现在我在我的项目中的所有记录器中使用具有相同配置的所有相同处理程序(相当多)。虽然通过唯一的方法来做,但感觉不对。通过这种方式,我只需将处理程序添加到 MyProjectLogger 一次,所有后代记录器将使用 MyProjectLogger 的处理程序在层次结构中上升。

我不想为此使用默认的根记录器,因为我有一些第三方库正在记录它,现在我希望我项目中的记录器与库中的记录器分开记录。

所以,总结一下:

  • 我想在层次结构中定义一个记录器 MyProjectLogger
  • 我希望它是根记录器的直接后代
  • 我希望它成为我源代码中所有记录器的父级
  • 我相信我应该使用 propagate=False 以便我可以将处理程序添加到 MyProjectLogger 并让它处理后代记录器

我唯一的疑问是:我如何给它起一个这样的名字,以便在 root 下并在其余部分之上?

我知道:

logging.getLogger()  # Gets the root logger
logging.getLogger(__name__)  # Gets a logger for the present file
logging.getLogger(__package__)  # Gets a logger for the present module

假设,如果我的项目有这个文件夹布局:

aaaBot/
   main.py  # Only file visible in this example.
            # Please assume the rest of folders have files
   common/
      utils/ 
   config/
   database/
   exceptions/
   model/
   wizards/

在每个文件夹的每个文件中,我使用 logging.getLogger(__name__)。根目录中的 __package__ 返回 None 并且在主可执行文件 main.py 中 __name__'__main__'

我应该添加前缀 + '.'为我项目中的所有记录器创建带有该前缀的 MyProjectLogger(如 getLogger(prefix+'.'))?

如果没有,我该怎么办?

最佳答案

这是一个工作示例,说明了模仿模块结构的记录器层次结构:

so-57021706
└── aaaBot
    ├── __init__.py
    ├── common
    │   ├── __init__.py  # empty
    │   └── utils.py
    └── main.py

来源

aaaBot/__init__.py:

import logging
import sys


PKG_LOGGER = logging.getLogger(__name__)


def setup_logging():
    msg_format = '%(asctime)s [%(levelname)8s] %(message)s (%(name)s - %(filename)s:%(lineno)s)'
    date_format = '%Y-%m-%d %H:%M:%S'
    formatter = logging.Formatter(fmt=msg_format, datefmt=date_format)
    console_handler = logging.StreamHandler(stream=sys.stdout)
    console_handler.setLevel(logging.DEBUG)
    console_handler.setFormatter(formatter)
    PKG_LOGGER.addHandler(console_handler)
    PKG_LOGGER.setLevel(logging.DEBUG)
    PKG_LOGGER.propagate = False
    PKG_LOGGER.info('finished logging setup!')

aaaBot/common/utils.py:

import logging


UTILS_LOGGER = logging.getLogger(__name__)


def spam():
    UTILS_LOGGER.debug('entered spam() function')
    output = 'eggs'
    UTILS_LOGGER.debug('leaving spam() function')
    return output

aaaBot/main.py:

import sys
from aaaBot import setup_logging
from aaaBot.common.utils import spam


if __name__ == '__main__':
    if sys.argv[-1] == '--with-logging':
        setup_logging()
    print(spam())

执行

正常运行:

$ python -m aaaBot.main
eggs

调试运行(打开登录):

$ python -m aaaBot.main --with-logging
2019-07-15 13:16:04 [    INFO] finished logging setup! (aaaBot - __init__.py:18)
2019-07-15 13:16:04 [   DEBUG] entered spam() function (aaaBot.common.utils - utils.py:8)
2019-07-15 13:16:04 [   DEBUG] leaving spam() function (aaaBot.common.utils - utils.py:10)
eggs

说明

在此示例项目中,aaaBot/__init__.py 下的PKG_LOGGER 是“项目”记录器,名称为aaaBot。它也是唯一一个配置的记录器;所有子记录器除了将记录传播到 PKG_LOGGER 之外什么都不做。子记录器的示例是 aaaBot/common/utils.py 中的 UTILS_LOOGER - 未配置且名称为 aaaBot.common.utils。这种情况下的层次结构是:

<b>root logger</b>           code: logging.getLogger()
                      name: "root"
                      configured: no
                      propagates to parent: no (already root)
└── <b>PKG_LOGGER</b>        code: logging.getLogger('aaaBot')
                      name: "aaaBot"
                      configured: yes
                      propagates to parent: no (because of propagate = False)
    └── <b>UTILS_LOGGER</b>  code: logging.getLogger('aaaBot.common.utils')
                      name: "aaaBot.common.utils"
                      configured: no
                      propagates to parent: yes (default behaviour)

配置的可能性是无限的,取决于您的特定用例。例如,您可以仅配置根记录器并确保所有记录器都进行传播(它们默认情况下会这样做)。如果他们想要记录任何内容,这还将打印来自您正在使用的第三方库的所有消息。或者您可以引入一个额外的记录器 aaaBot.common,它将记录从子记录器写入文件,除了将它们传播和发送到控制台等。

关于您的评论:

It seems like that thing would be ok for developing a library, but my project is an application.

没关系;它仅取决于 __name__ 变量的值(导入 模块与执行 它)。例如,在 aaaBot/main.py 中使用 logging.getLogger(__name__) 不会创建名称为 aaaBot.main 的记录器 aaaBot 作为 parent 。相反,将创建一个名为 __main__ 的记录器。

库和应用程序之间日志记录设置的区别仅在于记录器配置。如果需要日志记录,应用程序总是显式配置日志记录。一个库根本不配置任何日志记录,除了一个 NullHandler 到库的根记录器。例如,如果 aaaBot 是一个库,则 aaaBot/__init__.py 中的日志记录设置可能如下所示:

import logging
LIB_LOGGER = logging.getLogger('aaaBot')
if not LIB_LOGGER.handlers:
    LIB_LOGGER.addHandler(logging.NullHandler())

关于根目录下和我的项目记录器之上的层次结构中的 Python 记录器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57021706/

相关文章:

php - Symfony2 在监听器中使用记录器

python 看门狗 : Is there a way to pause the observer?

python - 使用Python/Tornado的音频流充当 "radio"

python - 值错误 : Math domain error (for a 2nd grade equation function)

python - MySQL 不会从 python 更新

Python 3 通过索引从 json 获取值

python - Pandas 的 pd.NA 与 np.nan

Python 文件路径常量

java - LoggerFactory.getLogger 无法解析为类型

java - 如何使用log4j2和slf4j将日志存储在不同的日志表中?