Skip to content

Commit 458497b

Browse files
committed
feat: [torrust#1514] add unit and description to metrics
It's also shown in the JSON export format. ```json { "metrics": [ { "type": "counter", "name": "torrent_repository_torrents_downloads_total", "unit": "count", "description": "The total number of torrent downloads.", "samples": [] } } ``` todo: show them in the Prometheus export format.
1 parent 031bf65 commit 458497b

File tree

8 files changed

+116
-58
lines changed

8 files changed

+116
-58
lines changed

packages/http-tracker-core/src/statistics/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub fn describe_metrics() -> Metrics {
1717
metrics.metric_collection.describe_counter(
1818
&metric_name!(HTTP_TRACKER_CORE_REQUESTS_RECEIVED_TOTAL),
1919
Some(Unit::Count),
20-
Some(&MetricDescription::new("Total number of HTTP requests received")),
20+
Some(MetricDescription::new("Total number of HTTP requests received")),
2121
);
2222

2323
metrics

packages/metrics/src/metric/mod.rs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,38 @@ use super::label::LabelSet;
99
use super::prometheus::PrometheusSerializable;
1010
use super::sample_collection::SampleCollection;
1111
use crate::gauge::Gauge;
12+
use crate::metric::description::MetricDescription;
1213
use crate::sample::Measurement;
14+
use crate::unit::Unit;
1315

1416
pub type MetricName = name::MetricName;
1517

1618
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
1719
pub struct Metric<T> {
1820
name: MetricName,
1921

22+
#[serde(rename = "unit")]
23+
opt_unit: Option<Unit>,
24+
25+
#[serde(rename = "description")]
26+
opt_description: Option<MetricDescription>,
27+
2028
#[serde(rename = "samples")]
2129
sample_collection: SampleCollection<T>,
2230
}
2331

2432
impl<T> Metric<T> {
2533
#[must_use]
26-
pub fn new(name: MetricName, samples: SampleCollection<T>) -> Self {
34+
pub fn new(
35+
name: MetricName,
36+
opt_unit: Option<Unit>,
37+
opt_description: Option<MetricDescription>,
38+
samples: SampleCollection<T>,
39+
) -> Self {
2740
Self {
2841
name,
42+
opt_unit,
43+
opt_description,
2944
sample_collection: samples,
3045
}
3146
}
@@ -34,9 +49,11 @@ impl<T> Metric<T> {
3449
///
3550
/// This function will panic if the empty sample collection cannot be created.
3651
#[must_use]
37-
pub fn without_samples(name: MetricName) -> Self {
52+
pub fn new_empty_with_name(name: MetricName) -> Self {
3853
Self {
3954
name,
55+
opt_unit: None,
56+
opt_description: None,
4057
sample_collection: SampleCollection::new(vec![]).expect("Empty sample collection creation should not fail"),
4158
}
4259
}
@@ -119,7 +136,7 @@ mod tests {
119136

120137
let samples = SampleCollection::<Gauge>::default();
121138

122-
let metric = Metric::<Gauge>::new(name.clone(), samples);
139+
let metric = Metric::<Gauge>::new(name.clone(), None, None, samples);
123140

124141
assert!(metric.is_empty());
125142
}
@@ -133,7 +150,7 @@ mod tests {
133150

134151
let samples = SampleCollection::new(vec![Sample::new(Counter::new(1), time, label_set.clone())]).unwrap();
135152

136-
Metric::<Counter>::new(name.clone(), samples)
153+
Metric::<Counter>::new(name.clone(), None, None, samples)
137154
}
138155

139156
#[test]
@@ -147,7 +164,7 @@ mod tests {
147164

148165
let samples = SampleCollection::<Gauge>::default();
149166

150-
let metric = Metric::<Gauge>::new(name.clone(), samples);
167+
let metric = Metric::<Gauge>::new(name.clone(), None, None, samples);
151168

152169
assert_eq!(metric.number_of_samples(), 0);
153170
}
@@ -166,7 +183,7 @@ mod tests {
166183

167184
let samples = SampleCollection::<Counter>::default();
168185

169-
let _metric = Metric::<Counter>::new(name, samples);
186+
let _metric = Metric::<Counter>::new(name, None, None, samples);
170187
}
171188

172189
#[test]
@@ -179,7 +196,7 @@ mod tests {
179196

180197
let samples = SampleCollection::new(vec![Sample::new(Counter::new(1), time, label_set.clone())]).unwrap();
181198

182-
let metric = Metric::<Counter>::new(name.clone(), samples);
199+
let metric = Metric::<Counter>::new(name.clone(), None, None, samples);
183200

184201
assert_eq!(metric.get_sample_data(&label_set).unwrap().value().value(), 1);
185202
}
@@ -200,7 +217,7 @@ mod tests {
200217

201218
let samples = SampleCollection::<Gauge>::default();
202219

203-
let _metric = Metric::<Gauge>::new(name, samples);
220+
let _metric = Metric::<Gauge>::new(name, None, None, samples);
204221
}
205222

206223
#[test]
@@ -213,7 +230,7 @@ mod tests {
213230

214231
let samples = SampleCollection::new(vec![Sample::new(Gauge::new(1.0), time, label_set.clone())]).unwrap();
215232

216-
let metric = Metric::<Gauge>::new(name.clone(), samples);
233+
let metric = Metric::<Gauge>::new(name.clone(), None, None, samples);
217234

218235
assert_relative_eq!(metric.get_sample_data(&label_set).unwrap().value().value(), 1.0);
219236
}

packages/metrics/src/metric_collection.rs

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use super::label::LabelSet;
1010
use super::metric::{Metric, MetricName};
1111
use super::prometheus::PrometheusSerializable;
1212
use crate::metric::description::MetricDescription;
13+
use crate::sample_collection::SampleCollection;
1314
use crate::unit::Unit;
1415
use crate::METRICS_TARGET;
1516

@@ -56,12 +57,12 @@ impl MetricCollection {
5657

5758
// Counter-specific methods
5859

59-
pub fn describe_counter(&mut self, name: &MetricName, opt_unit: Option<Unit>, opt_description: Option<&MetricDescription>) {
60+
pub fn describe_counter(&mut self, name: &MetricName, opt_unit: Option<Unit>, opt_description: Option<MetricDescription>) {
6061
tracing::info!(target: METRICS_TARGET, type = "counter", name = name.to_string(), unit = ?opt_unit, description = ?opt_description);
6162

62-
let metric = Metric::<Counter>::without_samples(name.clone());
63+
let metric = Metric::<Counter>::new(name.clone(), opt_unit, opt_description, SampleCollection::default());
6364

64-
self.counters.ensure_metric_exists(metric);
65+
self.counters.insert(metric);
6566
}
6667

6768
#[must_use]
@@ -123,12 +124,12 @@ impl MetricCollection {
123124

124125
// Gauge-specific methods
125126

126-
pub fn describe_gauge(&mut self, name: &MetricName, opt_unit: Option<Unit>, opt_description: Option<&MetricDescription>) {
127+
pub fn describe_gauge(&mut self, name: &MetricName, opt_unit: Option<Unit>, opt_description: Option<MetricDescription>) {
127128
tracing::info!(target: METRICS_TARGET, type = "gauge", name = name.to_string(), unit = ?opt_unit, description = ?opt_description);
128129

129-
let metric = Metric::<Gauge>::without_samples(name.clone());
130+
let metric = Metric::<Gauge>::new(name.clone(), opt_unit, opt_description, SampleCollection::default());
130131

131-
self.gauges.ensure_metric_exists(metric);
132+
self.gauges.insert(metric);
132133
}
133134

134135
#[must_use]
@@ -333,11 +334,15 @@ impl<T> MetricKindCollection<T> {
333334
self.metrics.keys()
334335
}
335336

336-
pub fn ensure_metric_exists(&mut self, metric: Metric<T>) {
337+
pub fn insert_if_absent(&mut self, metric: Metric<T>) {
337338
if !self.metrics.contains_key(metric.name()) {
338-
self.metrics.insert(metric.name().clone(), metric);
339+
self.insert(metric);
339340
}
340341
}
342+
343+
pub fn insert(&mut self, metric: Metric<T>) {
344+
self.metrics.insert(metric.name().clone(), metric);
345+
}
341346
}
342347

343348
impl<T: Clone> MetricKindCollection<T> {
@@ -377,9 +382,9 @@ impl MetricKindCollection<Counter> {
377382
///
378383
/// Panics if the metric does not exist.
379384
pub fn increment(&mut self, name: &MetricName, label_set: &LabelSet, time: DurationSinceUnixEpoch) {
380-
let metric = Metric::<Counter>::without_samples(name.clone());
385+
let metric = Metric::<Counter>::new_empty_with_name(name.clone());
381386

382-
self.ensure_metric_exists(metric);
387+
self.insert_if_absent(metric);
383388

384389
let metric = self.metrics.get_mut(name).expect("Counter metric should exist");
385390

@@ -394,9 +399,9 @@ impl MetricKindCollection<Counter> {
394399
///
395400
/// Panics if the metric does not exist.
396401
pub fn absolute(&mut self, name: &MetricName, label_set: &LabelSet, value: u64, time: DurationSinceUnixEpoch) {
397-
let metric = Metric::<Counter>::without_samples(name.clone());
402+
let metric = Metric::<Counter>::new_empty_with_name(name.clone());
398403

399-
self.ensure_metric_exists(metric);
404+
self.insert_if_absent(metric);
400405

401406
let metric = self.metrics.get_mut(name).expect("Counter metric should exist");
402407

@@ -421,9 +426,9 @@ impl MetricKindCollection<Gauge> {
421426
///
422427
/// Panics if the metric does not exist and it could not be created.
423428
pub fn set(&mut self, name: &MetricName, label_set: &LabelSet, value: f64, time: DurationSinceUnixEpoch) {
424-
let metric = Metric::<Gauge>::without_samples(name.clone());
429+
let metric = Metric::<Gauge>::new_empty_with_name(name.clone());
425430

426-
self.ensure_metric_exists(metric);
431+
self.insert_if_absent(metric);
427432

428433
let metric = self.metrics.get_mut(name).expect("Gauge metric should exist");
429434

@@ -438,9 +443,9 @@ impl MetricKindCollection<Gauge> {
438443
///
439444
/// Panics if the metric does not exist and it could not be created.
440445
pub fn increment(&mut self, name: &MetricName, label_set: &LabelSet, time: DurationSinceUnixEpoch) {
441-
let metric = Metric::<Gauge>::without_samples(name.clone());
446+
let metric = Metric::<Gauge>::new_empty_with_name(name.clone());
442447

443-
self.ensure_metric_exists(metric);
448+
self.insert_if_absent(metric);
444449

445450
let metric = self.metrics.get_mut(name).expect("Gauge metric should exist");
446451

@@ -455,9 +460,9 @@ impl MetricKindCollection<Gauge> {
455460
///
456461
/// Panics if the metric does not exist and it could not be created.
457462
pub fn decrement(&mut self, name: &MetricName, label_set: &LabelSet, time: DurationSinceUnixEpoch) {
458-
let metric = Metric::<Gauge>::without_samples(name.clone());
463+
let metric = Metric::<Gauge>::new_empty_with_name(name.clone());
459464

460-
self.ensure_metric_exists(metric);
465+
self.insert_if_absent(metric);
461466

462467
let metric = self.metrics.get_mut(name).expect("Gauge metric should exist");
463468

@@ -523,11 +528,15 @@ mod tests {
523528
MetricCollection::new(
524529
MetricKindCollection::new(vec![Metric::new(
525530
metric_name!("http_tracker_core_announce_requests_received_total"),
531+
None,
532+
None,
526533
SampleCollection::new(vec![Sample::new(Counter::new(1), time, label_set_1.clone())]).unwrap(),
527534
)])
528535
.unwrap(),
529536
MetricKindCollection::new(vec![Metric::new(
530537
metric_name!("udp_tracker_server_performance_avg_announce_processing_time_ns"),
538+
None,
539+
None,
531540
SampleCollection::new(vec![Sample::new(Gauge::new(1.0), time, label_set_1.clone())]).unwrap(),
532541
)])
533542
.unwrap(),
@@ -541,6 +550,8 @@ mod tests {
541550
{
542551
"type":"counter",
543552
"name":"http_tracker_core_announce_requests_received_total",
553+
"unit": null,
554+
"description": null,
544555
"samples":[
545556
{
546557
"value":1,
@@ -565,6 +576,8 @@ mod tests {
565576
{
566577
"type":"gauge",
567578
"name":"udp_tracker_server_performance_avg_announce_processing_time_ns",
579+
"unit": null,
580+
"description": null,
568581
"samples":[
569582
{
570583
"value":1.0,
@@ -603,10 +616,20 @@ mod tests {
603616

604617
#[test]
605618
fn it_should_not_allow_duplicate_names_across_types() {
606-
let counters =
607-
MetricKindCollection::new(vec![Metric::new(metric_name!("test_metric"), SampleCollection::default())]).unwrap();
608-
let gauges =
609-
MetricKindCollection::new(vec![Metric::new(metric_name!("test_metric"), SampleCollection::default())]).unwrap();
619+
let counters = MetricKindCollection::new(vec![Metric::new(
620+
metric_name!("test_metric"),
621+
None,
622+
None,
623+
SampleCollection::default(),
624+
)])
625+
.unwrap();
626+
let gauges = MetricKindCollection::new(vec![Metric::new(
627+
metric_name!("test_metric"),
628+
None,
629+
None,
630+
SampleCollection::default(),
631+
)])
632+
.unwrap();
610633

611634
assert!(MetricCollection::new(counters, gauges).is_err());
612635
}
@@ -699,6 +722,8 @@ mod tests {
699722
let metric_collection = MetricCollection::new(
700723
MetricKindCollection::new(vec![Metric::new(
701724
metric_name!("http_tracker_core_announce_requests_received_total"),
725+
None,
726+
None,
702727
SampleCollection::new(vec![
703728
Sample::new(Counter::new(1), time, label_set_1.clone()),
704729
Sample::new(Counter::new(2), time, label_set_2.clone()),
@@ -730,11 +755,11 @@ mod tests {
730755
let mut counters = MetricKindCollection::default();
731756
let mut gauges = MetricKindCollection::default();
732757

733-
let counter = Metric::<Counter>::without_samples(metric_name!("test_counter"));
734-
counters.ensure_metric_exists(counter);
758+
let counter = Metric::<Counter>::new_empty_with_name(metric_name!("test_counter"));
759+
counters.insert_if_absent(counter);
735760

736-
let gauge = Metric::<Gauge>::without_samples(metric_name!("test_gauge"));
737-
gauges.ensure_metric_exists(gauge);
761+
let gauge = Metric::<Gauge>::new_empty_with_name(metric_name!("test_gauge"));
762+
gauges.insert_if_absent(gauge);
738763

739764
let metric_collection = MetricCollection::new(counters, gauges).unwrap();
740765

@@ -760,6 +785,8 @@ mod tests {
760785
let mut metric_collection = MetricCollection::new(
761786
MetricKindCollection::new(vec![Metric::new(
762787
metric_name!("test_counter"),
788+
None,
789+
None,
763790
SampleCollection::new(vec![Sample::new(Counter::new(0), time, label_set.clone())]).unwrap(),
764791
)])
765792
.unwrap(),
@@ -819,10 +846,14 @@ mod tests {
819846
let result = MetricKindCollection::new(vec![
820847
Metric::new(
821848
metric_name!("test_counter"),
849+
None,
850+
None,
822851
SampleCollection::new(vec![Sample::new(Counter::new(0), time, label_set.clone())]).unwrap(),
823852
),
824853
Metric::new(
825854
metric_name!("test_counter"),
855+
None,
856+
None,
826857
SampleCollection::new(vec![Sample::new(Counter::new(0), time, label_set.clone())]).unwrap(),
827858
),
828859
]);
@@ -849,6 +880,8 @@ mod tests {
849880
MetricKindCollection::default(),
850881
MetricKindCollection::new(vec![Metric::new(
851882
metric_name!("test_gauge"),
883+
None,
884+
None,
852885
SampleCollection::new(vec![Sample::new(Gauge::new(0.0), time, label_set.clone())]).unwrap(),
853886
)])
854887
.unwrap(),
@@ -901,10 +934,14 @@ mod tests {
901934
let result = MetricKindCollection::new(vec![
902935
Metric::new(
903936
metric_name!("test_gauge"),
937+
None,
938+
None,
904939
SampleCollection::new(vec![Sample::new(Gauge::new(0.0), time, label_set.clone())]).unwrap(),
905940
),
906941
Metric::new(
907942
metric_name!("test_gauge"),
943+
None,
944+
None,
908945
SampleCollection::new(vec![Sample::new(Gauge::new(0.0), time, label_set.clone())]).unwrap(),
909946
),
910947
]);

packages/metrics/src/unit.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
//! The `Unit` enum is used to specify the unit of measurement for metrics.
55
//!
66
//! They were copied from the `metrics` crate, to allow future compatibility.
7-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7+
8+
use serde::{Deserialize, Serialize};
9+
10+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
11+
#[serde(rename_all = "snake_case")]
812
pub enum Unit {
913
Count,
1014
Percent,

0 commit comments

Comments
 (0)