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
How to log time taken by Rest web service in Spring 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 的作者
回答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 InMemoryHttpTraceRepository
by 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