聊聊springboot的TomcatMetricsBinder

2023-10-30 19:29:39 浏览数 (2)

本文主要研究一下springboot的TomcatMetricsBinder

TomcatMetricsAutoConfiguration

org/springframework/boot/actuate/autoconfigure/metrics/web/tomcat/TomcatMetricsAutoConfiguration.java

代码语言:javascript复制
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication
@ConditionalOnClass({ TomcatMetrics.class, Manager.class })
@AutoConfigureAfter(CompositeMeterRegistryAutoConfiguration.class)
public class TomcatMetricsAutoConfiguration {

	@Bean
	@ConditionalOnBean(MeterRegistry.class)
	@ConditionalOnMissingBean({ TomcatMetrics.class, TomcatMetricsBinder.class })
	public TomcatMetricsBinder tomcatMetricsBinder(MeterRegistry meterRegistry) {
		return new TomcatMetricsBinder(meterRegistry);
	}

}

TomcatMetricsAutoConfiguration在CompositeMeterRegistryAutoConfiguration之后自动配置,它会创建TomcatMetricsBinder

TomcatMetricsBinder

org/springframework/boot/actuate/metrics/web/tomcat/TomcatMetricsBinder.java

代码语言:javascript复制
public class TomcatMetricsBinder implements ApplicationListener<ApplicationStartedEvent>, DisposableBean {

	private final MeterRegistry meterRegistry;

	private final Iterable<Tag> tags;

	private volatile TomcatMetrics tomcatMetrics;

	public TomcatMetricsBinder(MeterRegistry meterRegistry) {
		this(meterRegistry, Collections.emptyList());
	}

	public TomcatMetricsBinder(MeterRegistry meterRegistry, Iterable<Tag> tags) {
		this.meterRegistry = meterRegistry;
		this.tags = tags;
	}

	@Override
	public void onApplicationEvent(ApplicationStartedEvent event) {
		ApplicationContext applicationContext = event.getApplicationContext();
		Manager manager = findManager(applicationContext);
		this.tomcatMetrics = new TomcatMetrics(manager, this.tags);
		this.tomcatMetrics.bindTo(this.meterRegistry);
	}

	private Manager findManager(ApplicationContext applicationContext) {
		if (applicationContext instanceof WebServerApplicationContext) {
			WebServer webServer = ((WebServerApplicationContext) applicationContext).getWebServer();
			if (webServer instanceof TomcatWebServer) {
				Context context = findContext((TomcatWebServer) webServer);
				return context.getManager();
			}
		}
		return null;
	}

	private Context findContext(TomcatWebServer tomcatWebServer) {
		for (Container container : tomcatWebServer.getTomcat().getHost().findChildren()) {
			if (container instanceof Context) {
				return (Context) container;
			}
		}
		return null;
	}

	@Override
	public void destroy() {
		if (this.tomcatMetrics != null) {
			this.tomcatMetrics.close();
		}
	}

}

TomcatMetricsBinder实现了ApplicationListener监听ApplicationStartedEvent,同时也实现了DisposableBean接口;其onApplicationEvent方法会获取applicationContext再获取tomcat的Manager,最后创建tomcatMetrics,然后执行bindTo方法;其close方法主要是执行tomcatMetrics的close方法

TomcatMetrics

io/micrometer/core/instrument/binder/tomcat/TomcatMetrics.java

代码语言:javascript复制
@NonNullApi
@NonNullFields
public class TomcatMetrics implements MeterBinder {

    private static final String JMX_DOMAIN_EMBEDDED = "Tomcat";
    private static final String JMX_DOMAIN_STANDALONE = "Catalina";
    private static final String OBJECT_NAME_SERVER_SUFFIX = ":type=Server";
    private static final String OBJECT_NAME_SERVER_EMBEDDED = JMX_DOMAIN_EMBEDDED   OBJECT_NAME_SERVER_SUFFIX;
    private static final String OBJECT_NAME_SERVER_STANDALONE = JMX_DOMAIN_STANDALONE   OBJECT_NAME_SERVER_SUFFIX;

    @Nullable
    private final Manager manager;

    private final MBeanServer mBeanServer;
    private final Iterable<Tag> tags;

    private volatile String jmxDomain;

    @Override
    public void bindTo(MeterRegistry registry) {
        registerGlobalRequestMetrics(registry);
        registerServletMetrics(registry);
        registerCacheMetrics(registry);
        registerThreadPoolMetrics(registry);
        registerSessionMetrics(registry);
    }

    //......
}            

TomcatMetrics实现了MeterBinder接口,其bindTo方法主要是执行了registerGlobalRequestMetrics、registerServletMetrics、registerCacheMetrics、registerThreadPoolMetrics、registerSessionMetrics

registerGlobalRequestMetrics

