vrl/stdlib/
to_syslog_severity.rs

1use crate::compiler::prelude::*;
2
3fn to_syslog_severity(level: &Value) -> Resolved {
4    let level = level.try_bytes_utf8_lossy()?;
5    // Severity levels: https://en.wikipedia.org/wiki/Syslog#Severity_level
6    let severity = match &level[..] {
7        "emerg" | "panic" => 0,
8        "alert" => 1,
9        "crit" => 2,
10        "err" | "error" => 3,
11        "warning" | "warn" => 4,
12        "notice" => 5,
13        "info" => 6,
14        "debug" => 7,
15        _ => return Err(format!("syslog level {level} not valid").into()),
16    };
17    Ok(severity.into())
18}
19
20#[derive(Clone, Copy, Debug)]
21pub struct ToSyslogSeverity;
22
23impl Function for ToSyslogSeverity {
24    fn identifier(&self) -> &'static str {
25        "to_syslog_severity"
26    }
27
28    fn usage(&self) -> &'static str {
29        "Converts the `value`, a Syslog [log level keyword](https://en.wikipedia.org/wiki/Syslog#Severity_level), into a Syslog integer severity level (`0` to `7`)."
30    }
31
32    fn category(&self) -> &'static str {
33        Category::Convert.as_ref()
34    }
35
36    fn internal_failure_reasons(&self) -> &'static [&'static str] {
37        &["`value` is not a valid Syslog level keyword."]
38    }
39
40    fn return_kind(&self) -> u16 {
41        kind::INTEGER
42    }
43
44    fn return_rules(&self) -> &'static [&'static str] {
45        &[
46            "The now-deprecated keywords `panic`, `error`, and `warn` are converted to `0`, `3`, and `4` respectively.",
47        ]
48    }
49
50    fn parameters(&self) -> &'static [Parameter] {
51        const PARAMETERS: &[Parameter] = &[Parameter::required(
52            "value",
53            kind::BYTES,
54            "The Syslog level keyword to convert.",
55        )];
56        PARAMETERS
57    }
58
59    fn examples(&self) -> &'static [Example] {
60        &[
61            example! {
62                title: "Coerce to Syslog severity",
63                source: r#"to_syslog_severity!("alert")"#,
64                result: Ok("1"),
65            },
66            example! {
67                title: "invalid",
68                source: "to_syslog_severity!(s'foobar')",
69                result: Err(
70                    r#"function call error for "to_syslog_severity" at (0:30): syslog level foobar not valid"#,
71                ),
72            },
73        ]
74    }
75
76    fn compile(
77        &self,
78        _state: &state::TypeState,
79        _ctx: &mut FunctionCompileContext,
80        arguments: ArgumentList,
81    ) -> Compiled {
82        let value = arguments.required("value");
83
84        Ok(ToSyslogSeverityFn { value }.as_expr())
85    }
86}
87
88#[derive(Debug, Clone)]
89struct ToSyslogSeverityFn {
90    value: Box<dyn Expression>,
91}
92
93impl FunctionExpression for ToSyslogSeverityFn {
94    fn resolve(&self, ctx: &mut Context) -> Resolved {
95        let level = self.value.resolve(ctx)?;
96        to_syslog_severity(&level)
97    }
98
99    fn type_def(&self, _: &state::TypeState) -> TypeDef {
100        TypeDef::integer().fallible()
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107    use crate::value;
108
109    test_function![
110        to_level => ToSyslogSeverity;
111
112        emergency {
113            args: func_args![value: value!("emerg")],
114            want: Ok(value!(0)),
115            tdef: TypeDef::integer().fallible(),
116        }
117
118        alert {
119            args: func_args![value: value!("alert")],
120            want: Ok(value!(1)),
121            tdef: TypeDef::integer().fallible(),
122        }
123
124        critical {
125            args: func_args![value: value!("crit")],
126            want: Ok(value!(2)),
127            tdef: TypeDef::integer().fallible(),
128        }
129
130        error {
131            args: func_args![value: value!("err")],
132            want: Ok(value!(3)),
133            tdef: TypeDef::integer().fallible(),
134        }
135
136        warning {
137            args: func_args![value: value!("warn")],
138            want: Ok(value!(4)),
139            tdef: TypeDef::integer().fallible(),
140        }
141
142        notice {
143            args: func_args![value: value!("notice")],
144            want: Ok(value!(5)),
145            tdef: TypeDef::integer().fallible(),
146        }
147
148        informational {
149            args: func_args![value: value!("info")],
150            want: Ok(value!(6)),
151            tdef: TypeDef::integer().fallible(),
152        }
153
154        debug {
155            args: func_args![value: value!("debug")],
156            want: Ok(value!(7)),
157            tdef: TypeDef::integer().fallible(),
158        }
159
160        invalid_level_1 {
161            args: func_args![value: value!("oopsie")],
162            want: Err("syslog level oopsie not valid"),
163            tdef: TypeDef::integer().fallible(),
164        }
165
166        invalid_level_2 {
167            args: func_args![value: value!("aww schucks")],
168            want: Err("syslog level aww schucks not valid"),
169            tdef: TypeDef::integer().fallible(),
170        }
171    ];
172}