Java中如何通过Logger实现不同日志级别记录系统运行信息?

2026-05-03 01:523阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1006个文字,预计阅读时间需要5分钟。

Java中如何通过Logger实现不同日志级别记录系统运行信息?

Java 自带的日志记录器 `java.util.logging.Logger` 默认只输出 `INFO` 及以上级别(即 `WARNING`、`SEVERE`)的消息。默认情况下,`FINE`、`FINER`、`FINEST` 级别的日志会被过滤掉——这并非 bug,而是默认的 `Level` 配置限制。

要记录 `FINE` 及以上级别的日志,并确保日志可以被输出,必须显式设置 `Handler` 的级别,同时确保 `Logger` 本身也允许该级别的日志输出。

常见误区是只调用 logger.setLevel(Level.FINE) 却没改 ConsoleHandler 的级别,结果日志依然不输出。

  • SEVERE:严重错误,应用可能已不可用(如空指针导致核心流程中断)
  • WARNING:潜在问题,但未中断执行(如配置项缺失,使用默认值)
  • INFO:关键业务节点(如“订单创建成功”,“缓存刷新完成”)
  • FINE:常规调试信息(如方法入参、SQL 执行前拼接结果)
  • FINER:更细粒度追踪(如循环内每次迭代的中间状态)
  • FINEST:高频/低价值细节(如网络请求每个 header 的收发)

如何让 FINE 级日志真正打印到控制台

必须同时设置 Logger 实例和它的 Handler(比如 ConsoleHandler)的级别,否则 Handler 会拦截掉低级别日志。

Logger logger = Logger.getLogger("MyApp"); logger.setLevel(Level.ALL); // 允许所有级别通过 Logger ConsoleHandler handler = new ConsoleHandler(); handler.setLevel(Level.ALL); // 关键:Handler 也要放开 handler.setFormatter(new SimpleFormatter()); // 可选,避免 XML 格式干扰阅读 logger.addHandler(handler);

如果使用 IDE 运行,注意部分环境(如 IntelliJ 的 JUnit 模式)会重定向 System.out,导致 ConsoleHandler 不可见——此时建议改用 FileHandler 或切换为 SLF4J + Logback。

立即学习“Java免费学习笔记(深入)”;

log.info() 和 log.log(Level.INFO, ...) 的区别

表面上等价,但参数处理逻辑不同:log.info(String) 是快捷方法,而 log.log(Level.INFO, String, Object) 支持延迟求值和异常堆栈自动附加。

  • log.info("User {0} logged in", userId) 时,若日志被禁用,userId.toString() 不会执行 —— 这是性能优势
  • log.log(Level.WARNING, "DB timeout", ex) 会自动把 ex 的 stack trace 输出在日志末尾;而 log.warning("DB timeout: " + ex) 只打印 toString(),丢失堆栈
  • 不要混用占位符风格和字符串拼接:log.info("id=" + id + ", name=" + name) 总是触发对象转换,无条件消耗 CPU

生产环境为什么不该直接用 JUL(java.util.logging)

JUL 的 Handler 是全局共享的,默认 ConsoleHandlerFileHandler 都是单例,多个 Logger.addHander() 会导致日志重复输出;且配置只能通过 logging.properties 文件或硬编码,无法按包动态调权。

真实项目中,几乎都用桥接方案:

  • 引入 slf4j-jdk14 把 SLF4J 日志转给 JUL(兼容遗留系统)
  • 更常见的是用 slf4j-api + logback-classic,通过 logback.xml 精确控制每个包的日志级别、输出格式、滚动策略
  • Spring Boot 默认集成 Logback,application.properties 中写 logging.level.com.example.service=DEBUG 就生效,比 JUL 的 properties 文件直观得多

如果你正在维护一个老系统且不能引入新依赖,那 JUL 能用,但得小心 Handler 复用和级别穿透问题——这点最容易在多模块共用同一个 Logger 名称时暴露出来。

