Skip to content

Commit 93fdf31

Browse files
committed
Merge #1516: Allow incrementing/decrementing gauge metrics.
243c254 feat: allow incrementing/decrementing gauge metrics (Jose Celano) Pull request description: It allows incrementing/decrementing gauge metrics. This feature was planned to be added, and it's needed in this [PR](#1513). Other [crates](https://docs.rs/metrics/latest/metrics/struct.Gauge.html) also implement it. ACKs for top commit: josecelano: ACK 243c254 Tree-SHA512: 4055825ec04229d65d6ce124ea90c88624ad76ee221b0d6ca5f6edb0b1f4d1e98e81d49b55d7e085cc18f308a2d9f2deb3a2444e2ff30c1b3f00e4cbd83b8a2a
2 parents b0bf307 + 243c254 commit 93fdf31

File tree

5 files changed

+187
-13
lines changed

5 files changed

+187
-13
lines changed

packages/metrics/src/gauge.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ impl Gauge {
2020
pub fn set(&mut self, value: f64) {
2121
self.0 = value;
2222
}
23+
24+
pub fn increment(&mut self, value: f64) {
25+
self.0 += value;
26+
}
27+
28+
pub fn decrement(&mut self, value: f64) {
29+
self.0 -= value;
30+
}
2331
}
2432

