【问题标题】:How to configure Logging in Python如何在 Python 中配置日志记录
【发布时间】:2012-08-13 01:36:51
【问题描述】:

我是 Python 新手,刚刚开始一个项目。我习惯在 Java 中使用 log4j,我想像在 Java 中一样记录 Python 中的所有模块和类。

在 Java 中,我在名为 log4j.properties 的 src 文件夹中有一个日志配置文件,如下所示:

log4j.rootLogger=DEBUG, Console, fileout

log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d{dd/MM/yyyy HH:mm:ss} %5p [%t] (%F:%L) - %m%n

log4j.appender.fileout=org.apache.log4j.RollingFileAppender
log4j.appender.fileout.File=servidor.log
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.ConversionPattern=%d{dd/MM/yyyy HH:mm:ss} (%F:%L) %p %t %c - %m%n

它记录到控制台和文件。

在我的类中,我只需要导入log4j 并添加一个静态属性来恢复加载配置的log4j 记录器,然后所有类都将登录控制台和文件。配置文件按名称自动加载。例如:

import org.apache.log4j.Logger;

public class Main {
    public static Logger logger = Logger.getLogger(Main.class);
    public static void main(String[] args) {
        logger.info("Hello");
    }
}

现在我在 Python 中设置日志记录时遇到问题,我已阅读文档,但找不到在许多模块/类中使用它的方法。如何以一种简单的方式设置 Python 日志记录,以便在每个模块/类中无需大量代码来记录我的模块和类?是否可以重现我在 Python 中编写的相同代码?

【问题讨论】:

标签: python python-2.7 logging


【解决方案1】:

实际上在 Python 中它看起来非常相似。有不同的方法可以做到这一点。我通常创建一个非常简单的记录器类:

import os
import logging 
import settings   # alternativly from whereever import settings  

class Logger(object):

    def __init__(self, name):
        name = name.replace('.log','')
        logger = logging.getLogger('log_namespace.%s' % name)    # log_namespace can be replaced with your namespace 
        logger.setLevel(logging.DEBUG)
        if not logger.handlers:
            file_name = os.path.join(settings.LOGGING_DIR, '%s.log' % name)    # usually I keep the LOGGING_DIR defined in some global settings file
            handler = logging.FileHandler(file_name)
            formatter = logging.Formatter('%(asctime)s %(levelname)s:%(name)s %(message)s')
            handler.setFormatter(formatter)
            handler.setLevel(logging.DEBUG)
            logger.addHandler(handler)
        self._logger = logger

    def get(self):
        return self._logger

然后,如果我想在类或模块中记录某些内容,我只需导入记录器并创建一个实例。传递类名将为每个类创建一个文件。然后,记录器可以通过调试、信息、错误等将消息记录到其文件中:

from module_where_logger_is_defined import Logger

class MyCustomClass(object):

    def __init__(self):
        self.logger = Logger(self.__class__.__name__).get()   # accessing the "private" variables for each class

    def do_something():
        ...
        self.logger.info('Hello')

    def raise_error():
        ...
        self.logger.error('some error message')

更新答案

多年来,我改变了我使用 Python 日志记录的方式。主要基于良好实践,我在应用程序启动期间首先加载的任何模块中配置整个应用程序的日志记录,然后在每个文件中使用单独的记录器。示例:


# app.py (runs when application starts)

import logging
import os.path

def main():
    logging_config = {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'standard': {
                'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
            },
        },
        'handlers': {
            'default_handler': {
                'class': 'logging.FileHandler',
                'level': 'DEBUG',
                'formatter': 'standard',
                'filename': os.path.join('logs', 'application.log'),
                'encoding': 'utf8'
            },
        },
        'loggers': {
            '': {
                'handlers': ['default_handler'],
                'level': 'DEBUG',
                'propagate': False
            }
        }
    }
    logging.config.dictConfig(logging_config)
    # start application ...

if __name__ == '__main__':
    main()

# submodule.py (any application module used later in the application)

import logging

# define top level module logger
logger = logging.getLogger(__name__)

def do_something():
    # application code ...
    logger.info('Something happended')
    # more code ...
    try:
        # something which might break
    except SomeError:
        logger.exception('Something broke')
        # handle exception
    # more code ...

以上是推荐的方法。每个模块都定义了自己的记录器,并且可以根据__name__ 属性轻松识别在您检查日志时哪个模块记录了哪个消息。这从我的原始答案中删除了样板文件,而是使用 Python 标准库中的 logging.config 模块。

【讨论】:

    【解决方案2】:

    文档provide a pretty good example of using your logger in multiple modules。基本上,您在程序开始时设置一次日志记录。然后,您将日志记录模块导入您想要记录的任何位置,并使用它。

    myapp.py

    ​​>
    import logging
    import mylib
    
    def main():
        logging.basicConfig(filename='myapp.log', level=logging.INFO)
        logging.info('Started')
        mylib.do_something()
        logging.info('Finished')
    
    if __name__ == '__main__':
        main()
    

    mylib.py

    ​​>
    import logging
    
    def do_something():
        logging.info('Doing something')
    

    此示例显示了一个非常简单的记录器设置,但您可以非常轻松地使用 various ways to configure logging 设置更高级的场景。

    【讨论】:

    • 如果你认为它是主题,你能澄清为什么import logging 需要在mylib.py 中定义,如果它已经在myapp.py 中定义,即不应该logging模块可用于随后导入的模块(如mylib.py)。
    • 我强烈建议您提出一个关于 Python 范围问题的新问题(或搜索类似问题)。过于简单地说,“范围”一词指的是一种语言用来确定对象变量(在本例中为 logging 变量)所指对象的规则。 Python 的作用域是这样的,一个模块不会隐式地查看其他模块。这是一件好事:通过强制mylib.py 明确定义logging 的含义,myapp.py 可以被更改(例如,从中删除的日志语句),而不必过多担心mylib.py 被破坏为变化的结果。
    【解决方案3】:

    python 中的内置日志记录模块需要几行代码来配置类似 log4j 的功能,即文件附加器、基于时间和大小的文件轮换。

    对于代码中功能的单行实现,您可以使用包autopylogger

    这里是基础知识。

    1.安装包

    pip install autopylogger
    

    2。用法

    # import the package
    from autopylogger import init_logging
    
    # Initialise the logging module
    mylogger = init_logging(log_name="myfirstlogger", log_directory="logsdir")
    

    就是这样,日志对象已经初始化并启用了文件写入和旋转功能。

    您可以通过以下命令写入日志。

    # Write logs - DEBUG | INFO | WARNING | ERROR
    mylogger.debug('This is a INFO log')
    mylogger.info('This is a DEBUG log')
    mylogger.warning('This is a WARNING log')
    mylogger.error('This is a ERROR log')
    

    为什么要使用 autopylogger?

    • 文件附加器 - 默认启用。

    • 日志轮换 - 默认启用。还可以基于timesize 配置轮换,这是基本日志库中缺少的。

    • 关键日志邮件功能 - 通过使用您的 SMTP 服务器凭据初始化库来发送关键日志邮件。在 PRODUCTION 环境中派上用场。

    有关文档,请参阅Official Github pagePyPI Official page

    【讨论】:

    • 请求社区反对者对给定的反对意见发表评论,并帮助建立高质量的社区。​​span>
    • 我同意,@Rohit。感谢您的回答。 +1
    猜你喜欢
    • 1970-01-01
    • 2011-04-27
    • 2011-02-27
    • 1970-01-01
    • 2022-06-15
    • 2018-10-12
    • 1970-01-01
    • 2020-01-03
    • 1970-01-01
    相关资源
    最近更新 更多