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);
    }
}


相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
相关文章
|
4月前
|
存储 缓存 负载均衡
Gateway 网关坑我! 被这个404 问题折腾了一年?
小富分享了一个困扰团队一年多的 SpringCloud Gateway 路由 404 问题。通过日志追踪和源码分析,发现是网关在 Nacos 配置更新后未能正确清理旧的路由权重缓存,导致负载均衡时仍使用已删除的路由数据。最终通过监听路由刷新事件并手动更新缓存,成功解决了问题。
927 125
Gateway 网关坑我! 被这个404 问题折腾了一年?
|
3月前
|
机器学习/深度学习 Kubernetes API
【Azure APIM】自建网关(self-host gateway)收集请求的Header和Body内容到日志中的办法
在Azure API Management中,通过配置trace策略可完整记录API请求的Header和Body信息。在Inbound和Outbound策略中分别使用context.Request/Response.Headers和Body.As&lt;string&gt;方法捕获数据,并写入Trace日志,便于排查与审计。
150 7
|
5月前
|
安全 虚拟化
Omnissa Secure Email Gateway 2.33 - 电子邮件网关
Omnissa Secure Email Gateway 2.33 - 电子邮件网关
121 0
|
9月前
|
JSON API 数据格式
【Azure APIM】如何把APIM中处理的请求的所有请求头保存在日志中?
Azure API Management 默认诊断日志不记录请求的 Header 和 Body 信息。为实现记录,可通过配置 Trace 策略解决。例如,使用 `context.Request.Headers` 和 `context.Request.Body` 获取相关信息,并以 JSON 或字符串格式保存。示例代码展示了如何将 Headers 转换为 JSON 或逗号分隔字符串形式记录。相关参考资料包括 Set Body Policy 和 Trace Policy 官方文档,帮助进一步了解与扩展功能。
230 36
|
负载均衡 Java 应用服务中间件
Gateway服务网关
Gateway服务网关
354 1
Gateway服务网关
|
负载均衡 Java API
项目中用的网关Gateway及SpringCloud
Spring Cloud Gateway 是一个功能强大、灵活易用的API网关解决方案。通过配置路由、过滤器、熔断器和限流等功能,可以有效地管理和保护微服务。本文详细介绍了Spring Cloud Gateway的基本概念、配置方法和实际应用,希望能帮助开发者更好地理解和使用这一工具。通过合理使用Spring Cloud Gateway,可以显著提升微服务架构的健壮性和可维护性。
746 0
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
878 5
|
Kubernetes 数据安全/隐私保护 容器
【Azure APIM】APIM Self-Hosted网关中,添加网关日志以记录请求头信息(Request Header / Response Header)
【Azure APIM】APIM Self-Hosted网关中,添加网关日志以记录请求头信息(Request Header / Response Header)
201 3
|
JavaScript Serverless Linux
函数计算产品使用问题之遇到Node.js环境下的请求日志没有正常输出时,该如何排查
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
缓存 网络协议 API
【Azure 环境】请求经过应用程序网关,当响应内容大时遇见504超时报错
应用程序网关的响应缓冲区可以收集后端服务器发送的全部或部分响应数据包,然后再将它们发送给客户端。 默认在应用程序网关上启用响应缓冲,这对于适应缓慢的客户端很有用。
162 0

热门文章

最新文章