diff --git a/README.md b/README.md index a6a754c..c80c7c5 100644 --- a/README.md +++ b/README.md @@ -1724,6 +1724,31 @@ Dependencies: ``` +Note that ```metrics-facade-prometheus``` uses +```xml + + io.prometheus + simpleclient_common + ... + +``` + +In case of conflict between the ```simpleclient_common``` version used in ```Metrics Facade``` and the one used in your project, you can resolve it with ```dependency.exclusions``` or any other available means. For example, see ```metrics-facade-samples/pom.xml```: +```xml + + com.ringcentral.platform.metrics + metrics-facade-prometheus + ${project.version} + + + + io.prometheus + simpleclient_common + + + +``` + Example: ```java MetricRegistry registry = new DefaultMetricRegistry(); diff --git a/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/reporters/prometheus/PrometheusMetricsExporter.java b/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/reporters/prometheus/PrometheusMetricsExporter.java index debd642..c126cd7 100644 --- a/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/reporters/prometheus/PrometheusMetricsExporter.java +++ b/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/reporters/prometheus/PrometheusMetricsExporter.java @@ -3,19 +3,27 @@ import com.ringcentral.platform.metrics.MetricRegistry; import com.ringcentral.platform.metrics.names.MetricName; import com.ringcentral.platform.metrics.reporters.MetricsExporter; -import com.ringcentral.platform.metrics.samples.*; -import com.ringcentral.platform.metrics.samples.prometheus.*; +import com.ringcentral.platform.metrics.samples.CompositeInstanceSamplesProvider; +import com.ringcentral.platform.metrics.samples.InstanceSamplesProvider; +import com.ringcentral.platform.metrics.samples.prometheus.PrometheusInstanceSample; +import com.ringcentral.platform.metrics.samples.prometheus.PrometheusInstanceSamplesProvider; +import com.ringcentral.platform.metrics.samples.prometheus.PrometheusSample; +import com.ringcentral.platform.metrics.samples.prometheus.collectorRegistry.SimpleCollectorRegistryPrometheusInstanceSamplesProvider; import com.ringcentral.platform.metrics.utils.StringBuilderWriter; +import io.prometheus.client.CollectorRegistry; import io.prometheus.client.exporter.common.TextFormat; import org.slf4j.Logger; -import java.io.*; +import java.io.IOException; +import java.io.Writer; import java.util.*; import static com.ringcentral.platform.metrics.reporters.prometheus.PrometheusMetricsExporter.Format.PROMETHEUS_TEXT_O_O_4; -import static io.prometheus.client.Collector.*; -import static java.lang.String.*; -import static java.util.Collections.*; +import static io.prometheus.client.Collector.MetricFamilySamples; +import static io.prometheus.client.Collector.sanitizeMetricName; +import static java.lang.String.join; +import static java.util.Collections.emptyList; +import static java.util.Collections.enumeration; import static java.util.stream.Collectors.toList; import static org.slf4j.LoggerFactory.getLogger; @@ -48,6 +56,12 @@ public PrometheusMetricsExporter(MetricRegistry registry) { this(new PrometheusInstanceSamplesProvider(registry)); } + public PrometheusMetricsExporter(MetricRegistry registry, CollectorRegistry... collectorRegistries) { + this( + new PrometheusInstanceSamplesProvider(registry), + new SimpleCollectorRegistryPrometheusInstanceSamplesProvider(collectorRegistries)); + } + public PrometheusMetricsExporter( MetricRegistry registry, boolean convertNameToLowercase, @@ -200,10 +214,7 @@ private void exportInstanceSample(PrometheusInstanceSample is, Map { String sampleName = name; - if (s.hasNameSuffix()) { - sampleName += - convertNameToLowercase ? - sanitizeMetricName(s.nameSuffix()).toLowerCase(locale) : - sanitizeMetricName(s.nameSuffix()); + if (s.hasName()) { + sampleName = buildName(s.name()); + } else if (s.hasNameSuffix()) { + sampleName += buildNameSuffix(s); } return new MetricFamilySamples.Sample( @@ -229,6 +239,17 @@ private MetricFamilySamples toMetricFamilySamples(PrometheusInstanceSample is) { .collect(toList())); } + private String buildName(MetricName name) { + final var sanitizedName = sanitizeMetricName(join(NAME_PARTS_DELIMITER, name)); + return convertNameToLowercase ? sanitizedName.toLowerCase(locale) : sanitizedName; + } + + private String buildNameSuffix(PrometheusSample ps) { + final var suffix = ps.nameSuffix(); + final var sanitizedSuffix = sanitizeMetricName(suffix); + return convertNameToLowercase ? sanitizedSuffix.toLowerCase(locale) : sanitizedSuffix; + } + private static String helpFor(PrometheusInstanceSample is) { return is.hasDescription() ? diff --git a/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusInstanceSamplesProviderBuilder.java b/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusInstanceSamplesProviderBuilder.java new file mode 100644 index 0000000..c83af94 --- /dev/null +++ b/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusInstanceSamplesProviderBuilder.java @@ -0,0 +1,74 @@ +package com.ringcentral.platform.metrics.samples.prometheus; + +import com.ringcentral.platform.metrics.MetricRegistry; +import com.ringcentral.platform.metrics.infoProviders.PredicativeMetricNamedInfoProvider; +import com.ringcentral.platform.metrics.samples.InstanceSampleMaker; +import com.ringcentral.platform.metrics.samples.InstanceSampleSpecProvider; +import com.ringcentral.platform.metrics.samples.SampleMaker; +import com.ringcentral.platform.metrics.samples.SampleSpecProvider; + +import static java.util.Objects.requireNonNull; + +public class PrometheusInstanceSamplesProviderBuilder { + + private InstanceSampleSpecProvider instanceSampleSpecProvider; + private PredicativeMetricNamedInfoProvider> instanceSampleSpecModsProvider; + private InstanceSampleMaker instanceSampleMaker; + private SampleSpecProvider sampleSpecProvider; + private PredicativeMetricNamedInfoProvider> sampleSpecModsProvider; + private SampleMaker sampleMaker; + private final MetricRegistry metricRegistry; + + public PrometheusInstanceSamplesProviderBuilder(MetricRegistry metricRegistry) { + this.metricRegistry = requireNonNull(metricRegistry); + this.instanceSampleSpecProvider = new PrometheusInstanceSampleSpecProvider(); + this.instanceSampleMaker = new PrometheusInstanceSampleMaker(); + this.sampleSpecProvider = new PrometheusSampleSpecProvider(); + this.sampleMaker = new PrometheusSampleMaker(); + } + + public static PrometheusInstanceSamplesProviderBuilder prometheusInstanceSamplesProvider(MetricRegistry metricRegistry) { + return new PrometheusInstanceSamplesProviderBuilder(metricRegistry); + } + + public PrometheusInstanceSamplesProviderBuilder instanceSampleSpecProvider(InstanceSampleSpecProvider instanceSampleSpecProvider) { + this.instanceSampleSpecProvider = requireNonNull(instanceSampleSpecProvider); + return this; + } + + public PrometheusInstanceSamplesProviderBuilder instanceSampleSpecModsProvider(PredicativeMetricNamedInfoProvider> instanceSampleSpecModsProvider) { + this.instanceSampleSpecModsProvider = instanceSampleSpecModsProvider; + return this; + } + + public PrometheusInstanceSamplesProviderBuilder instanceSampleMaker(InstanceSampleMaker instanceSampleMaker) { + this.instanceSampleMaker = requireNonNull(instanceSampleMaker); + return this; + } + + public PrometheusInstanceSamplesProviderBuilder sampleSpecProvider(SampleSpecProvider sampleSpecProvider) { + this.sampleSpecProvider = requireNonNull(sampleSpecProvider); + return this; + } + + public PrometheusInstanceSamplesProviderBuilder sampleSpecModsProvider(PredicativeMetricNamedInfoProvider> sampleSpecModsProvider) { + this.sampleSpecModsProvider = sampleSpecModsProvider; + return this; + } + + public PrometheusInstanceSamplesProviderBuilder sampleMaker(SampleMaker sampleMaker) { + this.sampleMaker = requireNonNull(sampleMaker); + return this; + } + + public PrometheusInstanceSamplesProvider build() { + return new PrometheusInstanceSamplesProvider( + instanceSampleSpecProvider, + instanceSampleSpecModsProvider, + instanceSampleMaker, + sampleSpecProvider, + sampleSpecModsProvider, + sampleMaker, + metricRegistry); + } +} diff --git a/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusSample.java b/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusSample.java index 052d51f..b08ac2b 100644 --- a/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusSample.java +++ b/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusSample.java @@ -13,7 +13,7 @@ public class PrometheusSample implements Sample { private final MetricName childInstanceSampleNameSuffix; private final Collector.Type childInstanceSampleType; - + private final MetricName name; private final String nameSuffix; private final List labelNames; private final List labelValues; @@ -22,6 +22,7 @@ public class PrometheusSample implements Sample { public PrometheusSample( MetricName childInstanceSampleNameSuffix, Collector.Type childInstanceSampleType, + MetricName name, String nameSuffix, List labelNames, List labelValues, @@ -35,6 +36,7 @@ public PrometheusSample( this.childInstanceSampleNameSuffix = childInstanceSampleNameSuffix; this.childInstanceSampleType = childInstanceSampleType; + this.name = name; this.nameSuffix = nameSuffix; this.labelNames = labelNames != null ? labelNames : emptyList(); this.labelValues = labelValues != null ? labelValues : emptyList(); @@ -57,12 +59,21 @@ public PrometheusSample notBelongingToChildInstanceSample() { return new PrometheusSample( null, null, + name, nameSuffix, labelNames, labelValues, value); } + public boolean hasName() { + return name != null; + } + + public MetricName name() { + return name; + } + public boolean hasNameSuffix() { return nameSuffix != null; } diff --git a/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusSampleMaker.java b/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusSampleMaker.java index 1ed2d7b..ef26445 100644 --- a/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusSampleMaker.java +++ b/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusSampleMaker.java @@ -93,6 +93,7 @@ public PrometheusSample makeSample(PrometheusSampleSpec spec, PrometheusInstance return new PrometheusSample( childInstanceSampleNameSuffix, childInstanceSampleType, + null, nameSuffix, labelNames, labelValues, diff --git a/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/samples/prometheus/collectorRegistry/SimpleCollectorRegistryPrometheusInstanceSamplesProvider.java b/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/samples/prometheus/collectorRegistry/SimpleCollectorRegistryPrometheusInstanceSamplesProvider.java new file mode 100644 index 0000000..1942be5 --- /dev/null +++ b/metrics-facade-prometheus/src/main/java/com/ringcentral/platform/metrics/samples/prometheus/collectorRegistry/SimpleCollectorRegistryPrometheusInstanceSamplesProvider.java @@ -0,0 +1,154 @@ +package com.ringcentral.platform.metrics.samples.prometheus.collectorRegistry; + +import com.ringcentral.platform.metrics.names.MetricName; +import com.ringcentral.platform.metrics.samples.InstanceSamplesProvider; +import com.ringcentral.platform.metrics.samples.prometheus.PrometheusInstanceSample; +import com.ringcentral.platform.metrics.samples.prometheus.PrometheusSample; +import io.prometheus.client.Collector.MetricFamilySamples; +import io.prometheus.client.CollectorRegistry; +import io.prometheus.client.Predicate; + +import java.util.*; +import java.util.function.Function; + +import static com.ringcentral.platform.metrics.utils.Preconditions.checkArgument; + +public class SimpleCollectorRegistryPrometheusInstanceSamplesProvider implements InstanceSamplesProvider< + PrometheusSample, + PrometheusInstanceSample> { + + private final Function nameBuilder; + private final Predicate metricFamilyNameFilter; + private final Predicate metricFamilySampleNameFilter; + private final Collection collectorRegistries; + + /** + * @param collectorRegistries must be not empty + */ + public SimpleCollectorRegistryPrometheusInstanceSamplesProvider(CollectorRegistry... collectorRegistries) { + this(null, collectorRegistries); + } + + /** + * @param namePrefix the prefix to be prepended to each MetricFamilySample.name when building PrometheusInstanceSample.instanceName/name + * and to be prepended to each MetricFamilySample.Sample.name when building PrometheusSample.name. + * Optional + * + * @param collectorRegistries must be not empty + */ + public SimpleCollectorRegistryPrometheusInstanceSamplesProvider( + MetricName namePrefix, + CollectorRegistry... collectorRegistries) { + + this(namePrefix, null, null, List.of(collectorRegistries)); + } + + /** + * @param namePrefix the prefix to be prepended to each MetricFamilySample.name when building PrometheusInstanceSample.instanceName/name + * and to be prepended to each MetricFamilySample.Sample.name when building PrometheusSample.name. + * Optional + * + * @param metricFamilyNameFilter optional + * @param metricFamilySampleNameFilter optional + * @param collectorRegistries must be not empty + */ + public SimpleCollectorRegistryPrometheusInstanceSamplesProvider( + MetricName namePrefix, + Predicate metricFamilyNameFilter, + Predicate metricFamilySampleNameFilter, + CollectorRegistry... collectorRegistries) { + + this(namePrefix, metricFamilyNameFilter, metricFamilySampleNameFilter, List.of(collectorRegistries)); + } + + /** + * @param namePrefix the prefix to be prepended to each MetricFamilySample.name when building PrometheusInstanceSample.instanceName/name + * and to be prepended to each MetricFamilySample.Sample.name when building PrometheusSample.name. + * Optional + * + * @param metricFamilyNameFilter optional + * @param metricFamilySampleNameFilter optional + * @param collectorRegistries must be not empty + */ + public SimpleCollectorRegistryPrometheusInstanceSamplesProvider( + MetricName namePrefix, + Predicate metricFamilyNameFilter, + Predicate metricFamilySampleNameFilter, + Collection collectorRegistries) { + + this( + n -> MetricName.of(namePrefix, n), + metricFamilyNameFilter, + metricFamilySampleNameFilter, + collectorRegistries); + } + + /** + * @param nameBuilder the function to be applied to each MetricFamilySample.name when building PrometheusInstanceSample.instanceName/name + * and to be applied to each MetricFamilySample.Sample.name when building PrometheusSample.name. + * Optional + * + * @param metricFamilyNameFilter optional + * @param metricFamilySampleNameFilter optional + * @param collectorRegistries must be not empty + */ + public SimpleCollectorRegistryPrometheusInstanceSamplesProvider( + Function nameBuilder, + Predicate metricFamilyNameFilter, + Predicate metricFamilySampleNameFilter, + Collection collectorRegistries) { + + this.nameBuilder = nameBuilder != null ? nameBuilder : MetricName::of; + this.metricFamilyNameFilter = metricFamilyNameFilter; + this.metricFamilySampleNameFilter = metricFamilySampleNameFilter; + + checkArgument( + collectorRegistries != null && !collectorRegistries.isEmpty(), + "collectorRegistries is null or empty"); + + this.collectorRegistries = collectorRegistries; + } + + @Override + public Set instanceSamples() { + Set result = new LinkedHashSet<>(); + collectorRegistries.forEach(collectorRegistry -> processCollectorRegistry(collectorRegistry, result)); + return result; + } + + private void processCollectorRegistry(CollectorRegistry collectorRegistry, Set result) { + Enumeration fsEnumeration = + metricFamilyNameFilter != null ? + collectorRegistry.filteredMetricFamilySamples(metricFamilyNameFilter) : + collectorRegistry.metricFamilySamples(); + + while (fsEnumeration.hasMoreElements()) { + MetricFamilySamples fs = fsEnumeration.nextElement(); + MetricName name = nameBuilder.apply(fs.name); + PrometheusInstanceSample instanceSample = new PrometheusInstanceSample(name, name, fs.help, fs.type); + + fs.samples.forEach(fsSample -> { + if (metricFamilySampleNameFilter != null && !metricFamilySampleNameFilter.test(fsSample.name)) { + return; + } + + MetricName sampleName = nameBuilder.apply(fsSample.name); + + PrometheusSample sample = new PrometheusSample( + null, + null, + sampleName, + null, + fsSample.labelNames, + fsSample.labelValues, + fsSample.value); + + instanceSample.add(sample); + }); + + if (!instanceSample.samples().isEmpty()) { + result.add(instanceSample); + } + } + } +} \ No newline at end of file diff --git a/metrics-facade-prometheus/src/test/java/com/ringcentral/platform/metrics/reporters/prometheus/PrometheusMetricsExporterTest.java b/metrics-facade-prometheus/src/test/java/com/ringcentral/platform/metrics/reporters/prometheus/PrometheusMetricsExporterTest.java index ae8ffc2..3a2d1bb 100644 --- a/metrics-facade-prometheus/src/test/java/com/ringcentral/platform/metrics/reporters/prometheus/PrometheusMetricsExporterTest.java +++ b/metrics-facade-prometheus/src/test/java/com/ringcentral/platform/metrics/reporters/prometheus/PrometheusMetricsExporterTest.java @@ -1,19 +1,27 @@ package com.ringcentral.platform.metrics.reporters.prometheus; import com.ringcentral.platform.metrics.samples.InstanceSamplesProvider; -import com.ringcentral.platform.metrics.samples.prometheus.*; +import com.ringcentral.platform.metrics.samples.prometheus.PrometheusInstanceSample; +import com.ringcentral.platform.metrics.samples.prometheus.PrometheusSample; import io.prometheus.client.Collector; +import io.prometheus.client.CollectorRegistry; +import io.prometheus.client.Summary; import org.junit.Test; -import java.util.*; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; import static com.ringcentral.platform.metrics.names.MetricName.name; -import static com.ringcentral.platform.metrics.reporters.prometheus.PrometheusMetricsExporter.Format.*; -import static com.ringcentral.platform.metrics.samples.prometheus.PrometheusSampleMaker.*; +import static com.ringcentral.platform.metrics.reporters.prometheus.PrometheusMetricsExporter.Format.OPENMETRICS_TEXT_1_0_0; +import static com.ringcentral.platform.metrics.reporters.prometheus.PrometheusMetricsExporter.Format.PROMETHEUS_TEXT_O_O_4; +import static com.ringcentral.platform.metrics.samples.prometheus.PrometheusSampleMaker.DEFAULT_MAX_CHILD_NAME_SUFFIX; +import static com.ringcentral.platform.metrics.samples.prometheus.PrometheusSampleMaker.DEFAULT_MEAN_CHILD_NAME_SUFFIX; import static java.util.Collections.emptyList; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; @SuppressWarnings("unchecked") public class PrometheusMetricsExporterTest { @@ -53,6 +61,7 @@ public void export() { null, null, null, + null, emptyList(), emptyList(), 1.0)); @@ -69,6 +78,7 @@ public void export() { null, null, null, + null, List.of(DIMENSION_1, DIMENSION_2), List.of("dimension_1_value", "dimension_2_value"), 2.0)); @@ -86,6 +96,7 @@ public void export() { null, null, null, + null, emptyList(), emptyList(), 3.0)); @@ -102,6 +113,7 @@ public void export() { null, null, null, + null, List.of(DIMENSION_1, DIMENSION_2, DIMENSION_3), List.of("dimension_1_value", "dimension_2_value", "dimension_3_value"), 4.0)); @@ -116,6 +128,7 @@ public void export() { Collector.Type.SUMMARY); instanceSample.add(new PrometheusSample( + null, null, null, "_count", @@ -127,6 +140,7 @@ public void export() { DEFAULT_MAX_CHILD_NAME_SUFFIX, Collector.Type.GAUGE, null, + null, emptyList(), emptyList(), 6.0)); @@ -135,6 +149,7 @@ public void export() { DEFAULT_MEAN_CHILD_NAME_SUFFIX, Collector.Type.GAUGE, null, + null, emptyList(), emptyList(), 7.0)); @@ -143,6 +158,7 @@ public void export() { null, null, null, + null, List.of("quantile"), List.of("0.50"), 8.0)); @@ -151,6 +167,7 @@ public void export() { null, null, null, + null, List.of("quantile"), List.of("0.75"), 9.0)); @@ -164,6 +181,7 @@ public void export() { Collector.Type.SUMMARY); instanceSample.add(new PrometheusSample( + null, null, null, "_count", @@ -175,6 +193,7 @@ public void export() { DEFAULT_MAX_CHILD_NAME_SUFFIX, Collector.Type.GAUGE, null, + null, List.of(DIMENSION_1, DIMENSION_2, DIMENSION_3), List.of("dimension_1_value", "dimension_2_value", "dimension_3_value"), 11.0)); @@ -183,6 +202,7 @@ public void export() { DEFAULT_MEAN_CHILD_NAME_SUFFIX, Collector.Type.GAUGE, null, + null, List.of(DIMENSION_1, DIMENSION_2, DIMENSION_3), List.of("dimension_1_value", "dimension_2_value", "dimension_3_value"), 12.0)); @@ -191,6 +211,7 @@ public void export() { null, null, null, + null, List.of(DIMENSION_1, DIMENSION_2, DIMENSION_3, "quantile"), List.of("dimension_1_value", "dimension_2_value", "dimension_3_value", "0.50"), 13.0)); @@ -199,13 +220,27 @@ public void export() { null, null, null, + null, List.of(DIMENSION_1, DIMENSION_2, DIMENSION_3, "quantile"), List.of("dimension_1_value", "dimension_2_value", "dimension_3_value", "0.75"), 14.0)); instanceSamples.add(instanceSample); + CollectorRegistry collectorRegistry = new CollectorRegistry(true); + + Summary summary = Summary.build() + .name("summary") + .labelNames("label_1", "label_2") + .help("Summary from defaultRegistry") + .register(collectorRegistry); + + summary.labels("label_1_value", "label_2_value").observe(10); + summary.labels("label_1_value", "label_2_value").observe(20); + summary.labels("label_1_value", "label_2_value").observe(30); - PrometheusMetricsExporter exporter = new PrometheusMetricsExporter(PROMETHEUS_TEXT_O_O_4, instanceSamplesProvider); + PrometheusMetricsExporter exporter = new PrometheusMetricsExporter( + PROMETHEUS_TEXT_O_O_4, + instanceSamplesProvider); assertThat(exporter.exportMetrics(), is( "# HELP a Generated from metric instances with name counter.a\n" + diff --git a/metrics-facade-prometheus/src/test/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusInstanceSampleTest.java b/metrics-facade-prometheus/src/test/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusInstanceSampleTest.java index 64b15ff..0a24cf6 100644 --- a/metrics-facade-prometheus/src/test/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusInstanceSampleTest.java +++ b/metrics-facade-prometheus/src/test/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusInstanceSampleTest.java @@ -21,6 +21,7 @@ public void addingSamples() { Collector.Type.UNKNOWN); instanceSample.add(new PrometheusSample( + null, null, null, "suffix_1", @@ -31,6 +32,7 @@ public void addingSamples() { instanceSample.add(new PrometheusSample( name("childSuffix_1"), Collector.Type.SUMMARY, + null, "suffix_2", List.of("dimension_1", "dimension_2"), List.of("dimension_1_value", "dimension_2_value"), @@ -40,6 +42,7 @@ public void addingSamples() { name("childSuffix_2"), Collector.Type.HISTOGRAM, null, + null, List.of("dimension_1"), List.of("dimension_1_value"), 3.0)); @@ -47,12 +50,14 @@ public void addingSamples() { instanceSample.add(new PrometheusSample( name("childSuffix_1"), Collector.Type.SUMMARY, + null, "suffix_2", List.of("dimension_1", "dimension_2"), List.of("dimension_1_value", "dimension_2_value"), 4.0)); instanceSample.add(new PrometheusSample( + null, null, null, "suffix_3", @@ -65,6 +70,7 @@ public void addingSamples() { check( instanceSample.samples().get(0), new PrometheusSample( + null, null, null, "suffix_1", @@ -75,6 +81,7 @@ public void addingSamples() { check( instanceSample.samples().get(1), new PrometheusSample( + null, null, null, "suffix_3", @@ -92,6 +99,7 @@ public void addingSamples() { check( child.samples().get(0), new PrometheusSample( + null, null, null, "suffix_2", @@ -102,6 +110,7 @@ public void addingSamples() { check( child.samples().get(1), new PrometheusSample( + null, null, null, "suffix_2", @@ -119,6 +128,7 @@ public void addingSamples() { null, null, null, + null, List.of("dimension_1"), List.of("dimension_1_value"), 3.0)); diff --git a/metrics-facade-prometheus/src/test/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusSampleMakerTest.java b/metrics-facade-prometheus/src/test/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusSampleMakerTest.java index bff3a38..0f89bdc 100644 --- a/metrics-facade-prometheus/src/test/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusSampleMakerTest.java +++ b/metrics-facade-prometheus/src/test/java/com/ringcentral/platform/metrics/samples/prometheus/PrometheusSampleMakerTest.java @@ -65,6 +65,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -87,6 +88,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -109,6 +111,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -121,6 +124,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -133,6 +137,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -145,6 +150,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -157,6 +163,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -169,6 +176,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -188,6 +196,7 @@ public void makingSample() { sampleSpec = new PrometheusSampleSpec(true, COUNT, 1.0); expectedSample = new PrometheusSample( + null, null, null, "_count", @@ -200,6 +209,7 @@ public void makingSample() { sampleSpec = new PrometheusSampleSpec(true, TOTAL_SUM, 1.0); expectedSample = new PrometheusSample( + null, null, null, "_sum", @@ -215,6 +225,7 @@ public void makingSample() { name("min"), Collector.Type.GAUGE, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -227,6 +238,7 @@ public void makingSample() { name("max"), Collector.Type.GAUGE, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -239,6 +251,7 @@ public void makingSample() { name("mean"), Collector.Type.GAUGE, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -251,6 +264,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -263,6 +277,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name(), "quantile"), List.of("value_1", "value_2", "0.5"), 1.0); @@ -275,6 +290,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name(), "quantile"), List.of("value_1", "value_2", "0.75"), 1.0); @@ -284,6 +300,7 @@ public void makingSample() { sampleSpec = new PrometheusSampleSpec(true, SEC_1_BUCKET, 1.0); expectedSample = new PrometheusSample( + null, null, null, "_bucket", @@ -306,6 +323,7 @@ public void makingSample() { sampleSpec = new PrometheusSampleSpec(true, COUNT, 1.0); expectedSample = new PrometheusSample( + null, null, null, "_count", @@ -318,6 +336,7 @@ public void makingSample() { sampleSpec = new PrometheusSampleSpec(true, TOTAL_SUM, 1.0); expectedSample = new PrometheusSample( + null, null, null, "_sum", @@ -333,6 +352,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -345,6 +365,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -357,6 +378,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -369,6 +391,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -381,6 +404,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -393,6 +417,7 @@ public void makingSample() { name("min"), Collector.Type.GAUGE, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -405,6 +430,7 @@ public void makingSample() { name("max"), Collector.Type.GAUGE, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -417,6 +443,7 @@ public void makingSample() { name("mean"), Collector.Type.GAUGE, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -429,6 +456,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -441,6 +469,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name(), "quantile"), List.of("value_1", "value_2", "0.5"), 1.0); @@ -453,6 +482,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name(), "quantile"), List.of("value_1", "value_2", "0.75"), 1.0); @@ -465,6 +495,7 @@ public void makingSample() { null, null, null, + null, List.of(DIMENSION_1.name(), DIMENSION_2.name()), List.of("value_1", "value_2"), 1.0); @@ -474,6 +505,7 @@ public void makingSample() { sampleSpec = new PrometheusSampleSpec(true, SEC_1_BUCKET, 1.0); expectedSample = new PrometheusSample( + null, null, null, "_bucket", diff --git a/metrics-facade-prometheus/src/test/java/com/ringcentral/platform/metrics/samples/prometheus/collectorRegistry/SimpleCollectorRegistryPrometheusInstanceSamplesProviderTest.java b/metrics-facade-prometheus/src/test/java/com/ringcentral/platform/metrics/samples/prometheus/collectorRegistry/SimpleCollectorRegistryPrometheusInstanceSamplesProviderTest.java new file mode 100644 index 0000000..097c33a --- /dev/null +++ b/metrics-facade-prometheus/src/test/java/com/ringcentral/platform/metrics/samples/prometheus/collectorRegistry/SimpleCollectorRegistryPrometheusInstanceSamplesProviderTest.java @@ -0,0 +1,101 @@ +package com.ringcentral.platform.metrics.samples.prometheus.collectorRegistry; + +import com.ringcentral.platform.metrics.names.MetricName; +import com.ringcentral.platform.metrics.samples.prometheus.PrometheusInstanceSample; +import com.ringcentral.platform.metrics.samples.prometheus.PrometheusSample; +import io.prometheus.client.*; +import org.junit.Test; + +import java.util.List; + +import static com.ringcentral.platform.metrics.names.MetricName.name; +import static java.util.Comparator.comparing; +import static java.util.stream.Collectors.toList; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.*; + +public class SimpleCollectorRegistryPrometheusInstanceSamplesProviderTest { + + @Test + public void providingInstanceSamples() { + CollectorRegistry collectorRegistry = new CollectorRegistry(true); + + SimpleCollectorRegistryPrometheusInstanceSamplesProvider instanceSamplesProvider = new SimpleCollectorRegistryPrometheusInstanceSamplesProvider( + name("defaultRegistry"), // optional prefix + new SampleNameFilter.Builder().nameMustNotStartWith("counter_1").build(), // optional filter + // A typical Prometheus collector adds a MetricsFamilySamples.Sample for its creation time. + // That sample has an unpredictable and hard to verify value. + // That's why we remove it with !sampleName.endsWith("created"). + sampleName -> !sampleName.contains("summary") || !sampleName.endsWith("created"), // optional filter + collectorRegistry); + + Counter counter_1 = Counter.build() + .name("counter_1") + .help("Counter 1 from defaultRegistry") + .register(collectorRegistry); + + counter_1.inc(1); + + Counter counter_2 = Counter.build() + .name("counter_2") + .help("Counter 2 from defaultRegistry") + .register(collectorRegistry); + + counter_2.inc(2); + + Summary summary = Summary.build() + .name("summary") + .labelNames("label_1", "label_2") + .help("Summary from defaultRegistry") + .register(collectorRegistry); + + summary.labels("label_1_value", "label_2_value").observe(10); + summary.labels("label_1_value", "label_2_value").observe(20); + summary.labels("label_1_value", "label_2_value").observe(30); + + List instanceSamples = instanceSamplesProvider.instanceSamples().stream() + .sorted(comparing(prometheusInstanceSample -> prometheusInstanceSample.name().toString())) + .collect(toList()); + + assertThat(instanceSamples.size(), is(2)); + + PrometheusInstanceSample instanceSample = instanceSamples.stream() + .filter(is -> is.name().lastPart().equals("counter_2")) + .findFirst().orElseThrow(); + + assertThat(instanceSample.instanceName(), is(name("defaultRegistry", "counter_2"))); + assertThat(instanceSample.name(), is(name("defaultRegistry", "counter_2"))); + assertThat(instanceSample.description(), is("Counter 2 from defaultRegistry")); + assertThat(instanceSample.type(), is(Collector.Type.COUNTER)); + assertFalse(instanceSample.hasChildren()); + + List samples = instanceSample.samples(); + assertThat(samples.size(), is(2)); + + PrometheusSample sample = samples.stream() + .filter(is -> is.name().lastPart().contains("total")) + .findFirst().orElseThrow(); + + assertNull(sample.childInstanceSampleNameSuffix()); + assertNull(sample.childInstanceSampleType()); + assertThat(sample.name(), is(MetricName.of("defaultRegistry", "counter_2_total"))); + assertNull(sample.nameSuffix()); + assertTrue(sample.labelNames().isEmpty()); + assertTrue(sample.labelValues().isEmpty()); + assertThat(sample.value(), is(2.0)); + + instanceSample = instanceSamples.stream() + .filter(is -> is.name().lastPart().equals("summary")) + .findFirst().orElseThrow(); + + assertThat(instanceSample.instanceName(), is(name("defaultRegistry", "summary"))); + assertThat(instanceSample.name(), is(name("defaultRegistry", "summary"))); + assertThat(instanceSample.description(), is("Summary from defaultRegistry")); + assertThat(instanceSample.type(), is(Collector.Type.SUMMARY)); + assertFalse(instanceSample.hasChildren()); + + samples = instanceSample.samples(); + assertThat(samples.size(), is(2)); + } +} \ No newline at end of file diff --git a/metrics-facade-samples/pom.xml b/metrics-facade-samples/pom.xml index f3afe7c..f288501 100644 --- a/metrics-facade-samples/pom.xml +++ b/metrics-facade-samples/pom.xml @@ -15,7 +15,7 @@ metrics-facade-samples - 0.10.0 + 0.16.0 2.1.0-SNAPSHOT 1.7.3 @@ -37,6 +37,13 @@ com.ringcentral.platform.metrics metrics-facade-prometheus ${project.version} + + + + io.prometheus + simpleclient_common + + @@ -72,6 +79,12 @@ jackson-databind + + io.prometheus + simpleclient_common + ${prometheus.version} + + io.prometheus simpleclient diff --git a/metrics-facade-samples/src/main/java/com/ringcentral/platform/metrics/samples/reporters/PrometheusMetricsExporterSample.java b/metrics-facade-samples/src/main/java/com/ringcentral/platform/metrics/samples/reporters/PrometheusMetricsExporterSample.java index e9146e6..6dbd0bc 100644 --- a/metrics-facade-samples/src/main/java/com/ringcentral/platform/metrics/samples/reporters/PrometheusMetricsExporterSample.java +++ b/metrics-facade-samples/src/main/java/com/ringcentral/platform/metrics/samples/reporters/PrometheusMetricsExporterSample.java @@ -2,22 +2,30 @@ import com.ringcentral.platform.metrics.MetricRegistry; import com.ringcentral.platform.metrics.defaultImpl.DefaultMetricRegistry; -import com.ringcentral.platform.metrics.histogram.*; +import com.ringcentral.platform.metrics.histogram.Histogram; +import com.ringcentral.platform.metrics.histogram.HistogramInstance; import com.ringcentral.platform.metrics.reporters.jmx.JmxMetricsReporter; import com.ringcentral.platform.metrics.reporters.prometheus.PrometheusMetricsExporter; import com.ringcentral.platform.metrics.samples.AbstractSample; import com.ringcentral.platform.metrics.samples.prometheus.*; +import com.ringcentral.platform.metrics.samples.prometheus.collectorRegistry.SimpleCollectorRegistryPrometheusInstanceSamplesProvider; import com.ringcentral.platform.metrics.timer.Timer; +import io.prometheus.client.CollectorRegistry; +import io.prometheus.client.Counter; +import io.prometheus.client.SampleNameFilter; +import io.prometheus.client.Summary; import java.util.Locale; import static com.ringcentral.platform.metrics.dimensions.MetricDimensionValues.forDimensionValues; import static com.ringcentral.platform.metrics.histogram.Histogram.*; import static com.ringcentral.platform.metrics.histogram.configs.builders.HistogramConfigBuilder.withHistogram; +import static com.ringcentral.platform.metrics.names.MetricName.name; import static com.ringcentral.platform.metrics.names.MetricName.withName; import static com.ringcentral.platform.metrics.names.MetricNameMask.*; import static com.ringcentral.platform.metrics.predicates.DefaultMetricInstancePredicate.forMetricInstancesMatching; import static com.ringcentral.platform.metrics.samples.prometheus.PrometheusInstanceSampleSpec.instanceSampleSpec; +import static com.ringcentral.platform.metrics.samples.prometheus.PrometheusInstanceSamplesProviderBuilder.prometheusInstanceSamplesProvider; import static com.ringcentral.platform.metrics.samples.prometheus.PrometheusSampleSpec.sampleSpec; import static com.ringcentral.platform.metrics.timer.configs.builders.TimerConfigBuilder.withTimer; import static java.util.concurrent.TimeUnit.SECONDS; @@ -72,19 +80,40 @@ public static void main(String[] args) throws Exception { PrometheusSampleMaker sampleMaker = new PrometheusSampleMaker(); - PrometheusInstanceSamplesProvider miSamplesProvider = new PrometheusInstanceSamplesProvider( - miSampleSpecProvider, - miSampleSpecModsProvider, - miSampleMaker, - sampleSpecProvider, - sampleSpecModsProvider, - sampleMaker, - registry); + PrometheusInstanceSamplesProvider miSamplesProvider = prometheusInstanceSamplesProvider(registry) + .instanceSampleSpecProvider(miSampleSpecProvider) + .instanceSampleSpecModsProvider(miSampleSpecModsProvider) + .instanceSampleMaker(miSampleMaker) + .sampleSpecProvider(sampleSpecProvider) + .sampleSpecModsProvider(sampleSpecModsProvider) + .sampleMaker(sampleMaker) + .build(); PrometheusMetricsExporter exporter = new PrometheusMetricsExporter( true, Locale.ENGLISH, - miSamplesProvider); + miSamplesProvider, + new SimpleCollectorRegistryPrometheusInstanceSamplesProvider( + name("defaultRegistry"), // optional prefix + new SampleNameFilter.Builder().nameMustNotStartWith("counter").build(), // optional filter + sampleName -> !sampleName.endsWith("created"), // optional filter + CollectorRegistry.defaultRegistry)); + + Counter defaultRegistry_Counter = Counter.build() + .name("counter") + .help("Counter from defaultRegistry") + .register(); + + defaultRegistry_Counter.inc(3); + + Summary defaultRegistry_Summary = Summary.build() + .name("summary") + .help("Summary from defaultRegistry") + .register(); + + defaultRegistry_Summary.observe(10); + defaultRegistry_Summary.observe(20); + defaultRegistry_Summary.observe(30); Histogram h = registry.histogram( withName("Histogram"), diff --git a/pom.xml b/pom.xml index 1bd6e0a..3243818 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,18 @@ Gleb Smirnov https://github.com/gleb4646 + + + mairovichaa + Andrei Mairovich + https://github.com/mairovichaa + + + + kkolyan + Nikolay Plekhanov + https://github.com/kkolyan +