SpringBoot自定义日志--(实现输出接口信息)

SpringBoot自定义日志–实现输出接口信息

在项目开发过程中我们排查错误过程中,为了更清晰明了的查看接口调用情况,我们会将接口的入参和响应进行Log打印,工作原理就是利用Spring的Aop进行日志打印,接下来我们一起进入正题

先上效果图

1. 请求

浏览器请求

2. 控制台日志

控制台日志

一、准备工作

  1. SpringBoot项目
  2. pom依赖 (SpringBoot基础依赖,Aop依赖,Swagger依赖 )
     <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    
        <!-- aop 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <!--json依赖-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.71</version>
        </dependency>
        <!--工具列-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.10</version>
        </dependency>
    
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>1.5.22</version>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    
    </dependencies>
    
    
  3. 准备Controller接口,参考如下
    package com.kid510.web;
    
    import com.kid510.config.WebLogAspectConfig;
    import io.swagger.annotations.ApiOperation;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @Author kid
     * @Classname HelloController
     * @Description 测试
     * @Date 2020/8/23 23:03
     */
    @RestController
    public class HelloController {
    
        private final static Logger logger = LoggerFactory.getLogger(HelloController.class);
    
    
        @GetMapping(value = "/hello")
        @ApiOperation(value = "测试请求")
        public Map<String, Object> hello(@RequestParam Map<String, Object> reqMap) {
            // 返回值map
            Map<String, Object> respMap = new HashMap<>();
            // 额外赋值
            respMap.put("key1", 123);
            respMap.put("key2", "123");
            respMap.put("key3", true);
            // 入参赋值
            reqMap.forEach(respMap::put);
    
            logger.info("~~~~~~~~业务逻辑日志~~~~~~~~");
    
            return respMap;
        }
    }
    
    

二、Aop配置

  1. 新建Aop配置类

    package com.kid510.config;
    
    import com.kid510.utils.JsonUtils;
    import io.swagger.annotations.ApiOperation;
    import org.apache.catalina.connector.RequestFacade;
    import org.apache.catalina.connector.ResponseFacade;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.servlet.http.HttpServletRequest;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    
    /**
     * @author kid
     * @Classname WebLogAspect
     * @Description 打印日志 -- 具体实现
     * @Date 2020/4/3 13:50
     */
    @Aspect
    @Component
    //@Profile({"dev", "test"})
    public class WebLogAspectConfig {
    
    
        private final static Logger logger = LoggerFactory.getLogger(WebLogAspectConfig.class);
        /**
         * 换行符
         */
        private static final String LINE_SEPARATOR = System.lineSeparator();
    
        /**
         * 以自定义 @ApiOperation 注解为切点
         */
        @Pointcut("@annotation(io.swagger.annotations.ApiOperation)")
        public void webLog() {
        }
    
        /**
         * 在切点之前织入
         */
        @Before("webLog()")
        public void doBefore(JoinPoint joinPoint) throws Throwable {
            // 开始打印请求日志
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
    
            // 获取 @WebLog 注解的描述信息
            String methodDescription = getAspectLogDescription(joinPoint);
    
            // 打印请求相关参数
            logger.info("========================================== Start ==========================================");
            // 打印请求 url
            logger.info("URL            : {}", request.getRequestURL().toString());
            // 打印描述信息
            logger.info("Description    : {}", methodDescription);
            // 打印 Http method
            logger.info("HTTP Method    : {}", request.getMethod());
            // 打印调用 controller 的全路径以及执行方法
            logger.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
            // 打印请求的 IP
            logger.info("IP             : {}", request.getRemoteAddr());
            // 打印请求入参
            Object[] args = joinPoint.getArgs();
            ArrayList<Object> objects = new ArrayList<>();
            // request 对象或者 response对象不打印信息
            for (Object arg : args) {
                // 不属于这些的话 打印
                if (!(arg instanceof ResponseFacade || arg instanceof RequestFacade || arg instanceof MultipartFile)) {
                    objects.add(arg);
                }
            }
            logger.info("Request Args   : {}", JsonUtils.serialize(objects));
            logger.info("===================================== Business Log Start ===================================");
        }
    
        /**
         * 在切点之后织入
         */
        @After("webLog()")
        public void doAfter() {
    
        }
    
        /**
         * 环绕
         */
        @Around("webLog()")
        public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            long startTime = System.currentTimeMillis();
            Object result = proceedingJoinPoint.proceed();
            logger.info("====================================== Business Log End ====================================");
            // 打印出参
            logger.info("Response Args  : {}", JsonUtils.serialize(result));
            // 执行耗时
            logger.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime);
            // 接口结束后换行,方便分割查看
            logger.info("=========================================== End ===========================================" + LINE_SEPARATOR);
            return result;
        }
    
        /**
         * 获取切面注解的描述
         *
         * @param joinPoint 切点
         * @return 描述信息
         */
        public String getAspectLogDescription(JoinPoint joinPoint)
                throws Exception {
            String targetName = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            Object[] arguments = joinPoint.getArgs();
            Class targetClass = Class.forName(targetName);
            Method[] methods = targetClass.getMethods();
            StringBuilder description = new StringBuilder("");
            for (Method method : methods) {
                if (method.getName().equals(methodName)) {
                    Class[] clazzs = method.getParameterTypes();
                    if (clazzs.length == arguments.length) {
                        description.append(method.getAnnotation(ApiOperation.class).value());
                        break;
                    }
                }
            }
            return description.toString();
        }
    
    }
    
    
    
  2. 实现原理 – 拦截了 接口上面 @ApiOperation注解,描述信息取得是 该注解的value值,大家可以根据自己的需要配置不同的信息
    比如说 request 对象或者 response对象不打印信息或者MultipartFile这些信息入参不打印,再有一些响应信息过大,觉得没必要打印,也可以通过配置进行解决

三、最后的话

  1. 这个接口打印日志是Aop很好的一个实践,希望有帮助到大家,项目中运用是结合logback等日志收集使用
  2. 最后附上gitee地址:日志输入接口信息
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring Boot中,我们可以使用logback作为默认的日志框架来记录日志。如果需要添加自定义日志,我们可以按照以下步骤进行操作: 1. 添加依赖 在`pom.xml`中添加如下依赖: ```xml <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </dependency> ``` 2. 添加日志配置文件 在`src/main/resources`下添加`logback.xml`文件,内容如下: ```xml <?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <logger name="com.example" level="DEBUG"/> <root level="INFO"> <appender-ref ref="console"/> </root> </configuration> ``` 这里的配置文件格式是logback的标准格式,可以根据需要进行修改。其中: - `appender`定义了日志输出的方式和格式,这里我们定义了一个名为`console`的控制台输出; - `logger`定义了日志记录器,这里我们定义了一个名为`com.example`的日志记录器,并设置了日志级别为DEBUG; - `root`定义了日志输出的根级别,这里设置为INFO。 3. 在代码中使用自定义日志 在代码中使用自定义日志非常简单,只需要使用`org.slf4j.Logger`接口即可。例如: ```java import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyService { private static final Logger logger = LoggerFactory.getLogger(MyService.class); public void doSomething() { logger.debug("Debug message"); logger.info("Info message"); logger.warn("Warn message"); logger.error("Error message"); } } ``` 这里我们使用`LoggerFactory.getLogger()`方法获取了一个名为`MyService`的日志记录器,然后可以使用`debug()`、`info()`、`warn()`、`error()`等方法记录不同级别的日志。 通过以上步骤,我们就可以在Spring Boot中添加自定义日志了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值