springboot使用slf4j+log4j2实现项目日志记录

后端Java是如何记录项目日志的

1.日志的概念

项目中日志文件作用的是什么
日志文件是用于记录系统操作事件的文件集合,可分为事件日志和消息日志。具有处理历史数据、诊断问题的追踪以及理解系统的活动等重要作用。
在计算机中,日志文件是记录在操作系统或其他软件运行中发生的事件或在通信软件的不同用户之间的消息的文件。记录是保持日志的行为。在最简单的情况下,消息被写入单个日志文件 。
许多操作系统,软件框架和程序包括日志系统。广泛使用的日志记录标准是在因特网 工程任务组(IETF )RFC 5424中定义的 syslog。 syslog标准使专用的标准化子系统能够生成,过滤,记录和分析日志消息。

什么是调试日志
软件开发中,我们经常需要去调试程序,做一些信息,状态的输出便于我们查询程序的运行状况。为了让我们能够更加灵活和方便的控制这些调试的信息,所有我们需要专业的日志技术。java中寻找bug会需要重现。调试也就是debug 可以在程序运行中暂停程序运行,可以查看程序在运行中的情况。日志主要是为了更方便的去重现问题。

什么是系统日志
系统日志是记录系统中硬件、软件和系统问题的信息,同时还可以监视系统中发生的事件。用户 可以通过它来检查错误发生的原因,或者寻找受到攻击时攻击者留下的痕迹。系统日志包括系统 日志、应用程序日志和安全日志。

系统日志的价值
系统日志策略可以在故障刚刚发生时就向你发送警告信息,系统日志帮助你在最短的时间内发现问题。
系统日志是一种非常关键的组件,因为系统日志可以让你充分了解自己的环境。这种系统日志信息对于决定故障的根本原因或者缩小系统攻击范围来说是非常关键的,因为系统日志可以让你了解故障或者袭击发生之前的所有事件。为虚拟化环境制定一套良好的系统日志策略也是至关重要的,因为系统日志需要和许多不同的外部组件进行关联。良好的系统日志可以防止你从错误的角度分析问题,避免浪费宝贵的排错时间。另外一种原因是借助于系统日志,管理员很有可能会发现一些之前从未意识到的问题,在几乎所有刚刚部署系统日志的环境当中。

2. 日志门面和日志实现

当我们的系统变的更加复杂的时候,我们的日志就容易发生混乱。随着系统开发的进行,可能会更新不同的日志框架,造成当前系统中存在不同的日志依赖,让我们难以统一的管理和控制。就算我们强制要求所有的模块使用相同的日志框架,系统中也难以避免使用其他类似
spring,mybatis等其他的第三方框架,它们依赖于我们规定不同的日志框架,而且他们自身的日志系统就有着不一致性,依然会出来日志体系的混乱。
所以我们需要借鉴JDBC的思想,为日志系统也提供一套门面,那么我们就可以面向这些接口规范来开发,避免了直接依赖具体的日志框架。这样我们的系统在日志中,就存在了日志的门面和日志的实现。

常见的日志门面 :
JCL:日志实现一套统一的api接口,apache推出的一个日志门面技术。JCL也是有缺陷的他当时只考虑了,主流的jcl和log4j。后面随着技术的的发展新的日志技术JCL是不支持的。后面jcl渐渐被淘汰了。

slf4j:slf4j站出来了,日志实现一套统一的api接口。日志门面技术比JCL更为强大,slf4j是目前主流的日志门面技术,可以操作所有的日志实现框架。

常见的日志实现:
JUL:java自带的日志实现框架,功能比较单一、
log4j:apache推出的实现框架,相对jul他的功能就比较强大了、
logback:日志实现框架性能比log4j好很多、比较火热的springboot2.0以后默认推荐使用了、
log4j2:Log4j 2是对Log4j的升级版,参考了logback的一些优秀的设计,并且修复了一些问题,因此带来了一些重大的提升log4j2是目前日志实现框架性能最好的,没有之一。

3. SpringBoot 中的日志使用

