你有没有遇到过这种情况:线上系统突然崩了,用户疯狂投诉,你打开代码一顿猛查,却连问题出在哪都找不到?最后只能靠猜,一行行“打桩”输出信息,折腾大半天,问题没解决,头发先掉了一把。
其实啊,这种情况在开发圈里太常见了。不是技术不行,而是很多人压根没把日志记录当回事。你说它重要吧,几乎每个程序员都懂;可真到写代码的时候,该省的省,该漏的漏,出了问题又抓瞎。
今天咱们就来聊聊,日志这事儿,到底怎么才能做好。

程序员导航
优网导航旗下整合全网优质开发资源,一站式IT编程学习与工具大全网站
日志不是“锦上添花”,而是“救命稻草”
文章里讲了个真实案例:一个同事小李,项目出错后完全没法定位问题。为啥?因为他平时写代码,日志就靠 System.out.println()
随便打几个字,根本不成体系。结果一出问题,就像在黑夜里摸路,啥也看不见。
你想想,现在的项目动辄几万行代码,模块嵌套复杂,没有清晰的日志,排查问题真的就是“大海捞针”。日志,其实就是你系统的“行车记录仪”,关键时刻能帮你回溯全过程,快速定位“车祸”原因。
别再用 System.out.println()
了!
很多人图省事,调试时直接用 System.out.println()
输出信息。看着方便,实则隐患巨大。
首先,它是同步I/O操作,频繁调用会严重拖慢程序性能。其次,它只能输出到控制台,没法按级别过滤、没法写入文件、没法做归档压缩——运维想看?门儿都没有。

AI 工具导航
优网导航旗下AI工具导航,精选全球千款优质 AI 工具集
所以,正经项目里,得用专业的日志框架。目前主流的有三个:Log4j、Log4j 2 和 Logback。
- Log4j 已经过时,有安全漏洞,直接pass。
- Log4j 2 性能强,用了Disruptor做异步处理,但历史上出过严重安全问题(比如“Log4j核弹级漏洞”),让人有点不放心。
- Logback 是 Spring Boot 默认集成的,和 SLF4J 天生一对,稳定又省心,推荐优先考虑。
SLF4J 是啥?为啥要用它?
SLF4J 不是具体的日志实现,而是一个“门面”(Facade)。你可以理解为它是个“前台”,你把日志交给它,它再转给背后的“Logback”或“Log4j2”去处理。
好处是啥?解耦!以后你想换日志框架,代码不用改,只要换一下依赖和配置就行。日志调用方式始终是 logger.info()
这一套,干净利落。
怎么写日志才高效又省事?
最原始的写法是这样的:
private static final Logger logger = LoggerFactory.getLogger(MyService.class);
但这样每个类都得写一遍,麻烦。更优雅的做法有两种:
- 用
this.getClass()
动态获取类名:private final Logger logger = LoggerFactory.getLogger(this.getClass());
- 直接上 Lombok 的
@Slf4j
注解(强烈推荐):@Slf4j public class WubaiService { public void doWork() { log.info("执行了某个xx"); } }
一行注解搞定,代码清爽,效率拉满,这才是现代Java开发该有的样子。
日志怎么打?别再拼字符串了!
很多人写日志喜欢这么写:

免费在线工具导航
优网导航旗下整合全网优质免费、免注册的在线工具导航大全
logger.debug("账号:" + userAccount + " 注册成功。");
这种字符串拼接的方式,即使日志级别关了,拼接操作依然执行,白白浪费性能。
正确姿势是用占位符 {}
:
logger.debug("账号:{} 注册成功。", userAccount);
日志框架会在真正需要输出时才替换参数,性能更好,也更规范。
异常日志也一样:
try {
// 业务逻辑
} catch (Exception e) {
logger.error("处理账号:{} 时发生异常:", userAccount, e);
}
日志太多怎么办?学会“节流”
日志不是越多越好。刷屏式的日志不仅占磁盘,还增加IO压力,甚至可能把服务器搞崩。
怎么控制?
- 避免在循环里狂打日志。比如批量处理1000条数据,没必要每条都打。可以每100条记录一次,或者用
StringBuilder
汇总后统一输出。 - 加级别判断:在打DEBUG日志前,先判断是否开启:
if (logger.isDebugEnabled()) { logger.debug("xxx"); }
避免不必要的字符串拼接。
- 配置文件过滤:通过
logback.xml
设置ThresholdFilter
,只允许INFO及以上级别通过,一键屏蔽DEBUG日志刷屏。
统一格式,让日志“看得懂”
日志格式乱七八糟,等于白记。比如:
注册成功 账号:wubai
错误 用账号:wubai2 注册失败!
这种日志,搜索都费劲。
推荐用统一格式,包含:时间、线程、级别、类名、内容,比如:
2025-05-31 17:50:39:555 [main] INFO com.wubai.service.UserService - 账号:wubai 注册成功
整齐清晰,支持按时间、级别、类名快速检索,排查问题效率翻倍。
高级玩法:异步日志 + AOP 自动打日志
对性能要求高的场景,可以用异步日志。Logback 支持通过 AsyncAppender
把写日志交给独立线程处理,避免阻塞主线程,提升系统吞吐量。
另外,用 AOP(面向切面编程) 可以自动记录方法执行、接口请求参数等信息。比如:
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.wubai.service..*(..))")
public void logBeforeMethod(JoinPoint joinPoint) {
logger.info("方法 {} 开始执行", joinPoint.getSignature().getName());
}
}
这样每个服务方法调用都有日志,再也不怕“谁调的我”这种灵魂拷问。
最后提醒:别打敏感信息!
日志里千万别记录手机号、身份证、密码这类敏感数据。万一日志泄露,后果不堪设想。打日志时多留个心眼,该脱敏的脱敏,该过滤的过滤。
说到底,日志看似是小事,实则是保障系统稳定运行的基石。写好日志,不是为了给别人看,而是为了未来的自己少受点罪。
从今天起,别再敷衍日志了。用对框架、写对格式、控制输出量,养成好习惯,你会发现,排查问题也能变得轻松又高效。