Skip to main content

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