【JavaEE】深入探索SpringBoot的日志管理功能与实践应用

news2024/9/23 3:11:52

目录

    • SpringBoot 日志
      • 日志概述
      • 日志使用
        • 打印日志
          • 在程序中得到⽇志对象
          • 使用日志对象打印日志
        • ⽇志框架介绍(了解)
          • ⻔⾯模式(外观模式)
          • SLF4J 框架介绍
          • 日志格式的说明
          • ⽇志级别
            • 日志级别的分类
            • 日志级别的使用
          • ⽇志配置
            • 配置⽇志级别
            • ⽇志持久化
            • 配置⽇志⽂件分割
            • 配置⽇志格式
        • 更简单的⽇志输出
          • 添加 lombok 依赖
          • 输出⽇志
      • 总结


SpringBoot 日志

日志概述

为什么要学日志

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

随着项⽬的复杂度提升, 我们对⽇志的打印也有了更⾼的需求, ⽽不仅仅是定位排查问题.

⽐如需要记录⼀些⽤⼾的操作记录(⼀些审计公司会要求), 也可能需要使⽤⽇志来记录⽤⼾的⼀些喜好,把⽇志持久化, 后续进⾏数据分析等. 但是 System.out.print 不能很好的满⾜我们的需求, 我们就需要使⽤⼀些专⻔⽇志框架(专业的事情交给专业的⼈去做)

⽇志的⽤途

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

  1. 系统监控

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

  1. 数据采集

数据采集是⼀个⽐较⼤的范围, 采集的数据可以作⽤在很多⽅⾯, ⽐如数据统计, 推荐排序等.

  • 数据统计: 统计⻚⾯的浏览量(PV), 访客量(UV), 点击量等, 根据这些数据进⾏数据分析, 优化公司运营策略
  • 推荐排序: ⽬前推荐排序应⽤在各个领域, 我们经常接触的各⾏各业很多也都涉及推荐排序, ⽐如购物, ⼴告, 新闻等领域. 数据采集是推荐排序⼯作中必须做的⼀环, 系统通过⽇志记录⽤⼾的浏览历史, 停留时⻓等, 算法⼈员通过分析这些数据, 训练模型, 给⽤⼾做推荐.下图中的数据源, 其中⼀部分就来⾃于⽇志记录的数据.

在这里插入图片描述

  1. ⽇志审计

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

⽐如, ⼤家平时都在做运营系统, 其中运营⼈员在通过界⾯处理⼀些数据的时候, 如果没有清楚的⽇志操作记录, ⼀条数据被删除或者修改, 你是⽆法找到是谁操作的,但是如果你做了相应的记录,该数据被谁删除或者修改就会⼀⽬了然.

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

日志使用

日志在企业中的实践:

  1. 对日志进行分类
  2. 借助消息队列,比如kafka,mq等

就是阻塞队列:生产者消费者模型

Spring Boot 项⽬在启动的时候默认就有⽇志输出,如下图所⽰:

在这里插入图片描述

它打印的⽇志和 System.out.print 有什么不同呢?

@RestController
public class LoggerController {
	@RequestMapping("/logger")
	public String logger(){
		System.out.println("打印⽇志");
		return "打印⽇志";
	}
}

观察⽇志输出

在这里插入图片描述

在这里插入图片描述

可以看到, 我们通过 System.out.print 打印的⽇志, ⽐ SpringBoot 打印的⽇志缺少了很多信息.

SpringBoot 内置了⽇志框架 Slf4j , 我们可以直接在程序中调⽤ Slf4j 来输出⽇志

打印日志

打印⽇志的步骤:

  • 在程序中得到⽇志对象.
  • 使⽤⽇志对象输出要打印的内容
在程序中得到⽇志对象

在程序中获取⽇志对象需要使⽤⽇志⼯⼚ LoggerFactory,如下代码所⽰:

private static Logger logger = LoggerFactory.getLogger(LoggerController.class);

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

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

在这里插入图片描述

在这里插入图片描述

使用日志对象打印日志

在这里插入图片描述

⽇志对象的打印⽅法有很多种,我们可以先使⽤ info() ⽅法来输出⽇志,如下代码所⽰:

  1. 定义日志对象
  2. 打印日志
