- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试在多处理服务器中实现日志记录。根据文档,“不支持从多个进程记录到单个文件”。我创建了一个小程序来检查这个语句:
import logging
import multiprocessing
import os
log = logging.getLogger()
def setup_logger():
formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s: %(message)s')
fileHandler = logging.FileHandler('test.log')
fileHandler.setFormatter(formatter)
log.setLevel(logging.DEBUG)
log.addHandler(fileHandler)
def write_log_entries(identifier, start_event):
start_event.wait()
for i in range(100):
s = ''.join(str(identifier) for k in range(30))
log.info('[{}, {}] --- {}'.format(os.getpid(), identifier, s))
if __name__ == '__main__':
setup_logger()
procs = []
start_event = multiprocessing.Event()
for i in range(100, 300):
p = multiprocessing.Process(target=write_log_entries, args=(i, start_event))
procs.append(p)
for p in procs:
p.start()
start_event.set()
for p in procs:
p.join()
执行完上面的代码后,我希望在“test.log”中看到一团糟,但一切似乎都很好(当然除了时间戳,它们不是按顺序排列的)。
谁能解释为什么多个进程同时写入日志文件时日志条目不重叠?在这种情况下,log.info() 可以被认为是原子的吗?
最佳答案
简短回答:内核锁定对write
的单次调用,所以只要消息很小就没问题,所以它们会在单次write
中刷新,这个 write
成功地一次写完了所有东西。没有普遍保证是这种情况,这就是为什么文档不 promise 这会起作用的原因。
长答案:每次调用 log.info
都会刷新日志输出。这是必要的,否则您将无法在文件中看到最新的日志条目。在 Python/libc 级别,flush 被实现为对 write(2) 系统调用的调用,它被调用以写出文件缓冲区的内容,如果有的话。在您的情况下,缓冲区内容是您的日志消息。因此,Python 或 libc,取决于正在使用的文件,最终会调用操作系统调用,例如:
write(fd, buf, buflen);
...其中 fd
是日志文件的系统级文件描述符,buf
是缓冲写入的内存,buflen
是消息的长度。 (如果你在 Linux 上使用 strace
等工具跟踪你的 Python 进程,你可以看到这些调用。) write
返回成功写入的字符数,内核不会将这些字符与文件同一区域中的其他写入交错。如果文件以 O_APPEND 模式打开,写入甚至可以保证在文件末尾,至少在 Unix 上是这样。所以,如果 buflen
很小,就像正常日志消息一样,一切都很好。但至少有两件事可能会出错。
首先,无法保证所有buflen
都将在一次write
中写出。 write
可以被信号中断,fd
可以指向接受固定大小写入的设备,或者您的日志消息可能大到内核无法接受它在一个 block 中。通常,这不是问题——正确编写的 write
总是作为循环实现的。但在您的情况下,这将是一场灾难,因为对 write
的不同调用会与其他进程交错。
其次,如果您的日志消息足够大以至于无法放入 stdio 缓冲区(8K 左右),那么它将在到达内核之前被分成 block 。在记录回溯或将日志格式化为 XML 等详细格式时,很容易发生这种情况。
关于Python multiprocessing+logging.FileHandler,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12238848/
我尝试添加、删除 FileHandler,但不起作用。此外,在现有 FileHandler 中更改 (URL) 后,该 url 仍然指向旧 URL。现有的 FileHandler 工作正常,但没有选择
我正在尝试禁用日志轮转,以供文件处理程序使用, FileHandler fh = new FileHandler ( "path" + "run.log", 1000000, 1, false
我了解当达到特定大小时 Java FileHandler 如何滚动到下一个日志文件。我想要的有点不同。我想使用 FileHandler 在程序启动时使用序列中最后写入时间最早的日志文件。 例如,如果我
我正在使用jdk日志记录,并且我在logging.properties中有以下内容: handlers= java.util.logging.FileHandler .level= INFO java
我想在线程完成或强制完成后关闭所有 FileHandler。 我创建了一个 closeLogger 函数,但它似乎没有被调用 因为我看到文件仍然锁定在文件夹中。 有什么问题? 在eclipse中强行终
我有以下代码: func syncShellExec(path: String, args: [String] = []) { let process = Process
我正在尝试使用 fs.open 和 FileHandle 在 Node 中逐字节读取二进制文件。使用 FileHandle.read(buffer, offset, length, position)
我正在使用 Python 日志记录包,我需要记录两种类型的消息: 仅应登录到标准输出的消息 应该只记录到文件中的消息。 但是我无法实现它。这是我的代码: import logging
假设我有一个 4GB 的文件需要处理,在 Perl 中有没有一种方法可以像数组一样引用文件句柄,而无需将其复制到实际的数组/内存中? 类似于: open (LOG, "less file.txt |"
我需要为 websphere 应用程序服务器 9 上安装和运行的每个应用程序生成一个日志文件。我使用 JUL 来生成日志文件。我的解决方案是创建一个继承自 FileHandler 的特定类,并通过配置
我有一个看起来像这样的代码: let fileName = "name.txt" let fileURL = URL(fileURLWithPath: NSTemporaryDirectory()).
我部署了一个servlet。我对生成的日志文件有点困惑。特别是我不知道该看哪一个。 使用相同的数据生成了多个。 我正在使用以下代码来初始化我的文件处理程序。 Logger logger = Logge
我不明白为什么 tell() 函数在这种情况下不起作用。让我们创建一个包含字符串“1\n2\n3\n4\n”的文件: f=open('test.tmp','w') f.write('1\n2\n3\n
我有一个日志配置文件: logger_config.yml version: 1 formatters: simple: format: '%(asctime)s - %(levelnam
我正在尝试将所有过度使用的打印更改为日志记录。*主要是因为我想要一个日志文件。 logger = logging.getLogger(__name__) formatter = logging.For
Java 日志记录配置文件让我可以定义命名记录器的属性,例如 name.heikoseeberger.heikotron.level = FINE name.heikoseeberger.heikot
我正在创建一个允许循环访问文件的 java.util.logging.FileHandler。当我的应用程序的多个实例运行时,将为应用程序的每个实例创建一个新的日志文件。我需要知道应用程序正在使用什么
我正在考虑使用 Java 日志记录和 FileHandler 在 J2EE 网络应用程序中记录业务事件。 我想知道这是否会导致性能瓶颈,因为许多日志记录将写入一个文件。 您的经验和意见是什么? 使用
我正在尝试使用 Pipe的 fileHandleForReading的 readabilityHandler阅读 standardOutput和 standardError的 Process .然而,
我正在尝试在多处理服务器中实现日志记录。根据文档,“不支持从多个进程记录到单个文件”。我创建了一个小程序来检查这个语句: import logging import multiprocessing i
我是一名优秀的程序员,十分优秀!