Gateway网关打印请求日志

简介: Gateway网关打印请求日志

一、请求日志输出

package com.tencentcloudapi.gateway.filter;
import com.tencentcloudapi.gateway.api.utils.UuidUtil;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.slf4j.MDC;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.nio.charset.StandardCharsets;
/**
 * @author Miller.Lai
 * @description: 请求日志输出过滤器
 * @date 2024-01-31 14:26:33
 */
@Component
@Slf4j
public class WrapperRequestGlobalFilter implements GlobalFilter, Ordered {
    /**
     * 优先级最高
     */
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
         // 在 ServerWebExchange 中设置变量
        exchange.getAttributes().put("requestId", UuidUtil.getShortUuid());
        // 添加线程日志号
        MDC.put("UUID", Thread.currentThread().getName());
        ServerHttpRequest request = exchange.getRequest();
        URI URIPath = request.getURI();
        String path = request.getPath().value();
        String method = request.getMethod().toString();
        HttpHeaders header = request.getHeaders();
        log.info("");
        log.info("{} --------------------- 请求开始 ------------------------",exchange.getAttributes().get("requestId"));
        log.info("{} 原始请求信息:URI = {}, path = {},method = {},header = {}。",exchange.getAttributes().get("requestId"), URIPath, path, method, header);
        if ("POST".equals(method)) {
            return DataBufferUtils.join(exchange.getRequest().getBody())
                    .flatMap(dataBuffer -> {
                        byte[] bytes = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(bytes);
                        String bodyString = new String(bytes, StandardCharsets.UTF_8);
                        bodyString = bodyString.replaceAll("\"ImageBase64\":\"[^\"]*\",", "");
                        log.info("{} 请求参数,不包含ImageBase64:" + bodyString,exchange.getAttributes().get("requestId"));
                        exchange.getAttributes().put("POST_BODY", bodyString);
                        DataBufferUtils.release(dataBuffer);
                        Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
                            DataBuffer buffer = exchange.getResponse().bufferFactory()
                                    .wrap(bytes);
                            return Mono.just(buffer);
                        });
                        ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
                                exchange.getRequest()) {
                            @NotNull
                            @Override
                            public Flux<DataBuffer> getBody() {
                                return cachedFlux;
                            }
                        };
                        return chain.filter(exchange.mutate().request(mutatedRequest)
                                .build()).doFinally(signalType -> {
                            // 请求处理完毕后清理变量
                            exchange.getAttributes().remove("requestId");
                            exchange.getAttributes().remove("hasAcquired");
                        });
                    });
        } else if ("GET".equals(method)) {
            MultiValueMap<String, String> queryParams = request.getQueryParams();
            log.info("{} 请求参数:" + queryParams,exchange.getAttributes().get("requestId"));
            return chain.filter(exchange);
        }
        return chain.filter(exchange);
    }
}

二、响应日志输出

package com.tencentcloudapi.gateway.filter;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
/**
 * @author Miller.Lai
 * @description: 响应日志输出过滤器
 * @date 2024-01-31 14:26:55
 */
@Component
@Slf4j
public class WrapperResponseGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public int getOrder() {
        //-1 is response write filter, must be called before that
        return -2;
    }
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取response的 返回数据
        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        StringBuffer responseBuffer =new StringBuffer();
        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            @NotNull
            @Override
            public Mono<Void> writeWith(@NotNull Publisher<? extends DataBuffer> body) {
                if ( body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                    return super.writeWith(fluxBody.map(dataBuffer -> {
                        byte[] content = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(content);
                        //释放掉内存
                        DataBufferUtils.release(dataBuffer);
                        //responseData就是下游系统返回的内容,可以查看修改
                        String responseData = new String(content, StandardCharsets.UTF_8);
                        responseBuffer.append(responseData);
                        if(responseBuffer.indexOf("RequestId") != -1  && responseBuffer.substring(responseBuffer.indexOf("RequestId")).length()>=48){
                            String responseStr = responseBuffer.toString();
                            String requestId = responseStr.substring(responseStr.indexOf("RequestId")+12,responseStr.indexOf("RequestId")+48);
                            responseBuffer.setLength(0);
                            log.info("{} 响应结果,code:{},RequestId:{}",exchange.getAttributes().get("requestId"),getStatusCode(),requestId);
                            log.info("{} --------------------- 请求结束 ------------------------",exchange.getAttributes().get("requestId"));
                            log.info("");
                        }
                        byte[] uppedContent = new String(content, StandardCharsets.UTF_8).getBytes();
                        return bufferFactory.wrap(uppedContent);
                    }));
                }
                return super.writeWith(body);
            }
        };
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }
    public static void main(String[] args) {
        String a = "\"RequestId\":\"1f123f96-56c7-4be4-9b4b-ac844de6f10b\"";
        String b = a.substring(a.indexOf("RequestId")+12,a.indexOf("RequestId")+48);
        System.out.println(a.substring(a.indexOf("RequestId")));
        System.out.println(b);
    }
}


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
2月前
|
Prometheus 网络协议 JavaScript
api 网关 kong 数据库记录请求响应报文
Kong的tcp-log-with-body插件是一个高效的工具,它能够转发Kong处理的请求和响应。这个插件非常适用于需要详细记录API请求和响应信息的情景,尤其是在调试和排查问题时。
49 0
api 网关 kong 数据库记录请求响应报文
|
2月前
|
监控 Java 应用服务中间件
网关大解密:探索Spring Cloud Alibaba中Gateway的奥秘
网关大解密:探索Spring Cloud Alibaba中Gateway的奥秘
112 1
|
3月前
|
监控 测试技术
PTS日志问题之请求压测报告失败如何解决
PTS(Performance Testing Service)是一项面向网站、应用等提供的压力测试服务,用于模拟不同场景下的用户访问,评估系统的性能表现;在进行PTS压测时,可能会出现一些异常或报错,本合集将PTS压测中频繁出现的问题及其解决办法进行汇编,旨在帮助用户更有效地进行性能测试和问题定位。
|
1月前
|
SpringCloudAlibaba Java 网络架构
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关
101 0
|
1月前
|
Java 网络架构 微服务
SpringCloud GateWay网关-学习笔记
SpringCloud GateWay网关-学习笔记
33 0
|
3月前
|
监控 Java API
springcloud5-服务网关zuul及gateway
springcloud5-服务网关zuul及gateway
118 1
springcloud5-服务网关zuul及gateway
|
3月前
|
监控 安全 前端开发
Nginx 访问日志中有 Get 别的网站的请求是什么原因?
Nginx 访问日志中有 Get 别的网站的请求是什么原因?
36 0
|
18天前
|
负载均衡 Nacos 数据安全/隐私保护
SpringCloud GateWay 使用
SpringCloud GateWay 使用
22 0
|
1月前
|
缓存 Java API
【云原生】Spring Cloud Gateway的底层原理与实践方法探究
【云原生】Spring Cloud Gateway的底层原理与实践方法探究
|
3月前
|
Java Spring
Spring Cloud Alibaba - 26 Gateway-自定义谓词工厂RoutePredicateFactory
Spring Cloud Alibaba - 26 Gateway-自定义谓词工厂RoutePredicateFactory
55 0