Skip to content

Commit e35e99d

Browse files
authored
fix(protobuf): Do not share label storage across families (#123)
Signed-off-by: ackintosh <[email protected]>
1 parent 51de116 commit e35e99d

File tree

2 files changed

+50
-15
lines changed

2 files changed

+50
-15
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3636
my_metric{a="42",b="42",unique="42"} 42
3737
```
3838

39+
### Fixed
40+
41+
- Fix label encoding in protobuf feature. See [PR 123].
42+
3943
[PR 82]: https://github.com/prometheus/client_rust/pull/82
4044
[PR 118]: https://github.com/prometheus/client_rust/pull/118
45+
[PR 123]: https://github.com/prometheus/client_rust/pull/123
4146

4247
## [0.19.0]
4348

src/encoding/protobuf.rs

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ fn encode_metric(
8585
let encoder = MetricEncoder {
8686
family: &mut family.metrics,
8787
metric_type: super::EncodeMetric::metric_type(metric),
88-
labels: &mut labels,
88+
labels,
8989
};
9090

9191
super::EncodeMetric::encode(metric, encoder.into())?;
@@ -105,11 +105,17 @@ impl From<MetricType> for openmetrics_data_model::MetricType {
105105
}
106106
}
107107

108+
/// Encoder for protobuf encoding.
109+
///
110+
/// This is an inner type for [`super::MetricEncoder`].
108111
#[derive(Debug)]
109112
pub(crate) struct MetricEncoder<'a> {
113+
/// OpenMetrics metric type of the metric.
110114
metric_type: MetricType,
115+
/// Vector of OpenMetrics metrics to which encoded metrics are added.
111116
family: &'a mut Vec<openmetrics_data_model::Metric>,
112-
labels: &'a mut Vec<openmetrics_data_model::Label>,
117+
/// Labels to be added to each metric.
118+
labels: Vec<openmetrics_data_model::Label>,
113119
}
114120

115121
impl<'a> MetricEncoder<'a> {
@@ -193,17 +199,18 @@ impl<'a> MetricEncoder<'a> {
193199
&'b mut self,
194200
label_set: &S,
195201
) -> Result<MetricEncoder<'b>, std::fmt::Error> {
202+
let mut labels = self.labels.clone();
196203
label_set.encode(
197204
LabelSetEncoder {
198-
labels: self.labels,
205+
labels: &mut labels,
199206
}
200207
.into(),
201208
)?;
202209

203210
Ok(MetricEncoder {
204211
metric_type: self.metric_type,
205212
family: self.family,
206-
labels: self.labels,
213+
labels,
207214
})
208215
}
209216

@@ -406,6 +413,7 @@ mod tests {
406413
use crate::metrics::info::Info;
407414
use crate::registry::Unit;
408415
use std::borrow::Cow;
416+
use std::collections::HashSet;
409417
use std::sync::atomic::AtomicI64;
410418

411419
#[test]
@@ -426,7 +434,7 @@ mod tests {
426434
extract_metric_type(&metric_set)
427435
);
428436

429-
match extract_metric_point_value(metric_set) {
437+
match extract_metric_point_value(&metric_set) {
430438
openmetrics_data_model::metric_point::Value::CounterValue(value) => {
431439
let expected = openmetrics_data_model::counter_value::Total::IntValue(1);
432440
assert_eq!(Some(expected), value.total);
@@ -456,7 +464,7 @@ mod tests {
456464
extract_metric_type(&metric_set)
457465
);
458466

459-
match extract_metric_point_value(metric_set) {
467+
match extract_metric_point_value(&metric_set) {
460468
openmetrics_data_model::metric_point::Value::CounterValue(value) => {
461469
// The counter should be encoded as `DoubleValue`
462470
let expected = openmetrics_data_model::counter_value::Total::DoubleValue(1.0);
@@ -507,7 +515,7 @@ mod tests {
507515
extract_metric_type(&metric_set)
508516
);
509517

510-
match extract_metric_point_value(metric_set) {
518+
match extract_metric_point_value(&metric_set) {
511519
openmetrics_data_model::metric_point::Value::CounterValue(value) => {
512520
// The counter should be encoded as `DoubleValue`
513521
let expected = openmetrics_data_model::counter_value::Total::DoubleValue(1.0);
@@ -545,7 +553,7 @@ mod tests {
545553
extract_metric_type(&metric_set)
546554
);
547555

548-
match extract_metric_point_value(metric_set) {
556+
match extract_metric_point_value(&metric_set) {
549557
openmetrics_data_model::metric_point::Value::GaugeValue(value) => {
550558
let expected = openmetrics_data_model::gauge_value::Value::IntValue(1);
551559
assert_eq!(Some(expected), value.value);
@@ -567,6 +575,13 @@ mod tests {
567575
])
568576
.inc();
569577

578+
family
579+
.get_or_create(&vec![
580+
("method".to_string(), "POST".to_string()),
581+
("status".to_string(), "200".to_string()),
582+
])
583+
.inc();
584+
570585
let metric_set = encode(&registry).unwrap();
571586

572587
let family = metric_set.metric_families.first().unwrap();
@@ -578,14 +593,21 @@ mod tests {
578593
extract_metric_type(&metric_set)
579594
);
580595

596+
// The order of the labels is not deterministic so we are testing the
597+
// value to be either
598+
let mut potential_method_value = HashSet::new();
599+
potential_method_value.insert("GET");
600+
potential_method_value.insert("POST");
601+
602+
// the first metric
581603
let metric = family.metrics.first().unwrap();
582604
assert_eq!(2, metric.labels.len());
583605
assert_eq!("method", metric.labels[0].name);
584-
assert_eq!("GET", metric.labels[0].value);
606+
assert!(potential_method_value.remove(&metric.labels[0].value.as_str()));
585607
assert_eq!("status", metric.labels[1].name);
586608
assert_eq!("200", metric.labels[1].value);
587609

588-
match extract_metric_point_value(metric_set) {
610+
match extract_metric_point_value(&metric_set) {
589611
openmetrics_data_model::metric_point::Value::CounterValue(value) => {
590612
let expected = openmetrics_data_model::counter_value::Total::IntValue(1);
591613
assert_eq!(Some(expected), value.total);
@@ -594,6 +616,14 @@ mod tests {
594616
}
595617
_ => panic!("wrong value type"),
596618
}
619+
620+
// the second metric
621+
let metric2 = &family.metrics[1];
622+
assert_eq!(2, metric2.labels.len());
623+
assert_eq!("method", metric2.labels[0].name);
624+
assert!(potential_method_value.remove(&metric2.labels[0].value.as_str()));
625+
assert_eq!("status", metric2.labels[1].name);
626+
assert_eq!("200", metric2.labels[1].value);
597627
}
598628

599629
#[test]
@@ -632,7 +662,7 @@ mod tests {
632662
assert_eq!("status", metric.labels[2].name);
633663
assert_eq!("200", metric.labels[2].value);
634664

635-
match extract_metric_point_value(metric_set) {
665+
match extract_metric_point_value(&metric_set) {
636666
openmetrics_data_model::metric_point::Value::CounterValue(value) => {
637667
let expected = openmetrics_data_model::counter_value::Total::IntValue(1);
638668
assert_eq!(Some(expected), value.total);
@@ -661,7 +691,7 @@ mod tests {
661691
extract_metric_type(&metric_set)
662692
);
663693

664-
match extract_metric_point_value(metric_set) {
694+
match extract_metric_point_value(&metric_set) {
665695
openmetrics_data_model::metric_point::Value::HistogramValue(value) => {
666696
assert_eq!(
667697
Some(openmetrics_data_model::histogram_value::Sum::DoubleValue(
@@ -694,7 +724,7 @@ mod tests {
694724
extract_metric_type(&metric_set)
695725
);
696726

697-
match extract_metric_point_value(metric_set) {
727+
match extract_metric_point_value(&metric_set) {
698728
openmetrics_data_model::metric_point::Value::HistogramValue(value) => {
699729
let exemplar = value.buckets.first().unwrap().exemplar.as_ref().unwrap();
700730
assert_eq!(1.0, exemplar.value);
@@ -795,7 +825,7 @@ mod tests {
795825
extract_metric_type(&metric_set)
796826
);
797827

798-
match extract_metric_point_value(metric_set) {
828+
match extract_metric_point_value(&metric_set) {
799829
openmetrics_data_model::metric_point::Value::InfoValue(value) => {
800830
assert_eq!(1, value.info.len());
801831

@@ -813,7 +843,7 @@ mod tests {
813843
}
814844

815845
fn extract_metric_point_value(
816-
metric_set: openmetrics_data_model::MetricSet,
846+
metric_set: &openmetrics_data_model::MetricSet,
817847
) -> openmetrics_data_model::metric_point::Value {
818848
let metric = metric_set
819849
.metric_families

0 commit comments

Comments
 (0)