当前位置: 首页 > 工具软件 > Micrometer > 使用案例 >

Prometheus系列第十篇一核心之micrometer源码分析一micrometer-registry-prometheus核心实现

逑俊楚
2023-12-01

源码分析一PrometheusMeterRegistry

  • scrape方法: 按照prometheus协议标准格式处理采样点的输出
  • newCounter方法: 创建度量供用户使用
    • PrometheusMeterRegistry的容器没有Counter,则将PrometheusCounter加入collectorMap
    • 为prometheus的CollectorRegistry创建MicrometerCollector并注册
    • 通过Consumer为MicrometerCollector创建child
    • 设置child的采样读取PrometheusCounter的统计值
  • 并通过MicrometerCollector完成micrometer与prometheus的关联
public class PrometheusMeterRegistry extends MeterRegistry {

    private final CollectorRegistry registry;
    /**                 -- Gauge
                        -- Histogram
     *        collector -- Summary
     *                  -- Counter
     *                  -- SimpleCollector
     *                  -()
     * 适配prometheus的collector
     */
    private final ConcurrentMap<String, MicrometerCollector> collectorMap = new ConcurrentHashMap<>();

    private final ExemplarSampler exemplarSampler;

   
    获取所有的label_value
    private static List<String> tagValues(Meter.Id id) {
        return stream(id.getTagsAsIterable().spliterator(), false).map(Tag::getValue).collect(toList());
    }


    
    按照prometheus协议标准格式处理采样点的输出
    private void scrape(Writer writer, String contentType, Enumeration<Collector.MetricFamilySamples> samples)
            throws IOException {
        TextFormat.writeFormat(contentType, writer, samples);
    }


    @Override
    public Counter newCounter(Meter.Id id) {
        根据唯一标志符创建PrometheusCounter
        PrometheusCounter counter = new PrometheusCounter(id, exemplarSampler);
        micrometer:
          - 如果PrometheusMeterRegistry的容器没有,则将PrometheusCounter加入collectorMap
          - 并且为prometheus的CollectorRegistry创建MicrometerCollector并注册
          - 通过Consumer为MicrometerCollector创建child
          - 设置child的采样读取PrometheusCounter的统计值
          - 从而完成micrometer与prometheus的关联
        prometheus:
        applyToCollector(id, new Consumer<MicrometerCollector>() {
            @Override
            public void accept(MicrometerCollector collector) {
                List<String> tagValues = tagValues(id);
                collector.add(tagValues,
                        new MicrometerCollector.Child() {
                            @Override
                            public Stream<MicrometerCollector.Family> samples(String conventionName, List<String> tagKeys) {
                                return Stream.of(new MicrometerCollector.Family(Collector.Type.COUNTER, conventionName,
                                        new Collector.MetricFamilySamples.Sample(conventionName, tagKeys, tagValues,
                                                counter.count(), counter.exemplar())));
                            }
                        });
            }
        });
        return counter;
    }

    @Override
    public DistributionSummary newDistributionSummary(Meter.Id id,
        ...... 删除创建实现,
        return summary;
    }

    @Override
    protected io.micrometer.core.instrument.Timer newTimer(Meter.Id id,
            DistributionStatisticConfig distributionStatisticConfig, PauseDetector pauseDetector) {
        ...... 删除创建实现,
        return timer;
    }

    @Override
    protected <T> io.micrometer.core.instrument.Gauge newGauge(Meter.Id id, @Nullable T obj,
            ToDoubleFunction<T> valueFunction) {
        ...... 删除创建实现,
        return gauge;
    }

    @Override
    protected LongTaskTimer newLongTaskTimer(Meter.Id id, DistributionStatisticConfig distributionStatisticConfig) {
        ...... 删除创建实现,
        return ltt;
    }

    Prometheus的registry
    public CollectorRegistry getPrometheusRegistry() {
        return registry;
    }

    private void applyToCollector(Meter.Id id, Consumer<MicrometerCollector> consumer) {

        collectorMap.compute(getConventionName(id), new BiFunction<String, MicrometerCollector, MicrometerCollector>() {
            @Override
            public MicrometerCollector apply(String name, MicrometerCollector existingCollector) {

                if (existingCollector == null) {
                    -- collectorMap中没有相关名称的MicrometerCollector,则创建
                    MicrometerCollector micrometerCollector = new MicrometerCollector(id, PrometheusMeterRegistry.this.config().namingConvention(),
                            prometheusConfig);
                    -- 为micrometerCollector创建child,并为child设置采样数据对象
                    consumer.accept(micrometerCollector);
                    -- 完成MicrometerCollector向prometheus注册
                    return micrometerCollector.register(registry);
                }

                List<String> tagKeys = PrometheusMeterRegistry.this.getConventionTags(id).stream().map(Tag::getKey).collect(toList());
                if (existingCollector.getTagKeys().equals(tagKeys)) {
                    consumer.accept(existingCollector);
                    return existingCollector;
                }

                return existingCollector;
            }
        });
    }

}

源码分析一MicrometerCollector

  • 兼容prometheus设计的Collector
  • 其child采样一般读取的是micrometer本身设计的Counter等度量对象的值;[实现可以参见上文分析]
class MicrometerCollector extends Collector implements Collector.Describable {

    private final Meter.Id id;

    private final Map<List<String>, Child> children = new ConcurrentHashMap<>();

    private final String conventionName;
    label值对
    private final List<String> tagKeys;

    private final String help;

    public MicrometerCollector(Meter.Id id, NamingConvention convention, PrometheusConfig config) {
        this.id = id;
        this.conventionName = id.getConventionName(convention);
        this.tagKeys = id.getConventionTags(convention).stream().map(Tag::getKey).collect(toList());
        this.help = config.descriptions() ? Optional.ofNullable(id.getDescription()).orElse(" ") : " ";
    }


    @Override
    public List<MetricFamilySamples> collect() {
        完成对外部的采集的数据暴露
        Map<String, Family> families = new HashMap<>();

        for (Child child : children.values()) {
            child.samples(conventionName, tagKeys).forEach(family -> {
                families.compute(family.getConventionName(), (name, matchingFamily) -> matchingFamily != null
                        ? matchingFamily.addSamples(family.samples) : family);
            });
        }

        return families.values().stream()
                .map(family -> new MetricFamilySamples(family.conventionName, family.type, help, family.samples))
                .collect(toList());
    }

     

    interface Child {
        micrometer通过匿名内部类,在这里通过读取micrometer自身的gauge,counter的度量信息 
        Stream<Family> samples(String conventionName, List<String> tagKeys);
    }
}

总结

  • 本文介绍micrometer与prometheus的集成模块: micrometer-registry-prometheus

  • 有了集成模块后,micrometer-core定义了一系列与不同中间件结合的度量,就可以通过micrometer-registry-prometheus上报prometheus服务端

 类似资料: