Java日志自定义时间、线程名和类名需通过日志框架的格式化配置实现:Logback用%d、%t、%c等转换词;Log4j2语法类似但更灵活;JUL需继承Formatter重写format()方法。

Java 日志中自定义输出时间、线程名和类名,关键在于配置日志框架的 PatternLayout(Log4j2 / Logback)或 PatternFormatter(JUL),而不是硬编码拼接字符串。不同框架写法略有差异,但核心都是通过占位符控制格式。
Logback(最常用):在 logback.xml 中配置 pattern
Logback 使用 %d、%t、%c 等转换词(conversion word)控制输出:
-
%d{yyyy-MM-dd HH:mm:ss.SSS}→ 格式化时间(支持 Java DateTimeFormatter 语法) -
%t→ 当前线程名(如main、http-nio-8080-exec-1) -
%c{1}→ 类名(短名,如UserService);%c输出全限定名(如com.example.UserService) - 补充常用项:
%L行号、%M方法名、%m日志消息、%n换行
示例 logback.xml 配置:
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%t] %-5level %c{1} - %m%n</pattern>
</encoder>
</appender>
输出效果:14:22:05.123 [main] INFO UserService - 用户登录成功
立即学习“Java免费学习笔记(深入)”;
Log4j2:在 log4j2.xml 或 properties 中设置 PatternLayout
Log4j2 使用类似但更灵活的语法,用 ${...} 或直接写转换器:
-
%d{HH:mm:ss.SSS}→ 时间(同 Logback) -
%t或%T→ 线程名(%t是简写,%T可指定长度) -
%c{1}→ 类名(短名);%C{1}也可用,但性能略低(需栈帧推断)
示例 log4j2.xml 片段:
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5p %c{1} - %m%n"/>
</Console>
注意类名获取的准确性
默认情况下,%c 和 %C 依赖调用栈推断——日志门面(如 SLF4J)调用底层实现时会跳过包装类。若使用了自定义工具类封装 logger.info(),可能导致类名显示为工具类而非真实业务类。
- Logback 推荐用
%class{1}(显式指定调用者类)并配合additivity="false"避免重复输出 - Log4j2 可用
%C{1.}+StackTrace增强,但会影响性能,一般不建议开启 - 最稳妥方式:确保日志语句直接写在业务类中,避免多层静态代理封装
JUL(java.util.logging):需自定义 Formatter
JUL 原生不支持类似 pattern 的简洁配置,需继承 Formatter 并重写 format():
private final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("HH:mm:ss.SSS");
@Override
public String format(LogRecord r) {
String time = dtf.format(r.getInstant().atZone(ZoneId.systemDefault()));
String thread = Thread.currentThread().getName();
String clazz = r.getSourceClassName() != null ?
r.getSourceClassName().substring(r.getSourceClassName().lastIndexOf('.') + 1) : "unknown";
return String.format("%s [%s] %s - %s%n", time, thread, clazz, r.getMessage());
}
}
然后在 logging.properties 中设置:java.util.logging.ConsoleHandler.formatter = com.example.CustomFormatter


