@RestController
public class LoggerController {
    //日志对象
    private static Logger logger= LoggerFactory.getLogger(LoggerController.class);

    @PostConstruct
    public void print(){
        System.out.println("打印日志");
        logger.info("--------------要输出日志的内容----------------");
    }
}

打印⽇志效果展⽰:

在这里插入图片描述

工厂模式:

以前创建对象都是new什么的,工厂模式就是通过一个类,比如上面的LoggerFactory,帮助我们创建对象

⽇志框架介绍(了解)

在这里插入图片描述

SLF4J不同于其他⽇志框架, 它不是⼀个真正的⽇志实现,而是一个日志门面,⽽是⼀个抽象层, 对⽇志框架制定的⼀种规范,标准, 接⼝. 所有SLF4J并不能独⽴使⽤, 需要和具体的⽇志框架配合使⽤.

具体实现是log4j1/2,logback等等

⻔⾯模式(外观模式)

Facade Pattern

SLF4J是⻔⾯模式的典型应⽤(但不仅仅使⽤了⻔⾯模式).

⻔⾯模式定义

⻔⾯模式(Facade Pattern)⼜称为外观模式(其实一般说外观模式更常见,只是这里经常说一个日志门面所以称门面模式),提供了⼀个统⼀的接⼝, ⽤来访问⼦系统中的⼀群接⼝.其主要特征是定义了⼀个⾼层接⼝, 让⼦系统更容易使⽤。目的其实就是为了解耦合

原⽂: Provide a unified interface to a set of interfaces in a subsystem.Facade defines a higher level interface that makes the subsystem easier to use.

解释:要求⼀个⼦系统的外部与其内部的通信必须通过⼀个统⼀的对象进⾏. ⻔⾯模式提供⼀个⾼层次的接⼝,使得⼦系统更易于使⽤.

在这里插入图片描述

⻔⾯模式主要包含2种⻆⾊:

外观⻆⾊(Facade): 也称⻔⾯⻆⾊,系统对外的统⼀接⼝.

⼦系统⻆⾊(SubSystem): 可以同时有⼀个或多个 SubSystem. 每个 SubSytem 都不是⼀个单独的类,⽽是⼀个类的集合. SubSystem 并不知道 Facade 的存在, 对于 SubSystem ⽽⾔, Facade 只是另⼀个客⼾端⽽已(即 Facade 对 SubSystem 透明)

⽐如去医院看病,可能要去挂号, ⻔诊, 化验, 取药, 让患者或患者家属觉得很复杂, 如果有提供接待⼈员, 只让接待⼈员来处理, 就很⽅便.

在这里插入图片描述

⻔⾯模式的实现

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

如果家⾥设置⼀个总开关, 来控制整个屋的灯就会很⽅便.

我们使⽤⻔⾯模式的实现

public class FacadePatternDemo {
    public static void main(String[] args) {
        LightFacade lightFacade = new LightFacade();
        lightFacade.lightOn();
        lightFacade.lightOff();
    }
}

/**
 * 灯的⻔⾯
 */
class LightFacade {
    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();
}

/**
 * 客厅灯
 */
class LivingRoomLight implements Light {

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

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

/**
 * ⾛廊灯
 */
class HallLight implements Light {

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

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

/**
 * 餐厅灯
 */
class DiningLight implements Light {

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

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

⻔⾯模式的优点

  • 减少了系统的相互依赖. 实现了客⼾端与⼦系统的耦合关系, 这使得⼦系统的变化不会影响到调⽤它的客⼾端;
  • 提⾼了灵活性, 简化了客⼾端对⼦系统的使⽤难度, 客⼾端⽆需关⼼⼦系统的具体实现⽅式, ⽽只需要和⻔⾯对象交互即可.
  • 提⾼了安全性. 可以灵活设定访问权限, 不在⻔⾯对象中开通⽅法, 就⽆法访问
SLF4J 框架介绍

SLF4J 其实不是真实的日志框架实现,就是其他⽇志框架的⻔⾯. SLF4J 可以理解为是提供⽇志服务的统⼀API接⼝, 并不涉及到具体的⽇志逻辑实现.

不引⼊⽇志⻔⾯

常⻅的⽇志框架有log4J, logback等. 如果⼀个项⽬已经使⽤了log4j,⽽你依赖的另⼀个类库,假如是Apache Active MQ, 它依赖于另外⼀个⽇志框架logback, 那么你就需要把logback也加载进去.

在这里插入图片描述

存在问题:

