首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >聊聊打印日志的几点技巧

聊聊打印日志的几点技巧

作者头像
勇哥java实战
发布2026-01-27 14:29:41
发布2026-01-27 14:29:41
1110
举报
文章被收录于专栏:勇哥编程游记勇哥编程游记

日志在系统开发和运维过程中扮演着极其重要的角色。

无论是定位线上问题、分析异常行为,还是复盘一次生产事故,日志往往都是最直接、也是最可靠的依据。很多时候,系统“看不见”的地方,最终只能通过日志来还原现场。

这篇文章,聊聊日志打印的几点技巧。

1 门面模式 slf4j

日志框架在开发和维护过程中扮演着不可或缺的角色,它能够帮助我们快速定位错误并进行有效的故障排查。

你可能听说过一些与日志框架相关的名词,比如 slf4jlog4jlogbackJDK Logging ,但他们之间到底是什么关系可能会让人感到困惑,所以我们先介绍他们之间的关系。

slf4j 是一个日志框架的简单门面,它提供了一个统一的日志接口,使得开发者可以在应用中使用统一的日志API。slf4j 本身并不提供日志的实现,而是通过与其他日志框架(如log4j、logback等)结合使用,来实现日志记录的功能。

图中,Logback、Log4j 都是日志框架,每一种日志框架都有自己单独的 API,要使用对应的框架就要使用其对应的 API,这就大大的增加应用程序代码对于日志框架的耦合性。

为了解决这个问题,就是在日志框架和应用程序之间架设一个沟通的桥梁,对于应用程序来说,无论底层的日志框架如何变,都不需要有任何感知。只要门面服务做的足够好,随意换另外一个日志框架,应用程序不需要修改任意一行代码,就可以直接上线。

在短信平台 SDK 模块里,我们并没有依赖日志框架,而是仅仅依赖 slf4j。

SDK 需要打印日志的类定义日志对象 Logger :

下图是代码简化图,Logger 对象定义了不同的日志级别输出方式。

业务应用中, 我们一般使用 debug 调试、info 信息、warn 警告、error 错误 ,等级由低到高 。

我们开发测试一般输出DEBUG级别的日志,生产环境配置只输出INFO级别甚至只输出ERROR级别的日志。

2 SpringBoot Logback

Spring Boot 默认的日志框架 SLF4J + Logback ,官方推荐优先使用带有 -spring 的文件名作为你的日志配置(如使用 logback-spring.xml,而不是 logback.xml ),命名为 logback-spring.xml的日志配置文件,将 xml 文件放至 src/main/resource下面。

下图是一个示例 Logback 文件:

Logback 日志框架中,有三个主要的元素:appenderloggerroot

1、Appender(输出器):用于指定日志输出的目的地的组件。

定义了两个输出器(appender),一个用于控制台输出( CONSOLE ),另一个用于文件输出( FILE )。

2、Logger(记录器):用于记录日志事件的组件,负责接收应用程序中产生的日志事件并将它们传送到相应的 Appender

对于 com.example.Main类,将其日志级别设置为 DEBUG,只有 DEBUG 级别及以上的日志事件才会被记录,并且仅会输出到控制台。

对于 com.example.service 包,将其日志级别设置为 WARN 。只有WARN级别及以上的日志事件才会被记录,并且仅会输出到文件。

3、Root(根Logger):日志记录器树结构的根节点.

我们将根Logger的日志级别设置为INFO,并将其绑定到两个输出器CONSOLEFILE,这意味着所有未特别指定Logger的日志事件将遵循此配置。

3 Logback 配置参考

下图是短信服务的 logback 配置文件:

这里面有两个要点:

1、日志格式

我们定义了两个 Appender , 分别输出到控制台、文件,他们的日志格式都是:

代码语言:javascript
复制
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %p %t %logger{36}:%L - %msg%n</pattern>

格式说明:

服务启动后的输出格式如下图所示:

启动日志里,我们可以看到线程名,以及类名以及代码行号,便于定位问题。

2、备份历史文件

因为本地磁盘容量限制,我们不可能永久的保存日志,笔者曾经遇到过因为 log4j 将磁盘占满,导致 tomcat 所有线程阻塞的场景 , 通过 jstack 命令定位到线程阻塞在 log4j 写日志的代码上。

因此我们可以配置文件的保留策略:日志文件大小达到指定阈值或每天生成新日志文件时进行滚动备份,并保留最近的一定数量的历史备份文件。

有的同学可能会问:全量数据去哪里查呢? 我们可以在机器上部署 filebeat 将日志异构存储到 ElasticSearch 或者其他的存储。

3 日志打印规范

1、日志打印出参入参

核心接口以及关键方法的入参和返回值都建议加上日志。

2、日志级别判断

这一条针对debug和trace这种低级别日志,同时为了减少线上调用日志打印没有日志浪费的情况:

代码语言:javascript
复制
User user = new User(666L, "xxxx", "xxxx");
if (log.isDebugEnabled()) {
    log.debug("userId is: {}", user.getId());
}

3、使用日志框架SLF4J中的API

还是要重点强调使 SLF4J 的 API ,减少应用程序对于日志实现框架的耦合。

4、占位符而不是+号,性能高且更优雅

代码语言:javascript
复制
Object[] paramArray = {newVal, below, above};
logger.debug("Value {} was inserted between {} and {}.", paramArray);

5、异常堆栈打印

下面的日志输出就不怎么规范:

代码语言:javascript
复制
try {
    //业务代码处理
} catch (Exception e) {
    // 错误
    LOG.error('你的程序有异常啦');
}

正确方式是:

代码语言:javascript
复制
try{
  // 业务代码处理
}catch(Exception e){
  log.error("你的程序有异常啦",e);
}

另外需要注意,e.getMessage()不会记录详细的堆栈异常信息,只会记录错误基本描述信息,不利于排查问题。

6、禁止在线上环境开启 debug

除了系统产生的大量 debug 日志,还可能存在框架本身输出 debug 日志的问题。在线上环境开启 debug 日志很容易导致日志文件不断增大,最终耗尽磁盘空间,并且可能引发 CPU 和磁盘 I/O 等待,进而直接影响系统的正常运行。

7、不要使用e.printStackTrace()

控制台打印出的堆栈日志跟业务代码日志是交错混合在一起的,容易造成排查异常日志不太方便。

往期推荐:

三个月写了个迷你版的短信平台,开源出来!

基于 RuoYi-Vue-Pro 定制了一个后台管理系统 , 开源出来!

短信平台 Pro 版本 ,比开源版本更强大

如果我的文章对你有所帮助,还请帮忙点赞、在看、转发一下,你的支持会激励我输出更高质量的文章,非常感谢!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-01-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 勇哥java实战分享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 门面模式 slf4j
  • 2 SpringBoot Logback
  • 3 Logback 配置参考
  • 3 日志打印规范
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档