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