使用日志中的模块名称登录多个类

ulo*_*oco 13 python logging namespaces

我想使用日志记录模块而不是打印调试信息和文档.目标是在控制台上使用DEBUG级别打印并登录到具有INFO级别的文件.

我阅读了很多关于日志记录模块的文档,食谱和其他教程,但无法弄清楚,我怎么能按照我想要的方式使用它.(我在python25上)

我想要在日志文件中写入日志的模块名称.

文档说我应该使用logger = logging.getLogger(__name__)但是如何声明其他模块/包中的类中使用的记录器,所以它们使用像主记录器一样的处理程序?要识别'父母'我可以使用,logger = logging.getLogger(parent.child)但我知道哪些人,谁调用了类/方法?`

下面的例子显示了我的问题,如果我运行它,输出将只有__main__登录并忽略日志Class

这是我的主文件:

# main.py

import logging
from module import Class

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

# create file handler which logs info messages
fh = logging.FileHandler('foo.log', 'w', 'utf-8')
fh.setLevel(logging.INFO)

# create console handler with a debug log level
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)

# creating a formatter
formatter = logging.Formatter('- %(name)s - %(levelname)-8s: %(message)s')

# setting handler format
fh.setFormatter(formatter)
ch.setFormatter(formatter)

# add the handlers to the logger
logger.addHandler(fh)
logger.addHandler(ch)

if __name__ == '__main__':
    logger.info('Script starts')
    logger.info('calling class Class')
    c = Class()
    logger.info('calling c.do_something()')
    c.do_something()
    logger.info('calling c.try_something()')
    c.try_something()
Run Code Online (Sandbox Code Playgroud)

模块:

# module.py

imnport logging

class Class:
    def __init__(self):
        self.logger = logging.getLogger(__name__) # What do I have to enter here?
        self.logger.info('creating an instance of Class')
        self.dict = {'a':'A'}
    def do_something(self):
        self.logger.debug('doing something')
        a = 1 + 1
        self.logger.debug('done doing something')
    def try_something(self):
        try:
            logging.debug(self.dict['b'])
        except KeyError, e:
            logging.exception(e)
Run Code Online (Sandbox Code Playgroud)

控制台输出:

- __main__ - INFO    : Script starts
- __main__ - INFO    : calling class Class
- __main__ - INFO    : calling c.do_something()
- __main__ - INFO    : calling c.try_something()
No handlers could be found for logger "module"
Run Code Online (Sandbox Code Playgroud)

另外:有没有办法让模块名称是我的日志文件中的日志,而不是像上面那样在每个类中声明一个新的记录器?也喜欢这种方式我self.logger.info()每次想要记录的东西都要去.我更愿意使用logging.info()logger.info()在我的整个代码中.

全球记录器可能是正确答案吗?但是后来我不会得到日志中出现错误的模块......

我的最后一个问题:这是pythonic吗?或者是否有更好的建议来做正确的事情.

sir*_*rfz 13

在您的主模块中,您正在使用不同的记录器在module.py中配置名称记录器'__main__'(或者__name__等同于您的情况).您需要为每个模块配置记录器,或者您可以logging.getLogger()在主模块中配置根记录器(通过配置),默认情况下将应用于项目中的所有记录器.

我建议使用配置文件来配置记录器.此链接应该让您对良好实践有所了解:http://victorlin.me/posts/2012/08/26/good-logging-practice-in-python

编辑:在格式化程序中使用%(模块)在日志消息中包含模块名称.

  • 只要您希望将相同的设置应用于项目中的所有记录器,只需配置根记录器即可.但是,如果您需要基于模块添加不同的处理程序,那么最好定义一个良好的清除配置文件并指定包级别记录器(例如,path.to.package1的记录器配置将应用于此包层次结构的所有子级) (2认同)
  • 如果您使用 `logger.getLogger(__name__)`,那么您将在日志消息中获得完整的模块名称(包括包层次结构)(前提是您有 `%(name)` 格式化程序元素)。请记住,如果配置了根记录器,那么它将应用于所有子项(即所有包和模块)。 (2认同)
  • 如果您只是从上面 main.py 模块中的 getLogger 调用中删除 `__name__`,一切都应该按您的意愿工作,无需任何其他修改(因为您将配置适用于所有子级的根记录器,包括 module.py)。试试看,你应该明白我的意思。 (2认同)

gon*_*opp 5

您的处理程序应该有一个全局记录器:

logger= logging.getLogger("myapp")
#configure handlers
Run Code Online (Sandbox Code Playgroud)

然后,在每个模块上:

logger= logging.getLogger("myapp."+__name__)

您是否需要每类记录器取决于您 - 我见过的大多数项目(最多)每个模块有一个记录器.我的建议是,如果你不需要不同类的不同处理程序,每个模块只需要一个记录器,或者每个项目都需要一个记录器 - 如果项目很小的话.

如果您需要更多日志上下文,请注意您可以使用%(funcName)s格式化程序打印当前函数名称

  • 嗯...这看起来太糟糕了,当我必须在每个类中显式插入名称时...必须有更好的方法 (2认同)
  • @drrtyrokka 理想情况下,您应该避免使用 `getLogger('')` - 您正在使用的库中的其他模块也可能最终使用根记录器,然后它们可以更改您的处理程序和格式化程序配置。简单地使用项目范围的前缀更安全 (2认同)
  • @uloco您可以利用装饰器为您将记录器添加到类中:https://xmedeko.blogspot.cz/2017/10/python-logger-by-class.html (2认同)