  1. 不同⽇志框架的API接⼝和配置⽂件不同, 如果多个⽇志框架共存, 那么不得不维护多套配置⽂件(这个配置⽂件是指⽤⼾⾃定义的配置⽂件).

  2. 如果要更换⽇志框架, 应⽤程序将不得不修改代码, 并且修改过程中可能会存在⼀些代码冲突.

  3. 如果引⼊的第三⽅框架, 使⽤了多套, 那就不得不维护多套配置.

引⼊⽇志⻔⾯

引⼊⻔⾯⽇志框架之后, 应⽤程序和⽇志框架(框架的具体实现)之间有了统⼀的API接⼝(⻔⾯⽇志框架实现), 此时应⽤程序只需要维护⼀套⽇志⽂件配置, 且当底层实现框架改变时, 也不需要更改应⽤程序代码.

在这里插入图片描述

SLF4J 就是这个⽇志⻔⾯.

总的来说,SLF4J使你的代码独⽴于任意⼀个特定的⽇志API,这是⼀个对于开发API的开发者很好的思想.

日志格式的说明

打印的⽇志分别代表什么呢?

在这里插入图片描述

从上图可以看到,⽇志输出内容元素具体如下:

  1. 时间⽇期:精确到毫秒
  2. ⽇志级别:ERROR, WARN, INFO, DEBUG 或TRACE
  3. 进程ID
  4. 线程名
  5. Logger名(通常使⽤源代码的类名)
  6. ⽇志内容
⽇志级别

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

试想⼀下这样的场景,假设你是⼀家 2 万⼈公司的⽼板, 如果每个员⼯的⽇常⼯作和琐碎的信息都要反馈给你, 那你⼀定⽆暇顾及. 于是就有了组织架构,⽽组织架构就会分级,有很多的级别设置,如下图所⽰:

在这里插入图片描述

有了组织架构之后,就可以逐级别汇报消息了, 例如:组员汇报给组⻓, 组⻓汇报给研发⼀组, 研发⼀组汇报给 Java 研发, 等等依次进⾏汇报.

⽇志级别⼤概是同样的道理,有了⽇志级别之后就可以过滤⾃⼰想看到的信息了, ⽐如只关注error级别的, 就可以根据级别过滤出来error级别的⽇志信息, 节约开发者的信息筛选时间.

日志级别的分类

⽇志的级别从⾼到低依次为: FATAL、ERROR、WARN、INFO、DEBUG、TRACE

