Python:日志记录模块 - 全局

cwo*_*ker 49 python logging module global-variables

我想知道如何实现一个可以在任何地方使用您自己的设置的全局记录器:

我目前有一个自定义记录器类:

class customLogger(logging.Logger):
   ...
Run Code Online (Sandbox Code Playgroud)

该类位于一个单独的文件中,包含一些格式化程序和其他内容.记录仪可以完美地完成.

我在我的主python文件中导入这个模块并创建一个这样的对象:

self.log = logModule.customLogger(arguments)
Run Code Online (Sandbox Code Playgroud)

但显然,我无法从代码的其他部分访问此对象.我使用了错误的方法吗?有一个更好的方法吗?

小智 108

使用logging.getLogger(name)创建一个名为全球记录.

main.py

import log
logger = log.setup_custom_logger('root')
logger.debug('main message')

import submodule
Run Code Online (Sandbox Code Playgroud)

log.py

import logging

def setup_custom_logger(name):
    formatter = logging.Formatter(fmt='%(asctime)s - %(levelname)s - %(module)s - %(message)s')

    handler = logging.StreamHandler()
    handler.setFormatter(formatter)

    logger = logging.getLogger(name)
    logger.setLevel(logging.DEBUG)
    logger.addHandler(handler)
    return logger
Run Code Online (Sandbox Code Playgroud)

submodule.py

import logging

logger = logging.getLogger('root')
logger.debug('submodule message')
Run Code Online (Sandbox Code Playgroud)

产量

2011-10-01 20:08:40,049 - DEBUG - main - main message
2011-10-01 20:08:40,050 - DEBUG - submodule - submodule message
Run Code Online (Sandbox Code Playgroud)

  • 每个子模块中定义的记录器不是全局参数,有没有办法让它成为一个?我希望当我在submodule.py中定义logger = logging.getLogger('root')时,它将与submodule2.py中logger = logging.getLogger('root')中定义的logger相同. (3认同)
  • 由于你必须在你的 `submodule.py` 中重新定义记录器,那么全局定义不是这样的。同样,可以在从配置文件读取的每个子模块中重新初始化记录器(实际上需要更少的击键)。 (2认同)

Den*_*nis 45

由于我没有找到满意的答案,我想详细阐述一下这个问题的答案,以便对loggingPython的标准库附带的库的工作和意图有所了解.

与OP(原始海报)的方法相反,库清楚地将接口与记录器和记录器本身的配置分开.

处理程序的配置是使用您的库的应用程序开发人员的特权.

这意味着你应该不是创建一个自定义logger类,并通过添加任何配置或任何配置类中的记录.

logging库引入了四个组件:记录器,处理程序,过滤器格式化程序.

  • 记录器公开应用程序代码直接使用的接口.
  • 处理程序将日志记录(由记录器创建)发送到适当的目标.
  • 过滤器提供了更精细的设施,用于确定要输出的日志记录.
  • Formatters指定最终输出中日志记录的布局.

一个常见的项目结构如下所示:

Project/
|-- .../
|   |-- ...
|
|-- project/
|   |-- package/
|   |   |-- __init__.py
|   |   |-- module.py
|   |   
|   |-- __init__.py
|   |-- project.py
|
|-- ...
|-- ...
Run Code Online (Sandbox Code Playgroud)

在代码中(比如在module.py中),您可以引用模块的记录器实例来记录特定级别的事件.

命名记录器时使用的一个好习惯是在每个使用日志记录的模块中使用模块级记录器,命名如下:

logger = logging.getLogger(__name__)
Run Code Online (Sandbox Code Playgroud)

特殊变量__name__是指模块的名称,看起来类似于project.package.module应用程序的代码结构.

module.py(和任何其他类)基本上看起来像这样:

import logging
...
log = logging.getLogger(__name__)

class ModuleClass:
    def do_something(self):
        log.debug('do_something() has been called!')
Run Code Online (Sandbox Code Playgroud)

每个模块中的记录器会将任何事件传播到父记录器,然后父记录器将信息传递给其附加的处理程序!类似于python包/模块结构,父记录器由名称空间使用"点模块名称"确定.这就是为什么用特殊__name__变量初始化记录器是有意义的(在上面的例子中,名称匹配字符串"project.package.module").

全局配置记录器有两个选项:

  • project.py中实例化一个记录器,其名称在本例中__package__等于"project",因此是所有子模块记录器的父记录器.只需要在记录器中添加适当的处理程序和格式化程序.

  • 在执行脚本(如main.py)中使用处理程序和格式化程序设置一个记录器,其名称为最顶层的程序包.

在开发使用日志记录的库时,您应该注意记录库如何使用日志记录 - 例如,使用的记录器的名称.

执行脚本,例如main.py,最终可能看起来像这样:

import logging
from project import App

def setup_logger():
    # create logger
    logger = logging.getLogger('project')
    logger.setLevel(logging.DEBUG)

    # create console handler and set level to debug
    ch = logging.StreamHandler()
    ch.setLevel(level)

    # create formatter
    formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(name)s: %(message)s')

    # add formatter to ch
    ch.setFormatter(formatter)

    # add ch to logger
    logger.addHandler(ch)

if __name__ == '__main__' and __package__ is None:
     setup_logger()
     app = App()
     app.do_some_funny_stuff()
Run Code Online (Sandbox Code Playgroud)

方法调用log.setLevel(...)指定记录器将处理但不一定输出的最低严重性日志消息!它只是意味着只要消息的严重性级别高于(或等于)设置的消息,消息就会传递给处理程序.但是处理程序负责处理日志消息(例如通过打印或存储它).

因此,logging图书馆提供了一种结构化和模块化的方法,只需要根据需要进行开发.

记录文档

  • 感谢您的详细回答。对于 python 3,这里是:https://docs.python.org/3/howto/logging.html#logging-advanced-tutorial (2认同)

Fun*_* LI 13

python 日志记录模块作为全局记录器已经足够好了,您可能只是寻找这个:

主要.py

import logging
logging.basicConfig(level = logging.DEBUG,format = '[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s')
Run Code Online (Sandbox Code Playgroud)

将上面的代码放入您的执行脚本中,然后您可以在项目中的任何位置使用具有相同配置的记录器:

模块.py

import logging
logger = logging.getLogger(__name__)
logger.info('hello world!')
Run Code Online (Sandbox Code Playgroud)

对于更复杂的配置,您可以使用带有日志记录的配置文件logging.conf

logging.config.fileConfig("logging.conf")
Run Code Online (Sandbox Code Playgroud)

  • 我正在记录的答案......感谢有趣的李#dadjokes (3认同)

Amb*_*ber 9

customLogger在日志模块中创建一个实例并将其用作单例 - 只需使用导入的实例,而不是类.