Skip to content

Commit

Permalink
Allow customizing PrometheusProperties via PrometheusConfig (#4921)
Browse files Browse the repository at this point in the history
Passes properties from `PrometheusConfig`'s new method `prometheusProperties` to the Prometheus client's `PrometheusPropertiesLoader` so they are used along with other methods of configuring the Prometheus client.

Resolves gh-4875
  • Loading branch information
jonatan-ivanov authored Apr 5, 2024
1 parent b3cc212 commit 7f2936a
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 46 deletions.
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ newrelic-api = "5.14.0"
# Kotlin 1.7 sample will fail from OkHttp 4.12.0 due to okio dependency being a Kotlin 1.9 module
okhttp = "4.11.0"
postgre = "42.7.2"
prometheus = "1.2.0"
prometheus = "1.2.1"
prometheusSimpleClient = "0.16.0"
reactor = "2022.0.16"
rest-assured = "5.4.0"
Expand Down
9 changes: 4 additions & 5 deletions implementations/micrometer-registry-prometheus/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ dependencies {
api project(':micrometer-core')

api('io.prometheus:prometheus-metrics-core') {
// We only need SpanContext from prometheus-metrics-tracer-common so we should
// exclude(group: 'io.prometheus', module: 'prometheus-metrics-tracer-initializer')
// But right now we cannot since ExemplarSampler imports SpanContextSupplier
exclude(group: 'io.prometheus', module: 'prometheus-metrics-tracer-otel')
exclude(group: 'io.prometheus', module: 'prometheus-metrics-tracer-otel-agent')
// We only need SpanContext from prometheus-metrics-tracer-common, we don't need
// prometheus-metrics-tracer-initializer nor the dependencies it pulls in
exclude(group: 'io.prometheus', module: 'prometheus-metrics-tracer-initializer')
}
api 'io.prometheus:prometheus-metrics-tracer-common'
implementation 'io.prometheus:prometheus-metrics-exposition-formats'

testImplementation 'io.prometheus:prometheus-metrics-tracer-common'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package io.micrometer.prometheusmetrics;

import io.prometheus.metrics.config.ExemplarsProperties;
import io.prometheus.metrics.config.PrometheusProperties;
import io.prometheus.metrics.core.exemplars.ExemplarSampler;
import io.prometheus.metrics.core.exemplars.ExemplarSamplerConfig;
import io.prometheus.metrics.tracer.common.SpanContext;
Expand All @@ -32,30 +31,31 @@
*/
class DefaultExemplarSamplerFactory implements ExemplarSamplerFactory {

private final ExemplarsProperties exemplarProperties = PrometheusProperties.get().getExemplarProperties();
private final ExemplarsProperties exemplarsProperties;

private final ConcurrentMap<Integer, ExemplarSamplerConfig> exemplarSamplerConfigsByNumberOfExemplars = new ConcurrentHashMap<>();

private final ConcurrentMap<double[], ExemplarSamplerConfig> exemplarSamplerConfigsByHistogramUpperBounds = new ConcurrentHashMap<>();

private final SpanContext spanContext;

public DefaultExemplarSamplerFactory(SpanContext spanContext) {
public DefaultExemplarSamplerFactory(SpanContext spanContext, ExemplarsProperties exemplarsProperties) {
this.spanContext = spanContext;
this.exemplarsProperties = exemplarsProperties;
}

@Override
public ExemplarSampler createExemplarSampler(int numberOfExemplars) {
ExemplarSamplerConfig config = exemplarSamplerConfigsByNumberOfExemplars.computeIfAbsent(numberOfExemplars,
key -> new ExemplarSamplerConfig(exemplarProperties, numberOfExemplars));
key -> new ExemplarSamplerConfig(exemplarsProperties, numberOfExemplars));
return new ExemplarSampler(config, spanContext);
}

@Override
public ExemplarSampler createExemplarSampler(double[] histogramClassicUpperBounds) {
ExemplarSamplerConfig config = exemplarSamplerConfigsByHistogramUpperBounds.computeIfAbsent(
histogramClassicUpperBounds,
key -> new ExemplarSamplerConfig(exemplarProperties, histogramClassicUpperBounds));
key -> new ExemplarSamplerConfig(exemplarsProperties, histogramClassicUpperBounds));
return new ExemplarSampler(config, spanContext);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
*/
package io.micrometer.prometheusmetrics;

import io.micrometer.common.lang.Nullable;
import io.micrometer.core.instrument.config.MeterRegistryConfig;
import io.micrometer.core.instrument.config.validate.Validated;

import java.time.Duration;
import java.util.Properties;

import static io.micrometer.core.instrument.config.MeterRegistryConfigValidator.checkAll;
import static io.micrometer.core.instrument.config.MeterRegistryConfigValidator.checkRequired;
Expand Down Expand Up @@ -58,6 +60,19 @@ default Duration step() {
return getDuration(this, "step").orElse(Duration.ofMinutes(1));
}

/**
* @return an instance of {@link Properties} that contains Prometheus Java Client
* config entries, for example
* {@code io.prometheus.exporter.exemplarsOnAllMetricTypes=true}.
* @see https://prometheus.github.io/client_java/config/config/
*/
@Nullable
default Properties prometheusProperties() {
Properties properties = new Properties();
properties.setProperty("io.prometheus.exporter.exemplarsOnAllMetricTypes", "true");
return properties;
}

@Override
default Validated<?> validate() {
return checkAll(this, checkRequired("step", PrometheusConfig::step));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.micrometer.core.instrument.internal.DefaultGauge;
import io.micrometer.core.instrument.internal.DefaultMeter;
import io.micrometer.core.instrument.util.TimeUtils;
import io.prometheus.metrics.config.PrometheusProperties;
import io.prometheus.metrics.config.PrometheusPropertiesLoader;
import io.prometheus.metrics.expositionformats.ExpositionFormats;
import io.prometheus.metrics.model.registry.PrometheusRegistry;
Expand Down Expand Up @@ -66,13 +67,12 @@
*/
public class PrometheusMeterRegistry extends MeterRegistry {

private final ExpositionFormats expositionFormats = ExpositionFormats
.init(PrometheusPropertiesLoader.load().getExporterProperties());

private final PrometheusConfig prometheusConfig;

private final PrometheusRegistry registry;

private final ExpositionFormats expositionFormats;

private final ConcurrentMap<String, MicrometerCollector> collectorMap = new ConcurrentHashMap<>();

@Nullable
Expand Down Expand Up @@ -101,7 +101,11 @@ public PrometheusMeterRegistry(PrometheusConfig config, PrometheusRegistry regis

this.prometheusConfig = config;
this.registry = registry;
this.exemplarSamplerFactory = spanContext != null ? new DefaultExemplarSamplerFactory(spanContext) : null;
PrometheusProperties prometheusProperties = config.prometheusProperties() != null
? PrometheusPropertiesLoader.load(config.prometheusProperties()) : PrometheusPropertiesLoader.load();
this.expositionFormats = ExpositionFormats.init(prometheusProperties.getExporterProperties());
this.exemplarSamplerFactory = spanContext != null
? new DefaultExemplarSamplerFactory(spanContext, prometheusProperties.getExemplarProperties()) : null;

config().namingConvention(new PrometheusNamingConvention());
config().onMeterRemoved(this::onMeterRemoved);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import io.micrometer.core.Issue;
import io.micrometer.core.instrument.*;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.binder.BaseUnits;
import io.micrometer.core.instrument.binder.jvm.JvmInfoMetrics;
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
Expand All @@ -30,10 +31,7 @@
import org.junit.jupiter.api.Test;

import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
Expand Down Expand Up @@ -638,8 +636,23 @@ void openMetricsScrape() {

@Test
void openMetricsScrapeWithExemplars() throws InterruptedException {
PrometheusMeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT, prometheusRegistry,
clock, new TestSpanContex());
PrometheusConfig prometheusConfig = new PrometheusConfig() {
@Override
public String get(String key) {
return null;
}

@Override
public Properties prometheusProperties() {
Properties properties = new Properties();
properties.putAll(PrometheusConfig.super.prometheusProperties());
properties.setProperty("io.prometheus.exemplars.sampleIntervalMilliseconds", "1");
return properties;
}
};

PrometheusMeterRegistry registry = new PrometheusMeterRegistry(prometheusConfig, prometheusRegistry, clock,
new TestSpanContex());

Counter counter = Counter.builder("my.counter").register(registry);
counter.increment();
Expand All @@ -651,18 +664,18 @@ void openMetricsScrapeWithExemplars() throws InterruptedException {

Timer timerWithHistogram = Timer.builder("timer.withHistogram").publishPercentileHistogram().register(registry);
timerWithHistogram.record(15, TimeUnit.MILLISECONDS);
Thread.sleep(100); // sleeping 100ms since the sample interval limit is 90ms
Thread.sleep(5); // sleeping 5ms since the sample interval limit is 1ms
timerWithHistogram.record(150, TimeUnit.MILLISECONDS);
Thread.sleep(100); // sleeping 100ms since the sample interval limit is 90ms
Thread.sleep(5); // sleeping 5ms since the sample interval limit is 1ms
timerWithHistogram.record(60, TimeUnit.SECONDS);

Timer timerWithSlos = Timer.builder("timer.withSlos")
.serviceLevelObjectives(Duration.ofMillis(100), Duration.ofMillis(200), Duration.ofMillis(300))
.register(registry);
timerWithSlos.record(Duration.ofMillis(15));
Thread.sleep(100); // sleeping 100ms since the sample interval limit is 90ms
Thread.sleep(5); // sleeping 5ms since the sample interval limit is 1ms
timerWithSlos.record(Duration.ofMillis(1_500));
Thread.sleep(100); // sleeping 100ms since the sample interval limit is 90ms
Thread.sleep(5); // sleeping 5ms since the sample interval limit is 1ms
timerWithSlos.record(Duration.ofMillis(150));

DistributionSummary summary = DistributionSummary.builder("summary.noHistogram").register(registry);
Expand All @@ -674,18 +687,18 @@ void openMetricsScrapeWithExemplars() throws InterruptedException {
.publishPercentileHistogram()
.register(registry);
summaryWithHistogram.record(0.15);
Thread.sleep(100); // sleeping 100ms since the sample interval limit is 90ms
Thread.sleep(5); // sleeping 5ms since the sample interval limit is 1ms
summaryWithHistogram.record(5E18);
Thread.sleep(100); // sleeping 100ms since the sample interval limit is 90ms
Thread.sleep(5); // sleeping 5ms since the sample interval limit is 1ms
summaryWithHistogram.record(15);

DistributionSummary slos = DistributionSummary.builder("summary.withSlos")
.serviceLevelObjectives(100, 200, 300)
.register(registry);
slos.record(10);
Thread.sleep(100); // sleeping 100ms since the sample interval limit is 90ms
Thread.sleep(5); // sleeping 5ms since the sample interval limit is 1ms
slos.record(1_000);
Thread.sleep(100); // sleeping 100ms since the sample interval limit is 90ms
Thread.sleep(5); // sleeping 5ms since the sample interval limit is 1ms
slos.record(250);

String scraped = registry.scrape("application/openmetrics-text");
Expand Down

This file was deleted.

0 comments on commit 7f2936a

Please sign in to comment.