openmetrics_parser/openmetrics/
parsers.rs

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