Django多进程日志文件问题
最近使用Django做一个项目。在部署的时候发现日志文件不能滚动(我使用的是RotatingFileHandler),只有一个日志文件。
查看Log发现一个错误消息:PermissionError: [WinError 32] 另一个程序正在使用此文件
。
因为我有一些进程需要使用Django的模型层来操作数据库。所以再这些单独的进程中引入了Django:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
import django
django.setup()
估计这就是主要原因,在使用Django时,Django本身就会使用setting中的log配置来初始化日志模块。而我正好使用的是基于文件的Handler,所以多个进程启动后,都会按照这个方式来初始化日志模块,导致多个进程都在引用此日志文件。在日志文件滚动时,是需要把当前日志文件重命名为xxx.1或者xxx.2。但是由于其他进程也在使用此文件,所以不能修改文件名。
后来再网上查python的多进程日志文件的滚动问题,发现大家都有类似问题。看来这是python自身的一个常见问题,但是还没有什么标准的解决方法,有的是采用多进程共享queue的方式,多个进程把日志往queue中写,然后一个线程负责把queue中的日志消息往文件中写。但多进程共享queue在linux上和windows上表现还有差异,真是越来越烦。具体讨论请参考这个文章:
https://stackoverflow.com/questions/641420/how-should-i-log-while-using-multiprocessing-in-python/894284
代码如下:
import logging
import multiprocessing
import threading
import time
from logging.handlers import RotatingFileHandler
class MultiProcessingLogHandler(logging.Handler):
def __init__(self, filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False):
logging.Handler.__init__(self)
self._handler = RotatingFileHandler(filename, mode, maxBytes, backupCount, encoding, delay)
self.queue = multiprocessing.Queue(-1)
t = threading.Thread(target=self.receive)
t.daemon = True
t.start()
def setFormatter(self, fmt):
logging.Handler.setFormatter(self, fmt)
self._handler.setFormatter(fmt)
def receive(self):
while True:
try:
record = self.queue.get()
self._handler.emit(record)
except (KeyboardInterrupt, SystemExit):
raise
except EOFError:
break
except:
traceback.print_exc(file=sys.stderr)
def send(self, s):
self.queue.put_nowait(s)
def _format_record(self, record):
# ensure that exc_info and args
# have been stringified. Removes any chance of
# unpickleable things inside and possibly reduces
# message size sent over the pipe
if record.args:
record.msg = record.msg % record.args
record.args =