python重复输出_使用Python日志记录模块时重复日志输出

使用Python日志记录模块时重复日志输出

我正在使用python logger。 以下是我的代码:

import os

import time

import datetime

import logging

class Logger :

def myLogger(self):

logger = logging.getLogger('ProvisioningPython')

logger.setLevel(logging.DEBUG)

now = datetime.datetime.now()

handler=logging.FileHandler('/root/credentials/Logs/ProvisioningPython'+ now.strftime("%Y-%m-%d") +'.log')

formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')

handler.setFormatter(formatter)

logger.addHandler(handler)

return logger

我遇到的问题是我在每个logger.info调用的日志文件中都有多个条目。 我怎么解决这个问题?

user865438 asked 2019-09-18T07:38:21Z

14个解决方案

73 votes

logging.getLogger()已经是单身人士了。(文档)

问题是,每次调用myLogger()时,它都会向实例添加另一个处理程序,从而导致重复日志。

也许是这样的?

import os

import time

import datetime

import logging

loggers = {}

def myLogger(name):

global loggers

if loggers.get(name):

return loggers.get(name)

else:

logger = logging.getLogger(name)

logger.setLevel(logging.DEBUG)

now = datetime.datetime.now()

handler = logging.FileHandler(

'/root/credentials/Logs/ProvisioningPython'

+ now.strftime("%Y-%m-%d")

+ '.log')

formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')

handler.setFormatter(formatter)

logger.addHandler(handler)

loggers[name] = logger

return logger

Werner Smit answered 2019-09-18T07:38:43Z

39 votes

import datetime

import logging

class Logger :

def myLogger(self):

logger=logging.getLogger('ProvisioningPython')

if not len(logger.handlers):

logger.setLevel(logging.DEBUG)

now = datetime.datetime.now()

handler=logging.FileHandler('/root/credentials/Logs/ProvisioningPython'+ now.strftime("%Y-%m-%d") +'.log')

formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')

handler.setFormatter(formatter)

logger.addHandler(handler)

return logger

为我做了伎俩

使用python 2.7

Guillaume Cisco answered 2019-09-18T07:39:14Z

34 votes

从Python 3.2开始,您只需检查处理程序是否已存在,如果存在,请在添加新处理程序之前清除它们。 调试时,这非常方便,代码包括记录器初始化

if (logger.hasHandlers()):

logger.handlers.clear()

logger.addHandler(handler)

rm957377 answered 2019-09-18T07:39:38Z

9 votes

您不止一次致电StreamHandler(sys.stderr)。 存储它返回某处的logger实例并重用它。

另请注意,如果在添加任何处理程序之前进行日志记录,则将创建默认值StreamHandler(sys.stderr)。

Matt Joiner answered 2019-09-18T07:40:09Z

4 votes

记录器的实现已经是单例。

对logging.getLogger('someLogger')的多次调用返回一个引用   到同一个记录器对象。 不仅在同一个地方也是如此   模块,但也可以跨模块,只要它在同一个Python中   翻译过程。 引用同一个对象是正确的;   此外,应用程序代码可以定义和配置父代   记录器在一个模块中并创建(但不配置)子记录器   一个单独的模块,所有对孩子的记录器调用都将传递给   父母。 这是一个主要模块

来源 - 使用登录多个模块

所以你应该利用它的方式是 -

假设我们已经在主模块中创建并配置了一个名为“main_logger”的记录器(它只是配置记录器,不会返回任何内容)。

# get the logger instance

logger = logging.getLogger("main_logger")

# configuration follows

...

现在在子模块中,如果我们在命名层次结构'main_logger.sub_module_logger'之后创建子记录器,我们不需要在子模块中配置它。 只需在命名层次结构后创建记录器就足够了。

# get the logger instance

logger = logging.getLogger("main_logger.sub_module_logger")

# no configuration needed

# it inherits the configuration from the parent logger

...

它也不会添加重复的处理程序。

请看这个问题,以获得更详细的答案。

narayan answered 2019-09-18T07:41:22Z

3 votes

您的记录器应该像单身人士一样工作。 你不应该多次创建它。以下是它的外观示例:

import os

import time

import datetime

