Python:如何将不同的进程日志记录到同一个文件?

21

Python的logging库是否提供将两个(或更多)独立的Python进程记录到同一文件中的序列化日志记录?从文档中并不清楚(我已阅读过)。

如果可以,那么在完全不同的机器上呢(共享日志文件存在于可以被两者访问的NFS导出中)。

3个回答

25

不支持同时从多个进程向同一文件写入日志。根据Python的logging cookbook

虽然日志记录是线程安全的,并且在单个进程中从多个线程向单个文件记录日志是受支持的,但不支持从多个进程向单个文件记录日志,因为在Python中没有标准的方法来序列化跨多个进程对单个文件的访问。

之后,该手册建议使用一个单独的套接字服务器进程来处理日志,其他进程将日志消息发送到该进程。在Sending and Receiving logging events across a network部分中有一个可行的示例。


1
个人而言,我会被他们的建议所吸引,并使用套接字服务器实现一个非常小的“日志服务器”,并像食谱中建议的那样记录到该套接字。 - Hayden Crocker
1
避免回答短句和链接,而是尝试包含实际回答问题的内容。这样可以更容易地在SO中搜索信息,并且请记住,链接可能会在将来失效。如果您想添加信息到您的答案中,应该编辑它而不是评论。 - Bakuriu
谢谢你的回答。我怀疑这就是情况。如果我有许多syslog守护程序记录到单个文件,那么情况可能是一样的吗?遗憾的是,要求日志存在于NFS共享上(可以从运行相同代码的许多不同机器访问)。由于我们的要求规定我们不能强加进程需要能够通信的限制(它们可能在不同的网络上),并且我们不能修改NFS共享(因为它需要与任何当前的NFS导出开箱即用)。看起来我将不得不在NFS共享上为每个进程解决1个日志。 - sjbx
1
遗憾的是,由于任何守护进程都将是唯一的进程,因此相同的规则将适用。从本质上讲,必须从单个点控制对该单个文件的访问。可能您可以找到一种基于命名约定合并这些单独的日志文件的好方法? 看看这里:https://dev59.com/hGw15IYBdhLWcg3wYKqo - Hayden Crocker
有这样的运气,可以使用rsyslog或logstash作为服务器部分 :) - Reishin
这基本上是胡扯,因为所有 POSIX 系统都有原子追加到文件的功能。在 Ubuntu 中,如果我记得对的话,默认的原子大小为 4KB,因此如果您有小日志,可以自由地从多个进程以追加模式写入一个文件。 - Andrey Nikishaev

3

解决这个问题的一个糟糕方法是创建一个日志记录进程,该进程在单个线程上侦听套接字,并输出其接收到的任何内容。

关键在于利用套接字队列作为仲裁机制。

#! /usr/bin/env python

import sys
import socket
import argparse

p = argparse.ArgumentParser()
p.add_argument("-p", "--port", help="which port to listen on", type=int)
p.add_argument("-b", "--backlog", help="accept backlog size", type=int)
p.add_argument("-s", "--buffersize", help="recv buffer size", type=int)
args = p.parse_args()

port = args.port if args.port else 1339
backlog = args.backlog if args.backlog else 5
size = args.buffersize if args.buffersize else 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', port))
s.listen(backlog)
print "Listening on port ", port, 'backlog size', backlog, 'buffer size', size, '\n'
while 1:
    try:
        (client, address) = s.accept()
        data = client.recv(size)
        print data
    except:
        client.close()

并且进行测试:

#! /usr/bin/env python

import sys
import socket
import argparse

p = argparse.ArgumentParser()
p.add_argument("-p", "--port", help="send port", action='store', default=1339, type=int)
p.add_argument("text", help="text to send")
args = p.parse_args()

if not args.quit and not args.text:
    p.print_help()
else:
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(('', args.port))
        s.send(args.text)
    except:
        s.close()

然后像这样使用它:
stdbuf -o L ./logger.py -b 10 -s 4096 >>logger.log 2>&1 &

可以使用以下方式监控最近的活动:

tail -f logger.log

任何给定进程的每个日志条目都将被原子地发出。将其添加到标准日志系统中不应该太难。使用套接字意味着多台机器也可以针对托管在专用机器上的单个日志。


0
最简单的方法是使用自定义处理程序进行日志记录,该处理程序将通过队列从子进程传递所有日志到主进程,并在那里记录。例如,在客户端应用程序上工作时,可以使用此方式记录日志,其中有主UI线程和工作线程。
此外,在POSIX系统上,您可以使用追加模式进行日志记录。在4kb范围内,它将是原子性的。

https://dev59.com/bYHba4cB1Zd3GeqPNB9Z#72870952 - Jean Monet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接