springboot框架在企业中的使用越来越普遍,springboot日志也是开发中常用的日志系统。springboot默认就是使用SLF4J作为日志门面,logback作为日志实现来记录日志。

4. SpringBoot中的日志设计

<dependency>
    <artifactId>spring-boot-starter-logging</artifactId>
    <groupId>org.springframework.boot</groupId>
</dependency>

spring-boot-starter-logging日志启动器默认就是完成日志传递的。该依赖用于开启springboot默认的slf4j日志门面和logback日志实现。由于spirngboot的依赖传递所以该依赖可以不用我们单独导入,导入springboot的相关依赖之后该依赖就存在了。
springboot日志依赖关系图:
在这里插入图片描述

5. springboot依赖总结

spring-boot-starter-logging日志启动器默认就是完成日志传递的

  1. springboot 底层默认使用logback作为日志实现。
  2. 使用了SLF4J作为日志门面
  3. 将JUL也转换成slf4j
  4. 也可以使用log4j2作为日志门面,但是最终也是通过slf4j调用logback

6. springboot使用slf4j+log4j2实现项目日志记录

虽然springboot默认就是使用SLF4J作为日志门面,logback作为日志实现来记录日志,但是围绕java的日志技术也在不断迭代升级。其中apache组织也对原有的日志实现技术log4j做出了升级,就是现在的日志实现框架log4j2。log4j2作为日志的实现框架他的功能,性能各方面要高于logback很多。所以现在在java项目中也十分主流:slf4j(日志的门面)+log4j2(日志的实现框架),来支撑我们java软件项目中需要的日志技术。
下面就对springboot中如何使用slf4j+log4j2来实现日志。以及记录日志文件在项目中是如何分类的,我们到地应该如何去正确的打印日志。做一个相对全面的demo示例。
start…

1.创建项目
在这里插入图片描述

2.pom文件导入日志相关依赖

<!--web-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <!-- 排除 logback 日志实现。排除日志启动器就表示排除logback了-->
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
    <version>2.1.5.RELEASE</version>
</dependency>

<!--starter-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <!--排除springbootloggging起步日志, 也就排除了logback-->
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
        <!--排除log4j的适配器,也就排除了log4j-->
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
    </exclusions>
    <version>2.1.5.RELEASE</version>
</dependency>

<!--导入log4j2依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

<!--导入log4j2 的异步日志依赖-->
<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.3.4</version>
</dependency>

<!--spring拦截器 AOP-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<!-- fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.4</version>
</dependency>

<!-- lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
</dependency>

说明:如果你正在做某某项目正好需要使用到slf4j+logj2,导入上面的的日志是十分必要的。除过log4j2的相关依赖我还导入了其他依赖。AOP、fastjson、lombok后面有用处。

3.日志的配置文件log4j2.xml,该配置的作用:可以将log4j2日志按级别输出到不同文件中。

<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--
    status="warn" Configuration后面日志框架本身的输出日志级别,可以不加入
    monitorInterval="5" 自动加载配置文件的间隔时间, 不低于 5 秒
    注: 我们的配置文件修改后在生产环境下无需重启应用, 可以实现热更新的效果
