《JavaEE进阶》----15.<Spring Boot 日志>

news2024/9/25 11:14:37

本篇文章将记录我学习SpringBoot日志

1.日志文件的用途

2.SpringBoot日志文件的配置

3.用lombook依赖引入@Slf4j注解,从而引入log对象。方便我们打印日志。

一、日志的作用

日志主要是为了发现问题、分析问题、定位问题。除此之外、日志还有许多其他的用途。

1.系统监控

我们可以通过日志记录这个系统的运行状态,每一个方法的响应时间、响应状态等。对数据进行分析,设置不同的规则。超过阈值时进行报警。比如统计日志中关键字的数量,并在关键字数量达到一定条件时报警。

2.数据采集

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

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

推荐排序:目前推荐排序应用在各个领域。比如购物、广告、新闻等待。数据采集是推荐排序中必须做的一环。系统通过日志记录用户的浏览历史,停留时长。算法人员通过分析这些数据。训练模型给用户做推荐。

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

3.日志审计

如今系统安全成为项目中的一个重要环节。安全审计也是系统中非常重要的部分。国家的政策法规、行业标准等都明确对日志审计提出了要求。通过系统日志分析,可以判断一些非法攻击、非法调用,以及系统处理过程中的安全隐患。

比如运行系统中运营人员在通过页面处理一些数据的时候。如果没有清楚的日志操作记录、一条数据被删除或者修改。是无法找到是谁操作的,若做了记录、就会一目了然。

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

 二、打印日志

打印日志的步骤

1.获取日志对象(Logger)

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

注意:

I、Logger类是org.slf4j包中的。

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

2.使用日志对象打印日志

通过定义一个Logger属性来打印日志。 

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

    @RequestMapping("/printfLog")
    public String printfLog(){

        logger.info("我是logger打印的日志..........");
        System.out.println("打印日志!");
        return "success";
    }
}

运行结果:

三、门面系统

3.1日志框架(了解)

PS:

slf4j是一个日志门面,不是一个真正的日志框架

log4j是一个日志框架。

3.2门面模式(外观模式)

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

3.2.1门面模式的定义及优点:

门面模式(Facade Pattern):

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

门面模式主要包含2中角色:

1.外观角色(Facade):也称门面角色,系统对外的统一接口。

2.子系统角色(SubSystem):可以同时有一个或多个SubSystem。每个SubSystem都不是单独的类,而是一个类的集合。SubSystem并不知道Facade的存在。对于SubSystem,Facade只是一个客户端而已。

比如去医院挂号,有个接待员就会方便很多:

接待员就是门面角色。

优点:

1.减少了系统的相互依赖,实现了客户端与子系统的耦合关系。使得子系统的变化不会影响到它的客户端。

2.提高了灵活性,简化了客户端对子系统的使用难度。客户端无需关心子系统的实现方式。只需要和门面对象交互就可以。

3.提高了安全性,可以灵活设定访问权限,不在门面对象中开通方法,就无法访问。

3.2.2 门面模式的实现

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

package com.qyy.springbootlog.demos.facade;
public class FacadeDemo {
    public static void main(String[] args) {
        LightFacade lightFacade = new LightFacade();
        lightFacade.on();
    }

}
打开卧室的灯!
打开客厅的灯!
打开走廊的灯!

通过调用LightFacade这个所有灯的门面。我们就可以实现将卧室、客厅、走廊的灯都打开。这就是门面模式。 

 LightFacade这个类的实现细节:

public class LightFacade {
    BedRoomLight bedRoomLight = new BedRoomLight();
    LivingRoomLight livingRoomLight = new LivingRoomLight();
    HallLight hallLight = new HallLight();
    //打开所有灯
    void on(){
        bedRoomLight.on();
        livingRoomLight.on();
        hallLight.on();
    }
    //关闭所有灯
    void off(){
        bedRoomLight.off();
        livingRoomLight.off();
        hallLight.off();
    }
}

客厅、走廊、卧室灯的实现细节:

