package works.weave.socks.cart.middleware; import io.prometheus.client.Histogram; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; import org.springframework.data.rest.core.config.RepositoryRestConfiguration; import org.springframework.data.rest.core.mapping.ResourceMappings; import org.springframework.data.rest.webmvc.RepositoryRestHandlerMapping; import org.springframework.data.rest.webmvc.support.JpaHelper; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.HashSet; import java.util.Set; public class HTTPMonitoringInterceptor implements HandlerInterceptor { static final Histogram requestLatency = Histogram.build() .name("http_request_duration_seconds") .help("Request duration in seconds.") .labelNames("service", "method", "path", "status_code") .register(); private static final String startTimeKey = "startTime"; @Autowired ResourceMappings mappings; @Autowired JpaHelper jpaHelper; @Autowired RepositoryRestConfiguration repositoryConfiguration; @Autowired ApplicationContext applicationContext; @Autowired RequestMappingHandlerMapping requestMappingHandlerMapping; private Set<PatternsRequestCondition> urlPatterns; @Value("${spring.application.name:orders}") private String serviceName; @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { httpServletRequest.setAttribute(startTimeKey, System.nanoTime()); return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { long start = (long) httpServletRequest.getAttribute(startTimeKey); long elapsed = System.nanoTime() - start; double seconds = (double) elapsed / 1000000000.0; String matchedUrl = getMatchingURLPattern(httpServletRequest); if (!matchedUrl.equals("")) { requestLatency.labels( serviceName, httpServletRequest.getMethod(), matchedUrl, Integer.toString(httpServletResponse.getStatus()) ).observe(seconds); } } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } private String getMatchingURLPattern(HttpServletRequest httpServletRequest) { String res = ""; for (PatternsRequestCondition pattern : getUrlPatterns()) { if (pattern.getMatchingCondition(httpServletRequest) != null && !httpServletRequest.getServletPath().equals("/error")) { res = pattern.getMatchingCondition(httpServletRequest).getPatterns().iterator() .next(); break; } } return res; } private Set<PatternsRequestCondition> getUrlPatterns() { if (this.urlPatterns == null) { this.urlPatterns = new HashSet<>(); requestMappingHandlerMapping.getHandlerMethods().forEach((mapping, handlerMethod) -> urlPatterns.add(mapping.getPatternsCondition())); RepositoryRestHandlerMapping repositoryRestHandlerMapping = new RepositoryRestHandlerMapping(mappings, repositoryConfiguration); repositoryRestHandlerMapping.setJpaHelper(jpaHelper); repositoryRestHandlerMapping.setApplicationContext(applicationContext); repositoryRestHandlerMapping.afterPropertiesSet(); repositoryRestHandlerMapping.getHandlerMethods().forEach((mapping, handlerMethod) -> urlPatterns.add(mapping.getPatternsCondition())); } return this.urlPatterns; } }