-->
<Configuration monitorInterval="5">

    <!--全局属性-->
    <Properties>
        <Property name="APP_NAME">duobao-log4j2</Property>
        <Property name="LOG_FILE_PATH">D:/logs/${APP_NAME}</Property>
        <Property name="PATTERN_FORMAT">%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n</Property>
    </Properties>

    <!--输出源-->
    <Appenders>

        <!--输出到控制台-->
        <Console name="Console" target="SYSTEM_ERR"><!--输出的类型SYSTEM_ERR-->
            <PatternLayout pattern="${PATTERN_FORMAT}"/>
        </Console>


        <!--输出info信息日志到文件 用来定义超过指定大小自动删除旧的创建新的的Appender.-->
        <RollingFile name="RollingInfoFile" fileName="${LOG_FILE_PATH}/info.log"
                     filePattern="${LOG_FILE_PATH}/$${date:yyyyMM}/info-%d{yyyyMMdd}-%i.log.gz">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <Filters>
                <ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL"/>  <!--高于warn级别就放行,低于这个级别就拦截-->
                <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>

            <PatternLayout>
                <pattern>${PATTERN_FORMAT}</pattern> <!--文件路径-->
            </PatternLayout>

            <!--设置文件具体拆分规则-->
            <Policies>
                <!--在系统启动时, 触发拆分规则,生产一个新的日志文件-->
                <OnStartupTriggeringPolicy/>
                <!--按照文件大小拆分, 30 MB -->
                <SizeBasedTriggeringPolicy size="30 MB"/>
                <!--按照时间节点拆分, 规则根据filePattern定义的-->
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <!--在同一个目录下,文件的个数限定为 30 个, 超过进行覆盖-->
            <DefaultRolloverStrategy max="30"/>
        </RollingFile>


        <!--输出警告日志到文件-->
        <RollingFile name="RollingWarnFile" fileName="${LOG_FILE_PATH}/warn.log"
                     filePattern="${LOG_FILE_PATH}/$${date:yyyyMM}/warn-%d{yyyyMMdd}-%i.log.gz">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <Filters>
                <ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/>
                <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>

            <PatternLayout>
                <pattern>${PATTERN_FORMAT}</pattern> <!--文件路径-->
            </PatternLayout>

            <!--设置文件具体拆分规则-->
            <Policies>
                <!--在系统启动时, 触发拆分规则,生产一个新的日志文件-->
                <OnStartupTriggeringPolicy/>
                <!--按照文件大小拆分, 30 MB -->
                <SizeBasedTriggeringPolicy size="30 MB"/>
                <!--按照时间节点拆分, 规则根据filePattern定义的-->
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <!--在同一个目录下,文件的个数限定为 30 个, 超过进行覆盖-->
            <DefaultRolloverStrategy max="30"/>
        </RollingFile>

        <!--输出错误日志到文件-->
        <RollingFile name="RollingErrorFile" fileName="${LOG_FILE_PATH}/error.log"
                     filePattern="${LOG_FILE_PATH}/$${date:yyyyMM}/error-%d{yyyyMMdd}-%i.log.gz">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>

            <PatternLayout>
                <pattern>${PATTERN_FORMAT}</pattern>
            </PatternLayout>

            <Policies>
                <!--在系统启动时, 触发拆分规则,生产一个新的日志文件-->
                <OnStartupTriggeringPolicy/>
                <!--按照文件大小拆分, 30 MB -->
                <SizeBasedTriggeringPolicy size="30 MB"/>
                <!--按照时间节点拆分, 规则根据filePattern定义的-->
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <!--在同一个目录下,文件的个数限定为 30 个, 超过进行覆盖-->
            <DefaultRolloverStrategy max="30"/>
        </RollingFile>

        <!--输出debug日志到文件-->
        <RollingFile name="RollingDebugFile" fileName="${LOG_FILE_PATH}/debug.log"
                     filePattern="${LOG_FILE_PATH}/$${date:yyyyMM}/debug-%d{yyyyMMdd}-%i.log.gz">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <Filters>
                <ThresholdFilter level="info" onMatch="DENY" onMismatch="NEUTRAL"/>  <!--高于warn级别就放行,低于这个级别就拦截-->
                <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>

            <PatternLayout>
                <pattern>${PATTERN_FORMAT}</pattern> <!--文件路径-->
            </PatternLayout>

            <!--设置文件具体拆分规则-->
            <Policies>
                <!--在系统启动时, 触发拆分规则,生产一个新的日志文件-->
                <OnStartupTriggeringPolicy/>
                <!--按照文件大小拆分, 30 MB -->
                <SizeBasedTriggeringPolicy size="30 MB"/>
                <!--按照时间节点拆分, 规则根据filePattern定义的-->
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <!--在同一个目录下,文件的个数限定为 30 个, 超过进行覆盖-->
            <DefaultRolloverStrategy max="30"/>
        </RollingFile>

    </Appenders>


    <!--定义logger,日志记录器配置-->
    <Loggers>
        <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
        <Logger name="org.springframework" level="INFO"/>
        <Logger name="org.mybatis" level="INFO"/>

        <!-- LOG "com.luis*" at TRACE level -->
        <Logger name="com.luis" level="INFO"/>

        <!--使用 rootLogger 配置 日志级别 level="trace"-->
        <Root level="ALL">
            <!--指定日志使用的处理器-->
            <AppenderRef ref="Console"/>
            <AppenderRef ref="RollingErrorFile"/>
            <AppenderRef ref="RollingWarnFile"/>
            <AppenderRef ref="RollingInfoFile"/>
            <AppenderRef ref="RollingDebugFile"/>
        </Root>
    </Loggers>

