如何使用Spring Boot 2和Micrometer测量服务方法

41

我开始使用Spring Boot 2(RC1)进行我的第一个项目。由于已经有很好的文档,所以从Spring Boot 1.x过来并不难。

然而,现在我想要集成度量指标时遇到了困难。据我所知,目前仅有默认度量指标的文档。但是我也想测量服务级别执行时间以及在dynamodb中使用的时间。

编辑 我正在寻找一种使用Micrometer的解决方案,这是与spring-boot 2一起提供的新执行器库中使用的库。

有没有任何指南可以告诉我应该如何完成这项工作?从这里我读到,目前还没有针对任意Spring Bean的简单注释解决方案。是否可以给我一个示例/链接,说明如何测量像下面这样的方法?

@Service
@Timed
public class MyService {
    public void doSomething() {
        ...;
    }
}
2个回答

54

@io.micrometer.core.annotation.Timed 注释似乎由于范围的缩小而无法用于自定义调用,正如在你提问的链接中提到的

你需要手动设置一个Aspect:

@Configuration
@EnableAspectJAutoProxy
public class AutoTimingConfiguration {
    @Bean
    public TimedAspect timedAspect(MeterRegistry registry) {
        return new TimedAspect(registry);
        }
}

这种方法像这样:

@Timed("GET_CARS")
public List<Car> getCars(){
        return Lists.newArrayList();
}

执行此操作将导致/actuator/metrics(默认)端点中出现GET_CARS指标。


4
我在Spring Boot 2.0.4中无法使其工作,有什么想法吗? - senseiwu
它在我的Spring Boot 2中运行良好,我可以在Prometheus端点看到输出。 - Rafael
1
Micrometer的Spring Boot配置无法识别任意方法上的@Timed。 - vanillaSugar
默认情况下是这样的,但是发布者指定的配置使得这对于任意方法都成立。 - PapaLazarou
只有在另一个bean中的任意方法才能被调用,如果从bean内部调用它将不起作用。 - Gunslinger
3
如果没有来自外部的调用,代理将不会被遍历,也不会有 AOP。 - WesternGun

33

以下是一个小样例,可以帮助你开始。这里并未展示Timer.record()的更多变体。(另外:领域注入仅用于简洁)。

2018-03-12更新:Micrometer 1.0.0开始引入了TimedAspect,因此您也可以使用@Timed注释。目前您需要自己注册Bean。(但请注意,当您在Spring-MVC或Jersey资源上具有自定义@Timed注释时需要谨慎处理。)这已经被Michal Stepan在后续的答案中提到。

package io.github.mweirauch.micrometered.eval;

import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import io.micrometer.core.annotation.Timed;
import io.micrometer.core.aop.TimedAspect;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.Timer.Sample;

@Configuration
@EnableAspectJAutoProxy
public class TimingStuff {

    @Service
    static class MyService {

        @Autowired
        private MeterRegistry registry;

        public void helloManual() {
            // you can keep a ref to this; ok to call multiple times, though
            Timer timer = Timer.builder("myservice").tag("method", "manual").register(registry);

            // manually do the timing calculation
            long start = System.nanoTime();
            doSomething();
            timer.record(System.nanoTime() - start, TimeUnit.NANOSECONDS);
        }

        public void helloSupplier() {
            Timer timer = Timer.builder("myservice").tag("method", "supplier").register(registry);

            // execution of the method is timed internally
            timer.record(() -> doSomething());
        }

        public void helloSample() {
            Timer timer = Timer.builder("myservice").tag("method", "sample").register(registry);

            // records time taken between Sample creation and registering the
            // stop() with the given Timer
            Sample sample = Timer.start(registry);
            doSomething();
            sample.stop(timer);
        }

        // TimedAspect adds "class" and "method" tags
        @Timed(value = "myservice.aspect")
        public void helloAspect() {
            doSomething();
        }

        private void doSomething() {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                //
            }
        }

    }

    @Autowired
    private MyService myService;

    @Bean
    TimedAspect timedAspect(MeterRegistry registry) {
        return new TimedAspect(registry);
    }

    @Scheduled(fixedRate = 1000)
    public void postConstruct() {
        myService.helloManual();
        myService.helloSupplier();
        myService.helloSample();
        myService.helloAspect();
    }

}

如果您选择使用Prometheus,您最终会得到类似以下的内容:

# HELP myservice_seconds  
# TYPE myservice_seconds summary
myservice_seconds_count{application="micrometered",method="manual",} 4.0
myservice_seconds_sum{application="micrometered",method="manual",} 0.200378014
myservice_seconds_max{application="micrometered",method="manual",} 0.050115291
myservice_seconds_count{application="micrometered",method="supplier",} 4.0
myservice_seconds_sum{application="micrometered",method="supplier",} 0.200393455
myservice_seconds_max{application="micrometered",method="supplier",} 0.05011635
myservice_seconds_count{application="micrometered",method="sample",} 4.0
myservice_seconds_sum{application="micrometered",method="sample",} 0.200527005
myservice_seconds_max{application="micrometered",method="sample",} 0.050250191
# HELP myservice_aspect_seconds  
# TYPE myservice_aspect_seconds summary
myservice_aspect_seconds_count{application="micrometered",class="io.github.mweirauch.micrometered.eval.TimingStuff$MyService",method="helloAspect",} 4.0
myservice_aspect_seconds_sum{application="micrometered",class="io.github.mweirauch.micrometered.eval.TimingStuff$MyService",method="helloAspect",} 0.201824272
myservice_aspect_seconds_max{application="micrometered",class="io.github.mweirauch.micrometered.eval.TimingStuff$MyService",method="helloAspect",} 0.051014296

1
更新代码片段的导入。 - mweirauch
出现错误:'org.springframework.beans.factory.BeanCreationException: 创建名为'org.springframework.aop.config.internalAutoProxyCreator'的bean时出错;嵌套异常是java.lang.NoClassDefFoundError: org/aspectj/lang/annotation/Around'。 - user_x
4
你需要将aspectj添加到你的依赖项中。最简单的方法是使用org.springframework.boot:spring-boot-starter-aop - mweirauch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接