1use std::io::{self, Write};
2
3use super::LogMessage;
4
5pub trait LoggerOutput {
6 fn log(&mut self, message: &LogMessage);
7}
8
9#[derive(Debug, Clone, Copy, Default)]
10pub struct NullOutput;
11
12impl LoggerOutput for NullOutput {
13 fn log(&mut self, _message: &LogMessage) {}
14}
15
16pub struct WriterOutput<W: Write> {
17 writer: W,
18}
19
20impl<W: Write> WriterOutput<W> {
21 pub fn new(writer: W) -> Self {
22 Self { writer }
23 }
24
25 pub fn flush(&mut self) -> io::Result<()> {
26 self.writer.flush()
27 }
28}
29
30impl<W: Write> LoggerOutput for WriterOutput<W> {
31 fn log(&mut self, message: &LogMessage) {
32 let message = match message {
33 LogMessage::LoadModule(module) => format!("Load Module {module}"),
34 LogMessage::UnloadModule(module) => format!("Unload Module {module}"),
35 LogMessage::RollbackLoadModule(module) => format!("Rollback Load Module {module}"),
36 LogMessage::RollbackUnloadModule(module) => format!("Rollback Unload Module {module}"),
37 LogMessage::CreateDir(path) => format!("Create Directory {}", path.to_string_lossy()),
38 LogMessage::CreateSymlink { src, dst } => format!(
39 "Create Symlink {} -> {}",
40 dst.to_string_lossy(),
41 src.to_string_lossy()
42 ),
43 LogMessage::RemoveDir(path) => format!("Remove Directory {}", path.to_string_lossy()),
44 LogMessage::RemoveSymlink { src, dst } => format!(
45 "Remove Symlink {} -> {}",
46 dst.to_string_lossy(),
47 src.to_string_lossy()
48 ),
49 };
50
51 let _ = writeln!(self.writer, "{message}").inspect_err(|err| {
53 eprintln!("Warning! Write log output to writer failed: {err}");
54 });
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use std::io::Cursor;
61
62 use super::*;
63 use crate::test_utils::prelude::*;
64
65 #[gtest]
66 fn writer_output() -> Result<()> {
67 let mut buf = Cursor::new(Vec::new());
68 let mut output = WriterOutput::new(&mut buf);
69 output.log(&LogMessage::CreateDir(PathBuf::from("test_dir")));
70 output.log(&LogMessage::CreateSymlink {
71 src: PathBuf::from("src"),
72 dst: PathBuf::from("dst"),
73 });
74 output.flush()?;
75
76 let content = String::from_utf8(buf.into_inner())?;
77 expect_eq!(
78 content,
79 "Create Directory test_dir\nCreate Symlink dst -> src\n"
80 );
81
82 Ok(())
83 }
84}