My App

日志技术

Path Intellisense

学习目标

  • 能用自己的话说明什么是日志为什么要在程序中记录日志
  • 能说出为什么不用 System.out.println 记录日志,以及专业日志框架带来的好处。
  • 了解常见日志框架(JUL、Log4j、Logback、Slf4j)及其关系;必须掌握 Slf4j + Logback 在 Spring Boot 中的使用。
  • 能在 Spring Boot 中引入/配置 Logback(控制台 + 文件),并理解日志级别与配置方式。
  • 能在 Controller/Service 中使用 @Slf4j 与 log.info/debug 等规范记录日志,并知道占位符 {} 的用法。

1. 从零开始:什么是日志?为什么要在程序中记录日志?

1.1 是什么

日志就像程序里的「日记」:用来记录应用的运行信息、状态信息、错误信息
谁在什么时候做了什么、结果如何、有没有报错,都可以通过日志追溯。

1.2 为什么

在程序中记录日志可以:

  • 追踪数据与执行过程:便于复盘请求链路、数据变化。
  • 性能优化:通过耗时、调用次数等日志做分析与优化。
  • 排查问题:出问题时,日志是定位错误原因的第一手资料。
  • 监控运行状态:配合监控系统,发现异常、告警。

1.3 小结

  • 日志 = 程序的运行/状态/错误记录。
  • 用途:追踪、优化、排错、监控。

2. 为什么不用 System.out.println 记录日志?

System.out.println(...) 虽然能「打出一行字」,但存在明显问题:

问题说明
硬编码想不输出某条日志,只能删代码或注释,无法通过配置灵活开关。
只能输出到控制台无法同时输出到文件、无法按日期/大小滚动、无法区分环境。
不便于扩展与维护无法统一格式、级别、输出目标,不利于团队协作和线上排查。

因此,项目开发中应使用专业日志框架,通过配置控制输出位置、格式、级别,而无需改代码。


3. 常见日志框架简介(了解即可)

常见日志框架

框架说明
JULJava 自带的日志框架(java.util.logging),配置简单但不够灵活,性能一般。
Log4j早期流行框架,支持多种输出目标和配置方式。
Logback可视为 Log4j 的升级版,功能更多、性能更好,与 Slf4j 配合默契。
Slf4jSimple Logging Facade for Java:一套门面/接口,不负责具体打日志,而是让程序「面向接口编程」,底层可切换为 Logback、Log4j 等。

必须掌握:在 Spring Boot 中,我们通常使用 Slf4j(门面)+ Logback(实现),代码里只依赖 Slf4j 的 API(如 LoggerFactory.getLoggerlog.info),具体输出由 Logback 完成。


4. Logback 入门(是什么、怎么做)

4.1 为什么选 Logback

  • Spring Boot 默认已集成 Logback,无需额外引入依赖(starter 已传递)。
  • 配置灵活:控制台、文件、级别、格式均可通过配置文件控制。
  • 性能优于 Log4j,与 Slf4j 无缝配合。

4.2 准备工作(两步)

1)依赖
Spring Boot 项目中一般无需单独引入 Logback;若为纯 Java 项目,可引入:

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.4.11</version>
</dependency>

2)配置文件
src/main/resources 下新建 logback.xml(Spring Boot 会自动识别),例如:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}-%msg%n</pattern>
        </encoder>
    </appender>

    <root level="ALL">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>
  • %d 日期;%thread 线程名;%-5level 级别(左对齐 5 字符);%logger{50} 类名;%msg 日志内容;%n 换行。

4.3 Logback 记录日志的步骤

使用 Logback 记录日志,可以归纳为两步:

  1. 引入 Logback 的依赖、配置文件 logback.xml(见上文 4.2 准备工作)。
  2. 定义日志记录对象 Logger,调用方法(debug / info / …)记录日志(见下方示例)。

4.4 示例:定义 Logger 并调用

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogTest {

    // 定义日志记录对象
    private static final Logger log = LoggerFactory.getLogger(LogTest.class);

    @Test
    public void testLog() {
        log.debug("开始计算...");
        int sum = 0;
        int[] nums = {1, 5, 3, 2, 1, 4, 5, 4, 6, 7, 4, 34, 2, 23};
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
        }
        log.info("计算结果为: " + sum);
        log.debug("结束计算...");
    }
}

