Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在多个模块中使用日志记录_Python_Logging_Config - Fatal编程技术网

Python 在多个模块中使用日志记录

Python 在多个模块中使用日志记录,python,logging,config,Python,Logging,Config,我有一个小型python项目,其结构如下- Project -- pkg01 -- test01.py -- pkg02 -- test02.py -- logging.conf 我计划使用默认的日志模块将消息打印到标准输出和日志文件。 要使用日志模块,需要进行一些初始化- import logging.config logging.config.fileConfig('logging.conf') logger = logging.getLogger('pyApp')

我有一个小型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\u 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")

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

实际上,每个日志记录器都是父级包日志记录器的子级(即
包.subpackage.module
包.subpackage>继承配置)
,因此只需配置根日志记录器即可。这可以通过(您自己的记录器配置)或(设置根记录器)实现。在输入模块中设置日志记录(
\uuuuu main\uuuuuuuuupy
或任何您想要运行的程序,例如
main\u script.py
\uuuuuuuu init\uuuuuuuuuupy
也可以运行)

使用basicConfig:

# package/__main__.py
import logging
import sys

logging.basicConfig(stream=sys.stdout, level=logging.INFO)
使用fileConfig:

# package/__main__.py
import logging
import logging.config

logging.config.fileConfig('logging.conf')
然后使用以下方法创建每个记录器:

# package/submodule.py
# or
# package/subpackage/submodule.py
import logging
log = logging.getLogger(__name__)

log.info("Hello logging!")

有关更多信息,请参阅。

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

import logging
logger = logging.getLogger(__name__)
靠近模块顶部,然后在模块中的其他代码中执行,例如

logger.debug('My message with %s', 'variable data')
如果需要在模块内细分日志记录活动,请使用

loggerA = logging.getLogger(__name__ + '.A')
loggerB = logging.getLogger(__name__ + '.B')
并根据需要登录到
loggerA
loggerB

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

def main():
    "your program code"

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

有关多个模块的日志记录,以及其他代码将用作库模块的代码的日志记录配置,请参阅


更新:调用
fileConfig()
时,如果您使用的是Python 2.6或更高版本,则可能需要指定
禁用现有的\u loggers=False
(有关更多信息,请参阅)。对于向后兼容性,默认值为
True
,这会导致所有现有记录器被
fileConfig()
禁用,除非它们或它们的祖先在配置中显式命名。当值设置为
False
时,现有的记录器将不受影响。如果使用Python 2.7/Python 3.2或更高版本,您可能希望考虑<代码>独占配置()/<代码> API,它比 FielEngI图()/代码>更好,因为它提供了对配置的更多控制。

您也可以提出这样的事情!

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

@亚基的解决方案似乎更好。我想再补充一点-

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可以插入整个应用程序。
希望它有意义和价值。

加入另一个解决方案

在我的模块的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__)
我的理解是,这被认为是非常糟糕的做法。原因是默认情况下,文件配置将禁用所有现有记录器。例如

#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.getLogger,为您的客户提供方便。帽子提示:我是从一个朋友那里了解到这种行为的

因此,最好的做法是始终在本地调用logging.getLogger。例如

#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,以防库设计者使用模块级记录器实例。

有几个答案。我最终得到了一个类似但不同的解决方案,这对我来说是有意义的,也许对你来说也是有意义的。 我的主要目标是能够按级别将日志传递给处理程序(将调试级别的日志传递给控制台,将警告和更高级别的日志传递给文件):

创建了一个名为logger.py的漂亮的util文件:

import logging

def get_logger(name):
    return logging.getLogger("flask.app." + name)
flask.app是flask中的硬编码值。应用程序记录器始终以flask.app作为其模块名称

现在,在每个模块中,我都可以在以下模式下使用它:

from logger import get_logger
logger = get_logger(__name__)

logger.info("new log")

这将以最小的工作量为“app.flask.MODULE_NAME”创建一个新日志。

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

python新手,所以我不知道这是否可取,但它非常适合不重新编写样板文件

项目必须具有init.py,才能作为模块加载

#将其放入模块的uuu init.py中
导入logging.config
导入系统
#我用了这个字典测试,你会说:
#logging.config.fileConfig('logging.conf')
#loggers中的“”条目是根记录器,教程始终为
#使用“根”,但我不能让它工作
logging.config.dictConfig({
“版本”:1,
“格式化程序”:{
“默认值”:{
“格式”:“%(asctime)s%(levelname)s%(name)s%(消息)s”
},
},
“处理程序”:{
“控制台”:{
“级别”:“调试”,
“类”:“logging.StreamHandler”,
“流”:ext://sys.stdout"
}
},
“伐木工人”:{
"": {
“级别”:“调试”,
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
from m_logger import getlogger
logger = getlogger()
logger.info('My mssg')
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")