You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为java.util.logging每条日志语句添加自定义上下文字段

给java.util.logging日志添加上下文信息(以俄罗斯方块得分为例)

嘿,针对你想用标准java.util.logging给俄罗斯方块日志加上当前得分这类上下文的需求,我整理了几个实用的方案,全都是基于JDK标准库实现的,不用额外引入依赖:

方案1:ThreadLocal存上下文 + 自定义Formatter(推荐)

这是最灵活的方式,适合需要在多个日志点共享上下文的场景:

第一步:做个上下文存储工具类

先搞个简单的类,用ThreadLocal来存当前游戏的得分,保证线程安全(哪怕以后做多人联机多线程游戏也能兼容):

public class GameContext {
    // 用ThreadLocal存储当前线程的得分
    private static final ThreadLocal<Integer> currentScore = new ThreadLocal<>();

    // 设置当前得分
    public static void setCurrentScore(int score) {
        currentScore.set(score);
    }

    // 获取当前得分
    public static Integer getCurrentScore() {
        return currentScore.get();
    }

    // 线程结束时清理,避免内存泄漏
    public static void clear() {
        currentScore.remove();
    }
}

第二步:自定义日志格式器

继承SimpleFormatter,重写format方法,把得分上下文拼到日志里:

import java.util.logging.LogRecord;
import java.util.logging.SimpleFormatter;

public class GameLogFormatter extends SimpleFormatter {
    @Override
    public String format(LogRecord record) {
        // 从上下文拿得分,没拿到就显示0
        Integer score = GameContext.getCurrentScore();
        String scoreTag = (score != null) ? "[Score: " + score + "]" : "[Score: 0]";
        
        // 先拿到父类生成的原始日志,再把得分标签加在前面
        String originalLog = super.format(record);
        return scoreTag + " " + originalLog;
    }
}

第三步:给Logger配置自定义Formatter

在你的Tetris类里,把默认的Handler换成咱们自定义的,这样所有日志都会带上得分:

package org.tester;

import java.util.logging.ConsoleHandler;
import java.util.logging.Logger;

public class Tetris implements HighScoreGame {
    static Logger logger = Logger.getLogger(Tetris.class.getName());

    static {
        // 先关掉父Logger的Handler,避免重复输出日志
        logger.setUseParentHandlers(false);
        // 创建控制台Handler,设置咱们的自定义Formatter
        ConsoleHandler consoleHandler = new ConsoleHandler();
        consoleHandler.setFormatter(new GameLogFormatter());
        // 把Handler加到Logger上
        logger.addHandler(consoleHandler);
    }

    private int score = 0;

    @Override
    public void addScore(int points) {
        score += points;
        // 更新上下文里的得分
        GameContext.setCurrentScore(score);
        logger.info("Added " + points + " points to score");
    }

    // 比如移动方块的日志
    public void moveBlockDown() {
        // 每次打日志前确保上下文是最新的得分
        GameContext.setCurrentScore(score);
        logger.fine("Moved game block down one row");
    }

    // 游戏结束记得清理上下文
    public void gameOver() {
        logger.info("Game over! Final score recorded");
        GameContext.clear();
    }
}

方案2:直接给LogRecord传上下文参数

如果不想用ThreadLocal,也可以每次打日志的时候把得分作为参数传进去,然后在Formatter里读取:

自定义Formatter读取参数

public class GameLogFormatter extends SimpleFormatter {
    @Override
    public String format(LogRecord record) {
        // 从LogRecord的参数里拿得分
        Integer score = (Integer) record.getParameters()[0];
        String scoreTag = "[Score: " + score + "]";
        String originalLog = super.format(record);
        return scoreTag + " " + originalLog;
    }
}

打日志时传入得分

public void addScore(int points) {
    score += points;
    // 把得分作为第二个参数传给log方法
    logger.log(Level.INFO, "Added " + points + " points", score);
}

这个方式的缺点是每次打日志都要手动传得分,适合上下文不频繁变化的场景。

小提示

  • 如果是多线程场景,一定要记得在任务结束时调用GameContext.clear(),避免ThreadLocal内存泄漏。
  • 也可以通过修改logging.properties配置文件来全局设置自定义Formatter,这样不用在代码里手动配置Handler:
    handlers=java.util.logging.ConsoleHandler
    java.util.logging.ConsoleHandler.formatter=org.tester.GameLogFormatter
    

这样你的每条日志就都会带上当前的得分上下文啦!

内容的提问来源于stack exchange,提问作者Caitlin Rainone

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 07:55:09