Skip to content

日志级别:什么时候记什么

日志级别是日志系统的核心概念。选对了级别,信息不冗余又不遗漏;选错了,要么告警满天飞,要么出了问题找不到原因。

五个级别

从低到高:

级别数字含义什么时候用
TRACE0最详细极度详细的执行路径,链路追踪
DEBUG1调试信息开发调试,生产环境通常关闭
INFO2一般信息正常业务流程的关键节点
WARN3警告潜在问题,但不影响功能
ERROR4错误影响功能,已发生的异常

低级别包含高级别:设为 INFO 后,DEBUG 和 TRACE 不输出;设为 ERROR 后,只有 ERROR 输出。

每个级别该记什么

ERROR:程序出问题了

java
// ✅ 记录业务异常
try {
    userRepository.save(user);
} catch (Exception e) {
    log.error("保存用户失败: userId={}", user.getId(), e);
    throw e; // 不要吞掉异常
}

// ✅ 记录无法恢复的错误
log.error("无法连接到数据库,程序即将退出", e);

WARN:值得关注但不紧急

java
// ✅ 重试次数多
if (retryCount > 3) {
    log.warn("重试 {} 次后成功,可能存在网络问题", retryCount);
}

// ✅ 资源接近上限
if (connectionPool.getActiveCount() > 80) {
    log.warn("连接池活跃连接数: {},接近上限: {}",
        connectionPool.getActiveCount(),
        connectionPool.getMaxSize());
}

// ✅ 配置使用了默认值
if (StringUtils.isBlank(config.getTimeout())) {
    log.warn("未配置超时时间,使用默认值: 3000ms");
}

INFO:业务里程碑

java
// ✅ 系统启动
log.info("Application started in {}ms", stopwatch.elapsedMillis());

// ✅ 业务流程关键节点
log.info("用户注册成功 | userId={} | email={}", user.getId(), email);

// ✅ 定时任务执行
log.info("数据同步任务开始 | records={}", records.size());

DEBUG:开发时用

java
// ✅ 方法入参(DEBUG 级别,生产不输出)
log.debug("调用外部API | url={} | params={}", url, params);

// ✅ 返回值
log.debug("外部API返回 | status={} | body={}", status, body);

// ✅ 循环中的状态(用采样减少日志量)
if (log.isDebugEnabled() && loopCount % 1000 == 0) {
    log.debug("处理进度 | count={}", loopCount);
}

生产环境建议

环境建议级别说明
开发DEBUG看到所有信息
测试INFO看到正常流程
生产INFO/WARN只看到问题和关键节点

生产环境开 DEBUG 级别的代价:日志量暴增,磁盘飞快写满,查询变慢。所以除非排查问题临时开启,DEBUG 在生产通常是关闭的。

动态调整日志级别

不需要重启应用,通过 JMX 或配置中心动态调整:

java
// JMX 方式
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
Logger logger = context.getLogger("com.example");
logger.setLevel(Level.DEBUG);

总结

写日志时先问自己:这条日志是给谁看的?给运维看 ERROR,给开发者看 DEBUG,给自己排查问题时临时打开看。

级别选对了,告警才有效;日志才有用。

基于 VitePress 构建