简体   繁体   English

使用多个模块进行记录时的记录器层次结构和根记录器

[英]Logger hierarchy and the root logger when logging with multiple modules

I have this setup:我有这个设置:

main.py
/module
/module/__init__.py (empty)
/module.py

And here is the code for my two files, main.py and module.py respectively:这是我的两个文件main.pymodule.py的代码:

main.py主文件

import logging
from module import module

logger = logging.getLogger(__name__)

def test():
    logger.warning('in main.py/test')

def main():
    handler = logging.StreamHandler()
    handler.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s %(name)s/%(module)s [%(levelname)s]: %(message)s', '%Y-%m-%d %H:%M:%S')
    handler.setFormatter(formatter)
    logger.addHandler(handler)

    logger.warning('in main.py/main')
    module.something()

if __name__ == "__main__":
    main()    

module.py模块.py

import logging
logger = logging.getLogger(__name__)

def something():
    logger.warning('in module.py/something')

So, what I noticed is that this outputs the following (notice how the module logger has no formatting):所以,我注意到它输出以下内容(注意模块记录器如何没有格式):

2019-10-01 09:03:40 __main__/main [WARNING]: in main.py/main
in module.py/something

It only seems like only after I make an edit in main.py to change logger = logging.getLogger( __ name __ ) to logger = logging.getLogger() or add logger = logging.getLogger() after def main(): that it logs like this (which is what I want):似乎只有在我在main.py中进行编辑以将logger = logging.getLogger( __ name __ )更改为logger = logging.getLogger()def main(): ) 之后添加logger = logging.getLogger()之后:它像这样记录(这是我想要的):

2019-10-01 09:04:13 root/main [WARNING]: in main.py/main
2019-10-01 09:04:13 module.module/module [WARNING]: in module.py/something

Why is that?这是为什么? I thought that because main.py is importing module.py , it is naturally higher on the hierarchical scale so module.py would inherit the logger settings as defined in main.py .我认为因为main.py正在导入module.py ,所以它在层次规模上自然更高,因此module.py将继承main.py中定义的记录器设置。 Do need to explicitly set the root logger (with logger = logging.getLogger() ) in main for the inheritance to work?是否需要在 main 中显式设置根记录器(使用logger = logging.getLogger() )才能使 inheritance 正常工作? Did I not configure my folder structure correctly to make module.py 's logger inherit main.py 's logger settings, or is folder structure irrelevant?我没有正确配置我的文件夹结构以使module.py的记录器继承main.py的记录器设置,还是文件夹结构无关紧要?

The reason I ask is because I thought one should use logger = logging.getLogger( __ name __ ) throughout (even in main.py ) and then based on the import structure (or folder structure?), that would determine the hierarchy and loggers would inherit accordingly.我问的原因是因为我认为应该始终使用logger = logging.getLogger( __ name __ ) (甚至在main.py中),然后根据导入结构(或文件夹结构?),这将确定层次结构和记录器会相应地继承。 And the reason I was making that assumption is because what if I was importing main.py into another program?我做出这个假设的原因是因为如果我将main.py导入另一个程序会怎样? I guess my point is, I want to make logging as generic as possible such that I can import one module into another and it always inherits the parent's logger settings.我想我的意思是,我想让日志记录尽可能通用,这样我就可以将一个模块导入另一个模块,并且它总是继承父级的记录器设置。 Is there a way to display the underlying hierarchy of all the modules for debugging/learning purposes?有没有办法显示所有模块的底层层次结构以进行调试/学习?

The logging hierarchy has nothing to do with file structure in your program.日志层次结构与程序中的文件结构无关。 The hierarchy is determined only by the names of the loggers.层次结构仅由记录器的名称确定。 When you configure a logger, all loggers with its name in the prefix of their name are its children and inherit its configuration unless explicitly stated otherwise.当您配置一个记录器时,除非另有明确说明,否则名称前缀中的所有记录器都是其子级并继承其配置。

In your example, logging setup has more to do with execution sequence and the names you've chosen than anything else.在您的示例中,日志记录设置更多地与执行顺序和您选择的名称有关。 When your program runs, it does the following:当您的程序运行时,它会执行以下操作:

  1. Runs logging.py from the standard library because of import logging由于import logging ,从标准库运行logging.py
  2. Runs module.py to fulfill from module import module运行module.py以实现from module import module
  3. Sets the logger attribute in main to a Logger named __main__ .main中的logger属性设置为名为__main__Logger
  4. Create a test function创建test function
  5. Create a main function创建main function
  6. Run the main function运行主function

Some consequences of this sequence of events:这一系列事件的一些后果:

  • module.logger is created before main.logger . module.loggermain.logger之前创建。 This doesn't affect the behavior you're seeing, but it's worth noting under the circumstances.这不会影响您看到的行为,但在这种情况下值得注意。
  • main.logger is named __main__ if you invoke main as a script.如果您将main作为脚本调用,则main.logger被命名为__main__ The behavior you see wouldn't change if it was called main , eg from python -m main .如果它被称为main ,您看到的行为不会改变,例如从python -m main
  • module is clearly not in the same hierarchy as main . module显然与main不在同一层次结构中。 Both are descendants of the root logger along different branches.两者都是沿不同分支的根记录器的后代。

The last item is really the answer to your question.最后一项确实是您问题的答案。 If you want all the loggers in your program to share the same default logging method, you should configure the root logger, or ensure that they have the same name prefix, which you then configure as if it was the root logger.如果您希望程序中的所有记录器共享相同的默认记录方法,则应配置根记录器,或确保它们具有相同的名称前缀,然后将其配置为就像它是根记录器一样。

You could make all the loggers inherit from main .您可以让所有记录器从main继承。 In module/module.py , you would domodule/module.py ,你会做

logger = logging.getLogger('__main__.' + __name__)

The issue here is that the name __main__ is hard coded.这里的问题是名称__main__是硬编码的。 You don't have a guarantee that it will be __main__ vs main .您不能保证它将是__main__main You could try import main in module so you could do main.__name__ + '.' + __name__你可以尝试import main in module这样你就可以做main.__name__ + '.' + __name__ main.__name__ + '.' + __name__ , but that wouldn't work as expected. main.__name__ + '.' + __name__ ,但这不会按预期工作。 If main was run as __main__ , importing it will actually create a second module object with an entirely separate logging hierarchy.如果main作为__main__运行,导入它实际上将创建第二个模块 object 具有完全独立的日志记录层次结构。

This is why the root logger has no name.这就是根记录器没有名称的原因。 It provides exactly the maintainability and consistency you want.它提供了您想要的可维护性和一致性。 You don't have to jump through hoops trying to figure out the root name.您不必为了找出根名称而费尽心思。

That being said, you should still have main.py logging to the __main__ or main logger.话虽如此,您仍然应该将main.py记录到__main__main记录器。 The root logger should only be set up in the import guard.根记录器只能在导入防护中设置。 That way, if main is imported as a regular module, it will respect the logging setup of the driver it is running under.这样,如果main作为常规模块导入,它将尊重正在运行的驱动程序的日志记录设置。

TL;DR TL;博士

It is conventional to set up the anonymous root logger in the driver of your program.通常在程序的驱动程序中设置匿名根记录器。 Don't try to inherit loggers from __main__ or the driver module name.不要尝试从__main__或驱动程序模块名称继承记录器。

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

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