问题
遇到的问题:同一个应用,Spring Boot(Java)和Grails(Groovy)混合编程,常规的Spring Controller,可通过Micromete + Pushgateway,
采集到http.server.requests
指标数据,注意下面的指标名称是点号(请忽略下面截图里的接口的uri并不是上面的截图里的)
在Prometheus页面,会发现指标名称已经变成下划线命名,且增加后缀_seconds_sum
为啥Grails的UrlMappings和controller,无法采集到http_server_requests指标数据?(请忽略下面的截图是另一个应用)
源码分析
一开始,我只知道MeterRegistry.registerMeterIfNecessary
方法,打个断点,调试可进入断点:
截图如上,tag里的uri全部变成root,也就是上面截图4中看到的所有接口全变成root,不同的是method方法。
为啥会变成root呢?
只能断点调试。
断点调试的前提是熟悉框架代码。想一想,如果不知道方法调用层级关系,怎么打断点呢?
如何熟悉代码?花时间。或者反复询问ChatGPT、DeepSeek、GitHub Copilot。
总之,这里直接给出原因。
WebMvcMetricsFilter类相关方法如下:
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
TimingContext timingContext = TimingContext.get(request);
if (timingContext == null) {
timingContext = startAndAttachTimingContext(request);
}
try {
filterChain.doFilter(request, response);
if (!request.isAsyncStarted()) {
// Only record when async processing has finished or never been started.
// If async was started by something further down the chain we wait until the second filter invocation (but we'll be using the TimingContext that was attached to the first)
Throwable exception = fetchException(request);
record(timingContext, request, response, exception);
}
} catch (Exception ex) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
record(timingContext, request, response, unwrapNestedServletException(ex));
throw ex;
}
}
private void record(TimingContext timingContext, HttpServletRequest request, HttpServletResponse response,
Throwable exception) {
try {
Object handler = getHandler(request);
Set<Timed> annotations = getTimedAnnotations(handler);
Timer.Sample timerSample = timingContext.getTimerSample();
AutoTimer.apply(this.autoTimer, this.metricName, annotations,
(builder) -> timerSample.stop(getTimer(builder, handler, request, response, exception)));
}
catch (Exception ex) {
logger.warn("Failed to record timer metrics", ex);