控制日志完整报文的输出频率

控制日志的输出频率

背景

在实际的生产开发中,记录日志是非常重要的一步。记录日志的主要原因是方便排查和分析问题。当软件出现异常、运行缓慢或数据错误时,日志记录可以提供大量有价值的信息,帮助开发人员快速定位问题的原因和位置,并加速问题的修复过程。

但是记录日志不是越详细越好,不是内容越多越优质。日志输出到文件中会占有大量的IO性能,拖慢程序吞吐量,加快服务器硬盘消耗,内容过多也对我们查找日志带来了难度。

针对日志对性能的消耗问题,我们首先考虑的是异步日志,这确实效果显著。但满屏的响应报文对我们查找日志并不有利,这个问题异步日志没办法解决。

有时候我们想,能不能给日志的响应报文设置一下长度,这样一来能提高性能,二来能方便我们找日志。但是如果需要完整的响应报文怎么办?那我们就随机将一些响应报文的长度限制一下,并不是针对所有的响应报文。

具体地说,通过一个注解给定预设值,程序生成一个随机数,并将其与预定义的值进行比较,以确定是否应该截取该日志消息。通过这种方式,应用程序可以更细粒度地控制日志的输出,避免记录过多的冗余信息或无关紧要的日志消息,以便更快地排除应用程序的问题或故障。

开发步骤

1.注解

package com.example.logcontrol.annotation;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface LogControl {
    int value() default 100;
}

2.响应日志切面

package com.example.logcontrol.advice;

import com.alibaba.fastjson2.JSON;
import com.example.logcontrol.annotation.LogControl;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Set;

@RestControllerAdvice
@Slf4j
public class ResponseResultAdvice implements ResponseBodyAdvice<Object> {

    // 文字内容限制长度
    private static final int RESPONSE_CONTENT_LENGTH = 200;

    // return true表示对响应进行处理,你可以用returnType来做判断什么时候不需要做处理
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType,
                                  MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {
        String responseStr = JSON.toJSONString(body);
        // 获取当前方法
        Method method = returnType.getMethod();
        // 是否被LogControl注解修饰
        if (method.isAnnotationPresent(LogControl.class)) {
            // 获得注解
            LogControl logControl = method.getAnnotation(LogControl.class);
            // 获得随机数
            Random random = new Random();
            int nextInt = random.nextInt(logControl.value());
            // 当生成的随机数为0时,对日志长度进行控制
            if (nextInt == 0) {
                // 将body转成json字符串 再截取预设的长度
                responseStr = JSON.toJSONString(body).substring(0, RESPONSE_CONTENT_LENGTH) + "...【内容太长啦】";
            }
        }
        log.info("【调用URL】:【{}】,【--返回结果--】:【{}】", request.getURI().toString(), responseStr);
        return body;
    }



}

如果注解上配置的数字为1,那生成的随机数就永远是0,则意味着对该接口的响应报文都截取长度

3.测试接口

package com.example.logcontrol.controller;

import com.example.logcontrol.annotation.LogControl;
import com.example.logcontrol.domain.Result;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

    @PostMapping("/ping")
    @LogControl(1)
    public Result Ping(@RequestBody String testStr) {
        String str =
                "拯救你就是拯救全世界,因为你就是我的全世界\n" +
                "你眼里的星辰大海,是我从未见过的皓月星空。\n" +
                "我喜欢的你是最好的,你喜欢的他是最好的,最好的你应该和最好的他在一起\n" +
                "一个从未见过的你,一件从未发生过的事,我们终于在一起~\n" +
                "下次再想去环游世界,我就围着你转一圈就好了。\n" +
                "说真的是想你。\n" +
                "我想你了。\n" +
                "猜到了你喜欢我,所以提前开心\n" +
                "太阳总是照着月亮,即使月亮属于地球" +
                "你不用多好,我喜欢你就好,我没有很好,你不嫌弃就好。\n" +
                "我直视不了阳光,我可以直视你呀\n" +
                "众多星星之间,我总是会想到你\n" +
                "我们来玩123木头人吧!完了我输了,我心动了\n" +
                "我的爱情长成你的样子。——苏亚伦\n" +
                "妙语连珠是猎物支支吾吾才是喜欢\n" +
                "世间万物皆苦,你明目张胆的偏爱就是救赎\n" +
                "If you are still looking for that one person who will change you life ,take a look in the mirror.\n" +
                "如果不是因为这世界有些古怪,我巴不得永远和你厮守在一起。\n" +
                "从看到你就心跳加快的那一刻开始,我便知道纵使我在厉害也逃不出你的五指山了。";
        return Result.SUCCESS(str);
    }

}

4.运行效果

在这里插入图片描述

完整代码

移步代码仓库:【https://gitcode.net/interestANd/logcontroldemo.git
如果你有好的建议,不要忘了push噢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值