openmetrics_parser/prometheus/
parsers.rs

1use std::convert::TryFrom;
2
3use pest::Parser;
4
5use crate::{
6    internal::{
7        CounterValueMarshal, LabelNames, MarshalledMetric, MarshalledMetricFamily,
8        MetricFamilyMarshal, MetricMarshal, MetricProcesser, MetricValueMarshal, MetricsType,
9    },
10    public::*,
11};
12
13#[derive(Parser)]
14#[grammar = "prometheus/prometheus.pest"]
15struct PrometheusParser;
16
17impl From<pest::error::Error<Rule>> for ParseError {
18    fn from(err: pest::error::Error<Rule>) -> Self {
19        ParseError::ParseError(err.to_string())
20    }
21}
22
23impl MarshalledMetricFamily for MetricFamilyMarshal<PrometheusType> {
24    type Error = ParseError;
25
26    fn validate(&self) -> Result<(), ParseError> {
27        if let Some(name) = &self.name {
28            // Counters have to end with _total
29            if self.family_type == Some(PrometheusType::Counter) && !name.ends_with("_total") {
30                return Err(ParseError::InvalidMetric(format!("Counters should have a _total suffix. Got {}", name)));
31            }
32        }
33
34        for metric in self.metrics.iter() {
35            metric.validate(self)?;
36        }
37
38        Ok(())
39    }
40
41    fn process_new_metric(
42        &mut self,
43        metric_name: &str,
44        metric_value: MetricNumber,
45        label_names: Vec<String>,
46        label_values: Vec<String>,
47        timestamp: Option<Timestamp>,
48        exemplar: Option<Exemplar>,
49    ) -> Result<(), Self::Error> {
50        let handlers = vec![
51            (
52                vec![PrometheusType::Histogram],
53                vec![
54                    (
55                        "_bucket",
56                        vec!["le"],
57                        MetricProcesser::new(
58                            |existing_metric: &mut MetricMarshal,
59                             metric_value: MetricNumber,
60                             label_names: Vec<String>,
61                             label_values: Vec<String>,
62                             exemplar: Option<Exemplar>,
63                             _: bool| {
64                                let bucket_bound: f64 = {
65                                    let bound_index =
66                                        label_names.iter().position(|s| s == "le").unwrap();
67
68                                    let bound = &label_values[bound_index];
69                                    match bound.parse() {
70                                        Ok(f) => f,
71                                        Err(_) => {
72                                            return Err(ParseError::InvalidMetric(format!(
73                                                "Invalid histogram bound: {}",
74                                                bound
75                                            )));
76                                        }
77                                    }
78                                };
79
80                                let bucket = HistogramBucket {
81                                    count: metric_value,
82                                    upper_bound: bucket_bound,
83                                    exemplar,
84                                };
85
86                                if let MetricValueMarshal::Histogram(value) =
87                                    &mut existing_metric.value
88                                {
89                                    value.buckets.push(bucket);
90                                } else {
91                                    unreachable!();
92                                }
93
94                                Ok(())
95                            },
96                        ),
97                    ),
98                    (
99                        "_count",
100                        vec![],
101                        MetricProcesser::new(
102                            |existing_metric: &mut MetricMarshal,
103                             metric_value: MetricNumber,
104                             _: Vec<String>,
105                             _: Vec<String>,
106                             _: Option<Exemplar>,
107                             _: bool| {
108                                if let MetricValueMarshal::Histogram(histogram_value) =
109                                    &mut existing_metric.value
110                                {
111                                    let metric_value = if let Some(value) = metric_value.as_i64() {
112                                        if value < 0 {
113                                            return Err(ParseError::InvalidMetric(format!(
114                                                "Histogram counts must be positive (got: {})",
115                                                value
116                                            )));
117                                        }
118
119                                        value as u64
120                                    } else {
121                                        return Err(ParseError::InvalidMetric(format!(
122                                            "Histogram counts must be integers (got: {})",
123                                            metric_value.as_f64()
124                                        )));
125                                    };
126
127                                    match histogram_value.count {
128                                        Some(_) => {
129                                            return Err(ParseError::DuplicateMetric);
130                                        }
131                                        None => {
132                                            histogram_value.count = Some(metric_value);
133                                        }
134                                    };
135                                } else {
136                                    unreachable!();
137                                }
138
139                                Ok(())
140                            },
141                        ),
142                    ),
143                    (
144                        "_sum",
145                        vec![],
146                        MetricProcesser::new(
147                            |existing_metric: &mut MetricMarshal,
148                             metric_value: MetricNumber,
149                             _: Vec<String>,
150                             _: Vec<String>,
151                             _: Option<Exemplar>,
152                             _: bool| {
153                                if let MetricValueMarshal::Histogram(histogram_value) =
154                                    &mut existing_metric.value
155                                {
156                                    if histogram_value.sum.is_some() {
157                                        return Err(ParseError::DuplicateMetric);
158                                    }
159
160                                    histogram_value.sum = Some(metric_value);
161
162                                    Ok(())
163                                } else {
164                                    unreachable!();
165                                }
166                            },
167                        ),
168                    ),
169                    (
170                        "",
171                        vec![],
172                        MetricProcesser::new(
173                            |existing_metric: &mut MetricMarshal,
174                             metric_value: MetricNumber,
175                             _: Vec<String>,
176                             _: Vec<String>,
177                             _: Option<Exemplar>,
178                             _: bool| {
179                                if let MetricValueMarshal::Histogram(histogram_value) =
180                                    &mut existing_metric.value
181                                {
182                                    let metric_value = if let Some(value) = metric_value.as_i64() {
183                                        if value < 0 {
184                                            return Err(ParseError::InvalidMetric(format!(
185                                                "Histogram counts must be positive (got: {})",
186                                                value
187                                            )));
188                                        }
189
190                                        value as u64
191                                    } else {
192                                        return Err(ParseError::InvalidMetric(format!(
193                                            "Histogram counts must be integers (got: {})",
194                                            metric_value.as_f64()
195                                        )));
196                                    };
197
198                                    match histogram_value.count {
199                                        Some(_) => {
200                                            return Err(ParseError::DuplicateMetric);
201                                        }
202                                        None => {
203                                            histogram_value.count = Some(metric_value);
204                                        }
205                                    };
206                                } else {
207                                    unreachable!();
208                                }
209
210                                Ok(())
211                            },
212                        ),
213                    ),
214                ],
215            ),
216            (
217                vec![PrometheusType::Counter],
218                vec![(
219                    "",
220                    vec![],
221                    MetricProcesser::new(
222                        |existing_metric: &mut MetricMarshal,
223                         metric_value: MetricNumber,
224                         _: Vec<String>,
225                         _: Vec<String>,
226                         _: Option<Exemplar>,
227                         _: bool| {
228                            if let MetricValueMarshal::Counter(counter_value) =
229                                &mut existing_metric.value
230                            {
231                                if counter_value.value.is_some() {
232                                    return Err(ParseError::DuplicateMetric);
233                                }
234
235                                let value = metric_value.as_f64();
236                                if value < 0. || value.is_nan() {
237                                    return Err(ParseError::InvalidMetric(format!(
238                                        "Counter totals must be non negative (got: {})",
239                                        metric_value.as_f64()
240                                    )));
241                                }
242
243                                counter_value.value = Some(metric_value);
244                            } else {
245                                unreachable!();
246                            }
247
248                            Ok(())
249                        },
250                    ),
251                )],
252            ),
253            (
254                vec![PrometheusType::Gauge],
255                vec![(
256                    "",
257                    vec![],
258                    MetricProcesser::new(
259                        |existing_metric: &mut MetricMarshal,
260                         metric_value: MetricNumber,
261                         _: Vec<String>,
262                         _: Vec<String>,
263                         _: Option<Exemplar>,
264                         _: bool| {
265                            if let MetricValueMarshal::Gauge(gauge_value) =
266                                &mut existing_metric.value
267                            {
268                                if gauge_value.is_some() {
269                                    return Err(ParseError::DuplicateMetric);
270                                }
271
272                                existing_metric.value =
273                                    MetricValueMarshal::Gauge(Some(metric_value));
274                            } else {
275                                unreachable!();
276                            }
277
278                            Ok(())
279                        },
280                    ),
281                )],
282            ),
283            (
284                vec![PrometheusType::Unknown],
285                vec![(
286                    "",
287                    vec![],
288                    MetricProcesser::new(
289                        |existing_metric: &mut MetricMarshal,
290                         metric_value: MetricNumber,
291                         _: Vec<String>,
292                         _: Vec<String>,
293                         _: Option<Exemplar>,
294                         _: bool| {
295                            if let MetricValueMarshal::Unknown(unknown_value) =
296                                &mut existing_metric.value
297                            {
298                                if unknown_value.is_some() {
299                                    return Err(ParseError::DuplicateMetric);
300                                }
301
302                                existing_metric.value =
303                                    MetricValueMarshal::Unknown(Some(metric_value));
304                            } else {
305                                unreachable!();
306                            }
307
308                            Ok(())
309                        },
310                    ),
311                )],
312            ),
313            (
314                vec![PrometheusType::Summary],
315                vec![
316                    (
317                        "_count",
318                        vec![],
319                        MetricProcesser::new(
320                            |existing_metric: &mut MetricMarshal,
321                             metric_value: MetricNumber,
322                             _: Vec<String>,
323                             _: Vec<String>,
324                             _: Option<Exemplar>,
325                             _: bool| {
326                                if let MetricValueMarshal::Summary(summary_value) =
327                                    &mut existing_metric.value
328                                {
329                                    let metric_value = if let Some(value) = metric_value.as_i64() {
330                                        if value < 0 {
331                                            return Err(ParseError::InvalidMetric(format!(
332                                                "Summary counts must be positive (got: {})",
333                                                value
334                                            )));
335                                        }
336                                        value as u64
337                                    } else {
338                                        return Err(ParseError::InvalidMetric(format!(
339                                            "Summary counts must be integers (got: {})",
340                                            metric_value.as_f64()
341                                        )));
342                                    };
343
344                                    if summary_value.count.is_none() {
345                                        summary_value.count = Some(metric_value);
346                                    } else {
347                                        return Err(ParseError::DuplicateMetric);
348                                    }
349                                } else {
350                                    unreachable!();
351                                }
352
353                                Ok(())
354                            },
355                        ),
356                    ),
357                    (
358                        "_sum",
359                        vec![],
360                        MetricProcesser::new(
361                            |existing_metric: &mut MetricMarshal,
362                             metric_value: MetricNumber,
363                             _: Vec<String>,
364                             _: Vec<String>,
365                             _: Option<Exemplar>,
366                             _: bool| {
367                                let value = metric_value.as_f64();
368                                if value < 0. || value.is_nan() {
369                                    return Err(ParseError::InvalidMetric(format!(
370                                        "Counter totals must be non negative (got: {})",
371                                        metric_value.as_f64()
372                                    )));
373                                }
374
375                                if let MetricValueMarshal::Summary(summary_value) =
376                                    &mut existing_metric.value
377                                {
378                                    if summary_value.sum.is_none() {
379                                        summary_value.sum = Some(metric_value);
380                                        Ok(())
381                                    } else {
382                                        Err(ParseError::DuplicateMetric)
383                                    }
384                                } else {
385                                    unreachable!();
386                                }
387                            },
388                        ),
389                    ),
390                    (
391                        "",
392                        vec!["quantile"],
393                        MetricProcesser::new(
394                            |existing_metric: &mut MetricMarshal,
395                             metric_value: MetricNumber,
396                             label_names: Vec<String>,
397                             label_values: Vec<String>,
398                             _: Option<Exemplar>,
399                             _: bool| {
400                                let value = metric_value.as_f64();
401                                if !value.is_nan() && value < 0. {
402                                    return Err(ParseError::InvalidMetric(
403                                        "Summary quantiles can't be negative".to_owned(),
404                                    ));
405                                }
406
407                                let bucket_bound: f64 = {
408                                    let bound_index =
409                                        label_names.iter().position(|s| s == "quantile").unwrap();
410                                    let bound = &label_values[bound_index];
411
412                                    match bound.parse() {
413                                        Ok(f) => f,
414                                        Err(_) => {
415                                            return Err(ParseError::InvalidMetric(format!(
416                                                "Summary bounds must be numbers (got: {})",
417                                                bound
418                                            )));
419                                        }
420                                    }
421                                };
422
423                                if !(0. ..=1.).contains(&bucket_bound) || bucket_bound.is_nan() {
424                                    return Err(ParseError::InvalidMetric(format!(
425                                        "Summary bounds must be between 0 and 1 (got: {})",
426                                        bucket_bound
427                                    )));
428                                }
429
430                                let quantile = Quantile {
431                                    quantile: bucket_bound,
432                                    value: metric_value,
433                                };
434
435                                if let MetricValueMarshal::Summary(summary_value) =
436                                    &mut existing_metric.value
437                                {
438                                    summary_value.quantiles.push(quantile);
439                                } else {
440                                    unreachable!();
441                                }
442
443                                Ok(())
444                            },
445                        ),
446                    ),
447                ],
448            ),
449        ];
450
451        let metric_type = self.family_type.as_ref().cloned().unwrap_or_default();
452
453        if !metric_type.can_have_exemplar(metric_name) && exemplar.is_some() {
454            return Err(ParseError::InvalidMetric(format!(
455                "Metric Type {:?} is not allowed exemplars",
456                metric_type
457            )));
458        }
459
460        for (test_type, actions) in handlers {
461            if test_type.contains(&metric_type) {
462                for (suffix, mandatory_labels, action) in actions {
463                    if !metric_name.ends_with(suffix) {
464                        continue;
465                    }
466
467                    let mut actual_label_names = label_names.clone();
468                    let mut actual_label_values = label_values.clone();
469                    for label in mandatory_labels {
470                        if !label_names.contains(&label.to_owned()) {
471                            return Err(ParseError::InvalidMetric(format!(
472                                "Missing mandatory label for metric: {}",
473                                label
474                            )));
475                        }
476
477                        let index = actual_label_names.iter().position(|s| s == label).unwrap();
478
479                        actual_label_names.remove(index);
480                        actual_label_values.remove(index);
481                    }
482
483                    let name = &metric_name.to_owned();
484                    self.try_set_label_names(
485                        name,
486                        LabelNames::new(name, metric_type.clone(), actual_label_names),
487                    )?;
488
489                    let metric_name = metric_name.trim_end_matches(suffix);
490                    if self.name.is_some() && self.name.as_ref().unwrap() != metric_name {
491                        return Err(ParseError::InvalidMetric(format!(
492                            "Invalid Name in metric family: {} != {}",
493                            metric_name,
494                            self.name.as_ref().unwrap()
495                        )));
496                    } else if self.name.is_none() {
497                        self.name = Some(metric_name.to_owned());
498                    }
499
500                    let (existing_metric, created) = match self
501                        .get_metric_by_labelset_mut(&actual_label_values)
502                    {
503                        Some(metric) => {
504                            match (metric.timestamp.as_ref(), timestamp.as_ref()) {
505                                (Some(metric_timestamp), Some(timestamp)) if timestamp < metric_timestamp => return Err(ParseError::InvalidMetric(format!("Timestamps went backwarts in family - saw {} and then saw{}", metric_timestamp, timestamp))),
506                                (Some(_), None) | (None, Some(_)) => return Err(ParseError::InvalidMetric("Missing timestamp in family (one metric had a timestamp, another didn't)".to_string())),
507                                (Some(metric_timestamp), Some(timestamp)) if timestamp >= metric_timestamp && !metric_type.can_have_multiple_lines() => return Ok(()),
508                                _ => (metric, false)
509                            }
510                        }
511                        None => {
512                            let new_metric = self
513                                .family_type
514                                .as_ref()
515                                .unwrap_or(&PrometheusType::Unknown)
516                                .get_type_value();
517                            self.add_metric(MetricMarshal::new(
518                                actual_label_values.clone(),
519                                timestamp,
520                                new_metric,
521                            ));
522                            (
523                                self.get_metric_by_labelset_mut(&actual_label_values)
524                                    .unwrap(),
525                                true,
526                            )
527                        }
528                    };
529
530                    return action.0(
531                        existing_metric,
532                        metric_value,
533                        label_names,
534                        label_values,
535                        exemplar,
536                        created,
537                    );
538                }
539            }
540        }
541
542        return Err(ParseError::InvalidMetric(format!(
543            "Found weird metric name for type ({:?}): {}",
544            metric_type, metric_name
545        )));
546    }
547}
548
549impl Default for PrometheusType {
550    fn default() -> Self {
551        PrometheusType::Unknown
552    }
553}
554
555impl From<MetricMarshal> for Sample<PrometheusValue> {
556    fn from(s: MetricMarshal) -> Sample<PrometheusValue> {
557        Sample::new(s.label_values, s.timestamp, s.value.into())
558    }
559}
560
561impl MarshalledMetric<PrometheusType> for MetricMarshal {
562    fn validate(&self, family: &MetricFamilyMarshal<PrometheusType>) -> Result<(), ParseError> {
563        // All the labels are right
564        if family.label_names.is_none() && !self.label_values.is_empty()
565            || (family.label_names.as_ref().unwrap().names.len() != self.label_values.len())
566        {
567            return Err(ParseError::InvalidMetric(format!(
568                "Metrics in family have different label sets: {:?} {:?}",
569                &family.label_names, self.label_values
570            )));
571        }
572
573        if family.unit.is_some() && family.metrics.is_empty() {
574            return Err(ParseError::InvalidMetric(
575                "Can't have metric with unit and no samples".to_owned(),
576            ));
577        }
578
579        if let MetricValueMarshal::Histogram(histogram_value) = &self.value {
580            if histogram_value.buckets.is_empty() {
581                return Err(ParseError::InvalidMetric(
582                    "Histograms must have at least one bucket".to_owned(),
583                ));
584            }
585
586            if !histogram_value
587                .buckets
588                .iter()
589                .any(|b| b.upper_bound == f64::INFINITY)
590            {
591                return Err(ParseError::InvalidMetric(format!(
592                    "Histograms must have a +INF bucket: {:?}",
593                    histogram_value.buckets
594                )));
595            }
596
597            let buckets = &histogram_value.buckets;
598
599            let has_negative_bucket = buckets.iter().any(|f| f.upper_bound < 0.);
600
601            if has_negative_bucket {
602                if histogram_value.sum.is_some() {
603                    return Err(ParseError::InvalidMetric(
604                        "Histograms cannot have a sum with a negative bucket".to_owned(),
605                    ));
606                }
607            } else if histogram_value.sum.is_some()
608                && histogram_value.sum.as_ref().unwrap().as_f64() < 0.
609            {
610                return Err(ParseError::InvalidMetric(
611                    "Histograms cannot have a negative sum without a negative bucket".to_owned(),
612                ));
613            }
614
615            if histogram_value.sum.is_some() && histogram_value.count.is_none() {
616                return Err(ParseError::InvalidMetric(
617                    "Count must be present if sum is present".to_owned(),
618                ));
619            }
620
621            if histogram_value.sum.is_none() && histogram_value.count.is_some() {
622                return Err(ParseError::InvalidMetric(
623                    "Sum must be present if count is present".to_owned(),
624                ));
625            }
626
627            let mut last = f64::NEG_INFINITY;
628            for bucket in buckets {
629                if bucket.count.as_f64() < last {
630                    return Err(ParseError::InvalidMetric(
631                        "Histograms must be cumulative".to_owned(),
632                    ));
633                }
634
635                last = bucket.count.as_f64();
636            }
637        }
638
639        Ok(())
640    }
641}
642
643impl From<MetricValueMarshal> for PrometheusValue {
644    fn from(m: MetricValueMarshal) -> PrometheusValue {
645        match m {
646            MetricValueMarshal::Unknown(u) => PrometheusValue::Unknown(u.unwrap()),
647            MetricValueMarshal::Gauge(g) => PrometheusValue::Gauge(g.unwrap()),
648            MetricValueMarshal::Counter(c) => PrometheusValue::Counter(c.into()),
649            MetricValueMarshal::Histogram(h) => PrometheusValue::Histogram(h),
650            MetricValueMarshal::Summary(s) => PrometheusValue::Summary(s),
651            _ => unreachable!(),
652        }
653    }
654}
655
656impl MetricsType for PrometheusType {
657    fn get_ignored_labels(&self, metric_name: &str) -> &[&str] {
658        match self {
659            PrometheusType::Histogram if metric_name.ends_with("_bucket") => &["le"],
660            _ => &[],
661        }
662    }
663
664    fn get_type_value(&self) -> MetricValueMarshal {
665        match self {
666            PrometheusType::Histogram => MetricValueMarshal::Histogram(HistogramValue::default()),
667            PrometheusType::Counter => MetricValueMarshal::Counter(CounterValueMarshal::default()),
668            PrometheusType::Unknown => MetricValueMarshal::Unknown(None),
669            PrometheusType::Gauge => MetricValueMarshal::Gauge(None),
670            PrometheusType::Summary => MetricValueMarshal::Summary(SummaryValue::default()),
671        }
672    }
673
674    fn can_have_multiple_lines(&self) -> bool {
675        matches!(
676            self,
677            PrometheusType::Counter | PrometheusType::Histogram | PrometheusType::Summary
678        )
679    }
680
681    fn can_have_exemplar(&self, metric_name: &str) -> bool {
682        match self {
683            PrometheusType::Counter => metric_name.ends_with("_total"),
684            PrometheusType::Histogram => metric_name.ends_with("_bucket"),
685            _ => false,
686        }
687    }
688
689    fn can_have_units(&self) -> bool {
690        false
691    }
692}
693
694impl From<MetricFamilyMarshal<PrometheusType>> for MetricFamily<PrometheusType, PrometheusValue> {
695    fn from(marshal: MetricFamilyMarshal<PrometheusType>) -> Self {
696        assert!(marshal.name.is_some());
697
698        MetricFamily::new(
699            marshal.name.unwrap(),
700            marshal
701                .label_names
702                .map(|names| names.names)
703                .unwrap_or_default(),
704            marshal.family_type.unwrap_or_default(),
705            marshal.help.unwrap_or_default(),
706            marshal.unit.unwrap_or_default(),
707        )
708        .with_samples(marshal.metrics.into_iter().map(|m| m.into()))
709        .unwrap()
710    }
711}
712
713impl TryFrom<&str> for PrometheusType {
714    type Error = ParseError;
715
716    fn try_from(value: &str) -> Result<Self, Self::Error> {
717        match value {
718            "counter" => Ok(PrometheusType::Counter),
719            "gauge" => Ok(PrometheusType::Gauge),
720            "histogram" => Ok(PrometheusType::Histogram),
721            "summary" => Ok(PrometheusType::Summary),
722            "unknown" => Ok(PrometheusType::Unknown),
723            _ => Err(ParseError::InvalidMetric(format!(
724                "Invalid metric type: {}",
725                value
726            ))),
727        }
728    }
729}
730
731pub fn parse_prometheus(
732    exposition_bytes: &str,
733) -> Result<MetricsExposition<PrometheusType, PrometheusValue>, ParseError> {
734    use pest::iterators::Pair;
735
736    fn parse_metric_descriptor(
737        pair: Pair<Rule>,
738        family: &mut MetricFamilyMarshal<PrometheusType>,
739    ) -> Result<(), ParseError> {
740        assert_eq!(pair.as_rule(), Rule::metricdescriptor);
741
742        let mut descriptor = pair.into_inner();
743        let descriptor_type = descriptor.next().unwrap();
744        let metric_name = descriptor.next().unwrap().as_str().to_string();
745
746        match descriptor_type.as_rule() {
747            Rule::kw_help => {
748                let help_text = descriptor.next().unwrap().as_str();
749                family.set_or_test_name(metric_name)?;
750                family.try_add_help(help_text.to_string())?;
751            }
752            Rule::kw_type => {
753                let family_type = descriptor.next().unwrap().as_str();
754                family.set_or_test_name(metric_name)?;
755                family.try_add_type(PrometheusType::try_from(family_type)?)?;
756            }
757            _ => unreachable!(),
758        }
759
760        Ok(())
761    }
762
763    fn parse_exemplar(pair: Pair<Rule>) -> Result<Exemplar, ParseError> {
764        let mut inner = pair.into_inner();
765
766        let labels = inner.next().unwrap();
767        assert_eq!(labels.as_rule(), Rule::labels);
768
769        let labels = parse_labels(labels)?
770            .into_iter()
771            .map(|(a, b)| (a.to_owned(), b.to_owned()))
772            .collect();
773
774        let id = inner.next().unwrap().as_str();
775        let id = match id.parse() {
776            Ok(i) => i,
777            Err(_) => {
778                return Err(ParseError::InvalidMetric(format!(
779                    "Exemplar value must be a number (got: {})",
780                    id
781                )))
782            }
783        };
784
785        let timestamp = match inner.next() {
786            Some(timestamp) => match timestamp.as_str().parse() {
787                Ok(f) => Some(f),
788                Err(_) => {
789                    return Err(ParseError::InvalidMetric(format!(
790                        "Exemplar timestamp must be a number (got: {})",
791                        timestamp.as_str()
792                    )))
793                }
794            },
795            None => None,
796        };
797
798        Ok(Exemplar::new(labels, id, timestamp))
799    }
800
801    fn parse_labels(pair: Pair<Rule>) -> Result<Vec<(&str, &str)>, ParseError> {
802        assert_eq!(pair.as_rule(), Rule::labels);
803
804        let mut label_pairs = pair.into_inner();
805        let mut labels: Vec<(&str, &str)> = Vec::new();
806
807        while label_pairs.peek().is_some() && label_pairs.peek().unwrap().as_rule() == Rule::label {
808            let mut label = label_pairs.next().unwrap().into_inner();
809            let name = label.next().unwrap().as_str();
810            let value = label.next().unwrap().as_str();
811
812            if labels.iter().any(|(n, _)| n == &name) {
813                return Err(ParseError::InvalidMetric(format!(
814                    "Found label `{}` twice in the same labelset",
815                    name
816                )));
817            }
818
819            labels.push((name, value));
820        }
821
822        labels.sort_by_key(|l| l.0);
823
824        Ok(labels)
825    }
826
827    fn parse_sample(
828        pair: Pair<Rule>,
829        family: &mut MetricFamilyMarshal<PrometheusType>,
830    ) -> Result<(), ParseError> {
831        assert_eq!(pair.as_rule(), Rule::metric);
832
833        let mut descriptor = pair.into_inner();
834        let metric_name = descriptor.next().unwrap().as_str();
835
836        let labels = if descriptor.peek().unwrap().as_rule() == Rule::labels {
837            parse_labels(descriptor.next().unwrap())?
838        } else {
839            Vec::new()
840        };
841
842        let (label_names, label_values) = {
843            let mut names = Vec::new();
844            let mut values = Vec::new();
845            for (name, value) in labels.into_iter() {
846                names.push(name.to_owned());
847                values.push(value.to_owned());
848            }
849
850            (names, values)
851        };
852
853        let value = descriptor.next().unwrap().as_str();
854        let value = match value.parse() {
855            Ok(f) => MetricNumber::Int(f),
856            Err(_) => match value.parse() {
857                Ok(f) => MetricNumber::Float(f),
858                Err(_) => {
859                    return Err(ParseError::InvalidMetric(format!(
860                        "Metric Value must be a number (got: {})",
861                        value
862                    )));
863                }
864            },
865        };
866
867        let mut timestamp = None;
868        let mut exemplar = None;
869
870        if descriptor.peek().is_some()
871            && descriptor.peek().as_ref().unwrap().as_rule() == Rule::timestamp
872        {
873            timestamp = Some(descriptor.next().unwrap().as_str().parse().unwrap());
874        }
875
876        if descriptor.peek().is_some()
877            && descriptor.peek().as_ref().unwrap().as_rule() == Rule::exemplar
878        {
879            exemplar = Some(parse_exemplar(descriptor.next().unwrap())?);
880        }
881
882        family.process_new_metric(
883            metric_name,
884            value,
885            label_names,
886            label_values,
887            timestamp,
888            exemplar,
889        )?;
890
891        Ok(())
892    }
893
894    fn parse_metric_family(
895        pair: Pair<Rule>,
896    ) -> Result<MetricFamily<PrometheusType, PrometheusValue>, ParseError> {
897        assert_eq!(pair.as_rule(), Rule::metricfamily);
898
899        let mut metric_family = MetricFamilyMarshal::empty();
900
901        for child in pair.into_inner() {
902            match child.as_rule() {
903                Rule::metricdescriptor => {
904                    if metric_family.metrics.is_empty() {
905                        parse_metric_descriptor(child, &mut metric_family)?;
906                    } else {
907                        return Err(ParseError::InvalidMetric(
908                            "Metric Descriptor after samples".to_owned(),
909                        ));
910                    }
911                }
912                Rule::metric => {
913                    parse_sample(child, &mut metric_family)?;
914                }
915                _ => unreachable!(),
916            }
917        }
918
919        metric_family.validate()?;
920
921        Ok(metric_family.into())
922    }
923
924    let exposition_marshal = PrometheusParser::parse(Rule::exposition, exposition_bytes)?
925        .next()
926        .unwrap();
927    let mut exposition = MetricsExposition::new();
928
929    assert_eq!(exposition_marshal.as_rule(), Rule::exposition);
930
931    for span in exposition_marshal.into_inner() {
932        match span.as_rule() {
933            Rule::metricfamily => {
934                let family = parse_metric_family(span)?;
935
936                if exposition.families.contains_key(&family.family_name) {
937                    return Err(ParseError::InvalidMetric(format!(
938                        "Found a metric family called {}, after that family was finalised",
939                        family.family_name
940                    )));
941                }
942
943                exposition
944                    .families
945                    .insert(family.family_name.clone(), family);
946            }
947            Rule::EOI => {}
948            _ => unreachable!(),
949        }
950    }
951
952    Ok(exposition)
953}