Skip to main content

openmetrics_parser/openmetrics/
parsers.rs

1use crate::{
2    internal::{
3        CounterValueMarshal, LabelNames, MarshalledMetric, MarshalledMetricFamily,
4        MetricFamilyMarshal, MetricMarshal, MetricProcesser, MetricValueMarshal, MetricsType,
5        unescape,
6    },
7    public::*,
8};
9use std::convert::TryFrom;
10
11use pest::Parser;
12
13#[derive(Parser)]
14#[grammar = "openmetrics/openmetrics.pest"]
15struct OpenMetricsParser;
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 From<MetricValueMarshal> for OpenMetricsValue {
24    fn from(s: MetricValueMarshal) -> OpenMetricsValue {
25        match s {
26            MetricValueMarshal::Unknown(s) => OpenMetricsValue::Unknown(s.unwrap()),
27            MetricValueMarshal::Gauge(s) => OpenMetricsValue::Gauge(s.unwrap()),
28            MetricValueMarshal::Counter(s) => OpenMetricsValue::Counter(s.into()),
29            MetricValueMarshal::Histogram(s) => OpenMetricsValue::Histogram(s),
30            MetricValueMarshal::StateSet(s) => OpenMetricsValue::StateSet(s.unwrap()),
31            MetricValueMarshal::GaugeHistogram(s) => OpenMetricsValue::GaugeHistogram(s),
32            MetricValueMarshal::Info => OpenMetricsValue::Info,
33            MetricValueMarshal::Summary(s) => OpenMetricsValue::Summary(s),
34        }
35    }
36}
37
38impl MetricsType for OpenMetricsType {
39    fn can_have_exemplar(&self, metric_name: &str) -> bool {
40        match self {
41            OpenMetricsType::Counter => metric_name.ends_with("_total"),
42            OpenMetricsType::Histogram | OpenMetricsType::GaugeHistogram => {
43                metric_name.ends_with("_bucket")
44            }
45            _ => false,
46        }
47    }
48
49    fn get_ignored_labels(&self, metric_name: &str) -> &[&str] {
50        match self {
51            OpenMetricsType::Histogram | OpenMetricsType::GaugeHistogram
52                if metric_name.ends_with("bucket") =>
53            {
54                &["le"]
55            }
56            _ => &[],
57        }
58    }
59
60    fn get_type_value(&self) -> MetricValueMarshal {
61        match self {
62            OpenMetricsType::Histogram => MetricValueMarshal::Histogram(HistogramValue::default()),
63            OpenMetricsType::GaugeHistogram => {
64                MetricValueMarshal::GaugeHistogram(HistogramValue::default())
65            }
66            OpenMetricsType::Counter => MetricValueMarshal::Counter(CounterValueMarshal::default()),
67            OpenMetricsType::Unknown => MetricValueMarshal::Unknown(None),
68            OpenMetricsType::Gauge => MetricValueMarshal::Gauge(None),
69            OpenMetricsType::StateSet => MetricValueMarshal::StateSet(None),
70            OpenMetricsType::Summary => MetricValueMarshal::Summary(SummaryValue::default()),
71            OpenMetricsType::Info => MetricValueMarshal::Info,
72        }
73    }
74
75    fn can_have_units(&self) -> bool {
76        matches!(
77            self,
78            OpenMetricsType::Counter | OpenMetricsType::Unknown | OpenMetricsType::Gauge
79        )
80    }
81
82    fn can_have_multiple_lines(&self) -> bool {
83        matches!(
84            self,
85            OpenMetricsType::Counter
86                | OpenMetricsType::GaugeHistogram
87                | OpenMetricsType::Histogram
88                | OpenMetricsType::Summary
89        )
90    }
91}
92
93impl TryFrom<&str> for OpenMetricsType {
94    type Error = ParseError;
95
96    fn try_from(value: &str) -> Result<Self, Self::Error> {
97        match value {
98            "counter" => Ok(OpenMetricsType::Counter),
99            "gauge" => Ok(OpenMetricsType::Gauge),
100            "histogram" => Ok(OpenMetricsType::Histogram),
101            "gaugehistogram" => Ok(OpenMetricsType::GaugeHistogram),
102            "stateset" => Ok(OpenMetricsType::StateSet),
103            "summary" => Ok(OpenMetricsType::Summary),
104            "info" => Ok(OpenMetricsType::Info),
105            "unknown" => Ok(OpenMetricsType::Unknown),
106            _ => Err(ParseError::InvalidMetric(format!(
107                "Invalid metric type: {}",
108                value
109            ))),
110        }
111    }
112}
113
114impl Default for OpenMetricsType {
115    fn default() -> Self {
116        OpenMetricsType::Unknown
117    }
118}
119
120impl From<MetricMarshal> for Sample<OpenMetricsValue> {
121    fn from(s: MetricMarshal) -> Sample<OpenMetricsValue> {
122        Sample::new(s.label_values, s.timestamp, s.value.into())
123    }
124}
125
126impl MarshalledMetric<OpenMetricsType> for MetricMarshal {
127    fn validate(&self, family: &MetricFamilyMarshal<OpenMetricsType>) -> Result<(), ParseError> {
128        // All the labels are right
129        if family.label_names.is_none() && !self.label_values.is_empty()
130            || (family.label_names.as_ref().unwrap().names.len() != self.label_values.len())
131        {
132            return Err(ParseError::InvalidMetric(format!(
133                "Metrics in family have different label sets: {:?} {:?}",
134                &family.label_names, self.label_values
135            )));
136        }
137
138        if family.unit.is_some() && family.metrics.is_empty() {
139            return Err(ParseError::InvalidMetric(
140                "Can't have metric with unit and no samples".to_owned(),
141            ));
142        }
143
144        match &self.value {
145            MetricValueMarshal::Histogram(histogram_value)
146            | MetricValueMarshal::GaugeHistogram(histogram_value) => {
147                let gauge_histogram = matches!(&self.value, MetricValueMarshal::GaugeHistogram(_));
148
149                if histogram_value.buckets.is_empty() {
150                    return Err(ParseError::InvalidMetric(
151                        "Histograms must have at least one bucket".to_owned(),
152                    ));
153                }
154
155                if !histogram_value
156                    .buckets
157                    .iter()
158                    .any(|b| b.upper_bound == f64::INFINITY)
159                {
160                    return Err(ParseError::InvalidMetric(format!(
161                        "Histograms must have a +INF bucket: {:?}",
162                        histogram_value.buckets
163                    )));
164                }
165
166                let buckets = &histogram_value.buckets;
167
168                let has_negative_bucket = buckets.iter().any(|f| f.upper_bound < 0.);
169
170                if has_negative_bucket {
171                    if histogram_value.sum.is_some() && !gauge_histogram {
172                        return Err(ParseError::InvalidMetric(
173                            "Histograms cannot have a sum with a negative bucket".to_owned(),
174                        ));
175                    }
176                } else if histogram_value.sum.is_some()
177                    && histogram_value.sum.as_ref().unwrap().as_f64() < 0.
178                {
179                    return Err(ParseError::InvalidMetric(
180                        "Histograms cannot have a negative sum without a negative bucket"
181                            .to_owned(),
182                    ));
183                }
184
185                if histogram_value.sum.is_some() && histogram_value.count.is_none() {
186                    return Err(ParseError::InvalidMetric(
187                        "Count must be present if sum is present".to_owned(),
188                    ));
189                }
190
191                if histogram_value.sum.is_none() && histogram_value.count.is_some() {
192                    return Err(ParseError::InvalidMetric(
193                        "Sum must be present if count is present".to_owned(),
194                    ));
195                }
196
197                let mut last = f64::NEG_INFINITY;
198                for bucket in buckets {
199                    if bucket.count.as_f64() < last {
200                        return Err(ParseError::InvalidMetric(
201                            "Histograms must be cumulative".to_owned(),
202                        ));
203                    }
204
205                    last = bucket.count.as_f64();
206                }
207            }
208            MetricValueMarshal::Counter(counter_value) => {
209                if counter_value.value.is_none() {
210                    return Err(ParseError::InvalidMetric(
211                        "Counter is missing a _total".to_string(),
212                    ));
213                }
214            }
215            _ => {}
216        }
217
218        Ok(())
219    }
220}
221
222impl MarshalledMetricFamily for MetricFamilyMarshal<OpenMetricsType> {
223    type Error = ParseError;
224
225    fn validate(&self) -> Result<(), ParseError> {
226        if self.name.is_none() {
227            return Err(ParseError::InvalidMetric(
228                "Metric didn't have a name".to_string(),
229            ));
230        }
231
232        if self.family_type == Some(OpenMetricsType::StateSet)
233            && self.label_names.is_some()
234            && !self
235                .label_names
236                .as_ref()
237                .unwrap()
238                .names
239                .contains(self.name.as_ref().unwrap())
240        {
241            return Err(ParseError::InvalidMetric(
242                "Stateset must not have a label with the same name as its MetricFamily".to_string(),
243            ));
244        }
245
246        for metric in self.metrics.iter() {
247            metric.validate(self)?;
248        }
249
250        Ok(())
251    }
252
253    fn process_new_metric(
254        &mut self,
255        metric_name: &str,
256        metric_value: MetricNumber,
257        label_names: Vec<String>,
258        label_values: Vec<String>,
259        timestamp: Option<Timestamp>,
260        exemplar: Option<Exemplar>,
261    ) -> Result<(), Self::Error> {
262        let handlers = vec![
263            (
264                vec![OpenMetricsType::Histogram],
265                vec![
266                    (
267                        "_bucket",
268                        vec!["le"],
269                        MetricProcesser::new(
270                            |existing_metric: &mut MetricMarshal,
271                             metric_value: MetricNumber,
272                             label_names: Vec<String>,
273                             label_values: Vec<String>,
274                             exemplar: Option<Exemplar>,
275                             _: bool| {
276                                let bucket_bound: f64 = {
277                                    let bound_index =
278                                        label_names.iter().position(|s| s == "le").unwrap();
279
280                                    let bound = &label_values[bound_index];
281                                    match bound.parse() {
282                                        Ok(f) => f,
283                                        Err(_) => {
284                                            return Err(ParseError::InvalidMetric(format!(
285                                                "Invalid histogram bound: {}",
286                                                bound
287                                            )));
288                                        }
289                                    }
290                                };
291
292                                let bucket = HistogramBucket {
293                                    count: metric_value,
294                                    upper_bound: bucket_bound,
295                                    exemplar,
296                                };
297
298                                if let MetricValueMarshal::Histogram(value) =
299                                    &mut existing_metric.value
300                                {
301                                    value.buckets.push(bucket);
302                                } else {
303                                    unreachable!();
304                                }
305
306                                Ok(())
307                            },
308                        ),
309                    ),
310                    (
311                        "_count",
312                        vec![],
313                        MetricProcesser::new(
314                            |existing_metric: &mut MetricMarshal,
315                             metric_value: MetricNumber,
316                             _: Vec<String>,
317                             _: Vec<String>,
318                             _: Option<Exemplar>,
319                             _: bool| {
320                                if let MetricValueMarshal::Histogram(histogram_value) =
321                                    &mut existing_metric.value
322                                {
323                                    let metric_value = if let Some(value) = metric_value.as_i64() {
324                                        if value < 0 {
325                                            return Err(ParseError::InvalidMetric(format!(
326                                                "Histogram counts must be positive (got: {})",
327                                                value
328                                            )));
329                                        }
330
331                                        value as u64
332                                    } else {
333                                        return Err(ParseError::InvalidMetric(format!(
334                                            "Histogram counts must be integers (got: {})",
335                                            metric_value.as_f64()
336                                        )));
337                                    };
338
339                                    match histogram_value.count {
340                                        Some(_) => {
341                                            return Err(ParseError::DuplicateMetric);
342                                        }
343                                        None => {
344                                            histogram_value.count = Some(metric_value);
345                                        }
346                                    };
347                                } else {
348                                    unreachable!();
349                                }
350
351                                Ok(())
352                            },
353                        ),
354                    ),
355                    (
356                        "_created",
357                        vec![],
358                        MetricProcesser::new(
359                            |existing_metric: &mut MetricMarshal,
360                             metric_value: MetricNumber,
361                             _: Vec<String>,
362                             _: Vec<String>,
363                             _: Option<Exemplar>,
364                             _: bool| {
365                                if let MetricValueMarshal::Histogram(histogram_value) =
366                                    &mut existing_metric.value
367                                {
368                                    match histogram_value.created {
369                                        Some(_) => {
370                                            return Err(ParseError::DuplicateMetric);
371                                        }
372                                        None => {
373                                            histogram_value.created = Some(metric_value.as_f64());
374                                        }
375                                    };
376                                } else {
377                                    unreachable!();
378                                }
379
380                                Ok(())
381                            },
382                        ),
383                    ),
384                    (
385                        "_sum",
386                        vec![],
387                        MetricProcesser::new(
388                            |existing_metric: &mut MetricMarshal,
389                             metric_value: MetricNumber,
390                             _: Vec<String>,
391                             _: Vec<String>,
392                             _: Option<Exemplar>,
393                             _: bool| {
394                                if let MetricValueMarshal::Histogram(histogram_value) =
395                                    &mut existing_metric.value
396                                {
397                                    if histogram_value.sum.is_some() {
398                                        return Err(ParseError::DuplicateMetric);
399                                    }
400
401                                    histogram_value.sum = Some(metric_value);
402
403                                    Ok(())
404                                } else {
405                                    unreachable!();
406                                }
407                            },
408                        ),
409                    ),
410                ],
411            ),
412            (
413                vec![OpenMetricsType::GaugeHistogram],
414                vec![
415                    (
416                        "_bucket",
417                        vec!["le"],
418                        MetricProcesser::new(
419                            |existing_metric: &mut MetricMarshal,
420                             metric_value: MetricNumber,
421                             label_names: Vec<String>,
422                             label_values: Vec<String>,
423                             exemplar: Option<Exemplar>,
424                             _: bool| {
425                                let bucket_bound: f64 = {
426                                    let bound_index =
427                                        label_names.iter().position(|s| s == "le").unwrap();
428
429                                    let bound = &label_values[bound_index];
430                                    match bound.parse() {
431                                        Ok(f) => f,
432                                        Err(_) => {
433                                            return Err(ParseError::InvalidMetric(format!("Expected histogram bucket bound to be an f64 (got: {})", bound)));
434                                        }
435                                    }
436                                };
437
438                                let bucket = HistogramBucket {
439                                    count: metric_value,
440                                    upper_bound: bucket_bound,
441                                    exemplar,
442                                };
443
444                                if let MetricValueMarshal::GaugeHistogram(value) =
445                                    &mut existing_metric.value
446                                {
447                                    value.buckets.push(bucket);
448                                } else {
449                                    unreachable!();
450                                }
451
452                                Ok(())
453                            },
454                        ),
455                    ),
456                    (
457                        "_gcount",
458                        vec![],
459                        MetricProcesser::new(
460                            |existing_metric: &mut MetricMarshal,
461                             metric_value: MetricNumber,
462                             _: Vec<String>,
463                             _: Vec<String>,
464                             _: Option<Exemplar>,
465                             _: bool| {
466                                if let MetricValueMarshal::GaugeHistogram(histogram_value) =
467                                    &mut existing_metric.value
468                                {
469                                    let metric_value = if let Some(value) = metric_value.as_i64() {
470                                        if value < 0 {
471                                            return Err(ParseError::InvalidMetric(format!(
472                                                "Histogram counts must be positive (got: {})",
473                                                value
474                                            )));
475                                        }
476
477                                        value as u64
478                                    } else {
479                                        return Err(ParseError::InvalidMetric(format!(
480                                            "Histogram counts must be integers (got: {})",
481                                            metric_value.as_f64()
482                                        )));
483                                    };
484
485                                    match histogram_value.count {
486                                        Some(_) => {
487                                            return Err(ParseError::DuplicateMetric);
488                                        }
489                                        None => {
490                                            histogram_value.count = Some(metric_value);
491                                        }
492                                    };
493                                } else {
494                                    unreachable!();
495                                }
496
497                                Ok(())
498                            },
499                        ),
500                    ),
501                    (
502                        "_gsum",
503                        vec![],
504                        MetricProcesser::new(
505                            |existing_metric: &mut MetricMarshal,
506                             metric_value: MetricNumber,
507                             _: Vec<String>,
508                             _: Vec<String>,
509                             _: Option<Exemplar>,
510                             _: bool| {
511                                if let MetricValueMarshal::GaugeHistogram(histogram_value) =
512                                    &mut existing_metric.value
513                                {
514                                    if histogram_value.sum.is_some() {
515                                        return Err(ParseError::DuplicateMetric);
516                                    }
517
518                                    histogram_value.sum = Some(metric_value);
519
520                                    Ok(())
521                                } else {
522                                    unreachable!();
523                                }
524                            },
525                        ),
526                    ),
527                ],
528            ),
529            (
530                vec![OpenMetricsType::Counter],
531                vec![
532                    (
533                        "_total",
534                        vec![],
535                        MetricProcesser::new(
536                            |existing_metric: &mut MetricMarshal,
537                             metric_value: MetricNumber,
538                             _: Vec<String>,
539                             _: Vec<String>,
540                             exemplar: Option<Exemplar>,
541                             _: bool| {
542                                if let MetricValueMarshal::Counter(counter_value) =
543                                    &mut existing_metric.value
544                                {
545                                    if counter_value.value.is_some() {
546                                        return Err(ParseError::DuplicateMetric);
547                                    }
548
549                                    let value = metric_value.as_f64();
550                                    if value < 0. || value.is_nan() {
551                                        return Err(ParseError::InvalidMetric(format!(
552                                            "Counter totals must be non negative (got: {})",
553                                            metric_value.as_f64()
554                                        )));
555                                    }
556
557                                    counter_value.value = Some(metric_value);
558                                    counter_value.exemplar = exemplar;
559                                } else {
560                                    unreachable!();
561                                }
562
563                                Ok(())
564                            },
565                        ),
566                    ),
567                    (
568                        "_created",
569                        vec![],
570                        MetricProcesser::new(
571                            |existing_metric: &mut MetricMarshal,
572                             metric_value: MetricNumber,
573                             _: Vec<String>,
574                             _: Vec<String>,
575                             _: Option<Exemplar>,
576                             _: bool| {
577                                if let MetricValueMarshal::Counter(counter_value) =
578                                    &mut existing_metric.value
579                                {
580                                    if counter_value.created.is_some() {
581                                        return Err(ParseError::DuplicateMetric);
582                                    }
583
584                                    counter_value.created = Some(metric_value.as_f64());
585                                    Ok(())
586                                } else {
587                                    unreachable!();
588                                }
589                            },
590                        ),
591                    ),
592                ],
593            ),
594            (
595                vec![OpenMetricsType::Gauge],
596                vec![(
597                    "",
598                    vec![],
599                    MetricProcesser::new(
600                        |existing_metric: &mut MetricMarshal,
601                         metric_value: MetricNumber,
602                         _: Vec<String>,
603                         _: Vec<String>,
604                         _: Option<Exemplar>,
605                         _: bool| {
606                            if let MetricValueMarshal::Gauge(gauge_value) =
607                                &mut existing_metric.value
608                            {
609                                if gauge_value.is_some() {
610                                    return Err(ParseError::DuplicateMetric);
611                                }
612
613                                existing_metric.value =
614                                    MetricValueMarshal::Gauge(Some(metric_value));
615                            } else {
616                                unreachable!();
617                            }
618
619                            Ok(())
620                        },
621                    ),
622                )],
623            ),
624            (
625                vec![OpenMetricsType::StateSet],
626                vec![(
627                    "",
628                    vec![],
629                    MetricProcesser::new(
630                        |existing_metric: &mut MetricMarshal,
631                         metric_value: MetricNumber,
632                         _: Vec<String>,
633                         _: Vec<String>,
634                         _: Option<Exemplar>,
635                         _: bool| {
636                            if let MetricValueMarshal::StateSet(stateset_value) =
637                                &mut existing_metric.value
638                            {
639                                if stateset_value.is_some() {
640                                    return Err(ParseError::DuplicateMetric);
641                                }
642
643                                if existing_metric.label_values.is_empty() {
644                                    return Err(ParseError::InvalidMetric(
645                                        "Stateset must have labels".to_string(),
646                                    ));
647                                }
648
649                                if metric_value.as_f64() != 0.
650                                    && (metric_value.as_f64() - 1.).abs() > f64::EPSILON
651                                {
652                                    return Err(ParseError::InvalidMetric(format!(
653                                        "Stateset value must be 0 or 1 (got: {})",
654                                        metric_value.as_f64()
655                                    )));
656                                }
657
658                                existing_metric.value =
659                                    MetricValueMarshal::StateSet(Some(metric_value));
660                            } else {
661                                unreachable!();
662                            }
663
664                            Ok(())
665                        },
666                    ),
667                )],
668            ),
669            (
670                vec![OpenMetricsType::Unknown],
671                vec![(
672                    "",
673                    vec![],
674                    MetricProcesser::new(
675                        |existing_metric: &mut MetricMarshal,
676                         metric_value: MetricNumber,
677                         _: Vec<String>,
678                         _: Vec<String>,
679                         _: Option<Exemplar>,
680                         _: bool| {
681                            if let MetricValueMarshal::Unknown(unknown_value) =
682                                &mut existing_metric.value
683                            {
684                                if unknown_value.is_some() {
685                                    return Err(ParseError::DuplicateMetric);
686                                }
687
688                                existing_metric.value =
689                                    MetricValueMarshal::Unknown(Some(metric_value));
690                            } else {
691                                unreachable!();
692                            }
693
694                            Ok(())
695                        },
696                    ),
697                )],
698            ),
699            (
700                vec![OpenMetricsType::Info],
701                vec![(
702                    "_info",
703                    vec![],
704                    MetricProcesser::new(
705                        |_: &mut MetricMarshal,
706                         metric_value: MetricNumber,
707                         _: Vec<String>,
708                         _: Vec<String>,
709                         _: Option<Exemplar>,
710                         created: bool| {
711                            let metric_value = if let Some(value) = metric_value.as_i64() {
712                                value as u64
713                            } else {
714                                return Err(ParseError::InvalidMetric(format!(
715                                    "Info values must be integers (got: {})",
716                                    metric_value.as_f64()
717                                )));
718                            };
719
720                            if metric_value != 1 {
721                                return Err(ParseError::InvalidMetric(format!(
722                                    "Info values must be 1 (got: {})",
723                                    metric_value
724                                )));
725                            }
726
727                            if !created {
728                                return Err(ParseError::DuplicateMetric);
729                            }
730
731                            Ok(())
732                        },
733                    ),
734                )],
735            ),
736            (
737                vec![OpenMetricsType::Summary],
738                vec![
739                    (
740                        "_count",
741                        vec![],
742                        MetricProcesser::new(
743                            |existing_metric: &mut MetricMarshal,
744                             metric_value: MetricNumber,
745                             _: Vec<String>,
746                             _: Vec<String>,
747                             _: Option<Exemplar>,
748                             _: bool| {
749                                if let MetricValueMarshal::Summary(summary_value) =
750                                    &mut existing_metric.value
751                                {
752                                    let metric_value = if let Some(value) = metric_value.as_i64() {
753                                        if value < 0 {
754                                            return Err(ParseError::InvalidMetric(format!(
755                                                "Summary counts must be positive (got: {})",
756                                                value
757                                            )));
758                                        }
759                                        value as u64
760                                    } else {
761                                        return Err(ParseError::InvalidMetric(format!(
762                                            "Summary counts must be integers (got: {})",
763                                            metric_value.as_f64()
764                                        )));
765                                    };
766
767                                    if summary_value.count.is_none() {
768                                        summary_value.count = Some(metric_value);
769                                    } else {
770                                        return Err(ParseError::DuplicateMetric);
771                                    }
772                                } else {
773                                    unreachable!();
774                                }
775
776                                Ok(())
777                            },
778                        ),
779                    ),
780                    (
781                        "_sum",
782                        vec![],
783                        MetricProcesser::new(
784                            |existing_metric: &mut MetricMarshal,
785                             metric_value: MetricNumber,
786                             _: Vec<String>,
787                             _: Vec<String>,
788                             _: Option<Exemplar>,
789                             _: bool| {
790                                let value = metric_value.as_f64();
791                                if value < 0. || value.is_nan() {
792                                    return Err(ParseError::InvalidMetric(format!(
793                                        "Summary sums must be non negative (got: {})",
794                                        metric_value.as_f64()
795                                    )));
796                                }
797
798                                if let MetricValueMarshal::Summary(summary_value) =
799                                    &mut existing_metric.value
800                                {
801                                    if summary_value.sum.is_none() {
802                                        summary_value.sum = Some(metric_value);
803                                        Ok(())
804                                    } else {
805                                        Err(ParseError::DuplicateMetric)
806                                    }
807                                } else {
808                                    unreachable!();
809                                }
810                            },
811                        ),
812                    ),
813                    (
814                        "",
815                        vec!["quantile"],
816                        MetricProcesser::new(
817                            |existing_metric: &mut MetricMarshal,
818                             metric_value: MetricNumber,
819                             label_names: Vec<String>,
820                             label_values: Vec<String>,
821                             _: Option<Exemplar>,
822                             _: bool| {
823                                let value = metric_value.as_f64();
824                                if !value.is_nan() && value < 0. {
825                                    return Err(ParseError::InvalidMetric(
826                                        "Summary quantiles can't be negative".to_owned(),
827                                    ));
828                                }
829
830                                let bucket_bound: f64 = {
831                                    let bound_index =
832                                        label_names.iter().position(|s| s == "quantile").unwrap();
833                                    let bound = &label_values[bound_index];
834
835                                    match bound.parse() {
836                                        Ok(f) => f,
837                                        Err(_) => {
838                                            return Err(ParseError::InvalidMetric(format!(
839                                                "Summary bounds must be numbers (got: {})",
840                                                bound
841                                            )));
842                                        }
843                                    }
844                                };
845
846                                if !(0. ..=1.).contains(&bucket_bound) || bucket_bound.is_nan() {
847                                    return Err(ParseError::InvalidMetric(format!(
848                                        "Summary bounds must be between 0 and 1 (got: {})",
849                                        bucket_bound
850                                    )));
851                                }
852
853                                let quantile = Quantile {
854                                    quantile: bucket_bound,
855                                    value: metric_value,
856                                };
857
858                                if let MetricValueMarshal::Summary(summary_value) =
859                                    &mut existing_metric.value
860                                {
861                                    summary_value.quantiles.push(quantile);
862                                } else {
863                                    unreachable!();
864                                }
865
866                                Ok(())
867                            },
868                        ),
869                    ),
870                ],
871            ),
872        ];
873
874        let metric_type = self.family_type.as_ref().cloned().unwrap_or_default();
875
876        if !metric_type.can_have_exemplar(metric_name) && exemplar.is_some() {
877            return Err(ParseError::InvalidMetric(format!(
878                "Metric Type {:?} is not allowed exemplars",
879                metric_type
880            )));
881        }
882
883        for (test_type, actions) in handlers {
884            if test_type.contains(&metric_type) {
885                for (suffix, mandatory_labels, action) in actions {
886                    if !metric_name.ends_with(suffix) {
887                        continue;
888                    }
889
890                    let mut actual_label_names = label_names.clone();
891                    let mut actual_label_values = label_values.clone();
892                    for label in mandatory_labels {
893                        if !label_names.contains(&label.to_owned()) {
894                            return Err(ParseError::InvalidMetric(format!(
895                                "Missing mandatory label for metric: {}",
896                                label
897                            )));
898                        }
899
900                        let index = actual_label_names.iter().position(|s| s == label).unwrap();
901
902                        actual_label_names.remove(index);
903                        actual_label_values.remove(index);
904                    }
905
906                    match &self.current_label_set {
907                        None => self.current_label_set = Some(actual_label_values.clone()),
908                        Some(s) => {
909                            if s != &actual_label_values
910                                && self.seen_label_sets.contains(&actual_label_values)
911                            {
912                                return Err(ParseError::InvalidMetric(format!(
913                                    "Interwoven labelsets: Found {:?} after {:?}",
914                                    s,
915                                    self.current_label_set.as_ref().unwrap()
916                                )));
917                            }
918                        }
919                    }
920
921                    self.current_label_set = Some(actual_label_values.clone());
922                    self.seen_label_sets.push(actual_label_values.clone());
923
924                    let name = &metric_name.to_owned();
925                    self.try_set_label_names(
926                        name,
927                        LabelNames::new(name, metric_type, actual_label_names),
928                    )?;
929
930                    let metric_name = metric_name.trim_end_matches(suffix);
931                    if self.name.is_some() && self.name.as_ref().unwrap() != metric_name {
932                        return Err(ParseError::InvalidMetric(format!(
933                            "Invalid Name in metric family: {} != {}",
934                            metric_name,
935                            self.name.as_ref().unwrap()
936                        )));
937                    } else if self.name.is_none() {
938                        self.name = Some(metric_name.to_owned());
939                    }
940
941                    let (existing_metric, created) = match self
942                        .get_metric_by_labelset_mut(&actual_label_values)
943                    {
944                        Some(metric) => {
945                            match (metric.timestamp.as_ref(), timestamp.as_ref()) {
946                                (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))),
947                                (Some(_), None) | (None, Some(_)) => return Err(ParseError::InvalidMetric("Missing timestamp in family (one metric had a timestamp, another didn't)".to_string())),
948                                (Some(metric_timestamp), Some(timestamp)) if timestamp >= metric_timestamp && !metric_type.can_have_multiple_lines() => return Ok(()),
949                                _ => (metric, false)
950                            }
951                        }
952                        None => {
953                            let new_metric = self
954                                .family_type
955                                .as_ref()
956                                .unwrap_or(&OpenMetricsType::Unknown)
957                                .get_type_value();
958                            self.add_metric(MetricMarshal::new(
959                                actual_label_values.clone(),
960                                timestamp,
961                                new_metric,
962                            ));
963                            (
964                                self.get_metric_by_labelset_mut(&actual_label_values)
965                                    .unwrap(),
966                                true,
967                            )
968                        }
969                    };
970
971                    return action.0(
972                        existing_metric,
973                        metric_value,
974                        label_names,
975                        label_values,
976                        exemplar,
977                        created,
978                    );
979                }
980            }
981        }
982
983        return Err(ParseError::InvalidMetric(format!(
984            "Found weird metric name for type ({:?}): {}",
985            metric_type, metric_name
986        )));
987    }
988}
989
990impl From<MetricFamilyMarshal<OpenMetricsType>>
991    for MetricFamily<OpenMetricsType, OpenMetricsValue>
992{
993    fn from(marshal: MetricFamilyMarshal<OpenMetricsType>) -> Self {
994        assert!(marshal.name.is_some());
995
996        MetricFamily::new(
997            marshal.name.unwrap(),
998            marshal
999                .label_names
1000                .map(|names| names.names)
1001                .unwrap_or_default(),
1002            marshal.family_type.unwrap_or_default(),
1003            marshal.help.unwrap_or_default(),
1004            marshal.unit.unwrap_or_default(),
1005        )
1006        .with_samples(marshal.metrics.into_iter().map(|m| m.into()))
1007        .unwrap()
1008    }
1009}
1010
1011pub fn parse_openmetrics(
1012    exposition_bytes: &str,
1013) -> Result<MetricsExposition<OpenMetricsType, OpenMetricsValue>, ParseError> {
1014    use pest::iterators::{Pair, Pairs};
1015
1016    // A quoted name (`"http.server.requests"`) can carry escapes, a bare one can't
1017    fn parse_name(pair: Pair<Rule>) -> String {
1018        match pair.as_rule() {
1019            Rule::quotedname => unescape(pair.into_inner().next().unwrap().as_str()),
1020            _ => pair.as_str().to_owned(),
1021        }
1022    }
1023
1024    fn parse_metric_descriptor(
1025        pair: Pair<Rule>,
1026        family: &mut MetricFamilyMarshal<OpenMetricsType>,
1027    ) -> Result<(), ParseError> {
1028        assert_eq!(pair.as_rule(), Rule::metricdescriptor);
1029
1030        let mut descriptor = pair.into_inner();
1031        let descriptor_type = descriptor.next().unwrap();
1032        let metric_name = parse_name(descriptor.next().unwrap());
1033
1034        match descriptor_type.as_rule() {
1035            Rule::kw_help => {
1036                let help_text = descriptor.next().map(|s| s.as_str()).unwrap_or_default();
1037                family.set_or_test_name(metric_name)?;
1038                family.try_add_help(unescape(help_text))?;
1039            }
1040            Rule::kw_type => {
1041                let family_type = descriptor.next().unwrap().as_str();
1042                family.set_or_test_name(metric_name)?;
1043                family.try_add_type(OpenMetricsType::try_from(family_type)?)?;
1044            }
1045            Rule::kw_unit => {
1046                let unit = descriptor.next().map(|s| s.as_str()).unwrap_or_default();
1047                if family.name.is_none() || &metric_name != family.name.as_ref().unwrap() {
1048                    return Err(ParseError::InvalidMetric(
1049                        "UNIT metric name doesn't match family".to_owned(),
1050                    ));
1051                }
1052                family.try_add_unit(unit.to_string())?;
1053            }
1054            _ => unreachable!(),
1055        }
1056
1057        Ok(())
1058    }
1059
1060    fn parse_exemplar(pair: Pair<Rule>) -> Result<Exemplar, ParseError> {
1061        let mut inner = pair.into_inner();
1062
1063        let labels = inner.next().unwrap();
1064        assert_eq!(labels.as_rule(), Rule::labels);
1065
1066        let labels = parse_labels(labels.into_inner())?.into_iter().collect();
1067
1068        let id = inner.next().unwrap().as_str();
1069        let id = match id.parse() {
1070            Ok(i) => i,
1071            Err(_) => {
1072                return Err(ParseError::InvalidMetric(format!(
1073                    "Exemplar value must be a number (got: {})",
1074                    id
1075                )))
1076            }
1077        };
1078
1079        let timestamp = match inner.next() {
1080            Some(timestamp) => match timestamp.as_str().parse() {
1081                Ok(f) => Some(f),
1082                Err(_) => {
1083                    return Err(ParseError::InvalidMetric(format!(
1084                        "Exemplar timestamp must be a number (got: {})",
1085                        timestamp.as_str()
1086                    )))
1087                }
1088            },
1089            None => None,
1090        };
1091
1092        Ok(Exemplar::new(labels, id, timestamp))
1093    }
1094
1095    fn parse_labels(label_pairs: Pairs<Rule>) -> Result<Vec<(String, String)>, ParseError> {
1096        let mut labels: Vec<(String, String)> = Vec::new();
1097
1098        for label in label_pairs {
1099            assert_eq!(label.as_rule(), Rule::label);
1100            let mut label = label.into_inner();
1101            let name = parse_name(label.next().unwrap());
1102            let value = unescape(label.next().unwrap().as_str());
1103
1104            if labels.iter().any(|(n, _)| n == &name) {
1105                return Err(ParseError::InvalidMetric(format!(
1106                    "Found label `{}` twice in the same labelset",
1107                    name
1108                )));
1109            }
1110
1111            labels.push((name, value));
1112        }
1113
1114        labels.sort_unstable();
1115
1116        Ok(labels)
1117    }
1118
1119    fn parse_sample(
1120        pair: Pair<Rule>,
1121        family: &mut MetricFamilyMarshal<OpenMetricsType>,
1122    ) -> Result<(), ParseError> {
1123        assert_eq!(pair.as_rule(), Rule::sample);
1124
1125        let mut descriptor = pair.into_inner();
1126        let first = descriptor.next().unwrap();
1127
1128        let (metric_name, labels) = if first.as_rule() == Rule::namedlabels {
1129            // `{"name", label="value"}`: the quoted name sits inside the braces, ahead of the labels
1130            let mut inner = first.into_inner();
1131            let name = parse_name(inner.next().unwrap());
1132            (name, parse_labels(inner)?)
1133        } else {
1134            let labels = match descriptor.peek().unwrap().as_rule() {
1135                Rule::labels => parse_labels(descriptor.next().unwrap().into_inner())?,
1136                _ => Vec::new(),
1137            };
1138            (first.as_str().to_owned(), labels)
1139        };
1140
1141        let (label_names, label_values): (Vec<_>, Vec<_>) = labels.into_iter().unzip();
1142
1143        let value = descriptor.next().unwrap().as_str();
1144        let value = match value.parse() {
1145            Ok(f) => MetricNumber::Int(f),
1146            Err(_) => match value.parse() {
1147                Ok(f) => MetricNumber::Float(f),
1148                Err(_) => {
1149                    return Err(ParseError::InvalidMetric(format!(
1150                        "Metric Value must be a number (got: {})",
1151                        value
1152                    )));
1153                }
1154            },
1155        };
1156
1157        let mut timestamp = None;
1158        let mut exemplar = None;
1159
1160        if descriptor.peek().is_some()
1161            && descriptor.peek().as_ref().unwrap().as_rule() == Rule::timestamp
1162        {
1163            timestamp = Some(descriptor.next().unwrap().as_str().parse().unwrap());
1164        }
1165
1166        if descriptor.peek().is_some()
1167            && descriptor.peek().as_ref().unwrap().as_rule() == Rule::exemplar
1168        {
1169            exemplar = Some(parse_exemplar(descriptor.next().unwrap())?);
1170        }
1171
1172        family.process_new_metric(
1173            &metric_name,
1174            value,
1175            label_names,
1176            label_values,
1177            timestamp,
1178            exemplar,
1179        )?;
1180
1181        Ok(())
1182    }
1183
1184    fn parse_metric_family(
1185        pair: Pair<Rule>,
1186    ) -> Result<MetricFamily<OpenMetricsType, OpenMetricsValue>, ParseError> {
1187        assert_eq!(pair.as_rule(), Rule::metricfamily);
1188
1189        let mut metric_family = MetricFamilyMarshal::empty();
1190
1191        for child in pair.into_inner() {
1192            match child.as_rule() {
1193                Rule::metricdescriptor => {
1194                    if metric_family.metrics.is_empty() {
1195                        parse_metric_descriptor(child, &mut metric_family)?;
1196                    } else {
1197                        return Err(ParseError::InvalidMetric(
1198                            "Metric Descriptor after samples".to_owned(),
1199                        ));
1200                    }
1201                }
1202                Rule::sample => {
1203                    parse_sample(child, &mut metric_family)?;
1204                }
1205                _ => unreachable!(),
1206            }
1207        }
1208
1209        metric_family.validate()?;
1210
1211        Ok(metric_family.into())
1212    }
1213
1214    let exposition_marshal = OpenMetricsParser::parse(Rule::exposition, exposition_bytes)?
1215        .next()
1216        .unwrap();
1217    let mut exposition = MetricsExposition::new();
1218
1219    assert_eq!(exposition_marshal.as_rule(), Rule::exposition);
1220
1221    let mut found_eof = false;
1222    for span in exposition_marshal.into_inner() {
1223        match span.as_rule() {
1224            Rule::metricfamily => {
1225                let family = parse_metric_family(span)?;
1226
1227                if exposition.families.contains_key(&family.family_name) {
1228                    return Err(ParseError::InvalidMetric(format!(
1229                        "Found a metric family called {}, after that family was finalised",
1230                        family.family_name
1231                    )));
1232                }
1233
1234                exposition
1235                    .families
1236                    .insert(family.family_name.clone(), family);
1237            }
1238            Rule::kw_eof => {
1239                found_eof = true;
1240
1241                if span.as_span().end() != exposition_bytes.len()
1242                    && !(span.as_span().end() == exposition_bytes.len() - 1
1243                        && exposition_bytes.ends_with('\n'))
1244                {
1245                    return Err(ParseError::InvalidMetric(
1246                        "Found text after the EOF token".to_string(),
1247                    ));
1248                }
1249            }
1250            _ => unreachable!(),
1251        }
1252    }
1253
1254    if !found_eof {
1255        return Err(ParseError::InvalidMetric(
1256            "Didn't find an EOF token".to_string(),
1257        ));
1258    }
1259
1260    Ok(exposition)
1261}