Prometheus系列第十一篇一核心之micrometer源码分析一micrometer-core核心实现一tomcat度量采集

模块架构

micrometer-core
  annotation
  aop
  instrument [插桩]
    binder [绑定]
      cache [针对缓存的度量采集,ehcache guava jcache等]
      commonspool2
      db [postgresql等度量采集]
      grpc[grpc客服端服务端度量采集]
      http[Java_servlet度量采集]
      httpcomponents[Apache http-client度量采集]
      hystrix
      server
      jetty
      jpa
      jvm
      kafka
      logging
      mongodb
      okhttp3
      system
      tomcat

示例一Tomcat

  • 通过bindTo注册prometheus
  • spring-actuator会自动创建TomcatMetrics
  • TomcatMetrics通过MBean技术完成指标采集

public class TomcatMetrics implements MeterBinder, AutoCloseable {

    private static final String JMX_DOMAIN_EMBEDDED = "Tomcat";

    private static final String JMX_DOMAIN_STANDALONE = "Catalina";

    private static final String OBJECT_NAME_SERVER_SUFFIX = ":type=Server";

    private static final String OBJECT_NAME_SERVER_EMBEDDED = JMX_DOMAIN_EMBEDDED + OBJECT_NAME_SERVER_SUFFIX;

    private static final String OBJECT_NAME_SERVER_STANDALONE = JMX_DOMAIN_STANDALONE + OBJECT_NAME_SERVER_SUFFIX;

    @Nullable
    private final Manager manager;

    private final MBeanServer mBeanServer;

    private final Iterable<Tag> tags;

    private final Set<NotificationListener> notificationListeners = ConcurrentHashMap.newKeySet();

    private volatile String jmxDomain;

    public TomcatMetrics(@Nullable Manager manager, Iterable<Tag> tags) {
        this(manager, tags, getMBeanServer());
    }

    public TomcatMetrics(@Nullable Manager manager, Iterable<Tag> tags, MBeanServer mBeanServer) {
        this.manager = manager;
        this.tags = tags;
        this.mBeanServer = mBeanServer;

        if (manager != null) {
            this.jmxDomain = manager.getContext().getDomain();
        }
    }

    public static void monitor(MeterRegistry registry, @Nullable Manager manager, String... tags) {
        monitor(registry, manager, Tags.of(tags));
    }

    public static void monitor(MeterRegistry registry, @Nullable Manager manager, Iterable<Tag> tags) {
        new TomcatMetrics(manager, tags).bindTo(registry);
    }

    public static MBeanServer getMBeanServer() {
        List<MBeanServer> mBeanServers = MBeanServerFactory.findMBeanServer(null);
        if (!mBeanServers.isEmpty()) {
            return mBeanServers.get(0);
        }
        return ManagementFactory.getPlatformMBeanServer();
    }

    @Override
    public void bindTo(MeterRegistry registry) {
        // 请求相关度量注册MeterRegistry[先注册micrometer,PrometheusMeterRegistry,后注册prometheus的CollectorRegistry]
        registerGlobalRequestMetrics(registry);
        registerServletMetrics(registry);
        registerCacheMetrics(registry);
        registerThreadPoolMetrics(registry);
        registerSessionMetrics(registry);
    }

    private void registerSessionMetrics(MeterRegistry registry) {
        if (manager == null) {
            // If the binder is created but unable to find the session manager don't
            // register those metrics
            return;
        }

        Gauge.builder("tomcat.sessions.active.max", manager, Manager::getMaxActive).tags(tags)
                .baseUnit(BaseUnits.SESSIONS).register(registry);

        Gauge.builder("tomcat.sessions.active.current", manager, Manager::getActiveSessions).tags(tags)
                .baseUnit(BaseUnits.SESSIONS).register(registry);

        FunctionCounter.builder("tomcat.sessions.created", manager, Manager::getSessionCounter).tags(tags)
                .baseUnit(BaseUnits.SESSIONS).register(registry);

        FunctionCounter.builder("tomcat.sessions.expired", manager, Manager::getExpiredSessions).tags(tags)
                .baseUnit(BaseUnits.SESSIONS).register(registry);

        FunctionCounter.builder("tomcat.sessions.rejected", manager, Manager::getRejectedSessions).tags(tags)
                .baseUnit(BaseUnits.SESSIONS).register(registry);

        TimeGauge.builder("tomcat.sessions.alive.max", manager, TimeUnit.SECONDS, Manager::getSessionMaxAliveTime)
                .tags(tags).register(registry);
    }

