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

Python 如何在Django中使用并发进程登录到单个文件,而不使用独占锁,python,django,logging,azure,Python,Django,Logging,Azure,给定一个Django应用程序在多台服务器上并发执行,该应用程序如何登录到单个共享日志文件(在网络共享中),而不以独占模式永久打开该文件 当您希望利用日志流时,这种情况适用于Windows Azure网站上托管的Django应用程序 在上,我一直在尝试这样使用: 在: 在: 日志已写入,但在网站运行时,文件似乎未刷新。此外,如果我尝试使用FTP读取文件,我会收到以下消息:“550该进程无法访问该文件,因为它正被另一个进程使用。” 如果我停止应用程序,该文件将关闭,我可以读取该文件并查看其中的所有日

给定一个Django应用程序在多台服务器上并发执行,该应用程序如何登录到单个共享日志文件(在网络共享中),而不以独占模式永久打开该文件

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

在上,我一直在尝试这样使用:

在:

在:

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

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


我假设ConcurrentLogHandler允许共享对日志文件的访问。这个假设是错误的吗?是否需要一些额外的配置?是否有替代方法?

替代方法是将所有Django日志发送到队列(例如,使用类似的Redis队列或
多处理.queue
)中,然后单个进程读取队列并将记录写入文件。有更多的活动部件,因此这可能适合您的需要,也可能不适合您的需要,但它将消除文件争用。有关使用多进程日志记录时的更多选项,请参阅


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

可扩展的纯日志方法(如仅使用系统日志组件)可以使用

syslog ng是syslog++,因此它不会破坏任何syslog配置和日志记录(如果您已经有了)。Ubuntu上的安装非常简单:

sudo apt-get install syslog-ng
有关windows上的安装,请参阅:

多个django应用程序或多个服务器登录到syslog ng,syslog ng使用UDP或TCP(取决于您的配置)将其发送到中央syslog ng服务器,中央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客户端配置

'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',
},
将其附加到/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);
};
系统日志ng聚合器配置

'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',
},
在destination_logserver.example.com上的syslog ng config文件中追加以下内容

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);
};