spring cloud gateway 全局请求日志打印

  • 实现GlobalFilter则所有该自定义Filter会对所有的路由生效。

把请求体的数据存入exchange,便于打印日志时获取

package com.qykj.gateway.filter;

import com.qykj.gateway.ConstantFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.DataBufferUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @calssName AppCacheRequestBodyFilter
 * @Description 将 request body 中的内容 copy 一份,记录到 exchange 的一个自定义属性中
 * @Author jiangshaoneng
 * @DATE 2020/9/27 14:42
 */
public class GlobalCacheRequestBodyFilter implements GlobalFilter, Ordered {

    private static final Logger logger = LoggerFactory.getLogger(GlobalCacheRequestBodyFilter.class);

    private int order;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //logger.info("GlobalCacheRequestBodyFilter ...");

        // 将 request body 中的内容 copy 一份,记录到 exchange 的一个自定义属性中
        Object cachedRequestBodyObject = exchange.getAttributeOrDefault(ConstantFilter.CACHED_REQUEST_BODY_OBJECT_KEY, null);
        // 如果已经缓存过,略过
        if (cachedRequestBodyObject != null) {
            return chain.filter(exchange);
        }
        // 如果没有缓存过,获取字节数组存入 exchange 的自定义属性中
        return DataBufferUtils.join(exchange.getRequest().getBody())
                .map(dataBuffer -> {
                    byte[] bytes = new byte[dataBuffer.readableByteCount()];
                    dataBuffer.read(bytes);
                    DataBufferUtils.release(dataBuffer);
                    return bytes;
                }).defaultIfEmpty(new byte[0])
                .doOnNext(bytes -> exchange.getAttributes().put(ConstantFilter.CACHED_REQUEST_BODY_OBJECT_KEY, bytes))
                .then(chain.filter(exchange));
    }

    @Override
    public int getOrder() {
        return this.order;
    }

    public GlobalCacheRequestBodyFilter(int order){
        this.order = order;
    }
}

编写全局日志拦截器代码

/**
 * @calssName LogFilter
 * @Description 全局日志打印,请求日志以及返回日志,并在返回结果日志中添加请求时间
 * @Author jiangshaoneng
 * @DATE 2020/9/25 14:54
 */
public class GlobalLogFilter implements GlobalFilter, Ordered {

    private static final Logger logger = LoggerFactory.getLogger(GlobalLogFilter.class);

    private int order;

    private static final String REQUEST_PREFIX = "\n--------------------------------- Request  Info -----------------------------";

    private static final String REQUEST_TAIL   = "\n-----------------------------------------------------------------------------";

    private static final String RESPONSE_PREFIX = "\n--------------------------------- Response Info -----------------------------";

    private static final String RESPONSE_TAIL   = "\n-------------------------------------------------------------------------->>>";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        long start = DateUtil.getCurrentTime();

        StringBuilder reqMsg = new StringBuilder();
        StringBuilder resMsg = new StringBuilder();
        // 获取请求信息
        ServerHttpRequest request = exchange.getRequest();
        InetSocketAddress address = request.getRemoteAddress();
        String method = request.getMethodValue();
        URI uri = request.getURI();
        HttpHeaders headers = request.getHeaders();
        // 获取请求body
        Object cachedRequestBodyObject = exchange.getAttributeOrDefault(ConstantFilter.CACHED_REQUEST_BODY_OBJECT_KEY, null);
        byte[] body = (byte[]) cachedRequestBodyObject;
        String params = new String(body);
        // 获取请求query
        Map queryMap = request.getQueryParams();
        String query = JSON.toJSONString(queryMap);

        // 拼接请求日志
        reqMsg.append(REQUEST_PREFIX);
        reqMsg.append("\n header=").append(headers);
        reqMsg.append("\n query=").append(query);
        reqMsg.append("\n params=").append(params);
        reqMsg.append("\n address=").append(address.getHostName()).append(address.getPort());
        reqMsg.append("\n method=").append(method);
        reqMsg.append("\n url=").append(uri.getPath());
        reqMsg.append(REQUEST_TAIL);
        logger.info(reqMsg.toString()); // 打印入参日志

        ServerHttpResponse response = exchange.getResponse();
        DataBufferFactory bufferFactory = response.bufferFactory();
        resMsg.append(RESPONSE_PREFIX);
        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(response) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                    return super.writeWith(fluxBody.map(dataBuffer -> {
                        byte[] content = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(content);
                        String responseResult = new String(content, Charset.forName("UTF-8"));
                        resMsg.append("\n status=").append(this.getStatusCode());
                        resMsg.append("\n header=").append(this.getHeaders());
                        resMsg.append("\n responseResult=").append(responseResult);
                        resMsg.append(RESPONSE_TAIL);

                        // 计算请求时间
                        long end = DateUtil.getCurrentTime();
                        long time = end - start;
                        resMsg.append("耗时ms:").append(time);
                        logger.info(resMsg.toString()); // 打印结果日志
                        return bufferFactory.wrap(content);
                    }));
                }
                return super.writeWith(body);
            }
        };
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }

    @Override
    public int getOrder() {
        return this.order;
    }

    public GlobalLogFilter(int order){
        this.order = order;
    }
}

在代码中配置全局拦截器

/**
 * @calssName GatewayConfig
 * @Description 网关配置
 * @Author jiangshaoneng
 * @DATE 2020/9/25 14:26
 */
@Configuration
public class GatewayConfig {
    /**
     * 全局过滤器:请求日志打印
     */
    @Bean
    public GlobalLogFilter globalLogFilter(){
        // 该值越小权重却大,所以应根据具体项目配置。需要尽早的获取到参数,一般会是一个比较小的值
        return new GlobalLogFilter(-20); 
    }
    
    // 其他的路由配置 ... 
}

你可能感兴趣的:(spring,cloud,经验分享,过滤器,java,filter)