    private void registerThreadPoolMetrics(MeterRegistry registry) {
        registerMetricsEventually(":type=ThreadPool,name=*", (name, allTags) -> {
            Gauge.builder("tomcat.threads.config.max", mBeanServer,
                    s -> safeDouble(() -> s.getAttribute(name, "maxThreads"))).tags(allTags).baseUnit(BaseUnits.THREADS)
                    .register(registry);

            Gauge.builder("tomcat.threads.busy", mBeanServer,
                    s -> safeDouble(() -> s.getAttribute(name, "currentThreadsBusy"))).tags(allTags)
                    .baseUnit(BaseUnits.THREADS).register(registry);

            Gauge.builder("tomcat.threads.current", mBeanServer,
                    s -> safeDouble(() -> s.getAttribute(name, "currentThreadCount"))).tags(allTags)
                    .baseUnit(BaseUnits.THREADS).register(registry);

            Gauge.builder("tomcat.connections.current", mBeanServer,
                    s -> safeDouble(() -> s.getAttribute(name, "connectionCount"))).tags(allTags)
                    .baseUnit(BaseUnits.CONNECTIONS).register(registry);

            Gauge.builder("tomcat.connections.keepalive.current", mBeanServer,
                    s -> safeDouble(() -> s.getAttribute(name, "keepAliveCount"))).tags(allTags)
                    .baseUnit(BaseUnits.CONNECTIONS).register(registry);

            Gauge.builder("tomcat.connections.config.max", mBeanServer,
                    s -> safeDouble(() -> s.getAttribute(name, "maxConnections"))).tags(allTags)
                    .baseUnit(BaseUnits.CONNECTIONS).register(registry);
        });
    }

    private void registerCacheMetrics(MeterRegistry registry) {
        registerMetricsEventually(":type=StringCache", (name, allTags) -> {
            FunctionCounter
                    .builder("tomcat.cache.access", mBeanServer,
                            s -> safeDouble(() -> s.getAttribute(name, "accessCount")))
                    .tags(allTags).register(registry);

            FunctionCounter
                    .builder("tomcat.cache.hit", mBeanServer, s -> safeDouble(() -> s.getAttribute(name, "hitCount")))
                    .tags(allTags).register(registry);
        });
    }

    private void registerServletMetrics(MeterRegistry registry) {
        registerMetricsEventually(":j2eeType=Servlet,name=*,*", (name, allTags) -> {
            FunctionCounter.builder("tomcat.servlet.error", mBeanServer,
                    s -> safeDouble(() -> s.getAttribute(name, "errorCount"))).tags(allTags).register(registry);

            FunctionTimer
                    .builder("tomcat.servlet.request", mBeanServer,
                            s -> safeLong(() -> s.getAttribute(name, "requestCount")),
                            s -> safeDouble(() -> s.getAttribute(name, "processingTime")), TimeUnit.MILLISECONDS)
                    .tags(allTags).register(registry);

            TimeGauge.builder("tomcat.servlet.request.max", mBeanServer, TimeUnit.MILLISECONDS,
                    s -> safeDouble(() -> s.getAttribute(name, "maxTime"))).tags(allTags).register(registry);
        });
    }

    private void registerGlobalRequestMetrics(MeterRegistry registry) {
        registerMetricsEventually(":type=GlobalRequestProcessor,name=*", (name, allTags) -> {
            FunctionCounter
                    .builder("tomcat.global.sent", mBeanServer,
                            s -> safeDouble(() -> s.getAttribute(name, "bytesSent")))
                    .tags(allTags).baseUnit(BaseUnits.BYTES).register(registry);

            FunctionCounter
                    .builder("tomcat.global.received", mBeanServer,
                            s -> safeDouble(() -> s.getAttribute(name, "bytesReceived")))
                    .tags(allTags).baseUnit(BaseUnits.BYTES).register(registry);

            FunctionCounter.builder("tomcat.global.error", mBeanServer,
                    s -> safeDouble(() -> s.getAttribute(name, "errorCount"))).tags(allTags).register(registry);

            FunctionTimer
                    .builder("tomcat.global.request", mBeanServer,
                            s -> safeLong(() -> s.getAttribute(name, "requestCount")),
                            s -> safeDouble(() -> s.getAttribute(name, "processingTime")), TimeUnit.MILLISECONDS)
                    .tags(allTags).register(registry);

            TimeGauge.builder("tomcat.global.request.max", mBeanServer, TimeUnit.MILLISECONDS,
                    s -> safeDouble(() -> s.getAttribute(name, "maxTime"))).tags(allTags).register(registry);
        });
    }
}

示例一Grpc

  • micrometer针对无法自动集成到spring的度量,一般都会在实现类上给出使用方法
  • 可以看到Grpc就是通过拦截器这个扩展点,完成对grpc的度量信息采集
  • 同时也通过newResponseCounterFor等方法完成相关度量的创建以及绑定prometheus的CollectorRegistry


/**
 * A gRPC server interceptor that will collect metrics using the given
 * {@link MeterRegistry}.
 *
 * <p>
 * <b>Usage:</b>
 * </p>
 *
 * <pre>
 * Server server = ServerBuilder.forPort(8080)
 *         .intercept(new MetricCollectingServerInterceptor(meterRegistry))
 *         .build();
 *
 * server.start()
 * </pre>
 *
 * @author Daniel Theuke (daniel.theuke@heuboe.de)
 * @since 1.7.0
 */
