• 使用feign调用记录日志篇


    Feign日志记录方案设计》

    1.需求背景

    随着我们内部系统间交互越发紧密,Feign的使用越来越多,但目前存在着Feign方式调用日志无法保存,报错难以排查等问题。
    为了解决上述问题,通过对Feign的日志功能进行重写的方式,实现了日志的格式化输出和存储。

    2.实现方案

    Feign默认提供了获取请求和响应报文并打印到控制台的功能,但需要进行开启,且只能打印到控制台中。为了将请求和响应信息进行存储,对Feign的功能进行了重新实现。

    2.1.重新实现FeignLoggerFactory接口

    通过自定义CustomizationFeignLoggerFactory来重新实现FeignLoggerFactory接口,可以将打印log的对象设置为我们新定义的对象,从而实现调用进行其他操作。

    2.1.1.重写定义log对象

    重写create方法,定义logger对象为

    2.1.2.开启feign日志打印功能

    通过设置Logger.Level为FULL,开启日志信息的获取和打印

    2.1.3.代码实现
    @Configuration
    public class CustomizationFeignLoggerFactory implements FeignLoggerFactory {
    
        /**
         * 是否开启feign日志记录功能标识
         * true-是,false-否
         */
        @Value("${feignlog.flag:false}")
        private boolean openFlag;
    
        public CustomizationFeignLoggerFactory() {
        }
    
        //实现create方法 new自定义的CustomizationFeignLogger
        @Override
        public Logger create(Class<?> type) {
            return openFlag ? new CustomizationFeignLogger() : new Slf4jLogger(type);
        }
    
        //开启openfeign的日志,Primary用来解决bean冲突
        @Bean
        @Primary
        Logger.Level feignLoggerLevel() {
            return Logger.Level.FULL;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    2.2.重写feign.Logger抽象类

    通过自定义CustomizationFeignLogger来重写feign.Logger对象,来重写实现日志相关操作。

    2.2.1.重写logRequest()方法

    通过重写logRequest()方法,来获取请求信息并将请求信息进行保存。

    2.2.2.重写logAndRebufferResponse()方法

    通过重写logAndRebufferResponse()方法,来获取响应信息并将响应信息进行对应的更新。

    2.2.3.代码实现
    @Slf4j
    public class CustomizationFeignLogger extends feign.Logger {
    
        /**
         * 用来存放logId
         */
        private static final ThreadLocal<Long> logIdCache = new ThreadLocal<>();
    
        private static final Long workerId = 1L;
    
        private static final Long dataCenterId = 1L;
    
        private static final String defaultValue = "result data is null";
    
    
        public CustomizationFeignLogger() {
        }
    
        @Override
        protected void log(String configKey, String format, Object... args) {
        }
    
        @Override
        protected void logRequest(String configKey, Level logLevel, Request request) {
            String method = request.method();
            String url = request.url();
            String param = (request.body() == null || request.body().length == 0) ? "" : new String(request.body(), UTF_8);
    
            //通过雪花算法生成主键logId
            Snowflake snowflake = new Snowflake(workerId, dataCenterId);
            long logId = snowflake.nextId();
            logIdCache.set(logId);
    
            //保存请求信息
            SpringUtils.getBean(FeignLoggerService.class).saveFeignLog(url, param, logId);
            log.debug("Feign请求信息为:method:{}, url:{}, param:{}", method, url, param);
    
        }
    
        //自定义响应日志
        @Override
        protected Response logAndRebufferResponse(String configKey, Level logLevel, Response response, long elapsedTime) throws IOException {
            String result = "";
            int status = response.status();
    
            try {
                if (response.body() != null) {
                    byte[] bodyData = Util.toByteArray(response.body().asInputStream());
                    result = decodeOrDefault(bodyData, UTF_8, defaultValue);
                    return response.toBuilder().body(bodyData).build();
                }
                return response;
            } finally {
                //更新响应信息
                Long logId = logIdCache.get();
                SpringUtils.getBean(FeignLoggerService.class).updateFeignLog(result, elapsedTime, logId);
                logIdCache.remove();
                log.debug("Feign响应信息为: status:{}, result:{}, ElapsedTime:[{}ms]", status, result, elapsedTime);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    3.数据库表设计

    选择在dbinc的库中新增t_feign_trans_log表,来记录feign的调用日志。

    3.1表设计
    CREATE TABLE `t_feign_trans_log` (
      `log_id` bigint(20) NOT NULL COMMENT '日志ID(对应交易流水号transId)',
      `pre_log_id` bigint(20) NOT NULL COMMENT '上一条日志ID',
      `trans_id` bigint(200) NOT NULL COMMENT '交易接口ID:对应d_trans表',
      `tenant_id` bigint(20) NOT NULL COMMENT '商户ID:对应t_tenant表',
      `application_id` bigint(20) NOT NULL COMMENT '应用ID:对应t_application表',
      `open_id` varchar(100) DEFAULT '1' COMMENT '请求用户ID:对应cms_user表id',
      `client_ip` varchar(255) DEFAULT NULL COMMENT '客户端IP地址',
      `req_url` varchar(100) DEFAULT NULL COMMENT '请求地址',
      `trans_time` datetime DEFAULT NULL COMMENT '交易时间',
      `req_time` datetime DEFAULT NULL COMMENT '请求时间',
      `rep_time` datetime DEFAULT NULL COMMENT '响应时间',
      `cost` double DEFAULT NULL COMMENT '耗时 单位秒',
      `req_msg` mediumtext COMMENT '请求报文',
      `rep_msg` mediumtext COMMENT '响应报文',
      `state` char(30) DEFAULT NULL COMMENT '交易状态 10-成功 12-异常',
      `trans_state` char(30) DEFAULT NULL COMMENT '交易状态 10-成功 12-异常',
      `busi_state` char(30) DEFAULT NULL COMMENT '业务状态 10-成功 11 校验失败',
      `error_detail` mediumtext COMMENT '错误信息',
      `CREATE_ID` varchar(60) DEFAULT NULL COMMENT '创建人',
      `MODIFY_ID` varchar(60) DEFAULT NULL COMMENT '修改人',
      `INSERT_TIME` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '插入时间',
      `UPDATE_TIME` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
      PRIMARY KEY (`log_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='feign日志记录表';
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    4.处理流程

    在这里插入图片描述

    5.使用方式

    5.1 修改pom.xml文件
    添加以下依赖:
    <!--引入feignlog依赖-->
    <dependency>
        <groupId>com.micro</groupId>
        <artifactId>micro-feignlog</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    5.2 修改application-xxx.yml配置文件

    在application-xxx.yml配置文件中添加以下配置:

    # feign日志记录开启标识,true-开启,false-关闭
    feignlog:
      flag: true
    
    • 1
    • 2
    • 3

    5.3 注意事项

    如果添加修改yml信息或配置为false,则不会记录feign调用日志

  • 相关阅读:
    JavaScript-对象、类与面向对象编程(理解对象)
    DC-3靶机
    【云原生kubernetes系列】--RBAC权限的使用
    SAP PO精炼图
    【软件工程】介绍
    业务测试常见问题(一)
    技术分享 | 接口测试中,请求超时该怎么办?
    iptables 放开http典型配置
    公共关系学试题与参考答案
    基于Tensorflow搭建卷积神经网络CNN(水果识别)保姆及级教程
  • 原文地址:https://blog.csdn.net/weixin_44503925/article/details/126164722