您的位置:首页 >怎么在 Java 中使用 Logger 记录不同级别的系统运行日志
发布于2026-05-03 阅读(0)
扫一扫,手机访问

先明确一个核心概念:Ja va自带的日志系统,其默认行为和我们直观的预期可能不太一样。比如,下面这段描述就点出了一个关键细节:
Ja va Logger默认只输出INFO及以上级别,FINE及更低级别需同时设置Logger和Handler(如ConsoleHandler)的level为ALL才能输出;SEVERE到FINEST共7级,按严重性降序排列,OFF关闭日志、ALL启用全部。
理解了这个前提,我们再来深入聊聊具体怎么用。
很多开发者初次接触ja va.util.logging.Logger时都会遇到一个困惑:明明调用了logger.fine(),为什么控制台一片寂静?这其实不是代码写错了,而是设计如此。JUL的Logger默认只输出INFO及以上级别(包括WARNING和SEVERE),而FINE、FINER、FINEST这些调试级别的日志,在默认配置下直接被过滤掉了。
这里最常见的“坑”就是只设置了Logger的级别,却忘了处理它的Handler。光调用logger.setLevel(Level.FINE)是没用的,必须让负责实际输出的ConsoleHandler也“放行”才行。
那么,这几个级别到底该怎么用?简单来说,可以这样对应:
SEVERE:最高级别,用于记录导致应用功能严重受损或即将终止的错误,比如空指针异常中断了核心业务流程。WARNING:潜在的问题,但程序还能继续运行。例如,某个配置项缺失,系统自动使用了默认值。INFO:记录关键的业务节点信息,比如“用户支付成功”、“订单已创建”、“缓存数据已刷新”。这是生产环境最常关注的级别。FINE:常规的调试信息,适合记录方法入参、SQL执行前的完整语句等。FINER:更细粒度的追踪,比如在循环体内记录每次迭代的中间状态。FINEST:最高频、最琐碎的细节,例如记录网络请求中每一个Header的收发情况,通常只在深度排查问题时开启。想让那些调试日志现身,关键在于“双管齐下”:既要配置Logger本身允许该级别通过,也要确保处理日志的Handler(比如ConsoleHandler)不会在半路把它拦截掉。
来看一段标准的配置代码:
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 IDEA)里以JUnit模式运行测试,有时会发现控制台看不到日志。这是因为测试环境可能重定向了System.out,导致ConsoleHandler的输出“消失”了。遇到这种情况,临时改用FileHandler输出到文件,或者考虑迁移到SLF4J + Logback这类更现代的日志框架,往往是更省心的选择。
立即学习“Ja va免费学习笔记(深入)”;
表面上看,log.info(“msg”)和log.log(Level.INFO, “msg”)效果一样,但底层逻辑有细微差别,而这些差别直接影响着性能和排查问题的便利性。
log.info(“User {0} logged in”, userId)这种带占位符的写法时,如果INFO级别的日志当前被禁用,那么userId.toString()这个方法根本不会执行。这避免了无谓的字符串拼接和对象转换,对性能友好。log.log(Level.WARNING, “DB timeout”, ex)这个方法会自动将异常ex的完整堆栈跟踪信息附加到日志末尾。而如果用log.warning(“DB timeout: ” + ex),打印出来的通常只是异常的toString()信息,宝贵的堆栈细节就丢失了。log.info(“id=” + id + “, name=” + name)。这种字符串拼接无论日志级别是否开启都会立即执行,白白消耗CPU资源。尽管JUL是Ja va标准库的一部分,但在现代生产环境中直接使用它,往往会遇到一些设计上的局限。
首要问题是Handler的全局性。默认的ConsoleHandler和FileHandler几乎是单例模式,如果在多个Logger实例上调用addHandler(),很容易导致同一条日志被重复输出多次。
其次是配置不够灵活。JUL主要依赖logging.properties文件或硬编码来配置,很难实现像“针对某个特定的包或类动态调整日志级别”这样的精细操作。
因此,真实项目里更常见的做法是采用桥接或替代方案:
slf4j-jdk14模块,将SLF4J的API调用桥接到JUL的实现上。slf4j-api作为门面,搭配logback-classic作为实现。通过logback.xml配置文件,可以轻松管理不同包的日志级别、定义丰富的输出格式、设置日志文件的滚动切割策略。application.properties里写一句logging.level.com.example.service=DEBUG,配置即刻生效,体验比JUL的properties文件直观得多。当然,如果你正在维护一个历史包袱很重、无法引入新依赖的老系统,那么JUL依然是可用的。只是需要格外小心前面提到的Handler复用和级别穿透问题,尤其是在多模块共享同一个Logger名称时,这个问题特别容易暴露出来。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
9