Log4j 之类的日志框架如何保证日志语句的顺序?

Posted

技术标签:

【中文标题】Log4j 之类的日志框架如何保证日志语句的顺序?【英文标题】:How do logging frameworks like Log4j guarantee log statement ordering? 【发布时间】:2020-11-13 03:31:23 【问题描述】:

这个问题一直困扰着我一段时间,像 Log4j 这样流行的日志框架如何允许日志顺序的并发、异步日志顺序保证没有性能瓶颈,即如果日志语句 L1 是在日志语句L2之前调用,L1保证在L2之前的日志文件中。

我知道 Log4j2 使用环形缓冲区和序列号,但它如何解决问题仍然不直观。

谁能给出一个直观的解释或指向一个资源做同样的事情?

【问题讨论】:

不完全确定在实现中实际使用了什么,但我会使用一个 FIFO-Queue,以及一个工作于该队列的工作人员 但即便如此,考虑到您将同时添加到队列中,您将如何确保将两个事件按生成顺序添加到 FIFO 队列中。 log4j2 documentation 声明:“异步 Logger 在内部使用 Disruptor,一个无锁的线程间通信库,而不是队列,从而提高吞吐量和降低延迟”。您也许可以研究它以查看实现。 我看了看,Disruptor 基本上是我在问题中提到的环形缓冲区。然而 AFAIK,disruptor 基本上是队列的替代品,但问题是如果您有并发提交到队列,您如何保证提交之前创建的队列也会被提交。 【参考方案1】:

这一切都取决于您所说的“记录顺序”。在谈论单个线程时,会保留日志记录顺序,因为每个日志记录调用都会导致写入。

当异步记录每个日志事件时,它会按照接收顺序添加到队列中,并按照先进/先出顺序进行处理,无论它是如何到达那里的。这并不是很有挑战性,因为编写器是单线程的。

但是,如果您谈论的是跨线程的日志记录顺序,则永远无法保证 - 即使是同步日志记录 - 因为它不能保证。线程 1 可以在线程 2 之前开始记录,但线程 2 可以在线程 1 之前的写入中到达同步点。同样,将事件添加到队列时也会发生同样的情况。在 logging 方法中锁定 logging 调用会保持顺序,但几乎没有好处,而且会带来灾难性的性能后果。

在多线程环境中,您完全有可能看到时间戳乱序的日志记录事件,因为线程 1 解析了时间戳,被线程 2 中断,然后线程 2 解析了时间戳并记录了事件。但是,如果您将日志写入 ElasticSearch 之类的东西,您将永远不会注意到,因为它按时间图对它们进行排序。

【讨论】:

以上是关于Log4j 之类的日志框架如何保证日志语句的顺序?的主要内容,如果未能解决你的问题,请参考以下文章

SSM框架下利用log4j日志打印sql语句

mybatis 打印sql日志

如何在struts2+ spring+ ibatis 框架中配置log4j让控制台显示sql语句

多应用中间的日志使用,log4j,log4j2,logback三个日志框架为例

如何使用Log4J在一行中打印日志语句?

大数据必学Java基础(一百零三): log4j日志框架