【JavaEE】Spring Boot日志

目录

[Spring Boot 日志](#Spring Boot 日志)

日志概述

日志的用途

日志使用

打印日志

在程序中得到日志对象

使用日志对象打印日志

日志框架介绍(了解)

SpringBoot日志体系

核心架构

配置方式

日志级别

门面模式(外观模式)

定义

角色与结构

[在Spring Boot日志中的应用](#在Spring Boot日志中的应用)

优势与场景

门面模式的实现


Spring Boot 日志

学习完本章后,大家应掌握以下两点:

  1. 了解日志文件的用途
  2. 学习Spring Boot日志文件的配置

日志概述

为什么学习日志

日志对我们来说并不陌生,从JavaSE部分,我们就在使用System.out.println来打印日志了。通过打印日志来发现和定位问题,或者根据日志来分析程序的运行过程。在Spring的学习中,也经常根据控制台的日志来分析和定位问题

随着项目复杂度的提升,我们对日志的打印也有了更高的需求,而不仅仅是定位排查问题

比如需要记录一些用户的操作记录(一些审计公司会要求),也可能需要使用日志来记录用户的一些喜好,把日志持久化,后续进行数据分析等。但是System.out.println不能很好的满足我们的需求,我们就需要使用一些专门日志框架去做

日志的用途

通过前面的学习,我们知道日志主要是为了发现问题,分析问题,定位问题的,但除此之外,日志还有很多用途

1.系统监控

监控现在几乎是一个成熟系统的标配,我们可以通过日志记录这个系统的运行状态,每一个方法的响应时间,响应状态等,对数据进行分析,设置不同的规则,超过阈值时进行报警。比如统计日志中关键字的数量,并在关键字数量达到一定条件时报警,这也是日志的常见需求之一

2.数据采集

数据采集是一个比较大的范围,采集的数据可以作用在很多方面,比如数据统计,推荐排序等

·数据统计:统计页面的浏览量(PV),访客量(UV),点击量等,根据这些数据进行数据分析,优化公司运营策略

·推荐排序:目前推荐排序应用在各个领域,我们经常接触的各行各业中很多也都涉及推荐排序,比如购物,广告,新闻等领域。数据采集是推荐排序工作中必须做的一环,系统通过日志记录用户的浏览历史,停留时长等,算法人员通过分析这些数据,训练模型,给用户做推荐

下图中的数据源,其中一部分就来自于日志记录的数据

3.日志审计

随着互联网的发展,众多企业的关键业务越来越多的运行于网络之上。网络安全也越来越受到大家的关注,系统安全也成为了项目中的一个重要环节,安全审计也是系统中非常重要的部分。国家的政策法规、行业标准等都明确对日志审计提出了要求。通过系统日志分析,可以判断一些非法攻击,非法调用,以及系统处理过程中的安全隐患

比如,大家平时都在做运营系统,其中运营人员在通过界面处理一些数据的时候,如果没有清楚的日志操作记录,一条数据被删除或者修改,你是无法找到是谁操作的,但是如果你做了响应的记录,该数据被谁删除或者修改就会一目了然

还有一些内部的违规和信息泄露(比如客户信息被卖掉)现象出现后,如果未记录留存日志,为事后调查提供依据,则事后很难追查(一些公司查看客户的信息都会记录日志,如果频繁查询也会报警)

日志使用

Spring Boot项目在启动的时候默认就有日志输出,如下图所示:

它所打印的日志和我们的System.out.println有什么不同呢?

我们可以看到上图,第一行即为 System.out.println所输出的,而后续即为日志所输出的

结果:我们可以知道System.out.println打印的日志,比Spring Boot打印的日志缺少了很多信息

Spring Boot中内置了日志框架SLF4J,我们可以直接在程序中调用该框架来输出日志

打印日志

步骤:

  1. 在程序中得到日志对象
  2. 使用日志对象输出要打印的内容

在程序中得到日志对象

为了在程序中获取日志对象,我们需要使用日志工厂LoggerFactory,代码如下所示:

java 复制代码
private final static Logger logger= LoggerFactory.getLogger(LogController.class);

LoggerFactory.getLogger需要传递一个参数,标识这个日志的名称。这样可以更清晰的知道是哪个类输出的日志。当有问题时,可以更方便直观的定位到问题类

注意:Logger对象是属于org.slf4j包下的,不要导入错包

使用日志对象打印日志

日志对象的打印方法有很多种,我们可以先使用info()方法来输出日志,代码如下所示:

java 复制代码
package com.fei.log.controller;

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


@RequestMapping("/log")
@RestController
public class LogController {

    //当然我们后续也可以使用注解的方式,实现下面这行代码
    private final static Logger logger= LoggerFactory.getLogger(LogController.class);

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

日志输出如下图:

日志框架介绍(了解)

SLF4J不同于其他日志框架,它不是一个真正的日志实现,而是一个抽象层,对日志框架制定的一种规范,标准,接口。所有SLF4J并不能独立使用,需要和具体的日志框架配合使用

理解:可以把SLF4J理解为Java代码中的接口,它需要有一个实现类来实现日志的打印

SpringBoot日志体系

核心架构

Spring Boot采用SLF4J作为日志门面结合Logback作为默认实现框架,形成分层架构:

SLF4J:提供统一的日志API(如Logger接口),屏蔽底层实现差异

Logback:作为SLF4J的原生实现,负责实际日志记录、格式化、输出等操作,性能优于Log4j 1.x

并且支持异步日志、滚动文件等高级功能

其他支持框架:通过适配器可集成Log4j 2、JUL(Java Util Logging)等,但需排除默认依赖(如spring-boot-starter-logging)并引入对应Starter(如spring-boot-starter-log4j2)

配置方式

这里我们通过application.properties/yml文件设置全局或包级别日志级别、输出格式、文件路径等

java 复制代码
properties
# 设置全局日志级别为 INFO
logging.level.root=INFO
# 设置特定包日志级别为 DEBUG
logging.level.com.example.demo=DEBUG
# 配置日志文件路径及名称
logging.file.name=./logs/app.log
# 控制台输出格式
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n

日志级别

从低到高分为:TRACE<DEBUG<INFO<WARN<ERROR<FATAL。默认级别为INFO,可通过配置调整。例如,设置logging.level.root=DEBUG 可输出调试信息,但需谨慎使用 以避免日志量过大

门面模式(外观模式)

SLF4J是门面模式的典型应用(但不仅仅使用了门面模式)

定义

门面模式又称为外观模式,提供了一个统一的接口(封装子系统的复杂交互),用来访问子系统中的一群接口,从而降低客户端与子系统的耦合度。其主要特征是定义了一个高层接口,让子系统更容易使用

核心目标包括:

简化使用:客户端无需了解子系统内部细节,仅需与门面交互

解耦:子系统变化不影响客户端代码

灵活扩展:支持替换或新增子系统实现,无需修改客户端

角色与结构

  1. 外观角色(Facade):也称门面角色,系统对外的统一接口
  2. 子系统角色(SubSystem):可以同时有一个或多个子系统。每个子系统都不是一个单独的类,而是一个类的集合。子系统并不知道门面角色(Facade)的存在,对于子系统而言,门面角色(Facade)只是另一个客户端而已(即Facade对SubSystem透明)
  3. 客户端角色(Client):通过门面调用子系统功能

举例

比如去医院看病,可能要去挂号,门诊,化验,取药,这会让患者或患者家属觉得很复杂,如果有提供接待人员,那让接待人员去处理上述步骤,就会显得很方便了

在Spring Boot日志中的应用

SLF4J作为门面:提供统一的Logger接口(如log.info()、log.error()),屏蔽底层实现(Logback、Log4j 2等)

子系统实现:Logback或Log4j 2等具体框架实现日志记录逻辑

客户端代码:通过SLF4J API记录日志,无需关心底层实现。例如:

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DemoService {
    private static final Logger log = LoggerFactory.getLogger(DemoService.class);

    public void process() {
        log.debug("Debug message");
        log.info("Info message");
        log.error("Error message");
    }
}

优势与场景

优势:

解耦:应用程序与日志框架解耦,便于切换实现(如从Logback迁移到Log4j 2)

统一管理:通过门面集中配置日志行为(如格式、级别),避免分散配置

简化代码:客户端代码简洁,无需处理不同日志框架的差异

典型场景:

需要隐藏子系统复杂性(如日志、支付、消息队列等模块的集成)

降低客户端与子系统的依赖关系,提高可维护性

支持多子系统协同工作(如一个门面类封装多个子系统调用)

门面模式的实现

场景:回家,我们会打开各个屋的灯。在离开家时,我们会关闭各个屋的灯

如果家里设置了一个总开关,来控制整个屋的灯就会很方便

我们使用门面模式的实现

java 复制代码
public class FacadePatternDemo {

    //灯的总开关控制:卧室灯/客厅灯/走廊灯
    static class LightFacede{
        private Light livingRoomLight=new LivingRoomLight();
        private Light hallLight=new HallLight();
        private Light diningLight=new DiningLight();

        //开灯/关灯
        public void lightOn(){
            livingRoomLight.on();
            hallLight.on();
            diningLight.on();
        }

        public void lightOff(){
            livingRoomLight.off();
            hallLight.off();
            diningLight.off();
        }
    }

    //灯的接口:开/关
    interface Light{
        void on();
        void off();
    }

    //客厅灯
    static class LivingRoomLight implements Light{
        @Override
        public void on() {
            System.out.println("打开客厅灯");
        }

        @Override
        public void off() {
            System.out.println("关闭客厅灯");
        }
    }

    //走廊灯
    static class HallLight implements Light{
        @Override
        public void on() {
            System.out.println("打开走廊灯");
        }

        @Override
        public void off() {
            System.out.println("关闭走廊灯");
        }
    }

    //餐厅灯
    static class DiningLight implements Light{
        @Override
        public void on() {
            System.out.println("打开餐厅灯");
        }

        @Override
        public void off() {
            System.out.println("关闭走廊灯");
        }
    }


    public static void main(String[] args) {
        LightFacede lightFacede=new LightFacede();//门面接口:控制家的所有灯
        lightFacede.lightOn();//回家开灯
        lightFacede.lightOff();//回家关灯
    }
}

输出结果:

相关推荐
zjeweler2 小时前
redis tools gui ---Redis图形化漏洞利用工具
数据库·redis·web安全·缓存
浮游本尊2 小时前
Java学习第31天 - 高级主题与深度实战
java
BD_Marathon2 小时前
【JavaWeb】IDEA关联Tomcat并使用Tomcat运行JavaWeb项目
java·tomcat·intellij-idea
Leon-Ning Liu2 小时前
Oracle 19c RAC ASM 密码文件恢复方案四:创建新密码文件覆盖恢复
数据库·oracle
思成不止于此2 小时前
【MySQL 零基础入门】DCL 核心语法全解析:用户管理与权限控制篇
数据库·笔记·sql·学习·mysql
柒.梧.2 小时前
手写Tomcat的实现代码分享
java·tomcat
y1y1z2 小时前
Spring MVC教程
java·spring·mvc
武子康2 小时前
Java-192 深入拆解 EVCache 内部原理:Memcached 架构、Slab 分配与 LRU 过期机制全解析
数据库·redis·缓存·架构·memcached·guava·evcache
CodersCoder2 小时前
SpringBoot整合Spring-AI并使用Redis实现自定义上下文记忆对话
人工智能·spring boot·spring