Skip to main content

dm_database_sqllog2db/
error_logger.rs

1use 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
7/// 将解析失败的原始数据记录到文件
8pub 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    /// 记录来自 dm-database-parser-sqllog 的解析错误(格式:file | error | line)
57    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}