11

我想知道从 Python 应用程序中执行日志记录的标准设置是什么。

我正在使用 Logging 类,并且我编写了自己的记录器类来实例化 Logging 类。然后我的 main 实例化我的记录器包装类。但是,我的 main 实例化了其他类,我希望这些其他类也能够通过 main 中的 logger 对象写入日志文件。

如何使该记录器对象可以被其他类调用?这几乎就像我们需要某种静态记录器对象来让它工作。

我想这个问题的长短是:如何在代码结构中实现日志记录,以便从 main 实例化的所有类都可以写入同一个日志文件?我是否只需要在指向同一文件的每个类中创建一个新的日志记录对象?

4

2 回答 2

34

我不知道你所说的类是什么意思Logging——Python 的内置日志记录中没有这样的类。您实际上并不需要包装器:这是一个如何从您编写的任意类进行日志记录的示例:

import logging

# This class could be imported from a utility module
class LogMixin(object):
    @property
    def logger(self):
        name = '.'.join([__name__, self.__class__.__name__])
        return logging.getLogger(name)


# This class is just there to show that you can use a mixin like LogMixin
class Base(object):
    pass

# This could be in a module separate from B
class A(Base, LogMixin):
    def __init__(self):
        # Example of logging from a method in one of your classes
        self.logger.debug('Hello from A')

# This could be in a module separate from A
class B(Base, LogMixin):
    def __init__(self):
        # Another example of logging from a method in one of your classes
        self.logger.debug('Hello from B')

def main():
    # Do some work to exercise logging
    a = A()
    b = B()
    with open('myapp.log') as f:
        print('Log file contents:')
        print(f.read())

if __name__ == '__main__':
    # Configure only in your main program clause
    logging.basicConfig(level=logging.DEBUG,
                        filename='myapp.log', filemode='w',
                        format='%(name)s %(levelname)s %(message)s')
    main()

通常没有必要在类级别拥有记录器:在 Python 中,与 Java 不同,程序(分解)组合的单元是模块。但是,正如我在上面所展示的,没有什么能阻止你这样做。该脚本在运行时显示:

Log file contents:
__main__.A DEBUG Hello from A
__main__.B DEBUG Hello from B

请注意,两个类的代码都记录到同一个文件 myapp.log。即使 A 和 B 在不同的模块中,这也可以工作。

于 2013-04-05T13:58:19.030 回答
6

尝试使用 logging.getLogger() 来获取您的日志记录对象实例:

http://docs.python.org/3/library/logging.html#logging.getLogger

使用给定名称对该函数的所有调用都返回相同的记录器实例。这意味着记录器实例永远不需要在应用程序的不同部分之间传递。

更新

推荐的方法是使用 getLogger() 函数并对其进行配置(设置处理程序、格式化程序等...):

# main.py
import logging
import lib


def main():
    logger = logging.getLogger('custom_logger')
    logger.setLevel(logging.INFO)
    logger.addHandler(logging.FileHandler('test.log'))
    logger.info('logged from main module')
    lib.log()

if __name__ == '__main__':
    main()

# lib.py
import logging


def log():
    logger = logging.getLogger('custom_logger')
    logger.info('logged from lib module')

如果您确实需要扩展记录器类,请查看logging.setLoggerClass(klass)

更新 2

有关如何在不更改 Logging 类的情况下添加自定义日志记录级别的示例:

# main.py
import logging
import lib


# Extend Logger class
CUSTOM_LEVEL_NUM = 9
logging.addLevelName(CUSTOM_LEVEL_NUM, 'CUSTOM')
def custom(self, msg, *args, **kwargs):
    self._log(CUSTOM_LEVEL_NUM, msg, args, **kwargs)
logging.Logger.custom = custom

# Do global logger instance setup
logger = logging.getLogger('custom_logger')
logger.setLevel(logging.INFO)
logger.addHandler(logging.FileHandler('test.log'))


def main():
    logger = logging.getLogger('custom_logger')
    logger.custom('logged from main module')
    lib.log()

if __name__ == '__main__':
    main()

请注意,不建议添加自定义级别:http: //docs.python.org/2/howto/logging.html#custom-levels

定义一个自定义处理程序并可能使用多个记录器可能会满足您的其他要求:可选输出到 stderr。

于 2013-04-03T06:30:47.107 回答