使用过滤器跟踪弹簧启动时的响应时间

时间:2017-10-29 16:30:43

标签: spring api filter

我使用spring boot实现了一个API,我想跟踪不同API调用的响应时间(GET,POST,DELETE,PUT)。

目前我一直在尝试使用以下代码作为过滤器

@Component
public class timeFilter implements Filter {

    private static final Logger LOGGER = LoggerFactory.getLogger(timeFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // empty
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        long time = System.currentTimeMillis();
        try {
            chain.doFilter(req, resp);
        } finally {
            time = System.currentTimeMillis() - time;
            LOGGER.trace("{}: {} ms ", ((HttpServletRequest) req).getRequestURI(),  time);
        }
    }

    @Override
    public void destroy() {
        // empty
    }
}

但是,这只会跟踪从我的存储库中检索所有学生的GET调用的响应时间。

有没有办法可以跟踪其他调用的响应时间,以及我需要在图表上绘制每个调用的响应时间。还有一个原因是我的第一个GET呼叫的响应时间大约为200-300 MS,但之后的任何呼叫的响应时间都在0-20之间?

2 个答案:

答案 0 :(得分:0)

你应该使用spring的OncePerRequestFilter,它应该完成工作 确保扫描此组件。

请注意,我还有动态属性testproject.logging.includeQueryParams,如果你需要包含查询参数,你可以控制它们,对于标题等也是如此。

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

/**
 * Implementation of Spring's {@link OncePerRequestFilter} to log each request
 * including the URI, query String and execution time.
 */

@Component
public class RequestLoggingInterceptor extends OncePerRequestFilter {

    /** {@code Logger} instance. */
    private final Logger logger = LoggerFactory.getLogger(RequestLoggingInterceptor.class);

    /** {@code true} if query parameters should be logged. */
    private boolean includeQueryParams = true;
    /** {@code true} if client address should be logged. */
    private boolean includeClient = true;
    /** {@code true} if request headers should be logged. */
    private boolean includeHeaders = true;


    @Override
    protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException {
        final long start = System.nanoTime();
        try {
            filterChain.doFilter(request, response);
        } finally {
            if( logger.isInfoEnabled() ) {
                final long end = System.nanoTime();
                logger.info(buildMessage(request, end - start));
            }
        }
    }

    /**
     * Builds the message to log from the specified {@code request} including
     * the {@code executionTime}.
     * 
     * @param request
     * @param executionTime in nanoseconds
     * @return log message
     */
    private String buildMessage(final HttpServletRequest request, final long executionTime) {
        final StringBuilder buffer = new StringBuilder();
        buffer.append("method=").append(request.getMethod());
        buffer.append(" uri=").append(request.getRequestURI());

        if( includeQueryParams && request.getQueryString() != null ) {
            buffer.append('?').append(request.getQueryString());
        }

        buffer.append(" executionTime=").append(executionTime);
        return buffer.toString();
    }

    /**
     * Sets whether to {@code include} the query parameter String when logging
     * the request URI.
     * 
     * @param include 
     */
    @Value("${testproject.logging.includeQueryParams:true}")
    public void setIncludeQueryParams(final boolean include) {
        includeQueryParams = include;
    }
}

答案 1 :(得分:0)

万一有人觉得有用,这是使用反应式WebFilter的一种方法

import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

@Component
public class RequestTimingFilter implements WebFilter {

    private static final Logger LOGGER = LoggerFactory.getLogger(RequestTimingFilter.class);
    private final boolean logParameters;

    @Autowired
    RequestTimingFilter(@Value("${flags.log.parameters:false}") boolean logParameters) {
        this.logParameters = logParameters;
    }

    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        long start = System.currentTimeMillis();
        String path = exchange.getRequest().getPath().toString();
        StringBuilder params = new StringBuilder();
        if (this.logParameters) {
            String pairs = exchange.getRequest().getQueryParams().toSingleValueMap()
            .entrySet()
            .stream()
            .map(em -> String.format("%s=%s", em.getKey(), em.getValue()))
            .collect(Collectors.joining(", "));
            params.append(pairs.isEmpty() ? "" : ", ").append(pairs);
        }

        return chain.filter(exchange)
               .doOnSuccess(v -> {
                    long endTime = System.currentTimeMillis();
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("tag={}, uri=\"{}\", time={}, unit=ms{}", "request-timing",
                    path, (endTime - start), params.toString());
                    }
               });
        }
 }