2533
impl From<f64> for Gauge {
@@ -72,6 +80,20 @@ mod tests {
7280
assert_relative_eq!(gauge.value(), 1.0);
7381
}
7482

83+
#[test]
84+
fn it_could_be_incremented() {
85+
let mut gauge = Gauge::new(0.0);
86+
gauge.increment(1.0);
87+
assert_relative_eq!(gauge.value(), 1.0);
88+
}
89+
90+
#[test]
91+
fn it_could_be_decremented() {
92+
let mut gauge = Gauge::new(1.0);
93+
gauge.decrement(1.0);
94+
assert_relative_eq!(gauge.value(), 0.0);
95+
}
96+
7597
#[test]
7698
fn it_serializes_to_prometheus() {
7799
let counter = Gauge::new(42.0);

packages/metrics/src/metric/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ impl Metric<Gauge> {
6161
pub fn set(&mut self, label_set: &LabelSet, value: f64, time: DurationSinceUnixEpoch) {
6262
self.sample_collection.set(label_set, value, time);
6363
}
64+
65+
pub fn increment(&mut self, label_set: &LabelSet, time: DurationSinceUnixEpoch) {
66+
self.sample_collection.increment(label_set, time);
67+
}
68+
69+
pub fn decrement(&mut self, label_set: &LabelSet, time: DurationSinceUnixEpoch) {
70+
self.sample_collection.decrement(label_set, time);
71+
}
6472
}
6573

6674
impl<T: PrometheusSerializable> PrometheusSerializable for Metric<T> {

packages/metrics/src/metric_collection.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,38 @@ impl MetricCollection {
136136
Ok(())
137137
}
138138

139+
/// # Errors
140+
///
141+
/// Return an error if a metrics of a different type with the same name
142+
/// already exists.
143+
pub fn increase_gauge(&mut self, name: &MetricName, label_set: &LabelSet, time: DurationSinceUnixEpoch) -> Result<(), Error> {
144+
if self.counters.metrics.contains_key(name) {
145+
return Err(Error::MetricNameCollisionAdding {
146+
metric_name: name.clone(),
147+
});
148+
}
149+
150+
self.gauges.increment(name, label_set, time);
151+
152+
Ok(())
153+
}
154+
155+
/// # Errors
156+
///
157+
/// Return an error if a metrics of a different type with the same name
158+
/// already exists.
159+
pub fn decrease_gauge(&mut self, name: &MetricName, label_set: &LabelSet, time: DurationSinceUnixEpoch) -> Result<(), Error> {
160+
if self.counters.metrics.contains_key(name) {
161+
return Err(Error::MetricNameCollisionAdding {
162+
metric_name: name.clone(),
163+
});
164+
}
165+
166+
self.gauges.decrement(name, label_set, time);
167+
168+
Ok(())
169+
}
170+
139171
pub fn ensure_gauge_exists(&mut self, name: &MetricName) {
140172
self.gauges.ensure_metric_exists(name);
141173
}
@@ -353,6 +385,36 @@ impl MetricKindCollection<Gauge> {
353385
metric.set(label_set, value, time);
354386
}
355387

388+
/// Increments the gauge for the given metric name and labels.
389+
///
390+
/// If the metric name does not exist, it will be created.
391+
///
392+
/// # Panics
393+
///
394+
/// Panics if the metric does not exist and it could not be created.
395+
pub fn increment(&mut self, name: &MetricName, label_set: &LabelSet, time: DurationSinceUnixEpoch) {
396+
self.ensure_metric_exists(name);
397+
398+
let metric = self.metrics.get_mut(name).expect("Gauge metric should exist");
399+
400+
metric.increment(label_set, time);
401+
}
402+
403+
/// Decrements the gauge for the given metric name and labels.
404+
///
405+
/// If the metric name does not exist, it will be created.
406+
///
407+
/// # Panics
408+
///
409+
/// Panics if the metric does not exist and it could not be created.
410+
pub fn decrement(&mut self, name: &MetricName, label_set: &LabelSet, time: DurationSinceUnixEpoch) {
411+
self.ensure_metric_exists(name);
412+
413+
let metric = self.metrics.get_mut(name).expect("Gauge metric should exist");
414+
415+
metric.decrement(label_set, time);
416+
}
417+
356418
#[must_use]
357419
pub fn get_value(&self, name: &MetricName, label_set: &LabelSet) -> Option<Gauge> {
358420
self.metrics

packages/metrics/src/sample.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ impl Sample<Gauge> {
6464
pub fn set(&mut self, value: f64, time: DurationSinceUnixEpoch) {
6565
self.measurement.set(value, time);
6666
}
67+
68+
pub fn increment(&mut self, time: DurationSinceUnixEpoch) {
69+
self.measurement.increment(time);
70+
}
71+
72+
pub fn decrement(&mut self, time: DurationSinceUnixEpoch) {
73+
self.measurement.decrement(time);
74+
}
6775
}
6876

6977
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@@ -121,6 +129,16 @@ impl Measurement<Gauge> {
121129
self.value.set(value);
122130
self.set_recorded_at(time);
123131
}
132+
133+
pub fn increment(&mut self, time: DurationSinceUnixEpoch) {
134+
self.value.increment(1.0);
135+
self.set_recorded_at(time);
136+
}
137+
138+
pub fn decrement(&mut self, time: DurationSinceUnixEpoch) {
139+
self.value.decrement(1.0);
140+
self.set_recorded_at(time);
141+
}
124142
}
125143

126144
/// Serializes the `recorded_at` field as a string in ISO 8601 format (RFC 3339).
@@ -273,14 +291,32 @@ mod tests {
273291
}
274292

275293
#[test]
276-
fn it_should_allow_incrementing_the_counter() {
294+
fn it_should_allow_setting_a_value() {
277295
let mut sample = Sample::new(Gauge::default(), DurationSinceUnixEpoch::default(), LabelSet::default());
278296

279297
sample.set(1.0, updated_at_time());
280298

281299
assert_eq!(sample.value(), &Gauge::new(1.0));
282300
}
283301

302+
#[test]
303+
fn it_should_allow_incrementing_the_value() {
304+
let mut sample = Sample::new(Gauge::new(0.0), DurationSinceUnixEpoch::default(), LabelSet::default());
305+
306+
sample.increment(updated_at_time());
307+
308+
assert_eq!(sample.value(), &Gauge::new(1.0));
309+
}
310+
311+
#[test]
312+
fn it_should_allow_decrementing_the_value() {
313+
let mut sample = Sample::new(Gauge::new(1.0), DurationSinceUnixEpoch::default(), LabelSet::default());
314+
315+
sample.decrement(updated_at_time());
316+
317+
assert_eq!(sample.value(), &Gauge::new(0.0));
318+
}
319+
284320
#[test]
285321
fn it_should_record_the_latest_update_time_when_the_counter_is_incremented() {
286322
let mut sample = Sample::new(Gauge::default(), DurationSinceUnixEpoch::default(), LabelSet::default());

packages/metrics/src/sample_collection.rs

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,24 @@ impl SampleCollection<Gauge> {
9090

9191
sample.set(value, time);
9292
}
93+
94+
pub fn increment(&mut self, label_set: &LabelSet, time: DurationSinceUnixEpoch) {
95+
let sample = self
96+
.samples
97+
.entry(label_set.clone())
98+
.or_insert_with(|| Measurement::new(Gauge::default(), time));
99+
100+
sample.increment(time);
101+
}
102+
103+
pub fn decrement(&mut self, label_set: &LabelSet, time: DurationSinceUnixEpoch) {
104+
let sample = self
105+
.samples
106+
.entry(label_set.clone())
107+
.or_insert_with(|| Measurement::new(Gauge::default(), time));
108+
109+
sample.decrement(time);
110+
}
93111
}
94112

95113
impl<T: Serialize> Serialize for SampleCollection<T> {
@@ -278,7 +296,7 @@ mod tests {
278296
#[test]
279297
fn it_should_increment_the_counter_for_a_preexisting_label_set() {
280298
let label_set = LabelSet::default();
281-
let mut collection = SampleCollection::default();
299+
let mut collection = SampleCollection::<Counter>::default();
282300

283301
// Initialize the sample
284302
collection.increment(&label_set, sample_update_time());
@@ -296,7 +314,7 @@ mod tests {
296314
#[test]
297315
fn it_should_allow_increment_the_counter_for_a_non_existent_label_set() {
298316
let label_set = LabelSet::default();
299-
let mut collection = SampleCollection::default();
317+
let mut collection = SampleCollection::<Counter>::default();
300318

301319
// Increment a non-existent label
302320
collection.increment(&label_set, sample_update_time());
@@ -312,7 +330,7 @@ mod tests {
312330
let label_set = LabelSet::default();
313331
let initial_time = sample_update_time();
314332

315-
let mut collection = SampleCollection::default();
333+
let mut collection = SampleCollection::<Counter>::default();
316334
collection.increment(&label_set, initial_time);
317335

318336
// Increment with a new time
@@ -330,7 +348,7 @@ mod tests {
330348
let label2 = LabelSet::from([("name", "value2")]);
331349
let now = sample_update_time();
332350

333-
let mut collection = SampleCollection::default();
351+
let mut collection = SampleCollection::<Counter>::default();
334352

335353
collection.increment(&label1, now);
336354
collection.increment(&label2, now);
@@ -351,9 +369,9 @@ mod tests {
351369
use crate::gauge::Gauge;
352370

353371
#[test]
354-
fn it_should_increment_the_gauge_for_a_preexisting_label_set() {
372+
fn it_should_allow_setting_the_gauge_for_a_preexisting_label_set() {
355373
let label_set = LabelSet::default();
356-
let mut collection = SampleCollection::default();
374+
let mut collection = SampleCollection::<Gauge>::default();
357375

358376
// Initialize the sample
359377
collection.set(&label_set, 1.0, sample_update_time());
@@ -369,9 +387,9 @@ mod tests {
369387
}
370388

371389
#[test]
372-
fn it_should_allow_increment_the_gauge_for_a_non_existent_label_set() {
390+
fn it_should_allow_setting_the_gauge_for_a_non_existent_label_set() {
373391
let label_set = LabelSet::default();
374-
let mut collection = SampleCollection::default();
392+
let mut collection = SampleCollection::<Gauge>::default();
375393

376394
// Set a non-existent label
377395
collection.set(&label_set, 1.0, sample_update_time());
@@ -383,11 +401,11 @@ mod tests {
383401
}
384402

385403
#[test]
386-
fn it_should_update_the_latest_update_time_when_incremented() {
404+
fn it_should_update_the_latest_update_time_when_setting() {
387405
let label_set = LabelSet::default();
388406
let initial_time = sample_update_time();
389407

390-
let mut collection = SampleCollection::default();
408+
let mut collection = SampleCollection::<Gauge>::default();
391409
collection.set(&label_set, 1.0, initial_time);
392410

393411
// Set with a new time
@@ -400,12 +418,12 @@ mod tests {
400418
}
401419

402420
#[test]
403-
fn it_should_increment_the_gauge_for_multiple_labels() {
421+
fn it_should_allow_setting_the_gauge_for_multiple_labels() {
404422
let label1 = LabelSet::from([("name", "value1")]);
405423
let label2 = LabelSet::from([("name", "value2")]);
406424
let now = sample_update_time();
407425

408-
let mut collection = SampleCollection::default();
426+
let mut collection = SampleCollection::<Gauge>::default();
409427

410428
collection.set(&label1, 1.0, now);
411429
collection.set(&label2, 2.0, now);
@@ -414,5 +432,33 @@ mod tests {
414432
assert_eq!(collection.get(&label2).unwrap().value(), &Gauge::new(2.0));
415433
assert_eq!(collection.len(), 2);
416434
}
435+
436+
#[test]
437+
fn it_should_allow_incrementing_the_gauge() {
438+
let label_set = LabelSet::default();
439+
let mut collection = SampleCollection::<Gauge>::default();
440+
441+
// Initialize the sample
442+
collection.set(&label_set, 1.0, sample_update_time());
443+
444+
// Increment
445+
collection.increment(&label_set, sample_update_time());
446+
let sample = collection.get(&label_set).unwrap();
447+
assert_eq!(*sample.value(), Gauge::new(2.0));
448+
}
449+
450+
#[test]
451+
fn it_should_allow_decrementing_the_gauge() {
452+
let label_set = LabelSet::default();
453+
let mut collection = SampleCollection::<Gauge>::default();
454+
455+
// Initialize the sample
456+
collection.set(&label_set, 1.0, sample_update_time());
457+
458+
// Increment
459+
collection.decrement(&label_set, sample_update_time());
460+
let sample = collection.get(&label_set).unwrap();
461+
assert_eq!(*sample.value(), Gauge::new(0.0));
462+
}
417463
}
418464
}

0 commit comments

Comments
 (0)