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;
}
});
}
}
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服务端