我有一个小的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')

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


当前回答

最好的做法是单独创建一个模块,该模块只有一个方法,我们的任务是为调用方法提供一个记录器处理程序。将该文件保存为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')

其他回答

这些答案中有几个建议在模块的顶部

import logging
logger = logging.getLogger(__name__)

据我所知,这是非常糟糕的做法。原因是文件配置默认情况下将禁用所有现有的记录器。如。

#my_module
import logging

logger = logging.getLogger(__name__)

def foo():
    logger.info('Hi, foo')

class Bar(object):
    def bar(self):
        logger.info('Hi, bar')

在主模块中:

#main
import logging

# load my module - this now configures the logger
import my_module

# This will now disable the logger in my module by default, [see the docs][1] 
logging.config.fileConfig('logging.ini')

my_module.foo()
bar = my_module.Bar()
bar.bar()

现在logging.ini中指定的日志将为空,因为现有的记录器已被fileconfig调用禁用。

虽然这当然是可能的(disable_existing_Loggers=False),但实际上你库的许多客户端不会知道这个行为,也不会接收到你的日志。通过始终调用logging使您的客户更容易。在本地getlog。温馨提示:我是从Victor Lin的网站上了解到这种行为的。

因此,好的做法是总是调用日志记录。在本地getlog。如。

#my_module
import logging

logger = logging.getLogger(__name__)

def foo():
    logging.getLogger(__name__).info('Hi, foo')

class Bar(object):
    def bar(self):
        logging.getLogger(__name__).info('Hi, bar')    

同样,如果你在main中使用fileconfig,设置disable_existing_loggers=False,以防你的库设计人员使用模块级记录器实例。

我总是这样做。

使用一个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")

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

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

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")

@Yarkee的解决方案似乎更好。我想再加一些

class Singleton(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances.keys():
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]


class LoggerManager(object):
    __metaclass__ = Singleton

    _loggers = {}

    def __init__(self, *args, **kwargs):
        pass

    @staticmethod
    def getLogger(name=None):
        if not name:
            logging.basicConfig()
            return logging.getLogger()
        elif name not in LoggerManager._loggers.keys():
            logging.basicConfig()
            LoggerManager._loggers[name] = logging.getLogger(str(name))
        return LoggerManager._loggers[name]    


log=LoggerManager().getLogger("Hello")
log.setLevel(level=logging.DEBUG)

所以LoggerManager可以插入到整个应用程序中。 希望它有意义和价值。

你也可以想出这样的东西!

def get_logger(name=None):
    default = "__app__"
    formatter = logging.Formatter('%(levelname)s: %(asctime)s %(funcName)s(%(lineno)d) -- %(message)s',
                              datefmt='%Y-%m-%d %H:%M:%S')
    log_map = {"__app__": "app.log", "__basic_log__": "file1.log", "__advance_log__": "file2.log"}
    if name:
        logger = logging.getLogger(name)
    else:
        logger = logging.getLogger(default)
    fh = logging.FileHandler(log_map[name])
    fh.setFormatter(formatter)
    logger.addHandler(fh)
    logger.setLevel(logging.DEBUG)
    return logger

现在你可以在同一个模块和整个项目中使用多个记录器,如果上面的定义在一个单独的模块中,并在其他模块中导入日志记录是必需的。

a=get_logger("__app___")
b=get_logger("__basic_log__")
a.info("Starting logging!")
b.debug("Debug Mode")