</Configuration>

如图:根据上面的log4j2.xml,进行日志输出配置,最终输出的日志就是如下效果。
在这里插入图片描述

4.全局异步配置:就是所有的日志都异步的记录,在log4j2.xml配置文件上不用做任何改动,只需要添加一个log4j2.component.properties 配置文件;

Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

说明:这里需要提一下什么是同步日志,什么是异步日志。同步日志是跟主线程进行执行的,也就是说日志全部记录完毕之后代码才会往下执行。会出现性能问题,就需要使用到异步日志。为日志重新开一个线程,专门执行日志操作。从而不会影响主线程操作。异步日志,为日志重新开一个线程,专门执行日志操作。从而不会影响主线程操作。

5.利用springAOP的技术,实现参数进入controller方法,返回统一加上日志。
说明:在前后端交互的过程中前端会给我们传递一些参数,我们后端接收到参数之后根据接口需求要返回给前端他所需要的数据。这个时候有一个非常重要的点,我们需要记录日志。记录的日志内容就是前端给我们传递了什么参数,我们要记录到日志文件中。我们给前端返回了什么数据,我们还要记录到日志文件中。还一个点需要我们记录日志,如果我某一个controller中方法出现异常了,出现程序错误这个时候需要记录出错的日志信息吧。那我应该如何拦截这个错误对象并且把他输出到日志文件中呢。

以下以下Aop切面类将解决上述问题。
以下Aop切面类,做的事情
(1) 在方法调用之前, 打印入参,记录日志。
(2) 方法返回之后,打印出参,记录日志
(3) 拦截方法中出现的异常对象。拿到对象之后打印到日志文件。
(value = “execution(public * com.duobao.web.controller...*(…))”):该配置表示对controller包下所有方法进行拦截,进行方法切入。

package com.duobao.web.aop;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/**
 * 利用springAOP的技术,实现参数进入controller方法,返回统一加上日志
 */
@Aspect
@Component
@Slf4j
public class ControllerLogAop {

    /**
     * 在方法调用之前, 打印入参,记录日志
     */
    @Before(value = "execution(public * com.duobao.web.controller.*.*.*(..))")
    public void before(JoinPoint joinPoint) {
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        StringBuilder params = new StringBuilder();
        for (Object arg : args) {
            params.append(arg).append(" ");
        }
        log.debug(className + "#" + methodName +"【入参】为: " +params.toString());
    }

    /**
     * 监测方法,方法出现异常,catch到异常之后返回包装后的错误信息,并打印日志信息
     * @param joinPoint
     * @return
     */
    @Around(value = "execution(public * com.duobao.web.controller.*.*.*(..))")
    public Object catchException(ProceedingJoinPoint joinPoint) {
        try {
            Object proceed = joinPoint.proceed();//方法执行完返回值
            return proceed;//返回出去
        } catch (Throwable e) {
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            log.error("在"+className+"的"+methodName+",发生了异常:{}",e);
            return "异常"; // return RestData.error("异常")
        }
    }

    /**
     * 返回之后,打印出参,记录日志
     */
    @AfterReturning(value = "execution(public * com.duobao.web.controller.*.*.*(..))",returning = "returnVal")
    public void afterReturn(JoinPoint joinPoint,Object returnVal){
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        log.debug(className +"#" + methodName + "【结果】为: " + JSON.toJSONString(returnVal));
    }
}