public class LivingRoomLight implements Light{
    @Override
    public void on() {
        System.out.println("打开客厅的灯!");
    }
    @Override
    public void off() {
        System.out.println("关闭客厅的灯");
    }
}
public class HallLight implements Light{
    @Override
    public void on() {
        System.out.println("打开走廊的灯!");
    }
    @Override
    public void off() {
        System.out.println("关闭走廊的灯!");
    }
}
public class BedRoomLight implements Light{
    @Override
    public void on() {
        System.out.println("打开卧室的灯!");
    }
    @Override
    public void off() {
        System.out.println("关闭卧室的灯!");
    }
}

 灯这个接口的实现细节。

interface Light {
    void on();
    void off();
}

流程图:

客户端只需要创建门面对象。来实现对所有灯的打开/关闭。

四、SLF4J 框架(门面)介绍

SLF4J就是其他日志框架的门面. SLF4J 可以理解为是提供日志服务的统一API接口,

并不涉及到具体的日志逻辑实现。

若不引入日志门面

当我们还没有引入日志门面的时候,常见的日志框架有log4J、logback等。

如果一个项目已经使用了log4j。而你依赖的另一个库,假如是Apache Active MQ,它依赖于另外一个日志框架logback。那么你需要把logback也加载进去。

 存在的问题:

1.不同日志框架的API接口和配置文件不同,如果多个日志框架共存。那么不得不维护多套配置文件(这个配置文件是指用户自定义的配置文件)

2.如果要更换日志框架,程序不得不修改代码。并且修改过程中可能存在一些代码冲突。

3.如果引入的第三方框架,使用了多套,那就不得不维护多套配置。

引入日志门面

引入门面日志框架后。应用程序和日志框架(框架的具体实现)之间有了统一的API接口(门面之日框架实现)。因此应用程序只需要维护一套日志文件的配置。且当底层实现框架改变时。也不需要更改应用程序代码。 

SLF4J就是这个日志门面

SLF4J让代码独立于任意一个特定的日志API。这是对于开发者很好的思想

五、日志的具体介绍

5.1日志的格式说明

我们看这段日志,讲解一下日志内容元素的具体介绍:

1.时间日期:精确到毫秒

2.日志级别:ERROR、WARN、INFO、DEBUG、TRACE

3.进程ID

4.线程名

5.Logger名(通常使用源代码的类名)

6.日志内容

5.2日志级别

日志级别代表日志信息对应问题的严重性。有了日志级别之后就可以过滤自己想看到的信息了,比如只关注error级别的,就可以根据级别过滤出来error级别的日志信息,节约开发者的信息筛选时间。

日志的级别从高到低依次为:FATAL、ERROR、WARN、INFO、DEBUG、TRACE。

FATAL:致命信息,表示需要立即被处理的系统级错误. 

ERROR:错误信息,级别较高的错误日志信息,但仍然不影响系统的继续运行,但需要我们进行处理。

WARN:警告信息,不影响使用,但需要注意的问题 

INFO:普通信息,用于记录应用程序正常运行时的一些信息,例如系统启动完成、请求处理完成等.

DEBUG:调试信息,需要调试时候的关键信息打印.

TRACE:追踪信息,比DEBUG更细粒度的信息事件(除非有特殊用意,否则请使用DEBUG级别替代)

注:

日志级别通常和测试人员的Bug级别没有关系。

日志级别是开发人员设置的,用来给开发人员看的。

 日志级别越高,收到的消息越少。

5.3日志级别的使用

日志级别是开发人员自己设置的。开发人员根据自己的理解来判断该信息的重要程度。

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

注:

  • SpringBoot默认的日志框架是Logback,Logback没有 FATAL 级别的日志。它被映射到ERROR 。
  • 出现fatal日志,表示服务已经出现了某种程度的不可用,需要需要系统管理员紧急介入处理.通常情 况下,一个进程生命周期中应该最多只有一次FATAL记录.
    @RequestMapping("/level")
    public String printfLevel(){
        logger.error("我是error级别的日志!");
        logger.warn("我是warn级别的日志!");
        logger.info("我是info级别的日志!");
        logger.debug("我是debug级别的日志!");
        logger.trace("我是trace级别的日志!");
        return "打印不同级别的日志";
    }

我们发现,debug、trace级别的日志没有被打印出来。

