package scanner import ( "bytes" "fmt" "os" "path/filepath" "time" "github.com/rs/zerolog" ) // ScanLogger is a custom logger struct for scanning operations. type ScanLogger struct { logger *zerolog.Logger logFile *os.File buffer *bytes.Buffer } // NewScanLogger creates a new ScanLogger with a log file named based on the current datetime. // - dir: The directory to save the log file in. This should come from the config. func NewScanLogger(outputDir string) (*ScanLogger, error) { // Generate a log file name with the current datetime logFileName := fmt.Sprintf("%s-scan.log", time.Now().Format("2006-01-02_15-04-05")) // Create the logs directory if it doesn't exist if _, err := os.Stat(outputDir); os.IsNotExist(err) { err := os.Mkdir(outputDir, 0755) if err != nil { return nil, err } } // Open the log file for writing logFile, err := os.OpenFile(filepath.Join(outputDir, logFileName), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { return nil, err } // Create a buffer for storing log entries buffer := new(bytes.Buffer) // Create an array writer to wrap the JSON encoder logger := zerolog.New(buffer).With().Logger() return &ScanLogger{&logger, logFile, buffer}, nil } // NewConsoleScanLogger creates a new mock ScanLogger func NewConsoleScanLogger() (*ScanLogger, error) { output := zerolog.ConsoleWriter{ Out: os.Stdout, TimeFormat: time.DateTime, } // Create an array writer to wrap the JSON encoder logger := zerolog.New(output).With().Logger() return &ScanLogger{logger: &logger, logFile: nil, buffer: nil}, nil } func (sl *ScanLogger) LogMediaContainer(level zerolog.Level) *zerolog.Event { return sl.logger.WithLevel(level).Str("context", "MediaContainer") } func (sl *ScanLogger) LogMatcher(level zerolog.Level) *zerolog.Event { return sl.logger.WithLevel(level).Str("context", "Matcher") } func (sl *ScanLogger) LogFileHydrator(level zerolog.Level) *zerolog.Event { return sl.logger.WithLevel(level).Str("context", "FileHydrator") } func (sl *ScanLogger) LogMediaFetcher(level zerolog.Level) *zerolog.Event { return sl.logger.WithLevel(level).Str("context", "MediaFetcher") } // Done flushes the buffer to the log file and closes the file. func (sl *ScanLogger) Done() error { if sl.logFile == nil { return nil } // Write buffer contents to the log file _, err := sl.logFile.Write(sl.buffer.Bytes()) if err != nil { return err } // Sync and close the log file err = sl.logFile.Sync() if err != nil { return err } return sl.logFile.Close() } func (sl *ScanLogger) Close() { if sl.logFile == nil { return } err := sl.logFile.Sync() if err != nil { return } }