我有一个小的python项目,它有以下结构-

Project 
 -- pkg01
   -- test01.py
 -- pkg02
   -- test02.py
 -- logging.conf

我计划使用默认日志记录模块将消息打印到标准输出和日志文件。 要使用日志记录模块,需要进行一些初始化

import logging.config

logging.config.fileConfig('logging.conf')
logger = logging.getLogger('pyApp')

logger.info('testing')

目前,在开始记录消息之前,我在每个模块中执行此初始化。是否可以只在一个地方执行一次初始化,以便通过记录整个项目来重用相同的设置?


当前回答

我总是这样做。

使用一个python文件将我的日志配置为名为'log_conf.py'的单例模式

#-*-coding:utf-8-*-

import logging.config

def singleton(cls):
    instances = {}
    def get_instance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return get_instance()

@singleton
class Logger():
    def __init__(self):
        logging.config.fileConfig('logging.conf')
        self.logr = logging.getLogger('root')

在另一个模块中,只需导入配置。

from log_conf import Logger

Logger.logr.info("Hello World")

这是一种简单有效的单例日志模式。

其他回答

再加入另一种溶液。

在我的模块的init.py中,我有这样的东西:

# mymodule/__init__.py
import logging

def get_module_logger(mod_name):
  logger = logging.getLogger(mod_name)
  handler = logging.StreamHandler()
  formatter = logging.Formatter(
        '%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
  handler.setFormatter(formatter)
  logger.addHandler(handler)
  logger.setLevel(logging.DEBUG)
  return logger

然后在每个模块我需要一个记录器,我做:

# mymodule/foo.py
from [modname] import get_module_logger
logger = get_module_logger(__name__)

当日志丢失时,您可以根据它们来自的模块来区分它们的来源。

最佳实践是,在每个模块中定义一个记录器,如下所示:

import logging
logger = logging.getLogger(__name__)

在模块的顶部附近,然后在模块中的其他代码中执行例如。

logger.debug('My message with %s', 'variable data')

如果你需要在一个模块中细分日志活动,使用例如。

loggerA = logging.getLogger(__name__ + '.A')
loggerB = logging.getLogger(__name__ + '.B')

和log到loggerA和loggerB。

在你的主程序中,执行以下操作:

def main():
    "your program code"

if __name__ == '__main__':
    import logging.config
    logging.config.fileConfig('/path/to/logging.conf')
    main()

or

def main():
    import logging.config
    logging.config.fileConfig('/path/to/logging.conf')
    # your program code

if __name__ == '__main__':
    main()

在这里可以查看来自多个模块的日志记录,在这里可以查看将被其他代码用作库模块的代码的日志记录配置。

Update: When calling fileConfig(), you may want to specify disable_existing_loggers=False if you're using Python 2.6 or later (see the docs for more information). The default value is True for backward compatibility, which causes all existing loggers to be disabled by fileConfig() unless they or their ancestor are explicitly named in the configuration. With the value set to False, existing loggers are left alone. If using Python 2.7/Python 3.2 or later, you may wish to consider the dictConfig() API which is better than fileConfig() as it gives more control over the configuration.

刚接触python,所以我不知道这是否可取,但它对于不重写样板文件非常有效。

你的项目必须有一个init.py,这样它才能作为一个模块加载

# Put this in your module's __init__.py
import logging.config
import sys

# I used this dictionary test, you would put:
# logging.config.fileConfig('logging.conf')
# The "" entry in loggers is the root logger, tutorials always 
# use "root" but I can't get that to work
logging.config.dictConfig({
    "version": 1,
    "formatters": {
        "default": {
            "format": "%(asctime)s %(levelname)s %(name)s %(message)s"
        },
    },
    "handlers": {
        "console": {
            "level": 'DEBUG',
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stdout"
        }
    },
    "loggers": {
        "": {
            "level": "DEBUG",
            "handlers": ["console"]
        }
    }
})

def logger():
    # Get the name from the caller of this function
    return logging.getLogger(sys._getframe(1).f_globals['__name__'])

Sys._getframe(1)的建议来自这里

然后在任何其他文件中使用您的记录器:

from [your module name here] import logger

logger().debug("FOOOOOOOOO!!!")

警告:

你必须将你的文件作为模块运行,否则import [your module]将不起作用: Python -m[你的模块名]。[你的文件名没有。py] 程序入口点的记录器名称将是__main__,但任何使用__name__的解决方案都会有这个问题。

在多个模块中使用一个日志库实例的简单方法是以下解决方案:

base_logger.py

import logging

logger = logging
logger.basicConfig(format='%(asctime)s - %(message)s', level=logging.INFO)

其他文件

from base_logger import logger

if __name__ == '__main__':
    logger.info("This is an info message")

最好的做法是单独创建一个模块,该模块只有一个方法,我们的任务是为调用方法提供一个记录器处理程序。将该文件保存为m_logger.py

import logger, logging

def getlogger():
    # logger
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.DEBUG)
    # create console handler and set level to debug
    #ch = logging.StreamHandler()
    ch = logging.FileHandler(r'log.txt')
    ch.setLevel(logging.DEBUG)
    # create formatter
    formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    # add formatter to ch
    ch.setFormatter(formatter)
    # add ch to logger
    logger.addHandler(ch)
    return logger

现在,只要需要记录器处理程序,就调用getlogger()方法。

from m_logger import getlogger
logger = getlogger()
logger.info('My mssg')