Micrometer 自定义 metrics

编程入门 行业动态 更新时间:2024-10-26 16:22:26

Micrometer <a href=https://www.elefans.com/category/jswz/34/1771438.html style=自定义 metrics"/>

Micrometer 自定义 metrics

Micrometer 提供了基于 Java的 monitor facade,其与 springboot 应用和 prometheus 的集成方式如下图展示

上图中展示得很清楚,应用通过Micrometer采集和暴露监控端点给prometheus,prometheus通过pull模式来采集监控时序数据信息。之后作为数据源提供给grafana进行展示。

Micrometer支持的度量方式及在springboot中的应用示例

Counter
Counter(计数器)简单理解就是一种只增不减的计数器。它通常用于记录服务的请求数量、完成的任务数量、错误的发生数量等等。

package com.olive.producter.monitor;import org.springframework.stereotype.Service;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Metrics;@Service("collectorService")
public class CollectorService {static final Counter userCounter = Metrics.counter("user.counter.total", "services", "demo");public void processCollectResult() throws InterruptedException {while (true) {userCounter.increment(1D);}}
}

Gauge
Gauge(仪表)是一个表示单个数值的度量,它可以表示任意地上下移动的数值测量。Gauge通常用于变动的测量值,如当前的内存使用情况,同时也可以测量上下移动的"计数",比如队列中的消息数量。

package com.olive.producter.monitor;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.stereotype.Component;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.ImmutableTag;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;@Component("passCaseMetric")
public class PassCaseMetric {List<Tag> init() {
ArrayList<Tag> list = new ArrayList() {};list.add(new ImmutableTag("service", "demo"));
return list;}AtomicInteger atomicInteger = new AtomicInteger(0);Gauge passCaseGuage = Gauge.builder("pass.cases.guage", atomicInteger, AtomicInteger::get).tag("service", "demo").description("pass cases guage of demo").register(new SimpleMeterRegistry());AtomicInteger passCases = Metrics.gauge("pass.cases.guage.value", init(), atomicInteger);public void handleMetrics() {while (true) {
if (System.currentTimeMillis() % 2 == 0) {passCases.addAndGet(100);
System.out.println("ADD + " + passCaseGuage.measure() + " : " + passCases);} else {int val = passCases.addAndGet(-100);
if (val < 0) {passCases.set(1);}
System.out.println("DECR - " + passCaseGuage.measure() + " : " + passCases);}}}}

增加一个controller,触发他们:

package com.olive.producter.web;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.olive.producter.monitor.CollectorService;
import com.olive.producter.monitor.PassCaseMetric;@RestController
@RequestMapping("/monitor")
public class MonitorController {@AutowiredCollectorService collectorService;@AutowiredPassCaseMetric passCaseMetric;@RequestMapping(value = "/counter", method = RequestMethod.GET)public String counter() throws InterruptedException {
collectorService.processCollectResult();
return "+1";}@RequestMapping(value = "/gauge", method = RequestMethod.GET)public String gauge() throws InterruptedException {
passCaseMetric.handleMetrics();
return "+gauge";}}

启动springboot应用,可以在http://host:port/actuator/prometheus 看到端点收集到的数据。其他的也是类似的不再一一截图展示。

这里使用了一个true的循环用来展示不断更新的效果。

同样的可以在grafana中看到监控展示信息

Timer
Timer(计时器)同时测量一个特定的代码逻辑块的调用(执行)速度和它的时间分布。简单来说,就是在调用结束的时间点记录整个调用块执行的总时间,适用于测量短时间执行的事件的耗时分布,例如消息队列消息的消费速率。

@Test
public void testTimerSample()Timer timer = Timer.builder("timer").tag("timer", "timersample").description("timer sample test.").register(new SimpleMeterRegistry());for(int i=0; i<2; i++) {timer.record(() -> {
try {TimeUnit.SECONDS.sleep(2);}catch (InterruptedException e){}});}System.out.println(timer.count());System.out.println(timer.measure());System.out.println(timer.totalTime(TimeUnit.SECONDS));System.out.println(timer.mean(TimeUnit.SECONDS));System.out.println(timer.max(TimeUnit.SECONDS));
}

响应数据

2
[Measurement{statistic='COUNT', value=2.0}, Measurement{statistic='TOTAL_TIME', value=4.005095763}, Measurement{statistic='MAX', value=2.004500494}]
4.005095763
2.0025478815
2.004500494

Summary
Summary(摘要)用于跟踪事件的分布。它类似于一个计时器,但更一般的情况是,它的大小并不一定是一段时间的测量值。在Micrometer中,对应的类是DistributionSummary,它的用法有点像Timer,但是记录的值是需要直接指定,而不是通过测量一个任务的执行时间。

@Test
public void testSummary()DistributionSummary summary = DistributionSummary.builder("summary").tag("summary", "summarySample").description("summary sample test").register(new SimpleMeterRegistry());summary.record(2D);summary.record(3D);summary.record(4D);System.out.println(summary.count());System.out.println(summary.measure());System.out.println(summary.max());System.out.println(summary.mean());System.out.println(summary.totalAmount());
}

响应数据:

3
[Measurement{statistic='COUNT', value=3.0}, Measurement{statistic='TOTAL', value=9.0}, Measurement{statistic='MAX', value=4.0}]
4.0
3.0
9.0

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

source: //wwwblogs/duanxz/p/10179946.html

分享&在看

更多推荐

Micrometer 自定义 metrics

本文发布于:2024-03-09 11:16:51,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1724824.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:自定义   Micrometer   metrics

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!