1use std::collections::BTreeMap;
4
5use nom::{
6 branch::alt,
7 bytes::complete::{is_not, tag, take_while, take_while1},
8 character::complete::{char, digit1},
9 combinator::{map, map_res, opt, recognize, value},
10 error::ParseError,
11 multi::fold_many0,
12 number::complete::double,
13 sequence::{delimited, pair, preceded},
14 Parser,
15};
16
17type IResult<'a, O> = Result<(&'a str, O), nom::Err<ErrorKind>>;
21
22#[derive(Debug, snafu::Snafu, PartialEq, Eq)]
23pub enum ErrorKind {
24 #[snafu(display("invalid metric type, parsing: `{}`", input))]
25 InvalidMetricKind { input: String },
26 #[snafu(display("expected token {:?}, parsing: `{}`", expected, input))]
27 ExpectedToken {
28 expected: &'static str,
29 input: String,
30 },
31 #[snafu(display("expected blank space or tab, parsing: `{}`", input))]
32 ExpectedSpace { input: String },
33 #[snafu(display("expected token {:?}, parsing: `{}`", expected, input))]
34 ExpectedChar { expected: char, input: String },
35 #[snafu(display("name must start with [a-zA-Z_], parsing: `{}`", input))]
36 ParseNameError { input: String },
37 #[snafu(display("parse float value error, parsing: `{}`", input))]
38 ParseFloatError { input: String },
39 #[snafu(display("parse timestamp error, parsing: `{}`", input))]
40 ParseTimestampError { input: String },
41
42 #[snafu(display("error kind: {:?}, parsing: `{}`", kind, input))]
44 Nom {
45 input: String,
46 kind: nom::error::ErrorKind,
47 },
48}
49
50impl From<ErrorKind> for nom::Err<ErrorKind> {
51 fn from(error: ErrorKind) -> Self {
52 nom::Err::Error(error)
53 }
54}
55
56impl From<nom::Err<ErrorKind>> for ErrorKind {
57 fn from(error: nom::Err<ErrorKind>) -> Self {
58 match error {
59 nom::Err::Incomplete(_) => unreachable!(),
61 nom::Err::Error(e) | nom::Err::Failure(e) => e,
62 }
63 }
64}
65
66impl nom::error::ParseError<&str> for ErrorKind {
67 fn from_error_kind(input: &str, kind: nom::error::ErrorKind) -> Self {
68 ErrorKind::Nom {
69 input: input.to_owned(),
70 kind,
71 }
72 }
73
74 fn append(_: &str, _: nom::error::ErrorKind, other: Self) -> Self {
75 other
76 }
77}
78
79type NomErrorType<'a> = (&'a str, nom::error::ErrorKind);
80
81type NomError<'a> = nom::Err<NomErrorType<'a>>;
82
83#[derive(Clone, Copy, Debug, Eq, PartialEq)]
84pub enum MetricKind {
85 Counter,
86 Gauge,
87 Histogram,
88 Summary,
89 Untyped,
90}
91
92#[derive(Debug, Clone, PartialEq, Eq)]
93pub struct Header {
94 pub metric_name: String,
95 pub kind: MetricKind,
96}
97
98#[derive(Debug, Clone, PartialEq)]
99pub struct Metric {
100 pub name: String,
101 pub labels: BTreeMap<String, String>,
102 pub value: f64,
103 pub timestamp: Option<i64>,
104}
105
106impl Metric {
107 fn parse(input: &str) -> IResult<Self> {
117 let input = trim_space(input);
118 let (input, name) = parse_name(input)?;
119 let (input, labels) = Self::parse_labels(input)?;
120 let (input, value) = Self::parse_value(input)?;
121 let (input, timestamp) = Self::parse_timestamp(input)?;
122 Ok((
123 input,
124 Metric {
125 name,
126 labels,
127 value,
128 timestamp,
129 },
130 ))
131 }
132
133 pub(crate) fn parse_value(input: &str) -> IResult<f64> {
135 let input = trim_space(input);
136 alt((
137 value(f64::INFINITY, tag("+Inf")),
138 value(f64::NEG_INFINITY, tag("-Inf")),
139 value(f64::NAN, tag("Nan")),
140 value(f64::NAN, tag("NaN")),
143 double,
144 ))
145 .parse(input)
146 .map_err(|_: NomError| {
147 ErrorKind::ParseFloatError {
148 input: input.to_owned(),
149 }
150 .into()
151 })
152 }
153
154 fn parse_timestamp(input: &str) -> IResult<Option<i64>> {
155 let input = trim_space(input);
156 opt(map_res(
157 recognize(pair(opt(char('-')), digit1)),
158 |s: &str| s.parse(),
159 ))
160 .parse(input)
161 .map_err(|_: NomError| {
162 ErrorKind::ParseTimestampError {
163 input: input.to_owned(),
164 }
165 .into()
166 })
167 }
168
169 fn parse_name_value(input: &str) -> IResult<(String, String)> {
170 map(
171 (parse_name, match_char('='), Self::parse_escaped_string),
172 |(name, _, value)| (name, value),
173 )
174 .parse(input)
175 }
176
177 fn element_parser(input: &str) -> IResult<Option<(String, String)>> {
182 match Self::parse_name_value(input) {
183 Ok((input, result)) => Ok((input, Some(result))),
184 Err(nom::Err::Error(parse_name_value_error)) => match match_char('}')(input) {
185 Ok((input, _)) => Ok((input, None)),
186 Err(nom::Err::Error(_)) => Err(nom::Err::Error(parse_name_value_error)),
187 Err(failure) => Err(failure),
188 },
189 Err(failure) => Err(failure),
190 }
191 }
192
193 fn parse_labels_inner(mut input: &str) -> IResult<BTreeMap<String, String>> {
194 let sep = match_char(',');
195
196 let mut result = BTreeMap::new();
197 loop {
198 match Self::element_parser(input)? {
199 (inner_input, None) => {
200 input = inner_input;
201 break;
202 }
203 (inner_input, Some((name, value))) => {
204 result.insert(name, value);
205
206 let inner_input = match sep(inner_input) {
210 Ok((inner_input, _)) => inner_input,
211 Err(sep_err) => match match_char('}')(inner_input) {
212 Ok((inner_input, _)) => {
213 input = inner_input;
214 break;
215 }
216 Err(_) => return Err(sep_err),
217 },
218 };
219
220 input = inner_input;
221 }
222 }
223 }
224 Ok((input, result))
225 }
226
227 fn parse_labels(input: &str) -> IResult<BTreeMap<String, String>> {
229 let input = trim_space(input);
230
231 match opt(char('{')).parse(input) {
232 Ok((input, None)) => Ok((input, BTreeMap::new())),
233 Ok((input, Some(_))) => Self::parse_labels_inner(input),
234 Err(failure) => Err(failure),
235 }
236 }
237
238 fn parse_escaped_string(input: &str) -> IResult<String> {
242 #[derive(Debug)]
243 enum StringFragment<'a> {
244 Literal(&'a str),
245 EscapedChar(char),
246 }
247
248 let parse_string_fragment = alt((
249 map(is_not("\"\\"), StringFragment::Literal),
250 map(
251 preceded(
252 char('\\'),
253 alt((
254 value('\n', char('n')),
255 value('"', char('"')),
256 value('\\', char('\\')),
257 )),
258 ),
259 StringFragment::EscapedChar,
260 ),
261 ));
262
263 let input = trim_space(input);
264
265 let build_string = fold_many0(
266 parse_string_fragment,
267 String::new,
268 |mut result, fragment| {
269 match fragment {
270 StringFragment::Literal(s) => result.push_str(s),
271 StringFragment::EscapedChar(c) => result.push(c),
272 }
273 result
274 },
275 );
276
277 fn match_quote(input: &str) -> IResult<char> {
278 char('"')(input).map_err(|_: NomError| {
279 ErrorKind::ExpectedChar {
280 expected: '"',
281 input: input.to_owned(),
282 }
283 .into()
284 })
285 }
286
287 delimited(match_quote, build_string, match_quote).parse(input)
288 }
289}
290
291impl Header {
292 fn space1(input: &str) -> IResult<()> {
293 take_while1(|c| c == ' ' || c == '\t')(input)
294 .map_err(|_: NomError| {
295 ErrorKind::ExpectedSpace {
296 input: input.to_owned(),
297 }
298 .into()
299 })
300 .map(|(input, _)| (input, ()))
301 }
302
303 fn parse(input: &str) -> IResult<Self> {
305 let input = trim_space(input);
306 let (input, _) = char('#')(input).map_err(|_: NomError| ErrorKind::ExpectedChar {
307 expected: '#',
308 input: input.to_owned(),
309 })?;
310 let input = trim_space(input);
311 let (input, _) = tag("TYPE")(input).map_err(|_: NomError| ErrorKind::ExpectedToken {
312 expected: "TYPE",
313 input: input.to_owned(),
314 })?;
315 let (input, _) = Self::space1(input)?;
316 let (input, metric_name) = parse_name(input)?;
317 let (input, _) = Self::space1(input)?;
318 let (input, kind) = alt((
319 value(MetricKind::Counter, tag("counter")),
320 value(MetricKind::Gauge, tag("gauge")),
321 value(MetricKind::Summary, tag("summary")),
322 value(MetricKind::Histogram, tag("histogram")),
323 value(MetricKind::Untyped, tag("untyped")),
324 ))
325 .parse(input)
326 .map_err(|_: NomError| ErrorKind::InvalidMetricKind {
327 input: input.to_owned(),
328 })?;
329 Ok((input, Header { metric_name, kind }))
330 }
331}
332
333#[derive(Debug, Clone, PartialEq)]
336pub enum Line {
337 Header(Header),
338 Metric(Metric),
339}
340
341impl Line {
342 pub(crate) fn parse(input: &str) -> Result<Option<Self>, ErrorKind> {
344 let input = input.trim();
345 if input.is_empty() {
346 return Ok(None);
347 }
348
349 let metric_error = match Metric::parse(input) {
350 Ok((_, metric)) => {
351 return Ok(Some(Line::Metric(metric)));
352 }
353 Err(e) => e.into(),
354 };
355
356 let header_error = match Header::parse(input) {
357 Ok((_, header)) => {
358 return Ok(Some(Line::Header(header)));
359 }
360 Err(e) => e.into(),
361 };
362
363 if let Ok((input, _)) = char::<_, NomErrorType>('#')(input) {
364 if (sp, tag::<_, _, NomErrorType>("TYPE")).parse(input).is_ok() {
365 return Err(header_error);
366 }
367 Ok(None)
368 } else {
369 Err(metric_error)
370 }
371 }
372}
373
374fn parse_name(input: &str) -> IResult<String> {
376 let input = trim_space(input);
377 let (input, (a, b)) = pair(
378 take_while1(|c: char| c.is_alphabetic() || c == '_'),
379 take_while(|c: char| c.is_alphanumeric() || c == '_' || c == ':'),
380 )
381 .parse(input)
382 .map_err(|_: NomError| ErrorKind::ParseNameError {
383 input: input.to_owned(),
384 })?;
385 Ok((input, a.to_owned() + b))
386}
387
388fn trim_space(input: &str) -> &str {
389 input.trim_start_matches([' ', '\t'])
390}
391
392fn sp<'a, E: ParseError<&'a str>>(i: &'a str) -> nom::IResult<&'a str, &'a str, E> {
393 take_while(|c| c == ' ' || c == '\t')(i)
394}
395
396fn match_char(c: char) -> impl Fn(&str) -> IResult<char> {
397 move |input| {
398 preceded(sp, char(c)).parse(input).map_err(|_: NomError| {
399 ErrorKind::ExpectedChar {
400 expected: c,
401 input: input.to_owned(),
402 }
403 .into()
404 })
405 }
406}
407
408#[cfg(test)]
409mod test {
410 use vector_common::btreemap;
411
412 use super::*;
413
414 #[test]
415 fn test_parse_escaped_string() {
416 fn wrap(s: &str) -> String {
417 format!(" \t \"{s}\" .")
418 }
419
420 let tail = " .";
422
423 let input = wrap("");
424 let (left, r) = Metric::parse_escaped_string(&input).unwrap();
425 assert_eq!(left, tail);
426 assert_eq!(r, "");
427
428 let input = wrap(r"a\\ asdf");
429 let (left, r) = Metric::parse_escaped_string(&input).unwrap();
430 assert_eq!(left, tail);
431 assert_eq!(r, "a\\ asdf");
432
433 let input = wrap(r#"\"\""#);
434 let (left, r) = Metric::parse_escaped_string(&input).unwrap();
435 assert_eq!(left, tail);
436 assert_eq!(r, "\"\"");
437
438 let input = wrap(r#"\"\\\n"#);
439 let (left, r) = Metric::parse_escaped_string(&input).unwrap();
440 assert_eq!(left, tail);
441 assert_eq!(r, "\"\\\n");
442
443 let input = wrap(r"\\n");
444 let (left, r) = Metric::parse_escaped_string(&input).unwrap();
445 assert_eq!(left, tail);
446 assert_eq!(r, "\\n");
447
448 let input = wrap(r#" 😂 "#);
449 let (left, r) = Metric::parse_escaped_string(&input).unwrap();
450 assert_eq!(left, tail);
451 assert_eq!(r, " 😂 ");
452 }
453
454 #[test]
455 fn test_parse_name() {
456 fn wrap(s: &str) -> String {
457 format!(" \t {s} .")
458 }
459 let tail = " .";
460
461 let input = wrap("abc_def");
462 let (left, r) = parse_name(&input).unwrap();
463 assert_eq!(left, tail);
464 assert_eq!(r, "abc_def");
465
466 let input = wrap("__9A0bc_def__");
467 let (left, r) = parse_name(&input).unwrap();
468 assert_eq!(left, tail);
469 assert_eq!(r, "__9A0bc_def__");
470
471 let input = wrap("99");
472 assert!(parse_name(&input).is_err());
473
474 let input = wrap("consul_serf_events_consul:new_leader");
475 let (left, r) = parse_name(&input).unwrap();
476 assert_eq!(left, tail);
477 assert_eq!(r, "consul_serf_events_consul:new_leader");
478 }
479
480 #[test]
481 fn test_parse_header() {
482 fn wrap(s: &str) -> String {
483 format!(" \t {s} .")
484 }
485 let tail = " .";
486
487 let input = wrap("# TYPE abc_def counter");
488 let (left, r) = Header::parse(&input).unwrap();
489 assert_eq!(left, tail);
490 assert_eq!(
491 r,
492 Header {
493 metric_name: "abc_def".into(),
494 kind: MetricKind::Counter,
495 }
496 );
497
498 let input = wrap("# TYPE abc_def counteraaaaaaaaaaa");
500 let (_, r) = Header::parse(&input).unwrap();
501 assert_eq!(
502 r,
503 Header {
504 metric_name: "abc_def".into(),
505 kind: MetricKind::Counter,
506 }
507 );
508
509 let input = wrap("#TYPE \t abc_def \t gauge");
510 let (left, r) = Header::parse(&input).unwrap();
511 assert_eq!(left, tail);
512 assert_eq!(
513 r,
514 Header {
515 metric_name: "abc_def".into(),
516 kind: MetricKind::Gauge,
517 }
518 );
519
520 let input = wrap("# TYPE abc_def histogram");
521 let (left, r) = Header::parse(&input).unwrap();
522 assert_eq!(left, tail);
523 assert_eq!(
524 r,
525 Header {
526 metric_name: "abc_def".into(),
527 kind: MetricKind::Histogram,
528 }
529 );
530
531 let input = wrap("# TYPE abc_def summary");
532 let (left, r) = Header::parse(&input).unwrap();
533 assert_eq!(left, tail);
534 assert_eq!(
535 r,
536 Header {
537 metric_name: "abc_def".into(),
538 kind: MetricKind::Summary,
539 }
540 );
541
542 let input = wrap("# TYPE abc_def untyped");
543 let (left, r) = Header::parse(&input).unwrap();
544 assert_eq!(left, tail);
545 assert_eq!(
546 r,
547 Header {
548 metric_name: "abc_def".into(),
549 kind: MetricKind::Untyped,
550 }
551 );
552 }
553
554 #[test]
555 fn test_parse_value() {
556 fn wrap(s: &str) -> String {
557 format!(" \t {s} .")
558 }
559 let tail = " .";
560
561 let input = wrap("+Inf");
562 let (left, r) = Metric::parse_value(&input).unwrap();
563 assert_eq!(left, tail);
564 assert!(r.is_infinite() && r.is_sign_positive());
565
566 let input = wrap("-Inf");
567 let (left, r) = Metric::parse_value(&input).unwrap();
568 assert_eq!(left, tail);
569 assert!(r.is_infinite() && r.is_sign_negative());
570
571 let input = wrap("Nan");
572 let (left, r) = Metric::parse_value(&input).unwrap();
573 assert_eq!(left, tail);
574 assert!(r.is_nan());
575
576 let input = wrap(&(u64::MAX).to_string());
577 let (left, r) = Metric::parse_value(&input).unwrap();
578 assert_eq!(left, tail);
579 assert_eq!(r as u64, u64::MAX);
580
581 let input = wrap(&(2_u64.pow(53)).to_string());
591 let (left, r) = Metric::parse_value(&input).unwrap();
592 assert_eq!(left, tail);
593 assert_eq!(r as u64, 2_u64.pow(53));
594
595 let input = wrap(&(2_u64.pow(53) - 1).to_string());
596 let (left, r) = Metric::parse_value(&input).unwrap();
597 assert_eq!(left, tail);
598 assert_eq!(r as u64, 2_u64.pow(53) - 1);
599
600 let input = wrap(&(u32::MAX as u64 + 1).to_string());
601 let (left, r) = Metric::parse_value(&input).unwrap();
602 assert_eq!(left, tail);
603 assert_eq!(r as u64, u32::MAX as u64 + 1);
604
605 let tests = [
606 ("0", 0.0f64),
607 ("0.25", 0.25f64),
608 ("-10.25", -10.25f64),
609 ("-10e-25", -10e-25f64),
610 ("-10e+25", -10e+25f64),
611 ("2020", 2020.0f64),
612 ("1.", 1f64),
613 ];
614 for (text, value) in &tests {
615 let input = wrap(text);
616 let (left, r) = Metric::parse_value(&input).unwrap();
617 assert_eq!(left, tail);
618 assert!((r - *value).abs() < f64::EPSILON);
619 }
620 }
621
622 #[test]
623 fn test_parse_labels() {
624 fn wrap(s: &str) -> String {
625 format!(" \t {s} .")
626 }
627 let tail = " .";
628
629 let input = wrap("{}");
630 let (left, r) = Metric::parse_labels(&input).unwrap();
631 assert_eq!(left, tail);
632 assert_eq!(r, BTreeMap::new());
633
634 let input = wrap(r#"{name="value"}"#);
635 let (left, r) = Metric::parse_labels(&input).unwrap();
636 assert_eq!(left, tail);
637 assert_eq!(r, BTreeMap::from([("name".into(), "value".into())]));
638
639 let input = wrap(r#"{name="value",}"#);
640 let (left, r) = Metric::parse_labels(&input).unwrap();
641 assert_eq!(left, tail);
642 assert_eq!(r, BTreeMap::from([("name".into(), "value".into())]));
643
644 let input = wrap(r#"{ name = "" ,b="a=b" , a="},", _c = "\""}"#);
645 let (left, r) = Metric::parse_labels(&input).unwrap();
646 assert_eq!(
647 r,
648 btreemap! {"name" => "", "a" => "},", "b" => "a=b", "_c" => "\""}
649 );
650 assert_eq!(left, tail);
651
652 let input = wrap("100");
653 let (left, r) = Metric::parse_labels(&input).unwrap();
654 assert_eq!(left, "100".to_owned() + tail);
655 assert_eq!(r, BTreeMap::new());
656
657 let input = wrap(r#"{name="value}"#);
660 let error = Metric::parse_labels(&input).unwrap_err().into();
661 assert!(matches!(
662 error,
663 ErrorKind::ExpectedChar { expected: '"', .. }
664 ));
665
666 let input = wrap(r#"{ a="b" c="d" }"#);
667 let error = Metric::parse_labels(&input).unwrap_err().into();
668 assert!(matches!(
669 error,
670 ErrorKind::ExpectedChar { expected: ',', .. }
671 ));
672
673 let input = wrap(r#"{ a="b" ,, c="d" }"#);
674 let error = Metric::parse_labels(&input).unwrap_err().into();
675 assert!(matches!(error, ErrorKind::ParseNameError { .. }));
676 }
677
678 #[test]
679 fn test_parse_timestamp() {
680 assert_eq!(Metric::parse_timestamp(""), Ok(("", None)));
681 assert_eq!(Metric::parse_timestamp("123"), Ok(("", Some(123))));
682 assert_eq!(Metric::parse_timestamp(" -23"), Ok(("", Some(-23))));
683 assert_eq!(
685 Metric::parse_timestamp("9223372036854775807"),
686 Ok(("", Some(9223372036854775807i64)))
687 );
688 assert_eq!(
689 Metric::parse_timestamp("-9223372036854775808"),
690 Ok(("", Some(-9223372036854775808i64)))
691 );
692 assert_eq!(
694 Metric::parse_timestamp("9223372036854775809"),
695 Ok(("9223372036854775809", None))
696 );
697 assert_eq!(
698 Metric::parse_timestamp("-9223372036854775809"),
699 Ok(("-9223372036854775809", None))
700 );
701 }
702
703 #[test]
704 fn test_parse_line() {
705 let input = r#"
706 # HELP http_requests_total The total number of HTTP requests.
707 # TYPE http_requests_total counter
708 http_requests_total{method="post",code="200"} 1027 1395066363000
709 http_requests_total{method="post",code="400"} 3 1395066363000
710
711 # Escaping in label values:
712 msdos_file_access_time_seconds{path="C:\\DIR\\FILE.TXT",error="Cannot find file:\n\"FILE.TXT\""} 1.458255915e9
713
714 # Minimalistic line:
715 metric_without_timestamp_and_labels 12.47
716
717 # A weird metric from before the epoch:
718 something_weird{problem="division by zero"} +Inf -3982045
719
720 # A histogram, which has a pretty complex representation in the text format:
721 # HELP http_request_duration_seconds A histogram of the request duration.
722 # TYPE http_request_duration_seconds histogram
723 http_request_duration_seconds_bucket{le="0.05"} 24054
724 http_request_duration_seconds_bucket{le="0.1"} 33444
725 http_request_duration_seconds_bucket{le="0.2"} 100392
726 http_request_duration_seconds_bucket{le="0.5"} 129389
727 http_request_duration_seconds_bucket{le="1"} 133988
728 http_request_duration_seconds_bucket{le="+Inf"} 144320
729 http_request_duration_seconds_sum 53423
730 http_request_duration_seconds_count 144320
731
732 # Finally a summary, which has a complex representation, too:
733 # HELP rpc_duration_seconds A summary of the RPC duration in seconds.
734 # TYPE rpc_duration_seconds summary
735 rpc_duration_seconds{quantile="0.01"} 3102
736 rpc_duration_seconds{quantile="0.05"} 3272
737 rpc_duration_seconds{quantile="0.5"} 4773
738 rpc_duration_seconds{quantile="0.9"} 9001
739 rpc_duration_seconds{quantile="0.99"} 76656
740 rpc_duration_seconds_sum 1.7560473e+07
741 rpc_duration_seconds_count 2693
742 "#;
743 assert!(input.lines().map(Line::parse).all(|r| r.is_ok()));
744 }
745}