我想知道 Log4j2 是否在构建时考虑到了这一点,或者在非常高的并发性下是否会出现问题(崩溃 | 丢失日志 | 等)

I would like to know if Log4j2 has been built with that in mind or if things may (crash | lose logs | etc) at very high concurrency

这个问题是针对 log4j 而不是 log4j2 提出的:Is it safe to use the same log file by two different appenders

从技术上讲,您可以在 Log4j2 中创建多个写入同一个文件的附加程序。这似乎运作良好。

这是我的 OS / JDK :

这是一个示例配置(在 yaml 中):

Configuration:
  status: debug

  Appenders:
    RandomAccessFile:
      - name: TestA
        fileName: logs/TEST.log
        PatternLayout:
          Pattern: "%msg%n"
      - name: TestB
        fileName: logs/TEST.log
        PatternLayout:
          Pattern: "%msg%n"

  Loggers:
    Root:
      level: trace
      AppenderRef:
        - ref: TestA
        - ref: TestB

我的Java样本

final Logger root = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
root.trace("!!! Trace World !!!");
root.debug("!!! Debug World !!!");
root.info("!!! Info World  !!!");
root.warn("!!! Warn World  !!!");
root.error("!!! Error World !!!");

我的日志文件 结果:

20150513T112956,819 TRACE "!!! Trace World !!!"
20150513T112956,819 TRACE "!!! Trace World !!!"
20150513T112956,819 DEBUG "!!! Debug World !!!"
20150513T112956,819 DEBUG "!!! Debug World !!!"
20150513T112956,819 INFO  "!!! Info World  !!!"
20150513T112956,819 INFO  "!!! Info World  !!!"
20150513T112956,819 WARN  "!!! Warn World  !!!"
20150513T112956,819 WARN  "!!! Warn World  !!!"
20150513T112956,819 ERROR "!!! Error World !!!"
20150513T112956,819 ERROR "!!! Error World !!!"

我想知道 Log4j2 是否在构建时考虑到了这一点,或者在非常高的并发时是否会出现问题(崩溃 | 丢失日志 | 等)。

更新

我运行这个基准测试没有丢失日志。不过,我不确定这个测试是否能完全解决问题。 :

public class Benchmark {

    private static final int nbThreads = 32;
    private static final int iterations = 10000;
    static List<BenchmarkThread> benchmarkThreadList = new ArrayList<>(nbThreads);
    private static Logger root;

    static {
        System.setProperty("Log4jContextSelector", "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector");
    }

    public static void main(String[] args) throws InterruptedException {

        root = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);


        // Create BenchmarkThreads
        for (int i = 1; i <= nbThreads; i++) {
            benchmarkThreadList.add(new BenchmarkThread("T" + i, iterations));
        }

        root.error("-----------------------------------------------------------");
        root.error("----------------------  WARMUP  ---------------------------");
        root.error("-----------------------------------------------------------");

        // Warmup loggers
        doBenchmark("WARMUP", 100);

        Thread.sleep(100);
        root.error("-----------------------------------------------------------");
        root.error("---------------------  BENCHMARK  -------------------------");
        root.error("-----------------------------------------------------------");

        // Execute Benchmark
        for (int i = 0; i < nbThreads; i++) {
            benchmarkThreadList.get(i).start();
        }

        Thread.sleep(100);
        root.error("-----------------------------------------------------------");
        root.error("----------------------  FINISHED  -------------------------");
        root.error("-----------------------------------------------------------");

    }

    protected static void doBenchmark(String name, int iteration) {
        for (int i = 1; i <= iteration; i++) {
            root.error("{};{}", name, i);
        }
    }


    protected static class BenchmarkThread extends Thread {

        protected final int iteration;
        protected final String name;

        public BenchmarkThread(String name, int iteration) {
            this.name = name;
            this.iteration = iteration;
        }

        @Override
        public void run() {
            Benchmark.doBenchmark(name, iteration);
        }
    }

}

更新: 我没有意识到您已经在使用异步记录器。在那种情况下,这确实是一个 log4j2 问题。 :-)

答案是肯定的,log4j2 尤其是 Async Loggers 在设计时就考虑到了非常高的并发性。多个线程中的多个记录器可以并发记录,并将产生的日志消息放在一个无锁队列中,供后台线程稍后处理。有一个后台线程按顺序调用所有附加程序,因此即使多个附加程序写入同一个文件,也不会丢弃任何消息,并且在写入下一条消息之前完全写入来自每个记录器线程的消息(没有部分写入)。

如果发生崩溃,队列中但尚未刷新到磁盘的消息可能会丢失。这是性能的权衡,所有异步日志记录都是如此。

如果您正在同步记录(例如,不使用异步记录器),那么问题是什么文件 I/O 原子性保证 JVM 和 OS 生成。

上一个答案: 这更像是 JVM/OS 问题而不是 log4j2 问题。换句话说:如果多个线程同时写入同一个文件,生成的文件是否包含所有消息(没有丢失,所有消息都是完整和正确的)? (您可能需要指定您的 JVM 供应商和版本以及 OS 名称和版本。)

如果您正在寻找安全的 log4j2 配置,请考虑使用 Async Loggers。 使用 Async Loggers,所有附加程序都在单个共享后台线程中按顺序调用,因此您可以确定不会发生损坏。此外,您还可以获得不错的性能优势。