JavaEE 进阶第十五期:Spring 日志的笔墨艺术

专栏:JavaEE 进阶跃迁营

个人主页:手握风云

目录

一、日志概述

[1.1. 学习日志的原因](#1.1. 学习日志的原因)

[1.2. 日志的核心用途](#1.2. 日志的核心用途)

二、日志的使用

[2.1. 打印日志](#2.1. 打印日志)

[2.2. 日志框架](#2.2. 日志框架)

[1. 门面模式](#1. 门面模式)

[2. SLF4J 框架](#2. SLF4J 框架)

[2.3. 日志格式说明](#2.3. 日志格式说明)

[2.4. 日志级别](#2.4. 日志级别)

[1. 日志级别的分类](#1. 日志级别的分类)

[2. 日志级别的使用](#2. 日志级别的使用)

[2.5. 日志配置](#2.5. 日志配置)

[1. 配置日志级别](#1. 配置日志级别)

[2. 日志持久化](#2. 日志持久化)

[3. 配置日志文件分割](#3. 配置日志文件分割)


一、日志概述

1.1. 学习日志的原因

日志是程序开发与维护中的基础工具,从 JavaSE 阶段就通过 System.out.print 打印日志以定位问题、分析程序运行过程,Spring 学习中也常依赖控制台日志排查问题。但随着项目复杂度提升,System.out.print 无法满足更高需求(如需留存用户操作记录以符合审计要求、持久化日志用于后续数据分析等),因此需引入专业日志框架,实现更灵活、全面的日志管理。

1.2. 日志的核心用途

  • 系统监控作为成熟系统的标配能力,日志可记录系统运行状态(如各方法的响应时间、响应状态),通过分析日志数据设置规则:当指标超过阈值(如异常关键字数量达标)时触发报警,及时发现系统异常。

  • 数据采集采集的数据可支撑业务优化与智能决策,主要分为两类场景:

    • 数据统计:记录页面浏览量(PV)、访客量(UV)、用户点击量等,基于数据优化公司运营策略;
    • 推荐排序:在购物、广告、新闻等领域,通过日志记录用户浏览历史、页面停留时长等行为数据,供算法人员训练推荐模型,实现精准推荐。
  • 日志审计为满足国家政策法规与行业标准对系统安全的要求,日志可追踪关键操作与风险行为:

    • 溯源操作:如运营系统中数据被删除 / 修改时,通过日志明确操作人,避免责任追溯困难;
    • 防范违规:记录内部人员对敏感信息(如客户信息)的访问行为,若出现频繁查询等异常操作可触发报警,防止信息泄露。

二、日志的使用

SpringBoot 默认集成 SLF4J(日志门面)+ Logback(日志实现),无需额外引入核心依赖即可使用;日志打印到控制台,包含 6 类结构化信息(时间日期、日志级别、进程 ID、线程名、Logger 名、日志内容)。

System.out 仅能打印简单文本,缺少上述结构化信息,无法实现分级筛选、格式定制等高级需求。

2.1. 打印日志

打印日志分为两个步骤:1. 在程序中获取日志对象;2. 使用日志对象输出内容。注意 Logger 和 LoggerFactory 都是来自于 org.slf4j 包下的。

java 复制代码
package com.yang.test2_2_1;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/logger")
@RestController
public class LoggerController {
    // 获取日志对象
    private Logger logger = LoggerFactory.getLogger("abc");

    @RequestMapping("/print")
    public String print() {
        System.out.println("打印日志");
        logger.info("打印日志");
        return "1";
    }
}

2.2. 日志框架

SLF4J 不同于其他日志框架,它不是一个真正的日志实现,而是一个抽象层,对日志框架制定的一种规范,标准,接口。所有SLF4J并不能独立使用,需要和具体的日志框架配合使用。比如我们在网购时,打开的界面就属于门面,当我们下单之后,电商平台会通知买家进行订单处理,发货等,这就属于实现。

1. 门面模式

门面模式 (Facade Pattern) 又称为外观模式,提供了一个统一的接口,用来访问子系统中的一群接口。其主要特征是定义了一个高层接口,让子系统更容易使用。

门面模式的实现:场景,回家,我们会开各个屋的灯;离开家时, 会关闭各个屋的灯​。如果家里设置一个总开关,来控制整个屋的灯就会很方便。

如果按照以前的面向对象思维来设计:

java 复制代码
package com.yang.test2_2_2.facade;

public class FacadeMain {
    public static void main(String[] args) {
        BedRoomLight light1 = new BedRoomLight();
        BathRoomLight light2 = new BathRoomLight();

        light1.on();
        light2.on();

        light1.off();
        light2.off();
    }
}
java 复制代码
package com.yang.test2_2_2.facade;

public class BedRoomLight implements Light {

    @Override
    public void on() {
        System.out.println("打开卧室的灯");
    }

    @Override
    public void off() {
        System.out.println("关闭卧室的灯");
    }
}
java 复制代码
package com.yang.test2_2_2.facade;

public class BathRoomLight implements Light {

    @Override
    public void on() {
        System.out.println("浴室灯打开");
    }

    @Override
    public void off() {
        System.out.println("浴室灯关闭");
    }
}
java 复制代码
package com.yang.test2_2_2.facade;

public interface Light {
    void on();

    void off();
}

采用门面设计模式实现:

java 复制代码
package com.yang.test2_2_2.facade;

public class FacadeLight {
    private BedRoomLight light1;
    private BathRoomLight light2;

    public FacadeLight() {
        light1 = new BedRoomLight();
        light2 = new BathRoomLight();
    }
    
    public void lightOn() {
        light1.on();
        light2.on();
    }
    
    public void lightOff() {
        light1.off();
        light2.off();
    }
}

门面模式的优点:

  • 减少了系统的相互依赖,实现了客户端与子系统的耦合关系,这使得子系统的变化不会影响到调用它的客户端;
  • 提高了灵活性,简化了客户端对子系统的使用难度,客户端无需关心子系统的具体实现方式,而只需要和门面对象交互即可;
  • 提高了安全性,可以灵活设定访问权限,不在门面对象中开通方法,就无法访问。

2. SLF4J 框架

SLF4J(Simple Logging Facade for Java)并非真正的日志实现框架,而是日志门面(Logging Facade)------ 即对日志框架制定的统一 API 接口规范,自身无法独立使用,必须与具体的日志实现框架(如 log4j、logback 等)配合才能生效。

如果不引入日志门面,当存在多日志框架共存场景(如项目自身用 log4j,依赖的第三方框架用 logback)时,会面临以下问题:多套配置文件维护;更换框架成本高;

引入 SLF4J 作为日志门面后,应用程序与具体日志实现框架之间通过统一 API 交互,可解决上述问题,简化配置、统一第三方适配。

2.3. 日志格式说明

Spring Boot 日志输出包含固定的核心元素,这些元素能清晰呈现日志的上下文信息,帮助开发者快速定位问题、分析程序运行状态。

元素序号 元素名称 说明
1 时间日期 精确到毫秒,用于记录日志产生的具体时间,便于时间线追溯问题
2 日志级别 标识日志信息的严重性,可选值:ERROR、WARN、INFO、DEBUG、TRACE(无 FATAL,Logback 中映射为 ERROR)
3 进程 ID 日志所属应用进程的唯一标识,多实例部署时可区分不同进程的日志
4 线程名 日志产生时的线程名称,用于多线程场景下定位线程相关问题
5 Logger 名 通常为源代码的类名,用于直接定位日志所属的业务类或框架类
6 日志内容 开发者自定义或框架自动生成的具体日志信息,记录程序运行细节或错误描述

2.4. 日志级别

日志级别代表着日志信息对应问题的严重性,为了更快的筛选符合目标的日志信息。

1. 日志级别的分类

日志级别 严重程度 核心含义与使用场景
FATAL 最高 致命信息,代表需立即处理的系统级错误,通常意味着服务已出现某种程度的不可用(如核心服务崩溃),一个进程生命周期中最多应只出现一次该级别日志。
ERROR 较高 错误信息,代表级别较高的错误,但不影响系统整体继续运行(如单个接口调用失败、数据查询异常),需开发人员关注并排查问题根源。
WARN 中等 警告信息,代表不影响功能使用,但需注意的潜在问题(如配置项未显式设置、使用即将废弃的 API),提醒开发人员关注可能的风险点。
INFO 较低 普通信息,用于记录应用程序正常运行时的关键状态(如系统启动完成、请求处理成功、服务连接建立),反映程序的常规运行流程。
DEBUG 更低 调试信息,用于开发阶段打印问题排查所需的关键细节(如变量值、方法调用链路、参数传递情况),帮助开发人员定位代码逻辑问题。
TRACE 最低 追踪信息,比 DEBUG 更细粒度的信息事件(如代码行级别的执行轨迹),除非有特殊追踪需求,否则建议用 DEBUG 级别替代,避免日志信息过度冗余。

2. 日志级别的使用

java 复制代码
package com.yang.test2_2_3;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/logger")
public class LoggerController {
    private Logger logger = LoggerFactory.getLogger(LoggerController.class);

    @RequestMapping("/print")
    public String print() {
        logger.trace("我是 trace 级别");
        logger.debug("我是 debug 级别");
        logger.info("我是 info 级别");
        logger.warn("我是 warn 级别");
        logger.error("我是 error 级别");
        return "1";
    }
}

这里是没有 fatal 级别的方法,它被映射到了 error。出现了 fatal 日志,就说明服务已经出现了某种程度的不可用,需要系统管理员紧急介入。比如,如果公司里面出现断电,或者磁盘满了,此时就不需要汇报,可能用户已经给客服打电话了。

运行程序,会发现只打印了 info、warn 和 error 级别的日志。这与日志的级别有关,日志输出默认级别为 info 级别,所以只会输出大于等于此级别的日志。

2.5. 日志配置

1. 配置日志级别

志级别配置只需要在配置文件中设置"logging.level"配置项即可,如下所示:

java 复制代码
logging:
  level:
    root: debug

2. 日志持久化

日志持久化指将原本仅输出到控制台的日志保存到文件中,核心目的是线上环境问题追溯------ 避免控制台日志随程序重启或会话结束丢失,便于后续排查故障、分析问题根源。日志持久化通过配置文件指定 "日志文件名" 或 "日志存储目录" 实现。

java 复制代码
logging:
  file:
    name: log.log

刷新下文件目录,会多出一个 log.log 的文件,我们再次启动程序也不会消失,这样就做到了持久化。

java 复制代码
logging:
  file:
    path: logger2/

再次启动,刷新,会多出一个文件 logger2,里面有一个 spring.log 的文件。

3. 配置日志文件分割

如果我们的日志都放在一个文件中,随着项目的运行,日志文件会越来越大,需要对日志文件进行分割。当然,日志框架也帮我们考虑到了这一点,所以如果不进行配置,就走自动配置​ 默认日志文件超过10M就进行分割​。

java 复制代码
logging:
  logback:
    rollingpolicy:
      max-file-size: 1KB
相关推荐
仟濹2 小时前
【Java加强】2 泛型 | 打卡day1
java·开发语言
Hx_Ma162 小时前
SpringBoot注册格式化器
java·spring boot·后端
V胡桃夹子2 小时前
VS Code / Lingma AI IDE Java 开发攻略手册
java·ide·人工智能
独自破碎E2 小时前
【回溯】二叉树的所有路径
android·java
风景的人生2 小时前
application/x-www-form-urlencoded
java·mvc
sheji34162 小时前
【开题答辩全过程】以 基于Java的流浪猫救济中心系统的设计与实现为例,包含答辩的问题和答案
java·开发语言
毕设源码-郭学长2 小时前
【开题答辩全过程】以 高校选修课管理系统的设计与实现为例,包含答辩的问题和答案
java
爱吃面条的猿2 小时前
FontMetrics 字体属性类 java
java
蒹葭玉树2 小时前
【C++上岸】C++常见面试题目--操作系统篇(第二十九期)
java·c++·面试