6.如下类中介绍了,什么时候打日志,日志输出格式。

package com.duobao.web.logTest;


import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.sql.Connection;


@Slf4j //@Slf4j:注解在类上; 为类提供一个属性名为log的slf4j日志对象
@RestController
@RequestMapping("/logs")
public class LogTest {

    //1.使用slf4j 日志门面框架, 来打印日志
    private static final Logger LOGGER = LoggerFactory.getLogger(LogTest.class);

    @GetMapping("/test")
    public void test() {
        // LOGGER.info("from log");
        log.info("from log");
        // log.error("error");  // 错误信息, 不会影响系统运行 ***
        // log.warn("warn");    // 警告信息, 可能会发生问题 ***
        // log.info("info");    // 运行信息, 一些普通信息。数据库连接、网络连接、IO 操作等等 *** //默认日志级别
        // log.debug("debug");  // 调试信息, 开发和测试阶段的调试信息, 记录程序变量传递信息等等 ***

        // log.trace("trace");  // 追踪信息, 记录程序所有的流程信息

        // 2.日志打印格式不一样,这个可以自己配 log4j2.xml.xml
        // %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n

        // 大型互联网项目的日志格式
        // 2019-12-01 00:00:00.000
        // |pid
        // |log-level
        // |[svc-name,trace-id,span-id,user-id,biz-id]
        // |thread-name
        // |package-name.class-name :
        // |log message

        // 时间
        // pid, pid
        // log-level, 日志级别
        // svc-name, 应用名称
        // trace-id, 调对链标识
        // span-id, 调用层级标识
        // user-id, 用户标识
        // biz-id, 业务标识
        // thread-name, 线程名称
        // package-name.class-name, 日志记录器名称
        // log message, 日志消息体

        // 3.方法日志
        checkUser("admin", "1234");

        // 4.外部调用 (外部http请求调用的时候)
        bizwithRpc("bywind");

        // 5.程序运行过程中 状态变更 或 条件分支
        stateChange();

        // 6.多个异常情况需要捕获
        tryCatch();
        // 7.能预测到的非正常情况
        someThingMayNotHappenButIncase(10);

        // 8.代码块执行效率记录(运行时间),获取关键数据记录等
        howLongTime();

        // =================日志虽好,也不要乱打哦!=================
        // 9.频繁打日志
        // 当日志生产的速度大于日志写磁盘的速度,会导致日志内容堆积在内存中,导致内存泄漏
        iLoveLog();

        // 10.无意义日志,容易混淆的日志
        useless();

        // 11.如果基础已抛出,请不要打日志, 交给调用者处理
        throwToYou();
    }


    // 3.方法日志
    public Boolean checkUser(String name, String password) {
        log.info("params,name:{},password:{}", name, password);
        System.out.println("do something");
        Boolean result = true;
        log.info("retValue:{} ", result);
        return result;
    }

    // 4.调用外部请求
    public Boolean bizwithRpc(String parameters) {
        log.debug("Calling external system:" + parameters);
        Object result = null;
        try {
            result = callRemotesSystem(parameters);
            log.debug("Called successfully. result is" + result);
        } catch (Exception e) {
            log.warn("Failed at calling xxx system . exception : " + e);
        }
        return true;
    }
    public Object callRemotesSystem(String parameters) {
        System.out.println(parameters);
        return "100";
    }

    // 5.程序运行过程中 状态变更 或 条件分支
    public void stateChange() {
        Boolean isRunning = true;
        log.info("System is running");
        //...
        isRunning = false;
        log.info("System was interrupted by" + Thread.currentThread().getName());
    }

    // 6.多个异常情况需要捕获
    public Boolean tryCatch() {
        try {
            //业务逻辑代码
            return true;
        } catch (RuntimeException e) {
            log.warn("Let me know anything", e);
        } catch (Exception e) {
            log.error("Description xxx", e);
        }
        return false;
    }