这与日志级别的配置有关,日志的输出级别默认是 info 级别,所以只会打印大于等于此级别的日志,也就是info、warn、error。

六、日志的配置

这里只做简单的介绍,更多的配置我们随时查阅都能查到。

常见的 Application Properties

6.1配置日志级别

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

properties和yml二者转换方式:

Properties文件的点( . )对应yml文件中的换行

我们将日志级别配置为debug级别(默认是info)。这里我们使用yml类型配置,配置代码如下:

logging:
  level:
    root: debug

重新运行上面的日志级别的打印。debug级别的日志就全部出来了。这里我们只截取了我们刚刚打印的部分。此时我们发现之前没有打印出来的debug级别日志就被打印出来了。除此之前Spring中的debug级别的日志也都被打印出来了。

其中root是根目录,这个代码配置整个项目的日志级别为debug。 

我们还可以更细致的配置某个包、甚至某个类是debug级别

logging:
#设置日志级别
  level:
    root: info
    com:
      qyy:
        springbootlog:
          demos:
            controller: debug

6.2日志配置持久化

概念

上面我们看到的日志都是输出在控制台上的,然而在线上环境中,我们需要把日志保存下来,以便于出现问题后追溯问题,把日志保存下来存到硬盘中就叫做日志的持久化

日志持久化方式

1.配置日志文件名

2.配置日志的存储目录

两个都配置的情况下.name生效。

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

示例:

logging:
#设置日志级别
  level:
    root: debug
#设置日志文件的路径和文件名
  file:
    name: logger/springboot.log

 

运行之后日志内容就被存放了这个路径之下了。

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

6.3 配置日志文件分割

我们可以对日志文件进行分割。这样更方便我们查看日志。

如果我们不进行配置,日志框架默认走自动配置。默认日志文件超过10M就进行分割。

#日志分割
logger:
  logback:
    rollingpolicy:
#分割后的格式设置:⽇志⽂件名为:⽇志名.⽇期.索引
      file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i
#日志分割条件
      max-file-size: 200MB

通常不需要开发人员设置,公司运维会统一进行处理。不仅仅设置这些,还会设置日志存放时间。

小公司可能例外。什么都要开发做。

6.4配置日志格式

 通常不需要我们自己设置,因为默认的已经很好了。

 配置项说明:

1. %clr(表达式){颜色} 设置输入日志的颜色

支持的颜色有:blue、cyan、faint(黑色)、green、magenta、red、yellow。

2.%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") 获取

3.

%5p 显示日志级别ERROR,MARN,INFO,DEBUG,TRACE.

4.

%t 线程名.

%c 类的全限定名.

%M method.

%L 为行号.

%thread 线程名称.

%m 或者%msg 显示输出消息.

%n 换行符

5.

%5 若字符长度小于5,则右边用空格填充.

%-5 若字符长度小于5,则左边用空格填充.

%.15 若 字符长度超过15,截去多余字符.

%15.15 若字符长度小于15,则右边用空格填充.若字符长度超过15,截去多余字符

设置了颜色,却没有生效?需要配置,

让idea支持控制台颜色显示

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

中文版 

 

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

3.重新启动程序就可以看到颜色了

七、更简单的志日输出(重点)

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

7.1.添加 lombok 框架支持 

lombok依赖

<dependency>
 <groupId>org.projectlombok</groupId>
 <artifactId>lombok</artifactId>
 <optional>true</optional>
</dependency>

7.2 输出日志

使用@slf4j 注解输出日志,lombok提供的 @Slf4j 会帮我们提供一个日志对象log,

我们直接使用就可以。

我们点进去@slf4j 注解

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package lombok.extern.slf4j;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE})
public @interface Slf4j {
    String topic() default "";
}

 @Retention代表生命周期。

RetentionPolicy.SOURCE 说明生命周期只存在于源码

@Slf4j
@RestController
@RequestMapping("log")
public class LoggerController {

    @RequestMapping("/printfLog")
    public String printfLog(){

        log.info("我是logger打印的日志..........");
        System.out.println("打印日志!");
        return "success";
    }
    @RequestMapping("/level")
    public String printfLevel(){
        log.error("我是error级别的日志!");
        log.warn("我是warn级别的日志!");
        log.info("我是info级别的日志!");
        log.debug("我是debug级别的日志!");
        log.trace("我是trace级别的日志!");
        return "打印不同级别的日志";
    }
}