代码语言:javascript复制
    private void registerGlobalRequestMetrics(MeterRegistry registry) {
        registerMetricsEventually("type", "GlobalRequestProcessor", (name, allTags) -> {
            FunctionCounter.builder("tomcat.global.sent", mBeanServer,
                s -> safeDouble(() -> s.getAttribute(name, "bytesSent")))
                .tags(allTags)
                .baseUnit(BaseUnits.BYTES)
                .register(registry);

            FunctionCounter.builder("tomcat.global.received", mBeanServer,
                s -> safeDouble(() -> s.getAttribute(name, "bytesReceived")))
                .tags(allTags)
                .baseUnit(BaseUnits.BYTES)
                .register(registry);

            FunctionCounter.builder("tomcat.global.error", mBeanServer,
                    s -> safeDouble(() -> s.getAttribute(name, "errorCount")))
                    .tags(allTags)
                    .register(registry);

            FunctionTimer.builder("tomcat.global.request", mBeanServer,
                    s -> safeLong(() -> s.getAttribute(name, "requestCount")),
                    s -> safeDouble(() -> s.getAttribute(name, "processingTime")), TimeUnit.MILLISECONDS)
                    .tags(allTags)
                    .register(registry);

            TimeGauge.builder("tomcat.global.request.max", mBeanServer, TimeUnit.MILLISECONDS,
                    s -> safeDouble(() -> s.getAttribute(name, "maxTime")))
                    .tags(allTags)
                    .register(registry);
        });
    }    

registerGlobalRequestMetrics主要是注册了请求相关的指标

registerServletMetrics

代码语言:javascript复制
    private void registerServletMetrics(MeterRegistry registry) {
        registerMetricsEventually("j2eeType", "Servlet", (name, allTags) -> {
            FunctionCounter.builder("tomcat.servlet.error", mBeanServer,
                    s -> safeDouble(() -> s.getAttribute(name, "errorCount")))
                    .tags(allTags)
                    .register(registry);

            FunctionTimer.builder("tomcat.servlet.request", mBeanServer,
                    s -> safeLong(() -> s.getAttribute(name, "requestCount")),
                    s -> safeDouble(() -> s.getAttribute(name, "processingTime")), TimeUnit.MILLISECONDS)
                    .tags(allTags)
                    .register(registry);

            TimeGauge.builder("tomcat.servlet.request.max", mBeanServer, TimeUnit.MILLISECONDS,
                    s -> safeDouble(() -> s.getAttribute(name, "maxTime")))
                    .tags(allTags)
                    .register(registry);
        });
    }

registerServletMetrics主要是注册了servlet相关的errorCount、requestCount及maxTime

registerCacheMetrics

代码语言:javascript复制
    private void registerCacheMetrics(MeterRegistry registry) {
        registerMetricsEventually("type", "StringCache", (name, allTags) -> {
            FunctionCounter.builder("tomcat.cache.access", mBeanServer,
                    s -> safeDouble(() -> s.getAttribute(name, "accessCount")))
                    .tags(allTags)
                    .register(registry);

            FunctionCounter.builder("tomcat.cache.hit", mBeanServer,
                    s -> safeDouble(() -> s.getAttribute(name, "hitCount")))
                    .tags(allTags)
                    .register(registry);
        });
    }

registerCacheMetrics主要是注册了tomcat内部cache的accessCount、hitCount

registerThreadPoolMetrics

代码语言:javascript复制
    private void registerThreadPoolMetrics(MeterRegistry registry) {
        registerMetricsEventually("type", "ThreadPool", (name, allTags) -> {
            Gauge.builder("tomcat.threads.config.max", mBeanServer,
                    s -> safeDouble(() -> s.getAttribute(name, "maxThreads")))
                    .tags(allTags)
                    .baseUnit(BaseUnits.THREADS)
                    .register(registry);

            Gauge.builder("tomcat.threads.busy", mBeanServer,
                    s -> safeDouble(() -> s.getAttribute(name, "currentThreadsBusy")))
                    .tags(allTags)
                    .baseUnit(BaseUnits.THREADS)
                    .register(registry);

            Gauge.builder("tomcat.threads.current", mBeanServer,
                    s -> safeDouble(() -> s.getAttribute(name, "currentThreadCount")))
                    .tags(allTags)
                    .baseUnit(BaseUnits.THREADS)
                    .register(registry);
        });
    }

registerThreadPoolMetrics主要是注册了tomcat线程池的相关指标

registerSessionMetrics

代码语言:javascript复制
    private void registerSessionMetrics(MeterRegistry registry) {
        if (manager == null) {
            // If the binder is created but unable to find the session manager don't register those metrics
            return;
        }

        Gauge.builder("tomcat.sessions.active.max", manager, Manager::getMaxActive)
                .tags(tags)
                .baseUnit("sessions")
                .register(registry);

        Gauge.builder("tomcat.sessions.active.current", manager, Manager::getActiveSessions)
                .tags(tags)
                .baseUnit("sessions")
                .register(registry);

        FunctionCounter.builder("tomcat.sessions.created", manager, Manager::getSessionCounter)
                .tags(tags)
                .baseUnit("sessions")
                .register(registry);

        FunctionCounter.builder("tomcat.sessions.expired", manager, Manager::getExpiredSessions)
                .tags(tags)
                .baseUnit("sessions")
                .register(registry);

        FunctionCounter.builder("tomcat.sessions.rejected", manager, Manager::getRejectedSessions)
                .tags(tags)
                .baseUnit("sessions")
                .register(registry);

        TimeGauge.builder("tomcat.sessions.alive.max", manager, TimeUnit.SECONDS, Manager::getSessionMaxAliveTime)
                .tags(tags)
                .register(registry);
    }

registerSessionMetrics主要是注册了tomcat的session相关指标

小结

springboot的TomcatMetricsBinder主要是接收ApplicationStartedEvent然后创建TomcatMetrics执行bindTo进行注册,TomcatMetrics主要注册了globalRequest、servlet、cache、threadPool、session相关的指标。

0 人点赞