StackPrometheusClient
StackPrometheusClient
Quickstart
This tutorial shows the quickest way to get started with the Prometheus Java metrics
library.
Dependencies
GradleMaven
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-core</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-instrumentation-jvm</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-exporter-httpserver</artifactId>
<version>1.0.0</version>
</dependency>
There are alternative exporters as well, for example if you are using a Servlet container
like Tomcat or Undertow you might want to use prometheus-exporter-servlet-
https://stackedit.io/app# 1/49
10/29/24, 8:33 PM StackEdit
Example Application
import io.prometheus.metrics.core.metrics.Counter;
import io.prometheus.metrics.exporter.httpserver.HTTPServer;
import io.prometheus.metrics.instrumentation.jvm.JvmMetrics;
import java.io.IOException;
counter.labelValues("ok").inc();
counter.labelValues("ok").inc();
counter.labelValues("error").inc();
Result
https://stackedit.io/app# 2/49
10/29/24, 8:33 PM StackEdit
Run the application and view http://localhost:9400/metrics with your browser to see the
raw metrics. You should see the my_count_total metric as shown below plus the jvm_
and process_ metrics coming from JvmMetrics .
Prometheus Configuration
To scrape the metrics with a Prometheus server, download the latest Prometheus server
release, and configure the prometheus.yml file as follows:
global:
scrape_interval: 10s # short interval for manual testing
scrape_configs:
- job_name: "java-example"
static_configs:
- targets: ["localhost:9400"]
Registry
https://stackedit.io/app# 3/49
10/29/24, 8:33 PM StackEdit
The register() call above builds the counter and registers it with the global static
PrometheusRegistry.defaultRegistry . Using the default registry is recommended.
PrometheusRegistry.defaultRegistry.register(eventsTotal);
https://stackedit.io/app# 4/49
10/29/24, 8:33 PM StackEdit
Custom registries are useful if you want to maintain different scopes of metrics, like a
debug registry with a lot of metrics, and a default registry with only a few metrics.
While it is ok to register the same metric with multiple registries, it is illegal to register
the same metric name multiple times with the same registry. The following code will
throw an IllegalArgumentException :
Unregistering a Metric
There is no automatic expiry of unused metrics (yet), once a metric is registered it will
remain registered forever.
PrometheusRegistry.defaultRegistry.unregister(eventsTotal);
https://stackedit.io/app# 5/49
10/29/24, 8:33 PM StackEdit
Labels
The example shows a counter metric named payments_total with two labels: status
and type . Each individual data point (each line in text format) is identified by the
unique combination of its metric name and its label name/value pairs.
Labels are supported for all metric types. We are using counters in this example,
however the labelNames() and labelValues() methods are the same for other
metric types.
The label names have to be specified when the metric is created and cannot change.
The label values are created on demand when values are observed.
https://stackedit.io/app# 6/49
10/29/24, 8:33 PM StackEdit
Labels are optional. The following example shows a metric without labels:
counter.inc(3.0);
Cardinality Explosion
Each combination of label names and values will result in a new data point, i.e. a new
line in text format. Therefore, a good label should have only a small number of possible
values. If you select labels with many possible values, like unique IDs or timestamps, you
may end up with an enormous number of data points. This is called cardinality explosion.
loginCount.labelValues(userId, timestamp).inc();
If you register a metric without labels, it will show up immediately with initial value of
zero.
https://stackedit.io/app# 7/49
10/29/24, 8:33 PM StackEdit
However, metrics with labels only show up after the label values are first used. In the
example above
counter.labelValues("paypal", "error").inc();
payments_total{status="error",type="paypal"} 1.0
will jump from non-existent to value 1.0. You will never see it with value 0.0.
This is usually not an issue. However, if you find this annoying and want to see all
possible label values from the start, you can initialize label values with
initLabelValues() like this:
Now the four combinations will be visible from the start with initial value zero.
https://stackedit.io/app# 8/49
10/29/24, 8:33 PM StackEdit
There is no automatic expiry of unused label values (yet). Once a set of label values is
used, it will remain there forever.
counter.remove("paypal", "error");
counter.remove("paypal", "success");
Const Labels
If you have labels values that never change, you can specify them in the builder as
constLabels() :
However, most use cases for constLabels() are better covered by target labels set by
the scraping Prometheus server, or by one specific metric (e.g. a build_info or a
machine_role metric). See also target labels, not static scraped labels.
Metric Types
The Prometheus Java metrics library implements the metric types defined in the
OpenMetrics standard:
Counter
Gauge
Histogram
Summary
Info
https://stackedit.io/app# 9/49
10/29/24, 8:33 PM StackEdit
StateSet
GaugeHistogram and Unknown
Counter
Counter is the most common and useful metric type. Counters can only increase, but
never decrease. In the Prometheus query language, the rate() function is often used for
counters to calculate the average increase per second.
serviceTimeSeconds.inc(Unit.millisToSeconds(200));
The resulting counter has the value 0.2 . As SECONDS is the standard time unit in
Prometheus, the Unit utility class has methods to convert other time units to seconds.
As defined in OpenMetrics, counter metric names must have the _total suffix. If you
create a counter without the _total suffix the suffix will be appended automatically.
Gauge
https://stackedit.io/app# 10/49
10/29/24, 8:33 PM StackEdit
.help("current temperature")
.labelNames("location")
.unit(Unit.CELSIUS)
.register();
temperature.labelValues("Berlin").set(22.3);
Histogram
Histograms are for observing distributions, like latency distributions for HTTP services
or the distribution of request sizes. Unlike with counters and gauges, each histogram
data point has a complex data structure representing different aspects of the
distribution:
Classic histograms: Bucket boundaries are explicitly defined when the histogram is
created.
Native histograms (exponential histograms): Infinitely many virtual buckets.
By default, histograms maintain both flavors. Which one is used depends on the scrape
request from the Prometheus server.
By default, the Prometheus server will scrape metrics in OpenMetrics format and
get the classic histogram flavor.
If the Prometheus server is started with --enable-feature=native-histograms ,
it will request metrics in Prometheus protobuf format and ingest the native
histogram.
If the Prometheus server is started with --enable-feature=native-histogram
and the scrape config has the option scrape_classic_histograms: true , it will
request metrics in Prometheus protobuf format and ingest both, the classic and
the native flavor. This is great for migrating from classic histograms to native
histograms.
Histograms implement the TimerApi interface, which provides convenience methods for
measuring durations.
The histogram builder provides a lot of configuration for fine-tuning the histogram
behavior. In most cases you don’t need them, defaults are good. The following is an
incomplete list showing the most important options:
See Javadoc for Histogram.Builder for a complete list of options. Some options can be
configured at runtime, see config.
Histograms and summaries are both used for observing distributions. Therefore, the
both implement the DistributionDataPoint interface. Using the
DistributionDataPoint interface directly gives you the option to switch between
histograms and summaries later with minimal code changes.
https://stackedit.io/app# 12/49
10/29/24, 8:33 PM StackEdit
.register();
// Like in the example above, the following still works perfectly fine
// if the successfulEvents and erroneousEvents are backed by a summary rath
successfulEvents.observe(0.7);
erroneousEvents.observe(0.2);
Summary
Like histograms, summaries are for observing distributions. Each summary data point
has a count and a sum like a histogram data point. However, rather than histogram
buckets summaries maintain quantiles.
https://stackedit.io/app# 13/49
10/29/24, 8:33 PM StackEdit
requestLatency.labelValues("ok").observe(2.7);
The example above creates a summary with the 50th percentile (median), the 95th
percentile, and the 99th percentile. Quantiles are optional, you can create a summary
without quantiles if all you need is the count and the sum.
The terms “percentile” and “quantile” mean the same thing. We use percentile when
we express it as a number in [0, 100], and we use quantile when we express it as a
number in [0.0, 1.0].
The second parameter to quantile() is the maximum acceptable error. The call
.quantile(0.5, 0.01) means that the actual quantile is somewhere in [0.49, 0.51].
Higher precision means higher memory usage.
The 0.0 quantile (min value) and the 1.0 quantile (max value) are special cases because
you can get the precise values (error 0.0) with almost no memory overhead.
Quantile values are calculated based on a 5 minutes moving time window. The default
time window can be changed with maxAgeSeconds() and numberOfAgeBuckets() .
In general you should prefer histograms over summaries. The Prometheus query
language has a function histogram_quantile() for calculating quantiles from histograms.
The advantage of query-time quantile calculation is that you can aggregate histograms
before calculating the quantile. With summaries you must use the quantile with all its
labels as it is.
Info
Info metrics are used to expose textual information which should not change during
process lifetime. The value of an Info metric is always 1 .
https://stackedit.io/app# 14/49
10/29/24, 8:33 PM StackEdit
As defined in OpenMetrics, info metric names must have the _info suffix. If you create
a counter without the _info suffix the suffix will be appended automatically.
StateSet
StateSet are a niche metric type in the OpenMetrics standard that is rarely used. The
main use case is to signal which feature flags are enabled.
stateSet.labelValues("dev").setFalse("feature1");
stateSet.labelValues("dev").setTrue("feature2");
feature_flags{env="dev",feature_flags="feature1"} 0
feature_flags{env="dev",feature_flags="feature2"} 1
These types are defined in the OpenMetrics standard but not implemented in the
prometheus-metrics-core API. However, prometheus-metrics-model implements
the underlying data model for these types. To use these types, you need to implement
your own Collector where the collect() method returns an UnknownSnapshot or a
HistogramSnapshot with .gaugeHistogram(true) .
Callbacks
The section on metric types showed how to use metrics that actively maintain their
state.
This section shows how to create callback-based metrics, i.e. metrics that invoke a
callback at scrape time to get the current values.
For example, let’s assume we have two instances of a Cache , a coldCache and a
hotCache . The following implements a callback-based cache_size_bytes metric:
GaugeWithCallback.builder()
.name("cache_size_bytes")
.help("Size of the cache in Bytes.")
.unit(Unit.BYTES)
.labelNames("state")
.callback(callback -> {
callback.call(coldCache.sizeInBytes(), "cold");
callback.call(hotCache.sizeInBytes(), "hot");
})
.register();
https://stackedit.io/app# 16/49
10/29/24, 8:33 PM StackEdit
The API for gauges and counters is very similar. For summaries the callback has a few
more parameters, because it accepts a count, a sum, and quantiles:
SummaryWithCallback.builder()
.name("example_callback_summary")
.help("help message.")
.labelNames("status")
.callback(callback -> {
callback.call(cache.getCount(), cache.getSum(), Quantiles.EMPTY, "o
})
.register();
Performance
This section has tips on how to use the Prometheus Java client in high performance
applications.
https://stackedit.io/app# 17/49
10/29/24, 8:33 PM StackEdit
For high performance applications, we recommend to specify label values only once, and
then use the data point directly.
This applies to all metric types. Let’s use a counter as an example here:
requestCount.labelValue("/", "200").inc();
However, the line above does not only increment the counter, it also looks up the label
values to find the right data point.
In high performance applications you can optimize this by looking up the data point only
once:
Now, you can increment the data point directly, which is a highly optimized operation:
successfulCalls.inc();
By default, histograms maintain two representations under the hood: The classic
histogram representation with static buckets, and the native histogram representation
with dynamic buckets.
While this default provides the flexibility to scrape different representations at runtime,
it comes at a cost, because maintaining multiple representations causes performance
overhead.
https://stackedit.io/app# 18/49
10/29/24, 8:33 PM StackEdit
You can either configure this in code for each histogram by calling classicOnly() or
nativeOnly(), or you use the corresponding config options.
One way to do this is with system properties in the command line when you start your
application
or
If you don’t want to add a command line parameter every time you start your
application, you can add a prometheus.properties file to your classpath (put it in the
src/main/resources/ directory so that it gets packed into your JAR file). The
prometheus.properties file should have the following line:
io.prometheus.metrics.histogramClassicOnly=true
or
io.prometheus.metrics.histogramNativeOnly=true
Future releases will add more configuration options, like support for configuration via
environment variable IO_PROMETHEUS_METRICS_HISTOGRAM_NATIVE_ONLY=true .
Multi-Target Pattern
https://stackedit.io/app# 19/49
10/29/24, 8:33 PM StackEdit
To support multi-target pattern you can create a custom collector overriding the
purposed internal method in ExtendedMultiCollector see
SampleExtendedMultiCollector in io.prometheus.metrics.examples.httpserver
public SampleExtendedMultiCollector() {
super();
}
@Override
protected MetricSnapshots collectMetricSnapshots(PrometheusScrapeReques
counterBuilder.dataPoint(counterDataPointBuilder.build());
gaugeBuilder.dataPoint(gaugeDataPointBuilder.build());
} else {
for (int i = 0; i < procs.length; i++) {
counterDataPointBuilder.labels(lbls.merge(Labels.of("proc",
gaugeDataPointBuilder.labels(lbls.merge(Labels.of("proc", p
https://stackedit.io/app# 20/49
10/29/24, 8:33 PM StackEdit
counterDataPointBuilder.value(Math.random());
gaugeDataPointBuilder.value(Math.random());
counterBuilder.dataPoint(counterDataPointBuilder.build());
gaugeBuilder.dataPoint(gaugeDataPointBuilder.build());
}
}
Collection<MetricSnapshot> snaps = new ArrayList<MetricSnapshot>();
snaps.add(counterBuilder.build());
snaps.add(gaugeBuilder.build());
MetricSnapshots msnaps = new MetricSnapshots(snaps);
return msnaps;
}
- job_name: "multi-target"
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: localhost:9401
static_configs:
- targets: ["target1", "target2"]
Exports
More
JavaDoc
Releases
Github
1. client_java
2. /
3. Exporters
4. /
5. Formats
Formats
The Prometheus server sends an Accept header to specify which format is requested.
By default, the Prometheus server will scrape OpenMetrics text format with gzip
encoding. If the Prometheus server is started with --enable-feature=native-
histograms , it will scrape Prometheus protobuf format instead.
If you view the /metrics endpoint with your Web browser you will see Prometheus
text format. For quick debugging of the other formats, exporters provide a debug URL
parameter:
Filter
All exporters support a name[] URL parameter for querying only specific metric names.
Examples:
https://stackedit.io/app# 23/49
10/29/24, 8:33 PM StackEdit
Add the following to the scape job configuration in prometheus.yml to make the
Prometheus server send the name[] parameter:
params:
name[]:
- jvm_threads_current
- jvm_threads_daemon
HTTPServer
By default, HTTPServer binds to any IP address, you can change this with hostname() or
inetAddress().
https://stackedit.io/app# 24/49
10/29/24, 8:33 PM StackEdit
Properties
Servlet
web.xml
Programmatic
Today, most Servlet applications use an embedded Servlet container and configure
Servlets programmatically rather than via web.xml . The API for that depends on the
https://stackedit.io/app# 25/49
10/29/24, 8:33 PM StackEdit
Spring
You can use the PrometheusMetricsServlet in Spring applications. See our Spring doc.
Pushgateway
The Prometheus Pushgateway exists to allow ephemeral and batch jobs to expose their
metrics to Prometheus. Since these kinds of jobs may not exist long enough to be
scraped, they can instead push their metrics to a Pushgateway. The Pushgateway then
exposes these metrics to Prometheus.
The PushGateway Java class allows you to push metrics to a Prometheus Pushgateway.
Example
GradleMaven
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-core</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-exporter-pushgateway</artifactId>
<version>1.3.0</version>
</dependency>
https://stackedit.io/app# 26/49
10/29/24, 8:33 PM StackEdit
Basic Auth
Bearer token
https://stackedit.io/app# 27/49
10/29/24, 8:33 PM StackEdit
SSL
However, this requires that the JVM can validate the server certificate.
If you want to skip certificate verification, you need to provide your own
HttpConnectionFactory. The PushGatewayTestApp in integration-tests/it-
pushgateway has a complete example of this.
Configuration Properties
Spring
Spring Boot has a built-in metric library named Micrometer, which supports Prometheus
exposition format and can be set up in three simple steps:
In most cases the built-in Spring metrics library will work for you and you don’t need the
Prometheus Java library in Spring applications.
However, you may have your reasons why you want to use the Prometheus metrics
library in Spring anyway. Maybe you want full support for all Prometheus metric types,
or you want to use the new Prometheus native histograms.
The easiest way to use the Prometheus metrics library in Spring is to configure the
PrometheusMetricsServlet to expose metrics.
Dependencies:
The following is the complete source code of a Spring Boot REST service using the
Prometheus metrics library:
import io.prometheus.metrics.core.metrics.Counter;
import io.prometheus.metrics.exporter.servlet.jakarta.PrometheusMetricsServ
import io.prometheus.metrics.instrumentation.jvm.JvmMetrics;
import org.springframework.boot.SpringApplication;
https://stackedit.io/app# 29/49
10/29/24, 8:33 PM StackEdit
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class DemoApplication {
@GetMapping("/")
public String sayHello() throws InterruptedException {
requestCount.inc();
return "Hello, World!\n";
}
@Bean
public ServletRegistrationBean<PrometheusMetricsServlet> createPromethe
return new ServletRegistrationBean<>(new PrometheusMetricsServlet()
}
}
The important part are the last three lines: They configure the
PrometheusMetricsServlet to expose metrics on /metrics :
@Bean
public ServletRegistrationBean<PrometheusMetricsServlet> createPrometheusMe
return new ServletRegistrationBean<>(new PrometheusMetricsServlet(), "/
}
https://stackedit.io/app# 30/49
10/29/24, 8:33 PM StackEdit
JVM
The JVM instrumentation module provides a variety of out-of-the-box JVM and process
metrics. To use it, add the following dependency:
GradleMaven
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-instrumentation-jvm</artifactId>
<version>1.0.0</version>
</dependency>
JvmMetrics.builder().register();
The line above will initialize all JVM metrics and register them with the default registry.
If you want to register the metrics with a custom PrometheusRegistry , you can pass
the registry as parameter to the register() call.
The sections below describe the individual classes providing JVM metrics. If you don’t
want to register all JVM metrics, you can register each of these classes individually
rather than using JvmMetrics .
JVM buffer pool metrics are provided by the JvmBufferPoolMetrics class. The data is
coming from the BufferPoolMXBean. Example metrics:
https://stackedit.io/app# 31/49
10/29/24, 8:33 PM StackEdit
jvm_buffer_pool_used_buffers{pool="direct"} 1.0
jvm_buffer_pool_used_buffers{pool="mapped"} 0.0
# HELP jvm_buffer_pool_used_bytes Used bytes of a given JVM buffer pool.
# TYPE jvm_buffer_pool_used_bytes gauge
jvm_buffer_pool_used_bytes{pool="direct"} 8192.0
jvm_buffer_pool_used_bytes{pool="mapped"} 0.0
JVM class loading metrics are provided by the JvmClassLoadingMetrics class. The data is
coming from the ClassLoadingMXBean. Example metrics:
JVM compilation metrics are provided by the JvmCompilationMetrics class. The data is
coming from the CompilationMXBean. Example metrics:
https://stackedit.io/app# 32/49
10/29/24, 8:33 PM StackEdit
JVM memory metrics are provided by the JvmMemoryMetrics class. The data is coming
from the MemoryMXBean and the MemoryPoolMXBean. Example metrics:
https://stackedit.io/app# 34/49
10/29/24, 8:33 PM StackEdit
jvm_memory_used_bytes{area="nonheap"} 1.1490688E7
The JVM runtime info metric is provided by the JvmRuntimeInfoMetric class. The data is
obtained via system properties and will not change throughout the lifetime of the
application. Example metric:
JVM thread metrics are provided by the JvmThreadsMetrics class. The data is coming
from the ThreadMXBean. Example metrics:
https://stackedit.io/app# 35/49
10/29/24, 8:33 PM StackEdit
Process Metrics
Process metrics are provided by the ProcessMetrics class. The data is coming from the
OperatingSystemMXBean, the RuntimeMXBean, and from the /proc/self/status file
on Linux. The metrics with prefix process_ are not specific to Java, but should be
provided by every Prometheus client library, see Process Metrics in the Prometheus
writing client libraries documentation. Example metrics:
https://stackedit.io/app# 36/49
10/29/24, 8:33 PM StackEdit
OTLP
The Prometheus Java client library allows you to push metrics to an OpenTelemetry
endpoint using the OTLP protocol.
GradleMaven
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>prometheus-metrics-exporter-opentelemetry</artifactId>
<version>1.0.0</version>
</dependency>
OpenTelemetryExporter.builder()
// optional: call configuration methods here
.buildAndStart();
In addition to the Prometheus Java client configuration, the exporter also recognizes
standard OpenTelemetry configuration. For example, you can set the
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT environment variable to configure the
endpoint. The Javadoc for OpenTelemetryExporter.Builder shows which settings have
corresponding OTel configuration. The intended use case is that if you attach the
OpenTelemetry Java agent for tracing, and use the Prometheus Java client for metrics, it
is sufficient to configure the OTel agent because the Prometheus library will pick up the
same configuration.
Tracing
First, if you attach the OpenTelemetry Java agent you might want to turn off OTel’s built-
in metrics, because otherwise you get metrics from both the Prometheus Java client
library and the OpenTelemetry agent (technically it’s no problem to get both metrics, it’s
just not a common use case).
https://stackedit.io/app# 38/49
10/29/24, 8:33 PM StackEdit
# This will tell the OpenTelemetry agent not to send metrics, just traces a
export OTEL_METRICS_EXPORTER=none
Now, start your application with the OpenTelemetry Java agent attached for traces and
logs.
With the OpenTelemetry Java agent attached, the Prometheus client library will do a lot
of magic under the hood.
Here’s more context on the exemplar="true" Span attribute: Many users of tracing
libraries don’t keep 100% of their trace data, because traces are very repetitive. It is very
common to sample only 10% of traces and discard 90%. However, this can be an issue
with Exemplars: In 90% of the cases Exemplars would point to a trace that has been
thrown away.
To solve this, the Prometheus Java client library annotates each Span that has been used
as an Exemplar with the exemplar="true" Span attribute.
The sampling policy in the OpenTelemetry collector can be configured to keep traces
with this attribute. There’s no risk that this results in a significant increase in trace data,
because new Exemplars are only selected every minRetentionPeriodSeconds seconds.
https://stackedit.io/app# 39/49
10/29/24, 8:33 PM StackEdit
policies:
[
{
name: keep-exemplars,
type: string_attribute,
string_attribute: { key: "exemplar", values: [ "true" ] }
},
{
name: keep-10-percent,
type: probabilistic,
probabilistic: { sampling_percentage: 10 }
},
]
Names
The goal is, if you set up a pipeline as illustrated below, you will see the same metric
names in the Prometheus server as if you had exposed Prometheus metrics directly.
https://stackedit.io/app# 40/49
10/29/24, 8:33 PM StackEdit
The main steps when converting OpenTelemetry metric names to Prometheus metric
names are:
OpenTelemetry defines not only a line protocol, but also semantic conventions, i.e.
standardized metric and label names. For example, OpenTelemetry’s Semantic
Conventions for HTTP Metrics say that if you instrument an HTTP server with
OpenTelemetry, you must have a histogram named http.server.duration .
Most names defined in semantic conventions use dots. In the Prometheus server, the
dot is an illegal character (this might change in future versions of the Prometheus
server).
The Prometheus Java client library allows dots, so that you can use metric names and
label names as defined in OpenTelemetry’s semantic conventions. The dots will
automatically be replaced with underscores if you expose metrics in Prometheus format,
but you will see the original names with dots if you push your metrics in OpenTelemetry
format.
That way, you can use OTel-compliant metric and label names today when
instrumenting your application with the Prometheus Java client, and you are prepared in
case your monitoring backend adds features in the future that require OTel-compliant
instrumentation.
Config
https://stackedit.io/app# 41/49
10/29/24, 8:33 PM StackEdit
The Prometheus metrics library provides multiple options how to override configuration
at runtime:
Properties file
System properties
Future releases will add more options, like configuration via environment variables.
Example:
io.prometheus.exporter.httpServer.port = 9401
The property above changes the port for the HTTPServer exporter to 9401.
Metrics Properties
https://stackedit.io/app# 42/49
10/29/24, 8:33 PM StackEdit
Name
Javadoc
Note
io.prometheus.metrics.exemplarsEnabled
Counter.Builder.withExemplars()
(1) (2)
io.prometheus.metrics.histogramNativeOnly
Histogram.Builder.nativeOnly()
(2)
io.prometheus.metrics.histogramClassicOnly
Histogram.Builder.classicOnly()
(2)
io.prometheus.metrics.histogramClassicUpperBounds
Histogram.Builder.classicUpperBounds()
(3)
io.prometheus.metrics.histogramNativeInitialSchema
Histogram.Builder.nativeInitialSchema()
io.prometheus.metrics.histogramNativeMinZeroThreshold
Histogram.Builder.nativeMinZeroThreshold()
io.prometheus.metrics.histogramNativeMaxZeroThreshold
Histogram.Builder.nativeMaxZeroThreshold()
io.prometheus.metrics.histogramNativeMaxNumberOfBuckets
Histogram.Builder.nativeMaxNumberOfBuckets()
https://stackedit.io/app# 43/49
10/29/24, 8:33 PM StackEdit
io.prometheus.metrics.histogramNativeResetDurationSeconds
Histogram.Builder.nativeResetDuration()
io.prometheus.metrics.summaryQuantiles
Summary.Builder.quantile(double)
(4)
io.prometheus.metrics.summaryQuantileErrors
Summary.Builder.quantile(double, double)
(5)
io.prometheus.metrics.summaryMaxAgeSeconds
Summary.Builder.maxAgeSeconds()
io.prometheus.metrics.summaryNumberOfAgeBuckets
Summary.Builder.numberOfAgeBuckets()
Notes
(1) withExemplars() and withoutExemplars() are available for all metric types, not just for
counters
(2) Boolean value. Format: property=true or property=false .
(3) Comma-separated list. Example: .005, .01, .025, .05, .1, .25, .5, 1, 2.5,
5, 10 .
(4) Comma-separated list. Example: 0.5, 0.95, 0.99 .
(5) Comma-separated list. If specified, the list must have the same length as
io.prometheus.metrics.summaryQuantiles . Example: 0.01, 0.005, 0.005 .
There’s one special feature about metric properties: You can set a property for one
specific metric only by specifying the metric name. Example: Let’s say you have a
histogram named latency_seconds .
The line above sets histogram buckets for all histograms. However:
https://stackedit.io/app# 44/49
10/29/24, 8:33 PM StackEdit
io.prometheus.metrics.latency_seconds.histogramClassicUpperBounds = 0.2, 0.
The line above sets histogram buckets only for the histogram named latency_seconds .
Exemplar Properties
Name
Javadoc
Note
io.prometheus.exemplars.minRetentionPeriodSeconds
ExemplarsProperties.getMinRetentionPeriodSeconds()
io.prometheus.exemplars.maxRetentionPeriodSeconds
ExemplarsProperties.getMaxRetentionPeriodSeconds()
io.prometheus.exemplars.sampleIntervalMilliseconds
ExemplarsProperties.getSampleIntervalMilliseconds()
Exporter Properties
Name
Javadoc
Note
io.prometheus.exporter.includeCreatedTimestamps
ExporterProperties.getIncludeCreatedTimestamps()
(1)
https://stackedit.io/app# 45/49
10/29/24, 8:33 PM StackEdit
io.prometheus.exporter.exemplarsOnAllMetricTypes
ExporterProperties.getExemplarsOnAllMetricTypes()
(1)
Name
Javadoc
Note
io.prometheus.exporter.filter.metricNameMustBeEqualTo
ExporterFilterProperties.getAllowedMetricNames()
(1)
io.prometheus.exporter.filter.metricNameMustNotBeEqualTo
ExporterFilterProperties.getExcludedMetricNames()
(2)
io.prometheus.exporter.filter.metricNameMustStartWith
ExporterFilterProperties.getAllowedMetricNamePrefixes()
(3)
io.prometheus.exporter.filter.metricNameMustNotStartWith
ExporterFilterProperties.getExcludedMetricNamePrefixes()
(4)
(1) Comma sparated list of allowed metric names. Only these metrics will be exposed.
(2) Comma sparated list of excluded metric names. These metrics will not be exposed.
https://stackedit.io/app# 46/49
10/29/24, 8:33 PM StackEdit
(3) Comma sparated list of prefixes. Only metrics starting with these prefixes will be
exposed.
(4) Comma sparated list of prefixes. Metrics starting with these prefixes will not be
exposed.
Name
Javadoc
Note
io.prometheus.exporter.httpServer.port
HTTPServer.Builder.port()
Name
Javadoc
Note
io.prometheus.exporter.opentelemetry.protocol
OpenTelemetryExporter.Builder.protocol()
(1)
io.prometheus.exporter.opentelemetry.endpoint
OpenTelemetryExporter.Builder.endpoint()
io.prometheus.exporter.opentelemetry.headers
OpenTelemetryExporter.Builder.headers()
(2)
https://stackedit.io/app# 47/49
10/29/24, 8:33 PM StackEdit
io.prometheus.exporter.opentelemetry.intervalSeconds
OpenTelemetryExporter.Builder.intervalSeconds()
io.prometheus.exporter.opentelemetry.timeoutSeconds
OpenTelemetryExporter.Builder.timeoutSeconds()
io.prometheus.exporter.opentelemetry.serviceName
OpenTelemetryExporter.Builder.serviceName()
io.prometheus.exporter.opentelemetry.serviceNamespace
OpenTelemetryExporter.Builder.serviceNamespace()
io.prometheus.exporter.opentelemetry.serviceInstanceId
OpenTelemetryExporter.Builder.serviceInstanceId()
io.prometheus.exporter.opentelemetry.serviceVersion
OpenTelemetryExporter.Builder.serviceVersion()
io.prometheus.exporter.opentelemetry.resourceAttributes
OpenTelemetryExporter.Builder.resourceAttributes()
(3)
Name
https://stackedit.io/app# 48/49
10/29/24, 8:33 PM StackEdit
Javadoc
Note
io.prometheus.exporter.pushgateway.address
PushGateway.Builder.address()
io.prometheus.exporter.pushgateway.scheme
PushGateway.Builder.scheme()
io.prometheus.exporter.pushgateway.job
PushGateway.Builder.job()
https://stackedit.io/app# 49/49