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 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}