注解的生命周期只存在于源码阶段、在编译的时候就已经没有了。 

写了这个注解就自动帮我们生成那一行代码。

小总结:

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

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

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

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

相关文章

玩转西门子 S7-1200/1500 的 Modbus RTU 通信诊断

01 概述工控人加入PLC工业自动化精英社群 Modbus RTU 是一种串行通信协议&#xff0c;由于具有协议透明&#xff0c;实现成本低&#xff0c;简单易用等诸多特点&#xff0c;至今仍然广泛应用在工业控制的各个领域。 为了通信可以长期稳定的运行&#xff0c;并且可以在故障时可…

Vue组件:依赖注入provide和inject的使用

1、Prop 逐级透传问题 通常情况下&#xff0c;当我们需要从父组件向子组件传递数据时&#xff0c;会使用 props。想象一下这样的结构&#xff1a;有一些多层级嵌套的组件&#xff0c;形成了一棵巨大的组件树&#xff0c;而某个深层的子组件需要一个较远的祖先组件中的部分数据…

智慧水务建设的核心内容

智慧水务解决方案的主要对象客户是全国各地水务投资集团、水务局、水司、水厂、农水办,也会有少量项目涉及到住建局或城管局。解决方案通常会以具体的某个业务单位的职能工作为切入点,配合物联感知、大数据分析、人工智能等技术手段,为城市供水、乡村供水的水质安全、供水调…

一文彻底了解DNS协议工作原理,恐怕没有比这更通俗易懂的了吧?

了解DNS工作原理有助于深入理解互联网通信的基础机制&#xff0c;对于网络运维、开发以及优化网站访问速度至关重要。它能帮助解决域名解析问题&#xff0c;提升用户体验&#xff0c;同时对于网络安全和防护也具有重要意义。本文博主反反复复、前前后后斟酌了三天&#xff0c;就…

【学习笔记】手写Tomcat 二

目录 响应静态资源 HTTP协议请求格式 1. 解析请求信息 创建解析请求类 HttpRequest 2. 创建静态资源目录 webs 3. 封装响应信息 创建静态资源处理器 StaticResourceHandler 创建响应类 HttpResponse 作业 1. 绘制 请求解析类 HttpRequest 和响应类 HttpResponse 的封…

动手学深度学习(pytorch土堆)-03常见的Transforms

Compose transforms.Compose 是 PyTorch 中的一个函数&#xff0c;用于将多个图像变换操作组合在一起&#xff0c;形成一个变换流水线。这样可以将一系列的图像处理操作整合为一个步骤&#xff0c;便于对图像进行批量预处理或增强。 基本用法 transforms.Compose 接受一个列表…

vue + Lodop 制作可视化设计页面 实现打印设计功能(四)

历史&#xff1a; vue2 Lodop 制作可视化设计页面 实现打印设计功能&#xff08;一&#xff09; vue Lodop 制作可视化设计页面 实现打印设计功能&#xff08;二&#xff09; vue Lodop 制作可视化设计页面 实现打印设计功能&#xff08;三&#xff09; 前言&#xff1a…

必看!实网环境下,合宙Cat.1模组低功耗详细数据

一、背景说明 合宙4G Cat.1模组以低功耗为显著特点&#xff0c;提供了三种功耗模式以适应不同需求。 分别是&#xff1a;常规模式&#xff0c;低功耗模式&#xff0c;PSM模式。 在实际应用中&#xff0c;用户可以根据不同的应用场景和需求&#xff0c;灵活选择合宙4G Cat.1模…

数据结构与算法图论 并查集

前言 写一道并查集的题 判断是否为亲戚 原题目&#xff1a;现在有若干家族图谱关系&#xff0c;给出了一些亲戚关系&#xff0c;如Marrv和Tom是亲戚&#xff0c;Tom和Ben是亲戚等等。从这些信息中&#xff0c;你可以推导出Marry和Ben是亲戚。请写一个程序&#xff0c;对于我…

