micrometer自定义metrics

本文主要研究下如何使用自定义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。

doc

转载于:https://my.oschina.net/go4it/blog/1647415

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值