oo_ide/log_matcher/
schema.rs1use serde::Deserialize;
8
9fn default_schema_version() -> u32 {
10 1
11}
12
13#[derive(Debug, Clone, Deserialize)]
19pub struct LogMatcherDef {
20 pub id: String,
22 pub source: String,
24 #[serde(default)]
26 pub priority: u32,
27 #[serde(default = "default_schema_version")]
29 pub schema_version: u32,
30 pub start: StartDef,
32 #[serde(default)]
34 pub body: Vec<BodyRuleDef>,
35 #[serde(default)]
37 pub max_lines: Option<u32>,
38 pub end: EndDef,
40 pub emit: EmitDef,
42}
43
44#[derive(Debug, Clone, Deserialize)]
49pub struct StartDef {
50 #[serde(rename = "match")]
52 pub pattern: String,
53}
54
55#[derive(Debug, Clone, Deserialize)]
60pub struct BodyRuleDef {
61 #[serde(rename = "match")]
63 pub pattern: String,
64 #[serde(default)]
66 pub optional: bool,
67 #[serde(default)]
69 pub repeat: bool,
70}
71
72#[derive(Debug, Clone, Deserialize)]
77pub struct EndDef {
78 pub condition: String,
80}
81
82#[derive(Debug, Clone, Deserialize)]
87pub struct EmitDef {
88 pub severity: String,
90 pub message: String,
92 #[serde(default)]
94 pub file: Option<String>,
95 #[serde(default)]
97 pub line: Option<String>,
98 #[serde(default)]
100 pub column: Option<String>,
101 #[serde(default)]
103 pub code: Option<String>,
104}
105
106#[cfg(test)]
111mod tests {
112 use super::*;
113
114 fn parse(yaml: &str) -> LogMatcherDef {
115 serde_saphyr::from_str(yaml).expect("should parse")
116 }
117
118 #[test]
119 fn parse_minimal_matcher() {
120 let yaml = r#"
121id: rust.cargo.error
122source: cargo
123start:
124 match: '^error'
125end:
126 condition: next_start
127emit:
128 severity: error
129 message: "{{ message }}"
130"#;
131 let def = parse(yaml);
132 assert_eq!(def.id, "rust.cargo.error");
133 assert_eq!(def.source, "cargo");
134 assert_eq!(def.priority, 0);
135 assert_eq!(def.schema_version, 1);
136 assert_eq!(def.start.pattern, "^error");
137 assert!(def.body.is_empty());
138 assert!(def.max_lines.is_none());
139 assert_eq!(def.end.condition, "next_start");
140 assert_eq!(def.emit.severity, "error");
141 assert_eq!(def.emit.message, "{{ message }}");
142 }
143
144 #[test]
145 fn parse_with_body_rules() {
146 let yaml = r#"
147id: my.matcher
148source: test
149start:
150 match: '^start'
151body:
152 - match: '^\s+\|'
153 repeat: true
154 optional: true
155end:
156 condition: blank_line
157emit:
158 severity: warning
159 message: "found"
160"#;
161 let def = parse(yaml);
162 assert_eq!(def.body.len(), 1);
163 assert!(def.body[0].repeat);
164 assert!(def.body[0].optional);
165 }
166
167 #[test]
168 fn parse_all_emit_fields() {
169 let yaml = r#"
170id: full.emit
171source: test
172start:
173 match: '^e'
174end:
175 condition: next_start
176emit:
177 severity: error
178 message: "{{ msg }}"
179 file: "{{ file }}"
180 line: "{{ line }}"
181 column: "{{ col }}"
182 code: "E{{ code }}"
183"#;
184 let def = parse(yaml);
185 assert!(def.emit.file.is_some());
186 assert!(def.emit.line.is_some());
187 assert!(def.emit.column.is_some());
188 assert!(def.emit.code.is_some());
189 }
190
191 #[test]
192 fn parse_max_lines() {
193 let yaml = r#"
194id: capped
195source: test
196start:
197 match: '^e'
198max_lines: 50
199end:
200 condition: next_start
201emit:
202 severity: error
203 message: "err"
204"#;
205 let def = parse(yaml);
206 assert_eq!(def.max_lines, Some(50));
207 }
208}