`
阅读更多

一、背景介绍

spring cloud 微服务架构中,需要对依赖服务的请求留痕(URL,出参,入参、耗时等)

1.现状

调用FeignClient(Integration类中)时 手工记录log

缺点:重复工作、log格式不统一

优点:充分满足个性化需求、灵活度极高(再说上天了)

 

2.目标

实现简洁统一的全局外部服务调用日志输出

示例如下:

get: GET 200 http://wwww.feigntest.com/dict/items?systemId=11 86 RESPONSE BODY:{"code":"000000","success":true}

post: POST 200 http://wwww.feigntest.com/limitBill 85 REQUEST BODY:{"custNo":"121212","startTime":null,"endTime":null} RESPONSE BODY:{"code":"001001010","success":false}

异常: POST UnknownHostException http://wwww.feigntest.com/errorUri 206 REQUEST BODY:{"custNo":"121212"}

3.实现基础

基于FeignClient已有的全局请求日志处理类feign.Logger

feign.Logger日志输出级别为debug

输出header信息较多,大多服务并不需要

 

网上有类似资料,讲解如何启用feign.Logger、如何修改debug为info级别

本文增加对输出内容的简化.

 

二、如何使用

step 1.重写feign.Logger 

-> 修改feign.Logger日志输出级别为info,简化输出内容

package com.cdfinance.mall.config;
import feign.Request;
import feign.Response;
import feign.Util;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import static feign.Util.UTF_8;
import static feign.Util.decodeOrDefault;
/**
 * Feign请求日志处理类<br/>
 * 所有通过Feign请求的外部接口都会被监控
 *
 * @version V1.0
 * @author: maoliang
 * @date: 2020/3/27
 */
@Slf4j
public class FeignLogger extends feign.Logger {
    static ThreadLocal<Map<String, String>> logContext = new ThreadLocal();
    static String PATH = "path";
    static String METHOD = "method";
    static String REQUEST_BODY = "body";
    @Override
    protected void logRequest(String configKey, Level logLevel, Request request) {
        Map<String, String> logMap = new HashMap<>(3);
        logMap.put(PATH, request.url());
        logMap.put(METHOD, request.method());
        logMap.put(REQUEST_BODY, request.body() == null ? null :
                request.charset() == null ? null : new String(request.body(), request.charset()));
        logContext.set(logMap);
    }
    @Override
    protected Response logAndRebufferResponse(
            String configKey, Level logLevel, Response response, long elapsedTime) throws IOException {
        Map<String, String> requetParam = logContext.get();
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder
                .append(requetParam.get(METHOD)).append(" ")
                .append(response.status()).append(" ")
                .append(requetParam.get(PATH)).append(" ")
                .append(elapsedTime);
        if (requetParam.get(REQUEST_BODY) != null) {
            stringBuilder.append(" REQUEST BODY:").append(requetParam.get(REQUEST_BODY));
        }
        logContext.remove();
        // 返回参数
        if (response.body() != null && !(response.status() == 204 || response.status() == 205)) {
            byte[] bodyData = Util.toByteArray(response.body().asInputStream());
            if (bodyData.length > 0) {
                String responseBody = decodeOrDefault(bodyData, UTF_8, "Binary data");
                stringBuilder
                        .append(" RESPONSE BODY:")
                        .append(responseBody.replaceAll("\\s*|\t|\r|\n", ""));
            }
            log.info(stringBuilder.toString());
            return response.toBuilder().body(bodyData).build();
        }
        log.info(stringBuilder.toString());
        return response;
    }
    protected IOException logIOException(String configKey, Level logLevel, IOException ioe, long elapsedTime) {
        Map<String, String> requetParam = logContext.get();
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder
                .append(requetParam.get(METHOD)).append(" ")
                .append(ioe.getClass().getSimpleName()).append(" ")
                .append(requetParam.get(PATH)).append(" ")
                .append(elapsedTime);
        if (requetParam.get(REQUEST_BODY) != null) {
            stringBuilder.append(" REQUEST BODY:").append(requetParam.get(REQUEST_BODY));
        }
        log.warn(stringBuilder.toString());
        logContext.remove();
        return ioe;
    }
    @Override
    protected void log(String configKey, String format, Object... args) {
        if (log.isInfoEnabled()) {
            log.info(String.format(methodTag(configKey) + format, args));
        }
    }
}

 

step 2.注册FeignLogger

-> 注册FeignLogger, 设置 Logger.Level为FULL

import feign.Logger;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
/**
 * 注册FeignClient请求日志配置
 *
 * @version V1.0
 * @author: mlxnle
 * @date: 2020/04/01
 */  
@Configuration  
public class FeignLoggerConfig {  
    @Bean  
    Logger.Level loggerLevel() {  
        return Logger.Level.FULL;  
    }  
    @Bean  
    Logger feignLogger() {  
        return new FeignLogger(); // 你的继承类 
    }  
}

 

step 3.开始你的请求

-> 没有第三步! 惊不惊喜

  • 大小: 7.4 KB
分享到:
评论

相关推荐

    后端feign学习资料

    3. **使用Feign Client**:在需要调用远程服务的地方,直接注入Feign Client,像调用本地方法一样调用远程服务。 4. **处理异常**:为Feign异常进行捕获和处理,比如处理HTTP状态码非200的情况。 5. **优化和扩展*...

    venus-cloud-feign-1.5.x.rar_cloud_feign_formery87_spring

    3. **配置Feign**:在Spring Boot的配置文件中,可以设置Feign的全局配置,如超时时间、连接池大小等。 4. **自定义配置**:利用Feign的 SPI(Service Provider Interface)机制,实现自定义的配置类,扩展Feign的...

    Feign调用丢失Header的解决方案.docx

    这可以通过两种方式进行:全局配置或针对特定Feign客户端进行配置。 ##### 全局配置 ```yaml feign: client: config: default: connectTimeout: 5000 readTimeout: 5000 loggerLevel: basic ...

    springcloud client

    search_client 可以集成这些工具,提供详细的请求链路日志,便于系统监控和问题定位。 总的来说,Spring Cloud Client 在这个例子中是整个微服务架构中的一个重要组成部分,它通过与 Spring Cloud 的其他组件协作,...

    基于spring-cloud2.X的Demo例子

    Spring Cloud 是一个基于 Spring Boot 实现的云应用开发工具集,它为开发者提供了在分布式系统(如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态)...

    关于spring cloud的学习源码

    Spring Cloud 是一个基于 Spring Boot 实现的云应用开发工具集,它为开发者提供了在分布式系统(如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态)...

    agileway:提供Java,Web,各种类库增强,应避免996。目前已支持feign,redis,datasource,shiro,httpclient,rest,codec,serialize等

    提供基于Feign的RestService动态创建 提供基于easyjson的编码器,解码器 集成负载均衡功能 提供多种param Expander 筛选器: 访问日志过滤器 编码过滤器 rr过滤器 全局响应过滤器 休息: 提供统一的异常处理 提供...

    spring cloud 入门操作手册(全)

    Spring Cloud 是一个基于 Spring Boot 实现的云应用开发工具集,它为开发者提供了在分布式系统(如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态等...

    java的springcloud面试篇学习资料

    - **API Gateway**:Zuul作为API网关,实现统一的权限验证、日志记录、动态路由等功能。 - **微服务间通信**:使用Feign进行服务间的HTTP请求,或者使用RabbitMQ、Kafka等消息中间件实现异步通信。 - **配置管理*...

    springcloud环境搭建.doc

    Spring Cloud是一套基于Spring Boot实现的微服务云应用开发框架,它为开发者提供了在分布式系统(如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态...

    springcloud练习项目代码

    例如,你可能会看到Eureka的配置文件(eureka-client.properties或eureka-server.properties),Zuul的路由配置,Hystrix的断路器配置,以及服务间的Feign调用实现等。 此外,这个项目可能还包括了数据库连接配置、...

    spring cloud 教程,包含文档和源码

    Spring Cloud 是一个基于 Spring Boot 实现的云应用开发工具集,它为开发者提供了在分布式系统(如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态)...

    Spring Cloud视频教学

    Spring Cloud 是一套基于 Spring Boot 实现的微服务云应用开发框架,它为开发者提供了在分布式系统(如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群...

    springcloud搭建

    SpringCloud是一个全面的云应用开发工具集,它为开发者提供了在分布式系统(如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态)快速构建一些常见...

    从零开始搭建SpringCloud第二节源码及截图

    Spring Cloud是一个全面的微服务解决方案,它为开发者提供了快速构建分布式系统中的一些常见模式,如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态...

    SpringCloud-Learning-master.zip

    Spring Cloud作为一个强大的微服务框架,为开发者提供了构建分布式系统中的配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态等多种功能。本资料集合了...

    springboot整合springcloud

    SpringCloud则是基于SpringBoot构建大型分布式系统的工具集,它提供了一整套解决方案,包括服务发现、配置中心、负载均衡、断路器、熔断机制、智能路由、微代理、控制总线、全局锁、领导选举、分布式会话、集群状态...

    Spring Cloud 微服务架构详细指南.docx

    - Spring Boot Actuator 提供了许多生产就绪的功能,如健康检查、指标收集、审计日志等。 - 添加依赖: ```xml &lt;groupId&gt;org.springframework.boot &lt;artifactId&gt;spring-boot-starter-actuator ``` - 配置...

    spring-cloud

    4. **服务消费者(first-client)**:这部分代码可能使用了Spring Cloud的Feign或者RestTemplate来消费服务提供者的接口,通过服务发现机制找到服务提供者的地址。 5. **断路器(Hystrix)**:断路器模式是应对服务...

    GRPC与Spring Cloud的集成

    而Spring Cloud则是一套为微服务提供配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态等工具的集合。 在集成GRPC和Spring Cloud的过程中,主要涉及以下几个关键...

Global site tag (gtag.js) - Google Analytics