    // 7.能预测到的非正常情况
    public Boolean someThingMayNotHappenButIncase(Integer a) {

        int absResult = Math.abs(a);
        if (absResult < 0) {
            log.info("Original int " + a + " has nagetive abs " + absResult);
        }
        return true;
    }

    // 8.代码块执行效率记录(运行时间),获取关键数据记录等
    public void howLongTime() {
        long start = System.currentTimeMillis();
        System.out.println("some amazing code");
        long end = System.currentTimeMillis();

        log.info("time spent :{}", (end - start));
    }

    // 9.当日志生产的速度大于日志写磁盘的速度,会导致日志内容堆积在内存中,导致内存泄漏
    private Boolean iLoveLog() {
        log.debug("method enter");
        System.out.println("call rpc method some code");
        log.info("the method seems good");
        System.out.println("some amazing code of mine");
        log.info("I will return the value");
        return true;
    }

    // 10.无意义日志,容易混淆的日志
    private Boolean useless() {
        File file = new File("xxx");
        if (!file.exists()) {
            log.warn("File does not exist");//Useless message
        }
        Connection connection = getConnection();
        if (connection ==null ){
            log.warn("System initialized unsuccessfully");//不要笼统的说系统异常,应该给出具体错误信息。
        }
        return false;
    }
    private Connection getConnection() { return null; }

    // 11.如果基础已抛出,请不要打日志, 交给调用者处理
    private void throwToYou() {
        try{
            //业务代码
        }catch (RuntimeException e) {
            //log.error("RuntimeException",e);
            throw new RuntimeException("he he");
        }

        
    }

}

7.测试:
定义类,测试日志记录。在该类中我进行了日志记录,主要目的是请求过来之后,测试日志文件中是否可以正常输出我这里打印的日志信息。对于日志信息,我既输出到了控制台同时会输出到文件中。

package com.duobao.web.controller.v1;

import com.duobao.common.dtos.ResponseResult;
import com.duobao.web.service.AdLoginService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;

/**
 * adUser用户登录
 **/
@Slf4j
@CrossOrigin
@RestController
@RequestMapping("/api/v1/login")
public class AdLoginController {

    @Autowired
    private AdLoginService adLoginService;

    /**
     * adUser用户登录
     *
     * @param account  账号
     * @param password 密码
     * @param request  http请求
     * @return token令牌
     */
    @PostMapping("/in")
    public ResponseResult login(@RequestParam("account") String account,
                                @RequestParam("password") String password, HttpServletRequest request) {
        log.error("error");  // 错误信息, 不会影响系统运行 ***
        log.warn("warn");    // 警告信息, 可能会发生问题 ***
        log.info("info");    // 运行信息, 一些普通信息。数据库连接、网络连接、IO 操作等等 *** //默认日志级别
        log.debug("debug");  // 调试信息, 开发和测试阶段的调试信息, 记录程序变量传递信息等等 ***
        return adLoginService.login(account, password, request);

    }

}

发送请求
在这里插入图片描述

查看日志控制台输出日志效果
在这里插入图片描述

查看输出的日志文件
在这里插入图片描述

8.特别说明:

  1. 在配置文件中我们一般会对rootlogger根日志对象进行配置当然也可以自定义logger,需要注意的是,如果rootlogger可以满足需要,直接用即可满足不了,就需要自定义logger。
  2. 项目中日志文件的分类,一般可以放在一个日志文件,也可以根据不同日志级别创建不同的文件,来存储日志。
  3. 项目发布后一般用的是Info,在开发过程中需要做Log的追踪,一般设置为Debug。

