Python未释放日志文件句柄
我有一个应用程序需要进行多次模拟运行。我想设置一个日志记录机制,把所有的日志记录都放到一个叫做general.log的文件里,而每次模拟运行的日志则放到run00001.log、run00002.log等文件中。为此,我定义了一个叫Run的类。在这个类的__init__()
方法里,我为每次运行的日志添加了一个新的文件句柄。
问题是,这些运行的日志文件句柄从来没有被释放,所以经过几次运行后,系统可用的句柄就用完了,导致程序崩溃。
我设置了一些例程来测试这个问题,具体如下:
主程序
import Model
try:
myrun = Model.Run('20130315150340_run_49295')
ha = raw_input('enter')
myrun.log.info("some info")
except:
traceback.print_exc(file=sys.stdout)
ha = raw_input('enter3')
Run类在模块Model中定义,具体如下:
import logging
class Run(object):
""" Implements the functionality of a single run. """
def __init__(self, runid):
self.logdir="."
self.runid = runid
self.logFile = os.path.join(self.logdir , self.runid + '.log')
self.log = logging.getLogger('Run'+self.runid)
myformatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
myhandler = logging.FileHandler(self.logFile)
myhandler.setLevel(logging.INFO)
myhandler.setFormatter(myformatter)
self.log.addHandler(myhandler)
然后我使用程序进程查看器来跟踪文件句柄。我看到运行日志文件出现了,但从来没有消失。
有没有办法强制释放这些文件句柄呢?
4 个回答
我们可能只想对 FileHandler
进行 .close()
操作,而不对其他的进行关闭,所以可以稍微修改一下被接受的答案,变成这样:
for handler in self.log.handlers:
if isinstance(handler, logging.FileHandler):
handler.close()
另外,对于一些简单的情况,比如我们只是用 logging.basicConfig()
配置了一个日志记录器,可以通过调用 logging.getLogger().handlers
来获取处理器。
你还可以完全关闭日志记录。这样的话,文件句柄就会被释放:
logging.shutdown()
它会关闭所有配置的日志处理器所打开的句柄。
我需要这样做是为了在单元测试结束后能够删除日志文件,而我可以在调用logging.shutdown()
方法后立刻删除它。
你需要在文件处理器上调用 .close()
方法。
当你的 Run
类完成时,记得调用:
handlers = self.log.handlers[:]
for handler in handlers:
self.log.removeHandler(handler)
handler.close()
每当有新的日志信息到来时,文件处理器会自动重新打开之前设置的文件名,所以调用 handler.close()
有时候看起来没什么用。把处理器从日志记录器中移除,可以阻止未来的日志记录发送到它;在上面的代码中,我们先这样做,以避免其他线程在不合适的时候重新打开处理器。
这里还有个答案建议你使用 logging.shutdown()
。不过,logging.shutdown()
实际上只是调用 handler.flush()
和 handler.close()
,我个人不太推荐使用它。因为使用后,日志模块会处于一种状态,让你不能可靠地再次使用 logging.shutdown()
。