public class MetricCollectingServerInterceptor extends AbstractMetricCollectingInterceptor
        implements ServerInterceptor {

   
    public MetricCollectingServerInterceptor(final MeterRegistry registry) {
        super(registry);
    }

  
    public MetricCollectingServerInterceptor(final MeterRegistry registry,
            final UnaryOperator<Counter.Builder> counterCustomizer, final UnaryOperator<Timer.Builder> timerCustomizer,
            final Code... eagerInitializedCodes) {
        super(registry, counterCustomizer, timerCustomizer, eagerInitializedCodes);
    }

    public void preregisterService(final BindableService service) {
        preregisterService(service.bindService());
    }

    public void preregisterService(final ServerServiceDefinition serviceDefinition) {
        preregisterService(serviceDefinition.getServiceDescriptor());
    }

    @Override
    protected Counter newRequestCounterFor(final MethodDescriptor<?, ?> method) {
        return this.counterCustomizer.apply(prepareCounterFor(method, METRIC_NAME_SERVER_REQUESTS_RECEIVED,
                "The total number of requests received")).register(this.registry);
    }

    @Override
    protected Counter newResponseCounterFor(final MethodDescriptor<?, ?> method) {
        return this.counterCustomizer.apply(
                prepareCounterFor(method, METRIC_NAME_SERVER_RESPONSES_SENT, "The total number of responses sent"))
                .register(this.registry);
    }

    @Override
    protected Function<Code, Timer> newTimerFunction(final MethodDescriptor<?, ?> method) {
        return asTimerFunction(() -> this.timerCustomizer.apply(prepareTimerFor(method,
                METRIC_NAME_SERVER_PROCESSING_DURATION, "The total time taken for the server to complete the call")));
    }

    @Override
    public <Q, A> ServerCall.Listener<Q> interceptCall(final ServerCall<Q, A> call, final Metadata requestHeaders,
            final ServerCallHandler<Q, A> next) {

        final MetricSet metrics = metricsFor(call.getMethodDescriptor());
        final Consumer<Status.Code> responseStatusTiming = metrics.newProcessingDurationTiming(this.registry);

        final MetricCollectingServerCall<Q, A> monitoringCall = new MetricCollectingServerCall<>(call,
                metrics.getResponseCounter());

        return new MetricCollectingServerCallListener<>(next.startCall(monitoringCall, requestHeaders),
                metrics.getRequestCounter(), monitoringCall::getResponseCode, responseStatusTiming);
    }
}


总结

  • micrometer-core针对常用中间件予以实现
  • 一般没有直接初始化的中间件,其代码注释都提供了使用方式,比如上文的grpc
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Micrometer-registry-prometheus是一个用于将Micrometer指标导出到Prometheus的注册表。它允许开发人员使用Micrometer来收集应用程序的度量,并将这些度量导出到Prometheus,以便进行监视和分析Micrometer-registry-prometheus提供了一种简单的方法来将Micrometer指标与Prometheus集成,使开发人员可以轻松地监视和分析应用程序的性能。 ### 回答2: Micrometer是一个metrics库,可以将metrics与不同的监控系统(如Prometheus)集成。Micrometer让开发人员可以更容易地收集和监控系统的metrics数据,以便更好地了解系统的运行状态和性能,以及及早发现可能存在的问题。 Prometheus是一个开的监控系统和时序数据库,它可以通过拉取方式(pull)收集和存储监控数据,并提供强大的查询和可视化功能。Micrometer使用Registry来对接不同的监控系统,比如在使用Prometheus时,可以通过Micrometer-registry-prometheusMicrometer的metrics数据导入到Prometheus中。 Micrometer-registry-prometheus扮演着Micrometer metrics在Prometheus中注册的角色,它可以通过一系列API方法对Micrometer的metrics进行注册和导出。这些API方法包括:Gauge,Counter,Timer,DistributionSummary和LongTaskTimer等。它还支持通过tags对metrics数据进行不同的分类和聚合,以便更好地展示和分析数据。 总之,Micrometer-registry-prometheus提供了一种简单,方便,可靠的方法来将Micrometer的metrics数据导入到Prometheus中,以便更好地监控和了解系统运行状态和性能。 ### 回答3: Micrometer是一种Java度量度量库,用于在应用程序中收集指标和度量,以及推送到不同的监视系统中,以便进行分析和可视化。Micrometer提供了一系列通用的度量API,并支持集成到众多开监控系统,比如Prometheus、Graphite、InfluxDB等等。 Prometheus是一种基于开的监控系统,采用拉模型(pull model)来采集和存储时间序列数据,并根据用户定义的规则定期进行数据聚合和警报。Prometheus提供了强大的查询语言和可扩展的图形化界面,以便用户更好地查看和理解系统的性能和行为。 MicrometerPrometheus集成,允许开发人员捕获细粒度的指标和计数器,并在Prometheus中公开指标,以便进行监视和分析。此外,Micrometer提供了许多其他有用的特性,比如对分布式跟踪的支持,以及数据导出和聚合处理。 总的来说,Micrometer-registry-prometheus是一种强大的Java度量和监控解决方案,能够帮助开发人员轻松地收集、公开和分析指标和度量,以便更好地处理和维护应用程序的性能和健康状况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值