注意:循环遍历数组时,条件应写 i < nums.length,不要写成 i <= nums.length,否则最后一次会访问 nums[nums.length],引发 ArrayIndexOutOfBoundsException。 [] 运行后,控制台会输出时间、线程名、级别、类名、消息,例如:

2025-02-03 10:00:00.123 [main] DEBUG c.i.LogTest-开始计算...
2025-02-03 10:00:00.124 [main] INFO  c.i.LogTest-计算结果为: 106
2025-02-03 10:00:00.124 [main] DEBUG c.i.LogTest-结束计算...

控制台输出效果示意:

控制台日志示例

4.5 常见坑

  • 没有 logback.xml:若需自定义,务必放在 src/main/resources 下,且文件名正确。
  • Logger 拿错类LoggerFactory.getLogger(LogTest.class) 建议传入当前类,便于定位输出位置。
  • 只记得 System.out:养成习惯用 log.info/debug/error,便于后续按级别过滤和统一管理。

5. Logback 配置文件详解

5.1 配置文件说明

  • 配置文件名logback.xml
  • 作用:该配置文件是对 Logback 日志框架输出的日志进行控制的,可以配置输出的格式、位置及日志开关等。
  • 常用的两种输出日志的位置控制台系统文件

下面分别说明如何配置这两种输出,以及如何通过 root 开启/关闭日志。

5.2 输出到控制台

<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}-%msg%n</pattern>
    </encoder>
</appender>

5.3 输出到系统文件(按天 + 按大小滚动)

<!-- 系统文件输出 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <FileNamePattern>D:/tlias-%d{yyyy-MM-dd}-%i.log</FileNamePattern>
        <MaxHistory>30</MaxHistory>
        <maxFileSize>10MB</maxFileSize>
    </rollingPolicy>
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}-%msg%n</pattern>
    </encoder>
</appender>
  • FileNamePattern:文件名规则,%d 日期,%i 序号(同一天多文件时)。
  • MaxHistory:最多保留 30 天历史。
  • maxFileSize:单文件超过 10MB 滚动到新文件。

生产环境可把 D:/ 改为服务器目录,如 /var/log/app/

5.4 日志开关:root 与 appender-ref

  • 开启日志level="ALL"(输出所有级别)。
  • 关闭日志level="OFF"(不输出任何日志)。

<root> 中通过 appender-ref 引用上面定义的 STDOUT(控制台)和 FILE(系统文件),即可同时输出到两处:

<root level="ALL">
    <!-- 输出到控制台 -->
    <appender-ref ref="STDOUT" />
    <!-- 输出到文件 -->
    <appender-ref ref="FILE" />
</root>
  • appender-ref ref="STDOUT":将日志输出到控制台。
  • appender-ref ref="FILE":将日志输出到系统文件。

6. Logback 日志级别(必须掌握)

日志级别指的是日志信息的类型,日志都会分级别。常见日志级别如下(级别由低到高):

日志级别说明记录方式
trace追踪,记录程序运行轨迹。【使用很少】log.trace("...")
debug调试,记录程序调试过程中的信息;实际应用中一般将其视为最低级别。【使用较多】log.debug("...")
info记录一般信息,描述程序运行的关键事件,如:网络连接、IO 操作。【使用较多】log.info("...")
warn警告信息,记录潜在有害的情况。【使用较多】log.warn("...")
error错误信息。【使用较多】log.error("...")

在 logback.xml 中配置 root 的 level 后,只有大于等于该级别的日志才会被输出。例如配置 level="info" 时,只会输出 INFO、WARN、ERROR,不输出 TRACE、DEBUG。

在 logback.xml 中控制 root 级别示例:

<root level="info">
    <appender-ref ref="STDOUT" />
    <appender-ref ref="FILE" />
</root>

即:只输出 INFO、WARN、ERROR,不输出 TRACE、DEBUG。
开发时可设为 level="debug" 便于排查;上线后常设为 infowarn,减少噪音与 I/O。


7. 案例:在 Controller 中用 @Slf4j 记录日志

实际项目中,我们更推荐用 Lombok 的 @Slf4j 自动生成 log 对象,避免每个类手写 Logger

