我在我的django应用程序中使用python日志记录。如果需要,连接到后端api的类会使用文件处理程序初始化此记录器。每次进行api调用时,类都会被实例化。我已经尝试确保每次都不添加其他处理程序,但
lsof | grep my.log
显示我的日志文件中有越来越多的处理程序,一段时间后我的服务器由于此文件打开限制而失败。
self.logger = logging.getLogger("FPA")
try:
if self.logger.handlers[0].__class__.__name__=="FileHandler":
pass
except Exception, e:
print 'new filehandler added'+str(e)
ch = logging.FileHandler(FPA_LOG_TARGET)
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s - %(pathname)s @ line %(lineno)d")
ch.setFormatter(formatter)
self.logger.setLevel(logging.DEBUG)
self.logger.addHandler(ch)
我意识到这可能不是最好的方法,但到目前为止我还没有在我的实现中发现错误。
答案 0 :(得分:1)
我没有分析是否很长一段时间,但它看起来像是一个并发问题。
每个进程/线程都将自己的文件句柄列表保存到打开的日志文件中。
如何解决?对于多线程代码,请确保存在保留所有句柄的全局字典。对于多进程 - 我担心我没有答案......每个进程都保留它自己的文件句柄,可能将它映射到内存(内存映射文件可能是一个选项),但我不确定这是一个很好的解决方案 - see this remark。
但主要的问题是为什么你需要做这样的事情。
首先,您可以使用logging.conf
文件来初始化所有记录器/处理程序/格式化程序,并在需要时(例如,特定的loger是广泛的,并且您希望将其记录到单独的文件中)添加另一个不同的记录器文件名。如果您要为每个django应用添加一个记录器,通过添加应用的主__init__.py
,这是非常明智的:
import logging
log = logging.getLogger(__name__)
然后在应用程序代码的其余部分(视图,模型等)中导入log
要使用logging.conf
将以下行添加到settings.py:
import os
import logging
DIRNAME = os.path.abspath(os.path.dirname(__file__))
logging.config.fileConfig(os.path.join(DIRNAME, 'logging.conf'))
是的,它是手动的,但您不需要更改代码,只需更改配置文件。
另一种方法(如果你真的希望每个记录器类型有一个文件)是一个单独的进程,它将保持文件打开,接受来自应用程序的连接。记录模块文档有nice example of this method。
最后,但并非最不重要的是,已经有一些很好的解决方案可能会有所帮助。一个,相当不错,是使用django-sentry。此模块可以记录所有异常,404(包括额外的中间件)并捕获所有日志记录(通过包含的日志记录处理程序)。
提供的UI将使您能够搜索所有已记录的消息,并按严重性和日志记录源对其进行过滤。但这不仅限于那些 - 您只需添加自己的模块。