序
本文主要研究下如何使用自定义micrometer的metrics
实例
DemoMetrics
public class DemoMetrics implements MeterBinder {
AtomicInteger count = new AtomicInteger(0);
@Override
public void bindTo(MeterRegistry meterRegistry) {
Gauge.builder("demo.count", count, c -> c.incrementAndGet())
.tags("host", "localhost")
.description("demo of custom meter binder")
.register(meterRegistry);
}
}
这里实现了MeterBinder接口的bindTo方法,将要采集的指标注册到MeterRegistry
注册
- 原始方式
new DemoMetrics().bindTo(registry);
- springboot autoconfigure
@Bean
public DemoMetrics demoMetrics(){
return new DemoMetrics();
}
在springboot只要标注下bean,注入到spring容器后,springboot会自动注册到registry。springboot已经帮你初始化了包括UptimeMetrics等一系列metrics。详见源码解析部分。
验证
curl -i http://localhost:8080/actuator/metrics/demo.count
返回实例
{
"name": "demo.count",
"measurements": [
{
"statistic": "VALUE",
"value": 6
}
],
"availableTags": [
{
"tag": "host",
"values": [
"localhost"
]
}
]
}
源码解析
MetricsAutoConfiguration
spring-boot-actuator-autoconfigure-2.0.0.RELEASE-sources.jar!/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java
@Configuration
@ConditionalOnClass(Timed.class)
@EnableConfigurationProperties(MetricsProperties.class)
@AutoConfigureBefore(CompositeMeterRegistryAutoConfiguration.class)
public class MetricsAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public Clock micrometerClock() {
return Clock.SYSTEM;
}
@Bean
public static MeterRegistryPostProcessor meterRegistryPostProcessor(
ApplicationContext context) {
return new MeterRegistryPostProcessor(context);
}
@Bean
@Order(0)
public PropertiesMeterFilter propertiesMeterFilter(MetricsProperties properties) {
return new PropertiesMeterFilter(properties);
}
@Configuration
@ConditionalOnProperty(value = "management.metrics.binders.jvm.enabled", matchIfMissing = true)
static class JvmMeterBindersConfiguration {
@Bean
@ConditionalOnMissingBean
public JvmGcMetrics jvmGcMetrics() {
return new JvmGcMetrics();
}
@Bean
@ConditionalOnMissingBean
public JvmMemoryMetrics jvmMemoryMetrics() {
return new JvmMemoryMetrics();
}
@Bean
@ConditionalOnMissingBean
public JvmThreadMetrics jvmThreadMetrics() {
return new JvmThreadMetrics();
}
@Bean
@ConditionalOnMissingBean
public ClassLoaderMetrics classLoaderMetrics() {
return new ClassLoaderMetrics();
}
}
@Configuration
static class MeterBindersConfiguration {
@Bean
@ConditionalOnClass(name = { "ch.qos.logback.classic.LoggerContext",
"org.slf4j.LoggerFactory" })
@Conditional(LogbackLoggingCondition.class)
@ConditionalOnMissingBean(LogbackMetrics.class)
@ConditionalOnProperty(value = "management.metrics.binders.logback.enabled", matchIfMissing = true)
public LogbackMetrics logbackMetrics() {
return new LogbackMetrics();
}
@Bean
@ConditionalOnProperty(value = "management.metrics.binders.uptime.enabled", matchIfMissing = true)
@ConditionalOnMissingBean
public UptimeMetrics uptimeMetrics() {
return new UptimeMetrics();
}
@Bean
@ConditionalOnProperty(value = "management.metrics.binders.processor.enabled", matchIfMissing = true)
@ConditionalOnMissingBean
public ProcessorMetrics processorMetrics() {
return new ProcessorMetrics();
}
@Bean
@ConditionalOnProperty(name = "management.metrics.binders.files.enabled", matchIfMissing = true)
@ConditionalOnMissingBean
public FileDescriptorMetrics fileDescriptorMetrics() {
return new FileDescriptorMetrics();
}
}
static class LogbackLoggingCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
ConditionMessage.Builder message = ConditionMessage
.forCondition("LogbackLoggingCondition");
if (loggerFactory instanceof LoggerContext) {
return ConditionOutcome.match(
message.because("ILoggerFactory is a Logback LoggerContext"));
}
return ConditionOutcome
.noMatch(message.because("ILoggerFactory is an instance of "
+ loggerFactory.getClass().getCanonicalName()));
}
}
}
可以看到这里注册了好多metrics,比如UptimeMetrics,JvmGcMetrics,ProcessorMetrics,FileDescriptorMetrics等
这里重点看使用@Bean标注了MeterRegistryPostProcessor
MeterRegistryPostProcessor
spring-boot-actuator-autoconfigure-2.0.0.RELEASE-sources.jar!/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryPostProcessor.java
class MeterRegistryPostProcessor implements BeanPostProcessor {
private final ApplicationContext context;
private volatile MeterRegistryConfigurer configurer;
MeterRegistryPostProcessor(ApplicationContext context) {
this.context = context;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof MeterRegistry) {
getConfigurer().configure((MeterRegistry) bean);
}
return bean;
}
@SuppressWarnings("unchecked")
private MeterRegistryConfigurer getConfigurer() {
if (this.configurer == null) {
this.configurer = new MeterRegistryConfigurer(beansOfType(MeterBinder.class),
beansOfType(MeterFilter.class),
(Collection<MeterRegistryCustomizer<?>>) (Object) beansOfType(
MeterRegistryCustomizer.class),
this.context.getBean(MetricsProperties.class).isUseGlobalRegistry());
}
return this.configurer;
}
private <T> Collection<T> beansOfType(Class<T> type) {
return this.context.getBeansOfType(type).values();
}
}
可以看到这里new了一个MeterRegistryConfigurer,重点注意这里使用beansOfType(MeterBinder.class)方法的返回值给其构造器
MeterRegistryConfigurer
spring-boot-actuator-autoconfigure-2.0.0.RELEASE-sources.jar!/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryConfigurer.java
class MeterRegistryConfigurer {
private final Collection<MeterRegistryCustomizer<?>> customizers;
private final Collection<MeterFilter> filters;
private final Collection<MeterBinder> binders;
private final boolean addToGlobalRegistry;
MeterRegistryConfigurer(Collection<MeterBinder> binders,
Collection<MeterFilter> filters,
Collection<MeterRegistryCustomizer<?>> customizers,
boolean addToGlobalRegistry) {
this.binders = (binders != null ? binders : Collections.emptyList());
this.filters = (filters != null ? filters : Collections.emptyList());
this.customizers = (customizers != null ? customizers : Collections.emptyList());
this.addToGlobalRegistry = addToGlobalRegistry;
}
void configure(MeterRegistry registry) {
if (registry instanceof CompositeMeterRegistry) {
return;
}
// Customizers must be applied before binders, as they may add custom
// tags or alter timer or summary configuration.
customize(registry);
addFilters(registry);
addBinders(registry);
if (this.addToGlobalRegistry && registry != Metrics.globalRegistry) {
Metrics.addRegistry(registry);
}
}
@SuppressWarnings("unchecked")
private void customize(MeterRegistry registry) {
LambdaSafe.callbacks(MeterRegistryCustomizer.class, this.customizers, registry)
.withLogger(MeterRegistryConfigurer.class)
.invoke((customizer) -> customizer.customize(registry));
}
private void addFilters(MeterRegistry registry) {
this.filters.forEach(registry.config()::meterFilter);
}
private void addBinders(MeterRegistry registry) {
this.binders.forEach((binder) -> binder.bindTo(registry));
}
}
可以看到configure方法里头调用了addBinders,也就是把托管给spring容器的MeterBinder实例bindTo到meterRegistry
小结
springboot2引入的micrometer,自定义metrics只需要实现MeterBinder接口,然后托管给spring即可,springboot的autoconfigure帮你自动注册到meterRegistry。