7.1 引入 Lombok(若项目未有)

Spring Boot 项目通常已包含 Lombok;否则在 pom.xml 中:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <scope>provided</scope>
</dependency>

7.2 使用 @Slf4j 与占位符

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RequestMapping("/depts")
@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    @GetMapping
    public Result list() {
        log.info("查询部门列表");
        List<Dept> deptList = deptService.findAll();
        return Result.success(deptList);
    }

    @DeleteMapping
    public Result delete(Integer id) {
        log.info("根据id删除部门, id: {}", id);
        deptService.deleteById(id);
        return Result.success();
    }

    @PostMapping
    public Result save(@RequestBody Dept dept) {
        log.info("新增部门, dept: {}", dept);
        deptService.save(dept);
        return Result.success();
    }

    @GetMapping("/{id}")
    public Result getById(@PathVariable Integer id) {
        log.info("根据ID查询, id: {}", id);
        Dept dept = deptService.getById(id);
        return Result.success(dept);
    }

    @PutMapping
    public Result update(@RequestBody Dept dept) {
        log.info("修改部门, dept: {}", dept);
        deptService.update(dept);
        return Result.success();
    }
}

要点

  • @Slf4j:Lombok 会在编译期生成 private static final Logger log = LoggerFactory.getLogger(DeptController.class);,无需手写。
  • 占位符 {}:用 log.info("删除部门, id: {}", id) 而不是 "id: " + id,便于日志框架做延迟拼接(例如当前级别不输出时可不拼接字符串),且格式统一。

7.3 常见错误与误区

  • 用字符串拼接代替占位符:如 log.info("id=" + id),在关闭 INFO 时仍会做字符串拼接,建议改为 log.info("id: {}", id)
  • 在 Controller 里不打日志:关键入口(如增删改查入口)建议至少打一条 INFO,便于追踪请求与排错。
  • 敏感信息写进日志:密码、手机号等不要明文输出,可脱敏或直接不记录。

8. 核心执行总结(最小可执行)

  1. 为什么用日志:追踪、优化、排错、监控;不用 System.out.println,用日志框架。
  2. 技术选型:Spring Boot 默认 Slf4j + Logback,代码只依赖 Slf4j API。
  3. 配置:在 src/main/resources 下放 logback.xml,配置控制台/文件 appender 和 <root level="...">
  4. 使用:类上加 @Slf4j,用 log.info/debug/error("消息", 占位符...),优先用 {} 占位符。
  5. 级别:生产常用 infowarn,开发可用 debug;只输出 ≥ 配置级别的日志。

9. 关键概念速记(考试背诵向)

  • 日志:记录程序运行信息、状态信息、错误信息的载体。
  • Slf4j:简单日志门面,提供统一 API;Logback:具体实现,负责输出。
  • logback.xml:Logback 的配置文件,控制输出位置、格式、级别。
  • Appender:输出目标(如 ConsoleAppender、RollingFileAppender)。
  • 日志级别:TRACE < DEBUG < INFO < WARN < ERROR;配置某级别则输出 ≥ 该级别的日志。
  • @Slf4j:Lombok 注解,自动生成 log 对象,等价于 LoggerFactory.getLogger(当前类.class)

10. 思维导图(层级与关联)

mindmap
  root(日志技术)
    为什么用
      追踪执行与数据
      性能优化
      排查问题
      监控状态
    为什么不用 System.out
      硬编码
      只能控制台
      难扩展维护
    常见框架
      JUL
      Log4j
      Logback
      Slf4j 门面
    使用方式
      logback.xml
      控制台/文件 Appender
      root level
      @Slf4j + log.info/debug/error
    级别
      TRACE
      DEBUG
      INFO
      WARN
      ERROR

11. 实际应用场景(3 则)

  • 接口排查:在 Controller 关键入口用 log.info 记录请求参数或关键 ID,出问题时根据时间戳和 ID 查日志、定位请求。
  • 异常与错误:在 catch 块中 log.error("描述", e),保留堆栈,便于线上报错后根据 trace 排查。
  • 性能与审计:对重要操作(如下单、支付)打 INFO 日志(含业务主键),便于后续做简单统计或审计追溯;敏感信息需脱敏。

On this page