(line: &str)
| 195 | } |
| 196 | |
| 197 | fn parse_log_entry(line: &str) -> Option<LogEntry> { |
| 198 | let trimmed = line.trim(); |
| 199 | if !trimmed.starts_with('{') { |
| 200 | return None; |
| 201 | } |
| 202 | |
| 203 | let payload: Value = serde_json::from_str(trimmed).ok()?; |
| 204 | let process_path = payload |
| 205 | .get("processImagePath") |
| 206 | .and_then(Value::as_str) |
| 207 | .unwrap_or(""); |
| 208 | let process = process_path |
| 209 | .rsplit('/') |
| 210 | .next() |
| 211 | .filter(|value| !value.is_empty()) |
| 212 | .unwrap_or("unknown") |
| 213 | .to_owned(); |
| 214 | |
| 215 | Some(LogEntry { |
| 216 | timestamp: string_field(&payload, "timestamp"), |
| 217 | level: non_empty_string_field(&payload, "messageType") |
| 218 | .unwrap_or_else(|| "Default".to_owned()), |
| 219 | process, |
| 220 | pid: payload.get("processID").cloned().unwrap_or(Value::Null), |
| 221 | subsystem: string_field(&payload, "subsystem"), |
| 222 | category: string_field(&payload, "category"), |
| 223 | message: non_empty_string_field(&payload, "eventMessage") |
| 224 | .or_else(|| non_empty_string_field(&payload, "formatString")) |
| 225 | .unwrap_or_default(), |
| 226 | }) |
| 227 | } |
| 228 | |
| 229 | fn string_field(payload: &Value, key: &str) -> String { |
| 230 | non_empty_string_field(payload, key).unwrap_or_default() |
no test coverage detected