vrl/stdlib/
parse_logfmt.rs

1use super::parse_key_value::{ParseKeyValueFn, Whitespace};
2use crate::compiler::prelude::*;
3
4#[derive(Clone, Copy, Debug)]
5pub struct ParseLogFmt;
6
7impl Function for ParseLogFmt {
8    fn identifier(&self) -> &'static str {
9        "parse_logfmt"
10    }
11
12    fn usage(&self) -> &'static str {
13        indoc! {r#"
14            Parses the `value` in [logfmt](https://brandur.org/logfmt).
15
16            * Keys and values can be wrapped using the `"` character.
17            * `"` characters can be escaped by the `\` character.
18            * As per this [logfmt specification](https://pkg.go.dev/github.com/kr/logfmt#section-documentation), the `parse_logfmt` function accepts standalone keys and assigns them a Boolean value of `true`.
19        "#}
20    }
21
22    fn category(&self) -> &'static str {
23        Category::Parse.as_ref()
24    }
25
26    fn internal_failure_reasons(&self) -> &'static [&'static str] {
27        &["`value` is not a properly formatted key-value string"]
28    }
29
30    fn return_kind(&self) -> u16 {
31        kind::OBJECT
32    }
33
34    fn parameters(&self) -> &'static [Parameter] {
35        const PARAMETERS: &[Parameter] = &[Parameter::required(
36            "value",
37            kind::BYTES,
38            "The string to parse.",
39        )];
40        PARAMETERS
41    }
42
43    fn examples(&self) -> &'static [Example] {
44        &[
45            example! {
46                title: "Parse simple logfmt log",
47                source: r#"parse_logfmt!("zork=zook zonk=nork")"#,
48                result: Ok(r#"{"zork": "zook", "zonk": "nork"}"#),
49            },
50            example! {
51                title: "Parse logfmt log",
52                source: indoc! {r#"
53                    parse_logfmt!(
54                        "@timestamp=\"Sun Jan 10 16:47:39 EST 2021\" level=info msg=\"Stopping all fetchers\" tag#production=stopping_fetchers id=ConsumerFetcherManager-1382721708341 module=kafka.consumer.ConsumerFetcherManager"
55                    )
56                "#},
57                result: Ok(indoc! {r#"{
58                    "@timestamp": "Sun Jan 10 16:47:39 EST 2021",
59                    "level": "info",
60                    "msg": "Stopping all fetchers",
61                    "tag#production": "stopping_fetchers",
62                    "id": "ConsumerFetcherManager-1382721708341",
63                    "module": "kafka.consumer.ConsumerFetcherManager"
64                }"#}),
65            },
66            example! {
67                title: "Parse logfmt log with standalone key",
68                source: r#"parse_logfmt!("zork=zook plonk zonk=nork")"#,
69                result: Ok(r#"{"plonk": true, "zork": "zook", "zonk": "nork"}"#),
70            },
71        ]
72    }
73
74    fn compile(
75        &self,
76        _state: &state::TypeState,
77        _ctx: &mut FunctionCompileContext,
78        arguments: ArgumentList,
79    ) -> Compiled {
80        let value = arguments.required("value");
81
82        // The parse_logfmt function is just an alias for `parse_key_value` with the following
83        // parameters for the delimiters.
84        let key_value_delimiter = Some(expr!("="));
85        let field_delimiter = Some(expr!(" "));
86        let whitespace = Whitespace::Lenient;
87        let standalone_key = Some(expr!(true));
88
89        Ok(ParseKeyValueFn {
90            value,
91            key_value_delimiter,
92            field_delimiter,
93            whitespace,
94            standalone_key,
95        }
96        .as_expr())
97    }
98}