向每个 JUL 日志语句添加新字段

Add new field to every JUL log statement

现在我有一个使用标准 java.util.logging 包和 SimpleFormatter 编写日志的应用程序。我想知道是否有办法将某种 "context" 字段添加到 every 日志语句。

我想要的是这样的。假设我有一个俄罗斯方块游戏,它一直在记录移动,我希望它在每个日志语句上写下当前分数:

package org.tester;

import java.util.logging.Logger;

public class Tetris implements HighScoreGame {
    static Logger logger = Logger.getLogger("org.tester.Tetris");
    int score;

    void horizontalMove(Move move) {
        logger.info("Going sideways: " + move.direction);
        moveTarget();
    }

    void verticalMove() {
        logger.info("Falling...");
        if(landed()) {
          updateScore();
          logger.info("Done falling");
        } else {
          logger.info("Falling again in 5s")
        }
    }
}

我可以将该字段附加到消息中。

logger.info("Score:" + score + " Falling...");

我不想这样做,因为我必须检查并编辑每条日志语句,而实际应用程序相当大。它还会阻止我使用 Formatter 配置日志条目。

我想我可以扩展 SimpleFormatter 和 Logger,但看起来类似的东西应该已经存在了。

我也意识到 JUL 可能太原始而不能做我想做的事情,所以切换到另一个日志记录框架(如 Log4j2)可能是正确的解决方案。 Log4j 特别有 Mapped Diagnostic Contexts,这可能是我需要的,除了它是按线程而不是按记录器。

最好的方法是什么?

JDK 日志记录设置为只包含您需要的所有内容作为日志参数。但是,您可以使用一些技巧,但您必须决定要将此上下文放置在何处。

如果您只想让呈现的输出显示分数,则子类化 SimpleFormatter 并重写 format 方法以在分数前面添加。只要您的子类引用了 Tetris 对象,您的自定义格式化程序就会生成输出。首选此方法,但您将无法在过滤时检查此方法。

另一种选择是创建生成日志记录的自定义 filter that modifies the current message by prepending the score and returning true. Then install the filter on the handler in use or install it on every logger。这里的一个问题是您应该检测 LogRecord 是否已被更改以确保您不会重复更改消息。