client_rust icon indicating copy to clipboard operation
client_rust copied to clipboard

Provide a way to set a `Counter` to an absolute value

Open K900 opened this issue 1 year ago • 12 comments

I'm writing a reexporter for another service that already outputs aggregated metrics (but not in a Prometheus compatible format). It would be very convenient to be able to directly call .set(existing_value) on a Prometheus counter, instead of having to track the previous value manually and inc_by a computed amount.

K900 avatar Dec 04 '24 13:12 K900

Would a const counter solve your use-case?

https://docs.rs/prometheus-client/latest/prometheus_client/metrics/counter/struct.ConstCounter.html

mxinden avatar Dec 05 '24 12:12 mxinden

AFAIUI const counters just can't be changed at all? I want to be able to change the value, I just already have it pre-aggregated.

K900 avatar Dec 05 '24 12:12 K900

You would use the Collector trait to implement your own metrics collector. On a scrape of your exporter by Prometheus, prometheus_client would call Collector::collect. Your collector implementation would retrieve the metric values from your actual monitoring target, and expose the values via e.g. ConstCounter. See Collector docs for details.

Hope this is helpful.

mxinden avatar Dec 05 '24 12:12 mxinden

Hmm, this would require a lot of refactoring, but I think it could work.

K900 avatar Dec 05 '24 12:12 K900

Actually, maybe not... Getting values from the target is async right now, and Collector's interface is sync, so I'd have to block...

K900 avatar Dec 05 '24 13:12 K900

OK so some refactoring later, it looks like I can't really do this without Collector being async, or using my own atomics or whatever to store values...

K900 avatar Dec 19 '24 09:12 K900

Getting values from the target is async right now, and Collector's interface is sync, so I'd have to block...

@K900 is that a problem? I assume you are running your /metrics http endpoint on a separate OS thread. Prometheus scrapes an enpoint on the order of seconds. I assume the latency to your target is low. Why is blocking on a future an issue here?

mxinden avatar Jan 06 '25 16:01 mxinden

Mostly just because I'm calling another API client that's already async. I can probably run it on another thread, but so far everything has been part of one big event loop.

K900 avatar Jan 06 '25 16:01 K900

I've encounterd with the same problem. and i found it could use the inner() method to get the reference of value, and set it. for example

let counter = Counter::<u64, AtomicU64>::default();
counter.inner().set(1234);

sialais avatar Jan 10 '25 08:01 sialais

Oh, that's kinda cursed but I guess it should work?

K900 avatar Jan 10 '25 08:01 K900

@sialais @K900 if you want to set the counter metric, why not using gauge instead of counter? Semantically, counter cannot be set, only incremented.

koushiro avatar Apr 21 '25 07:04 koushiro

This is mostly convenient for writing reexporters, where you're just converting data from some external thing to Prometheus format.

K900 avatar Apr 21 '25 07:04 K900