ConsoleHandler默认不支持setPattern(),因其未继承FileHandler且不暴露SimpleFormatter的pattern字段;必须通过自定义Formatter子类重写format()方法实现格式控制。

ConsoleHandler 默认输出为什么不能直接改 pattern?
ConsoleHandler 本身不支持 setPattern(),它没有继承 FileHandler,也不持有 SimpleFormatter 的 pattern 字段。你调用 handler.setFormatter(new SimpleFormatter()) 后,日志行还是固定格式:java.util.logging.SimpleFormatter.format 硬编码了前缀、时间、级别、类名、方法名等,且 pattern 是私有静态字段,无法外部注入。
替换 Formatter 是唯一可行路径
必须提供自定义 Formatter 子类,重写 format(LogRecord) 方法。关键点在于:
- 不要调用
super.format(record),否则还是走默认逻辑 - 用
record.getLevel()、record.getMessage()、record.getSourceClassName()等取原始数据 - 时间要用
new Date(record.getMillis()),别用record.getInstant()(JDK 9+ 才有,且ConsoleHandler在老版本中常见) - 如果需要 ANSI 颜色,直接拼接
"\u001b[32m"这类转义序列——ConsoleHandler输出到终端时能识别
示例最小可用实现:
public class ColoredConsoleFormatter extends Formatter {
private final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
@Override
public String format(LogRecord record) {
StringBuilder sb = new StringBuilder();
sb.append("[")
.append(sdf.format(new Date(record.getMillis())))
.append(" ")
.append(record.getLevel().getLocalizedName())
.append(" ")
.append(record.getLoggerName())
.append("] ")
.append(formatMessage(record))
.append(System.lineSeparator());
return sb.toString();
}
}
绑定 Formatter 到 ConsoleHandler 的时机很关键
必须在 ConsoleHandler 被任何 logger 使用前完成设置,否则可能被父 logger 的 handler 覆盖或忽略。常见错误操作:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 先获取
Logger.getLogger("myapp"),再配置 handler——此时 logger 可能已从 root 继承了默认 handler - 用
Logger.getAnonymousLogger()测试,但忘了它默认不关联任何 handler - 在 Web 容器(如 Tomcat)里配置,结果被容器自己的 JUL 配置覆盖
稳妥做法是:显式创建 handler,设 formatter,再添加到目标 logger,并禁用父级输出:
Logger logger = Logger.getLogger("myapp");
ConsoleHandler handler = new ConsoleHandler();
handler.setFormatter(new ColoredConsoleFormatter());
logger.addHandler(handler);
logger.setUseParentHandlers(false); // 防止重复输出到 root
注意 System.err 和 System.out 的实际流向
ConsoleHandler 默认写到 System.err,不是 System.out。如果你重定向了 stderr(比如 IDE 控制台把 err 和 out 合并显示),颜色和换行可能表现异常;如果部署到 systemd 或 Docker,stderr 更容易被捕获和结构化。这点常被忽略,导致本地看着正常,线上日志错乱或丢失。
真正要控制输出位置,得自己继承 ConsoleHandler 并重写 publish(),但绝大多数场景没必要——优先确保 formatter 生成的字符串本身干净、可读、兼容管道和日志采集工具。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