  • FATAL: 致命信息,表⽰需要⽴即被处理的系统级错误.
  • ERROR: 错误信息, 级别较⾼的错误⽇志信息, 但仍然不影响系统的继续运⾏.(不能长期不解决)
  • WARN: 警告信息, 不影响使⽤, 但需要注意的问题
  • INFO: 普通信息, ⽤于记录应⽤程序正常运⾏时的⼀些信息, 例如系统启动完成、请求处理完成等.
  • DEBUG: 调试信息, 需要调试时候的关键信息打印.
  • TRACE: 追踪信息, ⽐DEBUG更细粒度的信息事件(除⾮有特殊⽤意,否则请使⽤DEBUG级别替代)

⽇志级别通常和测试⼈员的Bug级别没有关系.

⽇志级别是开发⼈员设置的, ⽤来给开发⼈员看的. ⽇志级别的正确设置, 也与开发⼈员的⼯作经验有关. 如果开发⼈员把error级别的⽇志设置成了info, 就很有可能会影响开发⼈员对项⽬运⾏情况的判断. 出现error级别的⽇志信息较多时, 可能也没有任何问题. 测试的bug级别更多是依据现象和影响范围来判断

⽇志级别的顺序

在这里插入图片描述

级别越⾼, 收到的消息越少

日志级别的使用

⽇志级别是开发⼈员⾃⼰设置的. 开发⼈员根据⾃⼰的理解来判断该信息的重要程度

类似公司管理, 通常由领导来判断什么样的事情需要汇报, 什么样的事情不需要汇报

针对这些级别, Logger 对象分别提供了对应的⽅法, 来输出⽇志.

/**
 * 打印不同级别的⽇志
 * @return
 */
 @RequestMapping("/printLog")
 public String printLog() {
 	logger.trace("================= trace ===============");
 	logger.debug("================= debug ===============");
 	logger.info("================= info ===============");
 	logger.warn("================= warn ===============");
 	logger.error("================= error ===============");

 	return "打印不同级别的⽇志" ;
 }

SpringBoot 默认的⽇志框架是Logback, Logback没有 FATAL 级别, 它被映射到 ERROR .

出现fatal⽇志,表⽰服务已经出现了某种程度的不可⽤, 需要需要系统管理员紧急介⼊处理. 通常情况下, ⼀个进程⽣命周期中应该最多只有⼀次FATAL记录.

观察打印的⽇志结果:

在这里插入图片描述

结果发现, 只打印了info, warn和error级别的⽇志

这与⽇志级别的配置有关, Spring⽇志的输出级别默认是 info级别, 所以只会打印⼤于等于此级别的⽇志, 也就是info, warn和error.

但可以改,在 application.yml 文件中可以配置

logging:
	level:
 		root: debug

改成这样那些debug及其以上的日志就能打印出来了,但会变得很多

⽇志配置

上述是⽇志的使⽤, ⽇志框架⽀持我们更灵活的输出⽇志, 包括内容, 格式等.

配置⽇志级别

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

properties 和yml只需要配置其中⼀个即可.

⼆者转换⽅式: properties⽂件的点( . ) 对应yml⽂件中的换⾏

以下两个配置, 根据项⽬使⽤其中之⼀.

properties配置

logging.level.root: debug

yml配置

logging:
	level:
		root: debug

重新运⾏上述代码, 观察结果:

在这里插入图片描述

也可以分目录去打印日志

logging:
  level:
    root: info
    com:
      Hsu:
        demo: debug

这一段的意思就是Spring的日志只打印info级别以上的,而我们的项目日志打印debug级别以上的

⽇志持久化

长期保存。存储在外存硬盘中。因为内存一重启就刷新了

以上的⽇志都是输出在控制台上的, 然⽽在线上环境中, 我们需要把⽇志保存下来, 以便出现问题之后追溯问题. 把⽇志保存下来就叫持久化.

⽇志持久化有两种⽅式

  1. 配置⽇志⽂件名
  2. 配置⽇志的存储⽬录

在这里插入图片描述

配置⽇志⽂件的路径和⽂件名:

properties配置

logging.file.name: logger/springboot.log

yml配置

# 设置⽇志⽂件的⽂件名
logging:
	file: 
		name: logger/springboot.log

后⾯可以跟绝对路径或者相对路径

如果只是有文件名,那么就存放在工程目录下

在这里插入图片描述

配置⽇志⽂件的保存路径

properties配置

logging.file.path: D:/temp

yml配置

# 设置⽇志⽂件的⽂件名
logging:
	file:
		path: D:/temp

这种⽅式只能设置⽇志的路径, ⽂件名为固定的spring.log

运⾏程序, 该路径下多出⼀个⽇志⽂件: spring.log

在这里插入图片描述

注意:

logging.file.namelogging.file.path 两个都配置的情况下, 只⽣效其⼀, 以logging.file.name 为准

前者能设置名字也能设置路径,因此用前者就好

配置⽇志⽂件分割

**原因:**如果我们的⽇志都放在⼀个⽂件中, 随着项⽬的运⾏, ⽇志⽂件会越来越⼤, 需要对⽇志⽂件进⾏分割.

当然, ⽇志框架也帮我们考虑到了这⼀点, 所以如果不进⾏配置, 就⾛⾃动配置

默认⽇志⽂件超过10M就进⾏分割

配置项说明默认值
logging.logback.rollingpolicy.file-name-pattern⽇志分割后的⽂件名格式${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz
logging.logback.rollingpolicy.max-file-size⽇志⽂件超过这个⼤⼩就⾃动分割10MB

配置⽇志⽂件分割:

properties配置

logging.logback.rollingpolicy.file-name-pattern=${LOG_FILE}.%d{yyyy-MM-dd}.%i
logging.logback.rollingpolicy.max-file-size=1KB

yml配置

logging:
	logback:	
		rollingpolicy:
			max-file-size: 1KB
			file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i
  1. ⽇志⽂件超过1KB就分割(设置1KB是为了更好展⽰. 企业开发通常设置为200M, 500M等, 此处没有明确标准)

  2. 分割后的⽇志⽂件名为: ⽇志名.⽇期.索引

不是达到1KB就分割的,而是达到后以行来分割,而不是以字符

项⽬运⾏, 多打印⼀些⽇志, ⽇志分割结果:

在这里插入图片描述

配置⽇志格式

⽬前⽇志打印的格式是默认的

在这里插入图片描述

打印⽇志的格式, 也是⽀持配置的. ⽀持控制台和⽇志⽂件分别设置

配置项说明默认值
logging.pattern.console控制台日志格式%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
logging.pattern.file日志文件得到日志格式%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}

配置项说明:

