简体   繁体   English

跨模块以相同的日志记录级别进行日志记录

[英]logging with the same logging levels across modules

I'm somewhat new to Python, especially in writing modules and functions in several files and not just raw scripts. 我是Python的新手,尤其是在多个文件中编写模块和函数,而不仅仅是原始脚本。

I'm writing a command line app and I would like to have a single function (I call it argpconf ) that will parse the command line arguments and set a log level accordingly. 我正在编写一个命令行应用程序,我希望有一个函数(我称其为argpconf ),该函数将解析命令行参数并相应地设置日志级别。 Most importantly, I'd like the log level to be set once in this function and to be the same across all modules with minimum overhead when creating their loggers. 最重要的是,我希望在此功能中设置一次日志级别,并在创建其记录器时在所有模块中将其设置为最低开销。 Additionally, I would like to be able to identify the module from which the message came while using the common formatter: 另外,我希望能够在使用通用格式化程序时识别出消息所来自的模块:

logging.Formatter("%(levelname)s : %(name)s : %(message)s")

Partially based on a cookiecutter template , I've created the following files: 我部分地基于cookiecutter模板创建了以下文件:

├── api
│   ├── __init__.py
│   └── some_functionality.py
├── cli.py
├── core
│   ├── argpconf.py
│   ├── __init__.py
│   ├── logger.py
│   └── __version__.py
├── __init__.py
└── __main__.py

core/logger.py has the following content: core/logger.py具有以下内容:

from logging import Formatter, Logger as _Logger, NullHandler, StreamHandler

class Logger(_Logger):
    def __init__(self, name=None):
        super(Logger, self).__init__(name or __name__.split(".")[0])
        self.addHandler(NullHandler())  # default to no output
    def start(self, level="WARN", stream=None,
              fmt="%(levelname)s : %(name)s : %(message)s"):
        handler = StreamHandler(stream)
        handler.setFormatter(Formatter(fmt))
        self.addHandler(handler)
        self.setLevel(level.upper())
    def stop(self):
        for handler in self.handlers[1:]:
            # Remove everything but the NullHandler.
            self.removeHandler(handler)

logger = Logger()

Compared to the ideas suggested in the answers to these questions: 与这些问题的答案中提出的想法相比:

I really like the approach taken in the cookiecutter template with the logger since it allows you just to import logger and have a logger object that it's log level is the same across all modules. 我真的很喜欢在cookiecutter模板中使用记录器的方法,因为它允许您仅import logger并使logger对象的日志级别在所有模块中都相同。 However, I'm not totally satisfied with it, because in my case the argpconf.py is the first module that starts the logger so all log messages from all modules have their %(name)s substituted with core since it's argpconf.py 's __name__.split(".")[0] . 但是,我并不完全满意,因为在我的情况下, argpconf.py是启动logger的第一个模块,因此来自所有模块的所有日志消息都将%(name)s替换为core因为它是argpconf.py ' s __name__.split(".")[0]

How can I improve the logger module so it will detect the module that called it and print log messages with module as the %(name)s and perhaps even the function that prints them? 如何改善logger模块,使其能够检测到调用该模块的模块,并使用%(name)s甚至是打印它们的函数来打印日志消息?

This approach seems to be making things more complicated than they need to be. 这种方法似乎使事情变得比所需复杂。 I realise this is coming from the cookiecutter template you used, and it's just my opinion, but the approach to logging taken in that template isn't what I would regard as best practice. 我意识到这来自您使用的cookiecutter模板,这只是我的观点,但是在该模板中进行日志记录的方法并不是我认为的最佳实践。 You know your use case best, but if all I wanted was to 您最了解用例,但是如果我想做的就是

have a single function that will parse the command line arguments and set a log level accordingly. 具有一个可解析命令行参数并相应设置日志级别的函数。 Most importantly, I'd like the log level to be set once in this function and to be the same across all modules with minimum overhead when creating their loggers. 最重要的是,我希望在此功能中设置一次日志级别,并在创建其记录器时在所有模块中将其设置为最低开销。 Additionally, I would like to be able to identify the module from which the message came while using the common formatter 此外,我希望能够在使用通用格式化程序时识别消息所来自的模块

then the simplest approach is to import argparse and logging in your main script, process command line arguments and set the logging level accordingly, call basicConfig() (as suggested in Brian M. Sheldon's comment) and then dispatch to your application endpoint as determined by command line arguments. 那么最简单的方法是导入argparse并在您的主脚本中进行logging ,处理命令行参数并相应地设置日志记录级别,调用basicConfig() (如Brian M. Sheldon的注释中所建议),然后按以下方法将其分发到您的应用程序端点命令行参数。 Every module you use that needs to log something just needs to import logging and logger = logging.getLogger(__name__) and then logger.debug(...) or whatever, wherever needed in that module. 您使用的每个需要记录某些内容的模块只需要import logging logger = logging.getLogger(__name__) ,然后import logging logger = logging.getLogger(__name__) ,然后import logging logger = logging.getLogger(__name__) logger.debug(...)或该模块中所需的任何位置。 If you stick to this, all modules will use the logging level set in basicConfig() automatically, and if you use the fragment %(name)s in the format= argument to basicConfig() , then you will see the full module name in that place in the logged messages, as a fully-qualified dotted name (like api.some_functionality ). 如果你坚持这一点,所有的模块将使用日志记录级别的设置basicConfig()自动,如果你使用的片段%(name)sformat=参数basicConfig()那么你会在看到完整的模块名称在日志消息中的位置,以全限定的点名(如api.some_functionality )表示。 This approach will certainly have less overhead in creating loggers than the cookiecutter template does. 这种方法肯定会比cookiecutter模板具有更少的创建记录器的开销。

Update: I'll update the Python Logging Cookbook with an example. 更新:我将通过示例更新Python日志记录手册 For now, here's a Gist with just the code. 现在, 这里是仅包含代码的要点

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM