从多个线程进行 Java 日志记录的最佳实践?

2022-09-01 10:14:55

我希望有一个由管理数据的多个任务生成的诊断日志。这些任务可能位于多个线程中。每个任务都需要将一个元素(可能带有子元素)写入日志;上车,快出。如果这是一个单任务的情况,我会使用XMLStreamWriter,因为它似乎是简单性/功能的最佳匹配,而不必在内存中保存膨胀的XML文档。

但这不是一个单一任务的情况,我不确定如何最好地确保这是“线程安全”,其中“threadsafe”在此应用程序中意味着每个日志元素都应该正确和连续地写入日志(一个接一个,不以任何方式交错)。

有什么建议吗?我有一个模糊的直觉,即要走的方法是使用日志元素队列(每个元素都可以快速生成:我的应用程序正忙于做对性能敏感的实际工作),并且有一个单独的线程来处理日志元素并将其发送到文件,以便日志记录不会中断生产者。

日志记录不一定是 XML,但我确实希望它是结构化的和机器可读的。

编辑:我把“threadsafe”放在引号里。Log4j似乎是显而易见的选择(对我来说是新的,但对社区来说却是旧的),为什么要重新发明轮子......


答案 1

使用日志记录框架,如 Log4j


答案 2

我认为你走错了路。你说“线程安全”,但你实际上意味着“序列化”。线程安全意味着一个线程不会干扰来自其他线程的数据。大多数情况下,线程问题已事先解决,您不必担心只是为了记录而烦恼。例如,如果您编写:

myVariableSum = 0 + myVariable;
//here comes other thread - Not very likely!
logger.info("Log some INFO; myVariable has value" + myVariable.toString());

您必须确保从执行计算(第一行)的那一刻起,但在调用日志记录方法之前,myVariable 尚未被其他线程更改。如果发生这种情况,您将记录未用于执行操作的脏值,但记录由其他线程分配的值。这通常得到照顾;例如,本地(方法级别)变量不能被其他线程更改。无论如何,如果您在记录时必须担心这一点,那么99%的程序已经存在严重的线程问题。
所有主要的日志记录框架本身都是“线程安全的”,这意味着它们可以部署在多线程环境中,并且不会在内部显示类似于上述问题。
让跟踪按其发生顺序出现在日志中实际上通常称为调用的“序列化”。序列化日志写入将是任何多线程应用的主要性能瓶颈。如果使用日志记录框架(如 log4j),则来自所有线程的跟踪将或多或少地按顺序显示在单个位置。但是,一列通常是线程名称,因此您可以轻松地按线程过滤日志数据;每个线程将按时间顺序记录其数据。查看此链接:http://logging.apache.org/log4j/1.2/faq.html#1.7
最后,如果序列化日志写入是您真正需要的,那么您可以使用某种结构,例如java.util.concurrent.BlockingQueue来路由消息。