Java 如何在 Spring Boot 中记录 Rest Web 服务所花费的时间?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42857658/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 00:28:42  来源:igfitidea点击:

How to log time taken by Rest web service in Spring Boot?

javaspringloggingspring-boot

提问by VdeX

I am writing a web Rest web service using Spring Boot.

我正在使用Spring Boot编写一个 Web Rest Web 服务。

I want to log time taken by my webservice to process request. Also I want to log headers,method and URI called.

我想记录我的网络服务处理请求所花费的时间。另外我想记录标题、方法和调用的 URI。

I have done similar in my jersey web service few months back using ContainerRequestFilter and ContainerResponseFilter filter() method.

几个月前我在我的球衣网络服务中做了类似的使用 ContainerRequestFilter and ContainerResponseFilter filter() method.

Also, AOP is Better or Filter?

另外,AOP 更好还是过滤器更好?

采纳答案by David Pérez Cabrera

Have you tried with a basic filter like this?

您是否尝试过这样的基本过滤器?

import java.io.IOException;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@WebFilter("/*")
public class StatsFilter implements Filter {

    private static final Logger LOGGER = LoggerFactory.getLogger(StatsFilter.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
    }
}

回答by FPratama

Maybe you can use log4j and configure the log to DEBUG

也许您可以使用log4j并将日志配置为DEBUG

回答by bedrin

Answer by David is correct - filter is a good way to implement such functionality in Spring Boot.

David 的回答是正确的 - filter 是在 Spring Boot 中实现此类功能的好方法。

Spring Boot has a built-in endpointwhich returns the information about last 100 requests like shown below:

Spring Boot 有一个内置端点,它返回有关最近 100 个请求的信息,如下所示:

[{
    "timestamp": 1394343677415,
    "info": {
        "method": "GET",
        "path": "/trace",
        "headers": {
            "request": {
                "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
                "Connection": "keep-alive",
                "Accept-Encoding": "gzip, deflate",
                "User-Agent": "Mozilla/5.0 Gecko/Firefox",
                "Accept-Language": "en-US,en;q=0.5",
                "Cookie": "_ga=GA1.1.827067509.1390890128; ..."
                "Authorization": "Basic ...",
                "Host": "localhost:8080"
            },
            "response": {
                "Strict-Transport-Security": "max-age=31536000 ; includeSubDomains",
                "X-Application-Context": "application:8080",
                "Content-Type": "application/json;charset=UTF-8",
                "status": "200"
            }
        }
    }
},{
    "timestamp": 1394343684465,
    ...
}]

If your application is calling another services or querying the database consider using Sniffyfor profiling - it will show you not only time spent on your server but also time spent in calling downstream systems. See a live demo here(Check the black widget in top bottom corner).

如果您的应用程序正在调用其他服务或查询数据库,请考虑使用Sniffy进行分析 - 它不仅会显示在服务器上花费的时间,还会显示调用下游系统所花费的时间。在此处查看现场演示(检查顶部底部角落的黑色小部件)。

Disclaimer: I'm the author of Sniffy

免责声明:我是 Sniffy 的作者

Sniffy demo screenshot

Sniffy 演示截图

回答by Bhushan Uniyal

Spring boot :logging interceptor

Spring boot:日志拦截器

public class ApiLogger extends HandlerInterceptorAdapter {
  private static final Logger logger = LoggerFactory
    .getLogger(ApiLogger.class);

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    String requestId = UUID.randomUUID().toString();
    log(request,response, requestId);
    long startTime = System.currentTimeMillis();
    request.setAttribute("startTime", startTime);
    request.setAttribute("requestId", requestId);
      return true;
  }

  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    super.afterCompletion(request, response, handler, ex);
    long startTime = (Long)request.getAttribute("startTime");    
    long endTime = System.currentTimeMillis();
    long executeTime = endTime - startTime;
    logger.info("requestId {}, Handle :{} , request take time: {}",request.getAttribute("requestId"), handler, executeTime);
  }

  private void log(HttpServletRequest request, HttpServletResponse response, String requestId) {
    logger.info("requestId {}, host {}  HttpMethod: {}, URI : {}",requestId, request.getHeader("host"),
      request.getMethod(), request.getRequestURI() );
  }
}

register interceptor :

注册拦截器:

@Configuration
@EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new ApiLogger()).addPathPatterns("/api/v1/*");
  }
}

回答by aadidasu

If your controller is Async use Aspect to get the correct and complete execution time.

如果您的控制器是异步的,请使用 Aspect 来获得正确和完整的执行时间。

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.UUID;

@Aspect
@Component
public class LoggingAspect {

  static Logger log = LoggerFactory.getLogger(LoggingAspect.class);

  @Around("execution(* com.aakchoo.api.controller..*(..))")
  public Object profileExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {

    long start = System.currentTimeMillis();
    String className = joinPoint.getSignature().getDeclaringTypeName();
    String methodName = joinPoint.getSignature().getName();
    String apiName = className + "."+ methodName;
    HttpServletRequest request =
        ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
    String requestId = UUID.randomUUID().toString();
    log.info("----->>>>>\nREQUESTED_ID: {}\nHOST: {} HttpMethod: {}\nURI: {}\nAPI: {}\nArguments: {}\n",
        requestId,
        request.getHeader("host"),
        request.getMethod(),
        request.getRequestURI(),
        apiName,
        Arrays.toString(joinPoint.getArgs()));

    Object result = joinPoint.proceed();
    long elapsedTime = System.currentTimeMillis() - start;
    log.info("<<<<<-----\nExecution Time: {} ms [REQUESTED_ID: {}] [API: {}]", elapsedTime,requestId,apiName);

    return result;
  }
}

Add @EnableAspectJAutoProxy to your Applciation Class

将 @EnableAspectJAutoProxy 添加到您的 Applciation 类

@EnableAsync
@SpringBootApplication
@EnableAspectJAutoProxy
public class Application {
  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}

And your build.gradle will need the following

你的 build.gradle 将需要以下内容

compile 'org.aspectj:aspectjweaver:1.8.10'
compile 'org.springframework.boot:spring-boot-starter-aop'

回答by Suresh Naik

we can make use of Springboot InMemoryHttpTraceRepositoryby overriding add()method

我们可以InMemoryHttpTraceRepository通过覆盖add()方法来使用 Springboot

public class MyCustomTraceRepository extends InMemoryHttpTraceRepository {


    @Override
    public void add(HttpTrace trace) {
        log(trace);
        super.add(trace);
    }

    //Log only you interested in
    public void log(HttpTrace trace) {
        Map<String, Object> traceMap = new LinkedHashMap<>();
        traceMap.put("status", trace.getResponse().getStatus());
        traceMap.put("method", trace.getRequest().getMethod());
        traceMap.put("uri", trace.getRequest().getUri().getPath());
        traceMap.put("timeTaken", trace.getTimeTaken());

        logger.info(traceMap)
    }
}    

//will Result into
{status=<>, method=<>, uri=/<>, timeTaken=<>}

@See more request and response trace options: https://docs.spring.io/spring-boot/docs/current/actuator-api/html/#http-trace

@查看更多请求和响应跟踪选项:https://docs.spring.io/spring-boot/docs/current/actuator-api/html/#http-trace