import logging

class Logger :

logger = None

def myLogger(self):

if None == self.logger:

self.logger=logging.getLogger('ProvisioningPython')

self.logger.setLevel(logging.DEBUG)

now = datetime.datetime.now()

handler=logging.FileHandler('ProvisioningPython'+ now.strftime("%Y-%m-%d") +'.log')

formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')

handler.setFormatter(formatter)

self.logger.addHandler(handler)

return self.logger

s = Logger()

m = s.myLogger()

m2 = s.myLogger()

m.info("Info1")

m2.info("info2")

Zuljin answered 2019-09-18T07:41:46Z

2 votes

这是@ rm957377答案的补充,但解释了为什么会发生这种情况。 当您在AWS中运行lambda函数时,它们会在一个包含多个调用的包装实例中调用您的函数。 这意味着,如果在函数代码中调用addHandler(),则每次运行函数时,它将继续向日志单例添加重复处理程序。 记录单例通过多次调用lambda函数持续存在。

要解决此问题,您可以在设置之前清除处理程序:

logging.getLogger().handlers.clear()

logging.getLogger().addHandler(...)

Chad Befus answered 2019-09-18T07:42:18Z

1 votes

当您通过importlib.reload重新加载模块时,也可能发生双重(或三重或...... - 基于重新加载次数)记录器输出(出于与接受的答案中所述相同的原因)。 我正在添加这个答案只是为了将来的参考,因为我花了一段时间才弄清楚为什么我的输出是dupli(triple)cated。

rkuska answered 2019-09-18T07:42:43Z

0 votes

一个简单的解决方法就像

logger.handlers[:] = [handler]

这样您就可以避免将新处理程序附加到基础列表“处理程序”。

aihex answered 2019-09-18T07:43:14Z

0 votes

您可以获取特定记录器的所有处理程序列表,因此您可以执行此类操作

logger = logging.getLogger(logger_name)

handler_installed = False

for handler in logger:

# Here your condition to check for handler presence

if isinstance(handler, logging.FileHandler) and handler.baseFilename == log_filename:

handler_installed = True

break

if not handler_installed:

logger.addHandler(your_handler)

在上面的示例中,我们检查指定文件的处理程序是否已挂接到记录器,但是有权访问所有处理程序的列表,这使您能够决定应该添加另一个处理程序的标准。

Most Wanted answered 2019-09-18T07:43:46Z

0 votes

今天有这个问题。 由于我的函数是@staticmethod,上面的建议用random()解决了。

看起来像:

import random

logger = logging.getLogger('ProvisioningPython.{}'.format(random.random()))

Pacman answered 2019-09-18T07:44:16Z

0 votes

大多数情况下,当发生这种情况时,只需要每个模块只调用一次logger.getLogger()。 如果你有像我这样的多个类,我可以像这样调用它:

LOGGER = logger.getLogger(__name__)

class MyClass1:

log = LOGGER

def __init__(self):

self.log.debug('class 1 initialized')

class MyClass2:

log = LOGGER

def __init__(self):

self.log.debug('class 2 initialized')

然后两者都将拥有自己的完整包名称和记录方法。

Harlin answered 2019-09-18T07:44:48Z

0 votes

我已经使用logger作为Singleton并检查了logger.propagate = False,但仍然有重复:这是格式化的输出,然后是未格式化的。

解决我的情况:logger.propagate = False

相信这个答案和文档。

Mr. B. answered 2019-09-18T07:45:27Z

-1 votes

from logging.handlers import RotatingFileHandler

import logging

import datetime

# stores all the existing loggers

loggers = {}

def get_logger(name):

# if a logger exists, return that logger, else create a new one

global loggers

if name in loggers.keys():

return loggers[name]

else:

logger = logging.getLogger(name)

logger.setLevel(logging.DEBUG)

now = datetime.datetime.now()

handler = logging.FileHandler(

'path_of_your_log_file'

+ now.strftime("%Y-%m-%d")

+ '.log')

formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')

handler.setFormatter(formatter)

logger.addHandler(handler)

loggers.update(dict(name=logger))

return logger

Avinash Kumar answered 2019-09-18T07:45:45Z

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值