Reputation: 33
Is there a way to listen out for the /metrics endpoint when using https://quarkus.io/guides/micrometer?
I'd like to gather some metrics that require calling on a different API... and rather not set up a schedule (https://quarkus.io/guides/scheduler-reference)...
Example:
First /metrics
gives us:
# HELP test_metric_a
# TYPE test_metric_a gauge
test_metric_a{namespace="test123",user="admin",} 1.0
test_metric_a{namespace="testabc",user="admin",} 1.0
# HELP test_metric_b
# TYPE test_metric_b gauge
test_metric_b 0.0
Second /metrics
might give:
# HELP test_metric_a
# TYPE test_metric_a gauge
test_metric_a 0.0
# HELP test_metric_b
# TYPE test_metric_b gauge
test_metric_b{namespace="testabc",user="admin",} 2.0
How do I use https://quarkus.io/guides/micrometer to call on the Kubernetes API as nothing may have changed within the app to cause an update to the gauges/registry, but external events or time passing will cause the state (desired metrics output) to change...
Note that the custom metric (see comments below) only gets called once (it is a singleton I guess?). Ideally I'd want that called each time /metrics
is answered...
Further edit to show how the gauges are created/updated:
@ApplicationScoped
public class MyMetrics {
private final MeterRegistry registry;
MyMetrics(MeterRegistry registry) {
this.registry = registry;
}
//...
// somehow call this whenever /metrics is hit?
protected void updateGauges() {
// use KubernetesClient to query K8s API to gather some customer resources, then process that list... etc...
// there is a loop over the below for user/namespace pairs in the tags
//final Tags tags = getTags();
//int count = getCount();
//registry.gauge("test_metric_a", tags, count);
// so this could roll out to something like:
registry.gauge("test_metric_a", Tags.of("user", "user1", "namespace", "ns1"), 1);
registry.gauge("test_metric_a", Tags.of("user", "user2", "namespace", "ns1"), 2);
registry.gauge("test_metric_a", Tags.of("user", "user1", "namespace", "ns2"), 1);
registry.gauge("test_metric_b", Tags.of("user", "user1", "namespace", "ns1"), 1);
registry.gauge("test_metric_b", Tags.of("user", "user2", "namespace", "ns1"), 1);
}
}
...perhaps these gauges
could be counters
... but the question remains...
Upvotes: 2
Views: 928
Reputation: 3194
you could use the following MeterRegistry
interface to achieve your goal:
public <T> T gauge(String name, Iterable<Tag> tags,
@Nullable T stateObject, ToDoubleFunction<T> valueFunction)
the valueFunction
gets executed any time the /metrics endpoint is hit.
public class MyMetrics {
@Inject
MeterRegistry registry;
void onApplicationStart(@Observes StartupEvent e) {
Tags tags = Tags.of("user", "user1", "namespace", "ns1");
GaugeUpdater gaugeUpdater = registry.gauge("test_metric_a", tags,
new GaugeUpdater(registry), GaugeUpdater::getCount);
}
private static class GaugeUpdater {
private int count;
MeterRegistry registry;
public GaugeUpdater(MeterRegistry registry) {
this.registry = registry;
}
// this gets called whenever /metrics is hit!!!!
public double getCount(){
// use KubernetesClient to query K8s API to gather some customer resources, then process that list... etc...
// register further gauges
// registry.gauge("test_metric_a", Tags.of("user", "user1", "namespace", "ns1"), 1);
return count++;
}
}
}
Upvotes: 0
Reputation: 1280
Ok. As I stated in my comment, the value of a gauge is observed when metrics are collected (e.g. in the case of Prometheus, when the endpoint is scraped).
If you're talking about adding tags containing something like the namespace, the common tags example may have something for you, where you pre-calculate the label:
registry.config().commonTags("stack", "prod", "region", "us-east-1");
That would add those tags to all metrics, but you could use a MeterFilter to be more selective (e.g. add tags only to metrics that match some condition).
new MeterFilter() {
@Override
public Meter.Id map(Meter.Id id) {
if(id.getName().startsWith("test")) {
return id.withName("extra." + id.getName()).withTag("extra.tag", "value");
}
return id;
}
}
https://micrometer.io/docs/concepts#_common_tags
If you're trying to update tag/label values based on data retrieved from the Kubernetes API, you would want to run a periodic task (e.g. a scheduled task) that would re-register the gauge using the new tags.
Note that micrometer will either omit or return NaN (depending on the registry you're using) for gauges that have been garbage collected, so if you want gauges registered with previous tag values to stick around, you need to make them strong references.
Upvotes: 0