如何使用Django中的并发进程登录单个文件而不使用独占锁

时间:2013-07-27 22:12:59

标签: python django logging azure

鉴于正在多个服务器上同时执行的Django应用程序,该应用程序如何记录到单个共享日志文件(在网络共享中),而不保持此文件在独占模式下永久打开?

当您想要利用日志流时,这种情况适用于托管在Windows Azure网站上的Django应用程序。

this sample project上,我尝试使用ConcurrentLogHandler,如下所示:

settings.py中的

'ConcurrentLogHandler':{
    'level': 'DEBUG',
    'class': 'cloghandler.ConcurrentRotatingFileHandler',
    'formatter': 'verbose',
    'filename': os.getenv('LOGFILE', 'django.log')
},
views.py中的

from time import gmtime, strftime
import logging
from django.http import HttpResponse

logger = logging.getLogger(__name__)

def home(request):
    current_time = strftime("%Y-%m-%d %H:%M:%S", gmtime())
    logger.info('home ' + current_time)
    return HttpResponse("Hello from Django! It is now " + current_time + ".\n")

日志已写入,但网站运行时似乎没有刷新文件。此外,如果我尝试使用FTP读取文件,我会收到以下消息:“550进程无法访问该文件,因为它正被另一个进程使用。”

如果我停止应用程序,文件将关闭,我可以读取该文件并查看其中的所有日志。

我假设ConcurrentLogHandler允许对日志文件的共享访问。这个假设是错的吗?是否需要一些额外的配置?还有其他选择吗?

2 个答案:

答案 0 :(得分:3)

另一种方法是将所有Django日志记录发送到队列(例如Redis队列,使用thismultiprocessing.Queue之类的东西)然后单个进程读取队列并写入记录到文件。有更多移动部件,因此这可能适合您的需要,也可能不适合,但它会消除文件争用。有关使用多个进程记录的更多选项,请参阅this post

您当然也可以设置套接字服务器并使用SocketHandler将所有Django进程的日志记录事件发送到写入文件的服务器。 Python文档包含working example这样的服务器。

答案 1 :(得分:2)

可以使用syslog-ng

实现可扩展的纯日志记录方法(如仅使用系统日志记录组件)

syslog-ng是syslog ++,所以它不会破坏任何syslog配置和日志记录,如果你已经有了。在Ubuntu上安装非常简单:

sudo apt-get install syslog-ng

要在Windows上安装,请参阅:http://www.syslog.org/logged/running-syslog-ng-on-windows/

多个django应用程序或多个服务器登录到syslog-ng,它使用UDP或TCP(取决于您的配置)将其发送到中央syslog-ng服务器,该服务器将其记录在该计算机上。您可以使用基本正则表达式来识别syslog-ng中的应用程序并进行相应的路由。

Django日志记录配置

'syslog-verbose': {
    'format': 'myapp %(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
}

'ConcurrentLogHandler':{
    'level': 'DEBUG',
    'class': 'logging.handlers.SysLogHandler',
    'formatter': 'syslog-verbose',
},

请注意添加到格式化程序中的“myapp”字符串,以通过syslog-ng识别应用程序。

您甚至可以配置nginx,apache和其他服务器来登录syslog-ng。例如。对于apache:

CustomLog "| /usr/bin/logger -t 'apache' -u /var/run/apache_access_log.socket" combined

Syslog-ng客户端配置

将此附加到/etc/syslog-ng/syslog-ng.conf的末尾

filter filter_loghostclient {
    program("^myapp$");
};

destination dest_loghostclient {
    tcp("destination_logserver.example.com" port (514));
};

log {
    source(s_all);
    filter(filter_loghostclient);
    destination(dest_loghostclient);
};

source s_apache_access {
    #apache access logs getting written directly to a socket (as described above)
    unix-stream("/var/run/apache_access_log.socket" max-connections(512) keep-alive(yes)); 
};
log{
    source(s_apache_access);
    destination(dest_loghostclient);
};

filter f_apache_err {
    #Apache error logs
    program("apache") and level(err); 
}; 

log{
    source(s_all);
    filter(f_apache_err);
    destination(dest_loghostclient);
};

Syslog-ng聚合器配置

将以下内容附加到destination_logserver.example.com上的syslog-ng配置文件

source src_loghostserver {
    tcp(port(514) keep-alive(yes) max_connections(1000));
};

destination dest_loghostserver {
    file("/var/log/myproject/request_\$R_YEAR\$R_MONTH\$R_DAY.log");
};

log {
    source(src_loghostserver);
    destination(dest_loghostserver);
};