dm_database_sqllog2db/
error_logger.rs1use crate::error::{Error, ExportError, Result};
2use log::{debug, info};
3use std::fs::{File, OpenOptions};
4use std::io::{BufWriter, Write};
5use std::path::{Path, PathBuf};
6
7pub struct ErrorLogger {
9 writer: BufWriter<File>,
10 path: PathBuf,
11 count: usize,
12}
13
14impl std::fmt::Debug for ErrorLogger {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 f.debug_struct("ErrorLogger")
17 .field("path", &self.path)
18 .field("count", &self.count)
19 .finish_non_exhaustive()
20 }
21}
22
23impl ErrorLogger {
24 pub fn new<P: AsRef<Path>>(path: P) -> Result<Self> {
25 let path = path.as_ref().to_path_buf();
26
27 if let Some(parent) = path.parent().filter(|p| !p.exists()) {
28 std::fs::create_dir_all(parent).map_err(|e| {
29 Error::Export(ExportError::WriteError {
30 path: parent.to_path_buf(),
31 reason: e.to_string(),
32 })
33 })?;
34 }
35
36 let file = OpenOptions::new()
37 .create(true)
38 .append(true)
39 .open(&path)
40 .map_err(|e| {
41 Error::Export(ExportError::WriteError {
42 path: path.clone(),
43 reason: e.to_string(),
44 })
45 })?;
46
47 info!("Error logger initialized: {}", path.display());
48
49 Ok(Self {
50 writer: BufWriter::new(file),
51 path,
52 count: 0,
53 })
54 }
55
56 pub fn log_parse_error(
58 &mut self,
59 file_path: &str,
60 error: &dm_database_parser_sqllog::ParseError,
61 ) -> Result<()> {
62 writeln!(self.writer, "{file_path} | {error:?}").map_err(|e| {
63 Error::Export(ExportError::WriteError {
64 path: self.path.clone(),
65 reason: e.to_string(),
66 })
67 })?;
68 self.count += 1;
69 Ok(())
70 }
71
72 pub fn finalize(&mut self) -> Result<()> {
73 self.writer.flush().map_err(|e| {
74 Error::Export(ExportError::WriteError {
75 path: self.path.clone(),
76 reason: format!("flush failed: {e}"),
77 })
78 })?;
79 if self.count > 0 {
80 info!(
81 "Error log: {} ({} records)",
82 self.path.display(),
83 self.count
84 );
85 } else {
86 debug!("No parse errors");
87 }
88 Ok(())
89 }
90}