标签:Java

本文共计1006个文字,预计阅读时间需要5分钟。

Java中如何通过Logger实现不同日志级别记录系统运行信息?

Java 自带的日志记录器 `java.util.logging.Logger` 默认只输出 `INFO` 及以上级别(即 `WARNING`、`SEVERE`)的消息。默认情况下,`FINE`、`FINER`、`FINEST` 级别的日志会被过滤掉——这并非 bug,而是默认的 `Level` 配置限制。

要记录 `FINE` 及以上级别的日志,并确保日志可以被输出,必须显式设置 `Handler` 的级别,同时确保 `Logger` 本身也允许该级别的日志输出。

常见误区是只调用 logger.setLevel(Level.FINE) 却没改 ConsoleHandler 的级别,结果日志依然不输出。

  • SEVERE:严重错误,应用可能已不可用(如空指针导致核心流程中断)
  • WARNING:潜在问题,但未中断执行(如配置项缺失,使用默认值)
  • INFO:关键业务节点(如“订单创建成功”,“缓存刷新完成”)
  • FINE:常规调试信息(如方法入参、SQL 执行前拼接结果)
  • FINER:更细粒度追踪(如循环内每次迭代的中间状态)
  • FINEST:高频/低价值细节(如网络请求每个 header 的收发)

如何让 FINE 级日志真正打印到控制台

必须同时设置 Logger 实例和它的 Handler(比如 ConsoleHandler)的级别,否则 Handler 会拦截掉低级别日志。

Logger logger = Logger.getLogger("MyApp"); logger.setLevel(Level.ALL); // 允许所有级别通过 Logger ConsoleHandler handler = new ConsoleHandler(); handler.setLevel(Level.ALL); // 关键:Handler 也要放开 handler.setFormatter(new SimpleFormatter()); // 可选,避免 XML 格式干扰阅读 logger.addHandler(handler);

如果使用 IDE 运行,注意部分环境(如 IntelliJ 的 JUnit 模式)会重定向 System.out,导致 ConsoleHandler 不可见——此时建议改用 FileHandler 或切换为 SLF4J + Logback。

立即学习“Java免费学习笔记(深入)”;

log.info() 和 log.log(Level.INFO, ...) 的区别

表面上等价,但参数处理逻辑不同:log.info(String) 是快捷方法,而 log.log(Level.INFO, String, Object) 支持延迟求值和异常堆栈自动附加。

  • log.info("User {0} logged in", userId) 时,若日志被禁用,userId.toString() 不会执行 —— 这是性能优势
  • log.log(Level.WARNING, "DB timeout", ex) 会自动把 ex 的 stack trace 输出在日志末尾;而 log.warning("DB timeout: " + ex) 只打印 toString(),丢失堆栈
  • 不要混用占位符风格和字符串拼接:log.info("id=" + id + ", name=" + name) 总是触发对象转换,无条件消耗 CPU

生产环境为什么不该直接用 JUL(java.util.logging)

JUL 的 Handler 是全局共享的,默认 ConsoleHandlerFileHandler 都是单例,多个 Logger.addHander() 会导致日志重复输出;且配置只能通过 logging.properties 文件或硬编码,无法按包动态调权。

真实项目中,几乎都用桥接方案:

  • 引入 slf4j-jdk14 把 SLF4J 日志转给 JUL(兼容遗留系统)
  • 更常见的是用 slf4j-api + logback-classic,通过 logback.xml 精确控制每个包的日志级别、输出格式、滚动策略
  • Spring Boot 默认集成 Logback,application.properties 中写 logging.level.com.example.service=DEBUG 就生效,比 JUL 的 properties 文件直观得多

如果你正在维护一个老系统且不能引入新依赖,那 JUL 能用,但得小心 Handler 复用和级别穿透问题——这点最容易在多模块共用同一个 Logger 名称时暴露出来。

标签:Java