  1. %clr(表达式){颜⾊} 设置输⼊⽇志的颜⾊

⽀持颜⾊有以下⼏种:

  • blue
  • cyan
  • faint
  • green
  • magenta
  • red
  • yellow
  1. %d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd’T’HH:mm:ss.SSSXXX}} ⽇期和时间–精确到毫秒

%d{} ⽇期

${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX} ⾮空表达式, 获取系统属性 LOG_DATEFORMAT_PATTERN , 若属性 LOG_DATEFORMAT_PATTERN 不存在,则使⽤ -yyyy-MM-dd HH:mm:ss.SSSXXX 格式, 系统属性可以System.getProperty("LOG_DATEFORMAT_PATTERN") 获取

  1. %5p 显⽰⽇志级别ERROR,MARN,INFO,DEBUG,TRACE.

  2. %t 线程名. %c 类的全限定名. %M method. %L 为⾏号. %thread 线程名称. %m 或者%msg 显⽰输出消息. %n 换⾏符

  3. %5 若字符⻓度⼩于5,则右边⽤空格填充. %-5 若字符⻓度⼩于5,则左边⽤空格填充. %.15 若符⻓度超过15,截去多余字符. %15.15 若字符⻓度⼩于15,则右边⽤空格填充. 若字符⻓度超过15,截去多余字符

更多说明, 参考: https://logback.qos.ch/manual/layouts.html#conversionWord

日志可以设置颜色,但只能设置控制台的颜色。因为日志可以出现在控制台、文件、消息队列。因为这不是日志的支持,而是idea的支持

设置了颜⾊, 却没有⽣效?

需要配置, 让idea⽀持控制台颜⾊显⽰

  1. 启动类设置DemoApplication

  2. 打开启动配置, 添加VM options

在这里插入图片描述

  1. 添加VM options -Dspring.output.ansi.enabled=ALWAYS

在这里插入图片描述

  1. 重新启动程序, 就发现控制台⽀持颜⾊了

在这里插入图片描述

properties配置

logging.pattern.console='%d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'

yml配置

logging:
	pattern:
		console: '%d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'
			file: '%d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'

项⽬运⾏, 观察⽇志变化:

在这里插入图片描述

通常情况下, 咱们就使⽤默认的⽇志格式打印即可.

更简单的⽇志输出

每次都使⽤ LoggerFactory.getLogger(xxx.class) 很繁琐, 且每个类都添加⼀遍, lombok 给我们提供了⼀种更简单的⽅式.

  1. 添加 lombok 框架⽀持
  2. 使⽤ @slf4j 注解输出⽇志。
添加 lombok 依赖
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<optional>true</optional>
</dependency>
输出⽇志
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
public class LogController {
	public void log(){
		log.info("--------------要输出⽇志的内容----------------");
	}
}

lombok 提供的 @Slf4j 会帮我们提供⼀个⽇志对象 log, 我们直接使⽤就可以.

在这里插入图片描述

总结

  1. ⽇志是程序中的重要组成部分,使⽤⽇志可以快速的发现和定位问题,Spring Boot 内容了⽇志框架,默认情况下使⽤的是 info ⽇志级别将⽇志输出到控制台的,我们可以通过 lombok 提供的@Slf4j 注解和 log 对象快速的打印⾃定义⽇志.