一文读懂在线学习凸优化技术

一文读懂在线学习凸优化技术 在当今的数据驱动时代&#xff0c;机器学习算法已成为解决复杂问题的关键工具。在线学习凸优化作为机器学习中的一项核心技术&#xff0c;不仅在理论研究上具有重要意义&#xff0c;还在实际应用中展现出巨大的潜力。本文将深入浅出地介绍在线学习…

C++(三)----内存管理

1.C/C内存分布 看下面这个问题&#xff08;考考你们之前学的咋样&#xff09;&#xff1a; int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] {1, 2, 3, 4};char char2[] "abcd";char* pCh…

【leetcode C++】 动态规划

4. 91 解码方法 题目&#xff1a; 一条包含字母 A-Z 的消息通过以下映射进行了 编码 &#xff1a; "1" -> A "2" -> B ... "25" -> Y "26" -> Z 然而&#xff0c;在 解码 已编码的消息时&#xff0c;你意识到有许多不同的…

数据湖-方案对比

数据湖架构结合了数据湖和数据仓库。虽然它不仅仅是两者之间的简单集成&#xff0c;但其理念是充分发挥两种架构的优势&#xff1a;数据仓库的可靠交易以及数据湖的可扩展性和低成本。 Lakehouse 架构支持管理各种数据类型&#xff0c;例如结构化、半结构化和非结构化数据&…

巧用工具,Vue 集成 medium-zoom 实现图片缩放

文章目录 巧用工具&#xff0c;Vue 集成 medium-zoom 实现图片缩放介绍medium-zoomVue3集成 medium-zoom 示例Vue2集成 medium-zoom 示例进阶 - 可选参数 巧用工具&#xff0c;Vue 集成 medium-zoom 实现图片缩放 在现代网页开发中&#xff0c;为用户提供良好的视觉体验至关重…

爬虫逆向学习(六):补环境过某数四代

声明&#xff1a;本篇文章内容是整理并分享在学习网上各位大佬的优秀知识后的实战与踩坑记录 引用博客&#xff1a; https://blog.csdn.net/shayuchaor/article/details/103629294 https://blog.csdn.net/qq_36291294/article/details/127699273 https://blog.csdn.net/weixin_…

vivo手机已删除的短信还能恢复吗?

虽然现在我们很少使用vivo手机的短信功能&#xff0c;但是我们偶尔还会通过vivo手机短信功能接收一些重要的信息。如果我们在清理垃圾短信的时候误删了vivo手机重要短信&#xff0c;该怎么恢复呢&#xff1f; 方法一&#xff1a;通过vivo云服务恢复 1、确保您已开启vivo云服务…

Go常用正则函数整理

前言 在Go语言中&#xff0c;标准库regexp提供了丰富的API来处理正则表达式&#xff0c;支持编译、匹配、查找、替换等操作。以下是一个Go标准库正则函数的常用大全教程及部分使用示例。 Go标准库常用正则函数 Compile&#xff1a;编译正则表达式&#xff0c;返回一个可用于…

Qt 构建报错 undefined reference to xxx

初次学习使用Qt&#xff0c;在构建时报错。这是个典型报错&#xff0c;熟练vs与c的朋友一眼就可以看出要么是库出问题了&#xff0c;要么是库链接出问题了。那么就可以按照相对明确的方向找问题。 1、确认库与项目配置是否一致。32位还是64位&#xff0c;debug还是release一定…

如何逆转Instagram账号流量减少?4个实用技巧分享

Instagram作为全球十大社媒之一&#xff0c;不仅是个人分享生活的平台&#xff0c;还是跨境卖家进行宣传推广和客户开发的关键工具。在运营Instagram的过程中&#xff0c;稍有不慎就容易出现账号被限流的情况&#xff0c;对于账号状态和运营工作的进行都十分不利。 一、如何判断…

new String(),toString()和Arrays.toString()的区别

下面写了一段代码来展示结果 import javax.sound.midi.Soundbank; import java.util.Arrays; import java.util.Scanner;public class Main {public static void main(String[] args) {String str "abc";System.out.println("str:"str);char[] chars st…