一、快速入门:JUL基础用法
1. 基础日志输出
java
import java.util.logging.Logger;
import java.util.logging.Level;
public class BasicJUL {
// 获取Logger实例(推荐使用类全限定名)
private static final Logger LOG = Logger.getLogger(BasicJUL.class.getName());
public static void main(String[] args) {
// 输出不同级别日志
LOG.info("程序启动"); // 信息级别
LOG.warning("内存不足"); // 警告级别
LOG.severe("致命错误"); // 严重错误
// 带参数的日志
String userName = "张三";
LOG.log(Level.INFO, "用户登录: {0}", userName);
// 记录异常
try {
throw new IOException("文件未找到");
} catch (IOException e) {
LOG.log(Level.SEVERE, "发生IO异常", e);
}
}
}
二、核心配置:logging.properties详解
1. 默认配置问题
-
默认级别:INFO(只输出INFO及以上级别)
-
默认输出:控制台(ConsoleHandler)
-
默认格式:简单文本(无时间戳)
2. 自定义配置文件
ini
# logging.properties
# 全局日志级别
.level= INFO
# 控制台处理器配置
handlers= java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=[%1$tF %1$tT] [%4$-7s] %5$s %n
# 文件处理器配置
handlers= java.util.logging.FileHandler
java.util.logging.FileHandler.pattern = ./logs/app_%u.log
java.util.logging.FileHandler.limit = 10485760 # 10MB
java.util.logging.FileHandler.count = 5
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
3. 加载配置文件
csharp
// 启动时指定配置文件
public static void main(String[] args) throws IOException {
InputStream is = BasicJUL.class.getResourceAsStream("/logging.properties");
LogManager.getLogManager().readConfiguration(is);
// ...其他代码...
}
三、高级玩法:自定义Handler与Filter
1. 自定义邮件报警Handler
less
public class EmailHandler extends Handler {
@Override
public void publish(LogRecord record) {
if (record.getLevel().intValue() >= Level.SEVERE.intValue()) {
// 调用邮件发送API
sendAlertEmail(record.getMessage());
}
}
@Override public void flush() {}
@Override public void close() {}
private void sendAlertEmail(String msg) {
// 实现邮件发送逻辑
}
}
// 注册自定义Handler
LOG.addHandler(new EmailHandler());
2. 日志 过滤器
less
// 只记录包含特定关键字的日志
LOG.setFilter(record -> record.getMessage().contains("支付"));
// 组合过滤条件
LOG.setFilter(record ->
record.getLevel() == Level.SEVERE ||
record.getMessage().startsWith("用户")
);
四、性能优化:避免常见陷阱
1. 参数化日志(避免无效字符串拼接)
less
// 错误写法(即使日志级别关闭也会执行字符串拼接)
LOG.fine("用户信息:" + user.toString());
// 正确写法(使用lambda延迟计算)
LOG.fine(() -> "用户信息:" + user.toString());
2. 异步日志处理
scala
// 自定义异步Handler
public class AsyncHandler extends Handler {
private final Executor executor = Executors.newSingleThreadExecutor();
@Override
public void publish(LogRecord record) {
executor.execute(() -> {
// 转发给其他Handler处理
getHandlers().forEach(h -> h.publish(record));
});
}
// ...其他方法...
}
// 使用方式
Handler asyncHandler = new AsyncHandler();
asyncHandler.addHandler(new ConsoleHandler());
LOG.addHandler(asyncHandler);
五、与其他框架整合
1. 在Spring Boot中使用JUL
ini
# application.properties
# 禁用Spring Boot默认的Logback
logging.config=classpath:logging.properties
logging.level.org.springframework=WARN
logging.level.com.yourpackage=DEBUG
2. 与SLF4J 桥接
xml
<!-- pom.xml -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>2.0.7</version>
</dependency>
arduino
// 启动类配置
public class Main {
static {
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}
}
六、常见问题排雷指南
问题现象 | 解决方案 |
---|---|
日志文件不生成 | 检查文件路径权限,确认FileHandler配置正确 |
日志级别设置不生效 | 确保没有代码动态修改Logger级别 |
日志格式混乱 | 检查SimpleFormatter.format的转义字符 |
性能低下 | 使用异步Handler,避免同步阻塞 |
第三方库日志过多 | 单独设置包级别:com.third.package.level = WARNING |
JUL哲学:
虽然功能不如 Log4j / Logback 强大,但JUL作为Java 标准库 :
-
无需额外依赖,适合简单应用
-
可通过配置满足基本需求
-
与其他日志框架桥接方便
适合场景:
- 小型工具/脚本
- 对日志要求不高的场景
- 需要避免第三方依赖的项目