Spring Boot 2.x 自定义metrics 并导出到influxdb

Step 1.添加依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-influx</artifactId>
        </dependency>

Step 2.修改Spring配置文件application.yml

management:
  endpoints:
    enabled-by-default: true
    web:
      exposure:
        include: '*'
  endpoint:
    health:
      show-details: always
  metrics:
    export:
      influx:
        enabled: true
        db: spring
        uri: http://localhost:8086
        step: 10s
        user-name: admin
        password: admin

Step 3. 实现micrometer的MeterBinder接口

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

Step 4.注册

@Bean
public DemoMetrics demoMetrics(){
    return new DemoMetrics();
}
在springboot只要标注下bean,注入到spring容器后,springboot会自动注册到registry。springboot已经帮你初始化了包括UptimeMetrics等一系列metrics。

 

源码解析

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
posted @ 2019-03-14 14:04  April.Chen  阅读(3709)  评论(0编辑  收藏  举报