  2. ⽇志包含 6 个级别, ⽇志级别越⾼,收到的⽇志信息也就越少,我们可以通过配置⽇志的保存名称或保存⽬录来将⽇志持久化.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2048306.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IBMS管理平台,推动建筑行业向智能化发展

智能建筑管理系统是一套集成了多种技术和功能的综合性管理平台&#xff0c;旨在提高建筑设施的运行效率、减少能源消耗、改善室内环境质量&#xff0c;并为建筑管理者提供全面的监控、控制和分析手段。IBMS管理平台的特点和优势如下&#xff1a; IBMS系统融合了建筑自动化、能源…

2024 国内自闭症学校排名榜:突破边界,创造无限可能

在 2024 年&#xff0c;当家长们面对国内自闭症学校的排名榜时&#xff0c;心中或许充满了期待与困惑。然而&#xff0c;这些排名榜虽然能提供一定的参考&#xff0c;但绝不能成为选择学校的唯一依据。家长们更需要深入了解每所学校的真实情况&#xff0c;通过线下考察&#xf…

网络协议栈应用层的意义(内含思维导图和解析图通俗易懂超易理解)

绪论​&#xff1a; “节省时间的方法就是全力以赴的将所要做的事情完美快速的做完&#xff0c;不留返工重新学习的时间&#xff0c;才能省下时间给其他你认为重要的东西。” 本章主要讲到OSI网络协议栈中的应用层的作用和再次在应用层的角度理解协议的具体意义&#xff0c;以及…

#Datawhale AI夏令营第4期#多模态大模型Task3

写在前面的碎碎念》 为时一个礼拜的学习&#xff0c;即将结束了。回顾这一个礼拜&#xff0c;因此这次的任务较难&#xff0c;大部分的时间都花在跑模型上了&#xff0c;跑一次一天就没了&#xff0c;所以基本没有很好的去尝试优化上分&#xff0c;一个礼拜&#xff0c;差不多…

微商城系统 goods.php SQL注入漏洞复现

0x01 产品简介 微商城系统,又称微信商城系统,是基于微信等社交平台构建的一种小型电子商务系统。该系统融合了社交媒体的互动性和网络商城的交易功能,为商家提供了一个集商品展示、在线交易、营销推广、用户管理、数据分析等功能于一体的综合性电商平台。系统充分利用了微信…

【SecureLock】藏起你的秘密文件!

我们都知道&#xff0c;在 Windows 中可以右键文件夹&#xff0c;选择”属性“&#xff0c;勾选”隐藏“来实现隐藏某个文件夹。 我们还知道&#xff0c;在 Windows 中可以选择勾选 ”显示隐藏的项目和文件夹“&#xff0c;来使上述方法变得形同虚设。 本工具就是用于解决以上…

使用Linux内核自带的V4L2设备驱动 采集图像

一、定义 V4L2代表Video for Linux Two&#xff0c;它是Linux内核的一部分&#xff0c;提供了一种统一的方式来访问各种视频输入/输出设备&#xff0c;如摄像头、电视卡等。 二、工作流程&#xff08;重点&#xff09; 打开设备&#xff0d;> 检查和设置设备属性&#xf…

Elasticsearch-关键词随机查询(8.x)

目录 一、查询语句 二、Java代码实现 基础介绍&#xff1a; ES自定义评分机制:function_score查询详解-阿里云开发者社区ES自定义评分机制:function_score查询详解https://developer.aliyun.com/article/1054571 开发版本详见&#xff1a;Elasticsearch-经纬度查询(8.x-半径…

面向对象程序设计(C++)之 vector(初阶)

1. vector 的构造 vector 需要显式实例化类模版&#xff0c;在创建 vector 类型的容器时可以直接创建&#xff0c;也可以进行初始化&#xff0c;例如 v2 &#xff0c;也可以使用迭代器的方式创建&#xff0c;具体关于更多vector的知识: vector //模版类只能显式实例化 vector&l…

Linux ubuntu 24.04 安装运行《帝国时代3》免安装绿色版游戏,解决 “Could not load DATAP.BAR”等问题

Linux ubuntu 24.04 安装运行《帝国时代3》游戏&#xff0c;解决 “Could not load DATAP.BAR" 等问题 《帝国时代 3》是一款比较经典的即时战斗游戏&#xff0c;伴随了我半个高中时代&#xff0c;周末有时间就去泡网吧&#xff0c;可惜玩的都是简单人机&#xff0c;高难…

构建具有音频功能的中英翻译器:一个Python应用程序的旅程

在当今的全球化世界中&#xff0c;语言翻译工具变得越来越重要。作为一名软件开发者&#xff0c;我最近完成了一个有趣的项目&#xff1a;一个结合了翻译、文字转语音和数据管理功能的中英翻译器。在这篇博客中&#xff0c;我将分享这个应用程序的主要特性和开发过程中的一些见…

CSC7261BH PD20瓦快充芯片

CSC7261BH是一款20瓦内置高压MOS的高性能、多工作模式的PWM控制芯片&#xff0c;内置多种保护机制。当系统为空载和轻载时&#xff0c;CSC7261BH 采用Burst和Green控制模式可有效地减少了空载和轻载时的损耗。当系统为中载和重载时&#xff0c;CSC7261BH采用CCM模式可有效提升电…

【kubernetes】K8S常见的发布方式

一、K8S常见的发布方式 蓝绿发布 两套环境交替升级&#xff0c;旧版本保留一定时间便于回滚 优点&#xff1a;对用户无感&#xff0c;是最安全的发布方式&#xff0c;业务稳定 缺点&#xff1a;需要两套系统&#xff0c;对资源要求比较高&#xff0c;成本特别高 灰度发布&…

STM32标准库学习笔记-3.外部中断

参考教程&#xff1a;【STM32入门教程-2023版 细致讲解 中文字幕】 中断 中断含义&#xff1a;在计算机执行主程序运行过程中&#xff0c;出现了特定的中断触发条件&#xff08;中断源&#xff09;&#xff0c;使得CPU暂停当前正在运行的程序&#xff0c;转而去处理中断程序&…

使用docker compose一键部署 Portainer

使用docker compose一键部署 Portainer Portainer 是一款轻量级的应用&#xff0c;它提供了图形化界面&#xff0c;用于方便地管理Docker环境&#xff0c;包括单机环境和集群环境。 1、创建安装目录 mkdir /data/partainer/ -p && cd /data/partainer2、创建docker…

【C语言篇】数组和函数的实践:扫雷游戏(附源码)

文章目录 前言扫雷游戏的分析和设计扫雷游戏的功能说明游戏的分析和设计文件结构设计 扫雷游戏的代码实现初始化棋盘打印棋盘布置雷排查雷 扫雷游戏的拓展 前言 源码在最后 扫雷游戏的分析和设计 经典扫雷游戏 扫雷游戏的功能说明 使⽤控制台实现经典的扫雷游戏 游戏可以通…

8月14日微语报,星期三,农历七月十一

8月14日微语报&#xff0c;星期三&#xff0c;农历七月十一&#xff0c;工作愉快&#xff0c;生活喜乐&#xff01; 一份微语报&#xff0c;众览天下事&#xff01; 1、巴黎奥运会&#xff1a;32项次世界纪录被刷新&#xff0c;125项次奥运纪录被改写。 2、国家邮政局&#…

鸿蒙应用程序框架基础

鸿蒙应用程序框架基础 应用程序包基础知识应用的多Module设计机制Module类型 Stage模型应用程序包结构开发态包结构编译包形态发布台包结构选择合适的包类型 应用程序包基础知识 应用的多Module设计机制 **支持模块化开发&#xff1a;**一个应用通常会包含多种功能&#xff0…

【stm32项目】多功能智能家居室内灯光控制系统设计与实现(完整工程资料源码)

多功能智能家居室内灯光控制系统设计与实现 目录&#xff1a; 目录&#xff1a; 前言&#xff1a; 一、项目背景与目标 二、国内外研究现状&#xff1a; 2.1 国内研究现状&#xff1a; 2.2 国外研究现状&#xff1a; 2.3 发展趋势 三、硬件电路设计 3.1 总体概述 3.2 硬件连接总…

[NSSCTF 2022 Spring Recruit]babyphp

if嵌套&#xff0c;先过第一个if&#xff0c;需要a不含数字而且intval取整数 intval:通过使用指定的进制 base 转换&#xff08;默认是十进制&#xff09;&#xff0c;返回变量 value 的 int 数值。 intval() 不能用于 object&#xff0c;否则会产生 E_WARNING 错误并返回 1。…