该示例基本可以满足开发项目时的日常日志记录,是本人查阅了很多资料视频总结所得~

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: Spring Boot可以很方便地集成SLF4JLog4j2。以下是集成步骤: 1. 在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> ``` 2. 在application.properties文件中配置日志级别和日志输出路径: ``` logging.level.root=INFO logging.file=/var/log/myapp.log ``` 3. 在代码中使用SLF4J进行日志记录: ``` import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyClass { private static final Logger logger = LoggerFactory.getLogger(MyClass.class); public void doSomething() { logger.info("Doing something..."); } } ``` 以上就是Spring Boot集成SLF4JLog4j2的简单步骤。 ### 回答2: Spring Boot是一个开发web应用和微服务的框架,而SLF4JLog4j2是一种记录日志信息的工具。将SLF4JLog4j2这两种工具集成到Spring Boot应用中可以方便地进行日志记录SLF4J是一个抽象的日志接口,它允许您在不更改应用程序代码的情况下更改底层日志记录器。Log4j2是一个快速、灵活且配置方便的日志组件,它可以完全控制日志记录和输出。 在Spring Boot集成SLF4JLog4j2之前,需要在pom.xml文件中添加以下依赖项: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency> ``` 以上依赖项将引入Spring Boot和Log4j2所需的库。 在应用程序的配置文件application.yaml中,需要添加以下内容: ``` logging: config: log4j2.xml ``` 以上内容将告诉Spring Boot使用Log4j2记录日志,并使用log4j2.xml文件来配置Log4j2。 在log4j2.xml文件中,需要定义一个或多个logger,例如: ``` <Logger name="com.example.myapp" level="info"> <AppenderRef ref="stdout" /> </Logger> ``` 通过上述配置,当com.example.myapp的日志级别为info时,日志信息将被输出到stdout。 除此之外,还需要在应用程序的Java类中添加日志记录代码,例如: ``` import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyApp { private static final Logger logger = LoggerFactory.getLogger(MyApp.class); public void myMethod() { logger.info("This is an info message"); logger.error("This is an error message"); } } ``` 在上述代码中,使用LoggerFactory获取Logger对象,然后使用.info()和.error()方法记录日志信息。在日志信息中,可以添加变量,例如: ``` logger.info("This is a message with variables: {} {} {}", var1, var2, var3); ``` 上述代码中,var1、var2和var3是将被替换为实际值的变量。 总之,Spring Boot集成SLF4JLog4j2可以方便地进行日志记录,只需要在配置文件application.yaml和log4j2.xml中进行相应的配置即可。同时,在Java类中添加日志记录代码可以很容易地实现记录日志的功能。 ### 回答3: Spring Boot是一款非常流行的Java开发框架,而Slf4jLog4j2则是用于Java项目中的日志库。这两个库的集成是非常常见的需求,因为它们可以协同工作,帮助我们记录日志和排查问题。 首先,在pom.xml文件中添加Slf4jLog4j2的依赖项。这个过程非常简单,只需要在<dependencies>标签内添加以下代码段即可: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.13.3</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.13.3</version> </dependency> ``` 这里我们添加了Spring Boot Web启动器,以及Slf4jLog4j2的相关依赖项。我们还需要在application.properties文件中设置日志级别和输出格式。 在application.properties文件中添加以下代码: ``` logging.level.root=INFO logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} %5p [%t] - %m%n ``` 这里我们设置root日志的级别为INFO,表示只输出INFO级别及以上的日志信息。同时,我们设置日志输出格式,包括日期、日志级别、线程名和消息等。你可以根据项目的需求来自定义日志输出格式。 现在,我们已经完成了Slf4jLog4j2的集成工作。在我们的Java代码中,可以通过Logger接口来记录日志信息,如下所示: ``` import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Controller public class HomeController { private static final Logger logger = LoggerFactory.getLogger(HomeController.class); @GetMapping("/") public String home() { logger.info("Welcome home!"); return "home"; } } ``` 这里我们使用LoggerFactory类来获取Logger对象,Logger对象可以使用info()、debug()、error()等方法来记录不同级别的日志信息。在这个例子中,我们在HomeController类的home()方法中记录了一条info级别的日志信息。这个日志信息将会被Slf4j记录下来,并使用Log4j2将它输出到终端上。 以上就是Spring Boot集成Slf4jLog4j2的基本步骤。这个过程非常简单,只需要几步就可以完成。如果你想深入了解Slf4jLog4j2的更多特性,可以查看官方文档或其他相关资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值