1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//! Logger utility for application-wide logging
//!
//! This module provides a custom logger implementation that works alongside
//! the standard log crate, but adds file output capabilities.
use std::fs::File;
use std::io::{self, Write};
use std::path::Path;
use std::sync::Mutex;
use log::{Log, Record, Level, Metadata, LevelFilter};
/// Custom logger implementation
pub struct Logger {
/// File handle for log output
file: Mutex<Option<File>>,
}
impl Logger {
/// Creates a new logger instance
///
/// # Arguments
///
/// * `log_file` - Path to the log file
///
/// # Returns
///
/// A new Logger instance or an error if the file cannot be created
pub fn new(log_file: &str) -> io::Result<Self> {
let file = File::create(Path::new(log_file))?;
Ok(Logger {
file: Mutex::new(Some(file)),
})
}
/// Logs a message to the log file
///
/// # Arguments
///
/// * `message` - The message to log
pub fn log(&self, message: &str) -> io::Result<()> {
if let Some(file) = &mut *self.file.lock().unwrap() {
writeln!(file, "{}", message)?;
file.flush()?;
}
Ok(())
}
/// Logs GeoKey directory information in a formatted way
///
/// # Arguments
///
/// * `geo_key_data` - Vector of GeoKey data tuples
pub fn print_geo_key_directory(&self, geo_key_data: Vec<(u16, &str, u16, u16, u16, String)>) -> io::Result<()> {
self.log("GeoKey Directory:")?;
for (key_id, key_name, tiff_tag_location, count, _, value_str) in geo_key_data {
let message = format!(
" Key ID: {} ({}), Location: {}, Count: {}, Value: {}",
key_id, key_name, tiff_tag_location, count, value_str
);
self.log(&message)?;
}
Ok(())
}
/// Static method to initialize the global logger
pub fn init_global_logger(log_file: &str) -> io::Result<()> {
// Create a dedicated logger for the log crate
let global_logger = Logger::new(log_file)?;
// Set up the global logger - we'll ignore the SetLoggerError
// since we only call this once at startup
if let Err(_) = log::set_boxed_logger(Box::new(global_logger)) {
// Logger was already set - this should not happen in normal usage
eprintln!("Warning: Global logger was already initialized");
}
log::set_max_level(LevelFilter::Debug);
Ok(())
}
}
// Implement the Log trait to make our Logger work with the log crate
impl Log for Logger {
fn enabled(&self, metadata: &Metadata) -> bool {
metadata.level() <= Level::Debug
}
fn log(&self, record: &Record) {
if self.enabled(record.metadata()) {
let message = format!("[{}] {}", record.level(), record.args());
let _ = self.log(&message);
// Also print to console
println!("{}", message);
}
}
fn flush(&self) {
// Already flushing in the log method
}
}