JUL的Logger默认不输出日志,因两级过滤(logger level和handler level)均需≥日志级别,默认均为INFO,故FINE等低级别日志被拦截;须显式设置level并添加配置好的Handler,且调用setUseParentHandlers(false)避免重复输出。

Java标准库里的 Logger 类(来自 java.util.logging,即 JUL)能用,但默认配置下几乎不输出日志——不是代码写错了,是它压根没把日志打到控制台或文件。
为什么 new Logger() 会报错?
Logger 是抽象类,不能直接 new。必须用静态工厂方法获取实例:
-
Logger.getLogger(String name):最常用,name 通常用类全限定名(如"com.example.MyService"),用于区分日志来源 - 名字相同就返回同一个实例,所以别随便传
""或"root"——JUL 里 root logger 是特殊存在,手动创建同名 logger 不等于它 - 首次调用时若 handler 未配置,默认只继承 root logger 的 handler;而 root logger 默认只有一个
ConsoleHandler,但它被设置了Level.INFO以上才输出,DEBUG和TRACE级别直接被拦掉
INFO 以下级别日志不显示的真正原因
不只是 logger 自身 level 设置问题,JUL 是两级过滤:logger level + handler level,两者都得 >= 当前日志级别才会输出。
- 默认 root logger level 是
Level.INFO - 默认
ConsoleHandlerlevel 也是Level.INFO - 所以
logger.fine("debug info")(对应Level.FINE)会被两层同时拒绝 - 修复方式(任选其一):
– 调整 logger 级别:logger.setLevel(Level.ALL)
– 调整 handler 级别:handler.setLevel(Level.ALL)
– 或两者都设(推荐)
如何让日志真正输出到控制台
别依赖“默认”,显式配置 handler 才可靠:
立即学习“Java免费学习笔记(深入)”;
Logger logger = Logger.getLogger(MyClass.class.getName()); logger.setLevel(Level.ALL); ConsoleHandler handler = new ConsoleHandler(); handler.setLevel(Level.ALL); handler.setFormatter(new SimpleFormatter()); // 否则输出纯文本,无时间/级别等元信息 logger.addHandler(handler); // 注意:如果之前有其他 handler(比如 root logger 的),可能重复输出,可先移除: logger.setUseParentHandlers(false);
-
setUseParentHandlers(false)很关键,否则日志可能打印两遍(自己加的 handler + root 的 handler) -
SimpleFormatter输出带时间戳和级别的格式;XMLFormatter输出 XML,一般不用 - JUL 没有内置异步、滚动文件等功能,要写入文件得自己配
FileHandler,且注意路径权限和编码(默认平台编码,中文易乱码)
和 SLF4J / Logback 比,JUL 最容易被忽略的限制
不是功能少,而是设计上“太守规矩”:
- 不能动态修改已注册 handler 的 formatter ——
setFormatter()必须在 handler 添加到 logger 前调用,之后调用无效 - 日志名(name)决定继承链,但无法跨 classloader 隔离;web 应用中多个应用共用 JUL 全局配置时容易互相干扰
- 没有 MDC(Mapped Diagnostic Context),做链路追踪需自行包装
LogRecord或改用桥接方案(如slf4j-jdk14) - 性能上比 Logback 略低,尤其高并发场景下
ConsoleHandler的同步刷写会成瓶颈
用 JUL 不是不行,但得清楚它每一步默认做了什么、又没做什么。很多“日志不输出”问题,其实卡在 handler 级别和 parent handlers 这两个开关上。










