// logger.go package main import ( "fmt" "log" "os" "runtime" "time" ) type Logger struct { *log.Logger file *os.File level LogLevel } type LogLevel int const ( DEBUG LogLevel = iota INFO WARN ERROR ) var ( instance *Logger // Map for converting string to LogLevel logLevelMap = map[string]LogLevel{ "DEBUG": DEBUG, "INFO": INFO, "WARN": WARN, "ERROR": ERROR, } ) // Initialize creates a new logger instance with specified level func Initialize(logPath string) (*Logger, error) { if instance != nil { return instance, nil } file, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { return nil, fmt.Errorf("failed to open log file: %v", err) } // Default to INFO if no level specified logger := &Logger{ Logger: log.New(file, "", 0), file: file, level: INFO, } instance = logger return logger, nil } // SetLogLevel sets the logging level from a string func (l *Logger) SetLogLevel(levelStr string) error { level, ok := logLevelMap[levelStr] if !ok { return fmt.Errorf("invalid log level: %s. Must be one of: DEBUG, INFO, WARN, ERROR", levelStr) } l.level = level return nil } // GetLogLevel returns the current logging level as a string func (l *Logger) GetLogLevel() string { for str, level := range logLevelMap { if level == l.level { return str } } return "UNKNOWN" } // GetLogger returns the singleton logger instance func GetLogger() *Logger { return instance } // Close closes the log file func (l *Logger) Close() error { if l.file != nil { return l.file.Close() } return nil } func (l *Logger) log(level LogLevel, format string, v ...interface{}) { if l == nil { return } // Check if this message should be logged based on current level if level < l.level { return } // Get caller information _, file, line, _ := runtime.Caller(2) // Create timestamp timestamp := time.Now().Format("2006-01-02 15:04:05") // Create level string levelStr := "INFO" switch level { case DEBUG: levelStr = "DEBUG" case WARN: levelStr = "WARN" case ERROR: levelStr = "ERROR" } // Format message message := fmt.Sprintf(format, v...) // Final log format logLine := fmt.Sprintf("[%s] [%s] [%s:%d] %s\n", timestamp, levelStr, file, line, message, ) l.Logger.Print(logLine) } // Debug logs a debug message func (l *Logger) Debug(format string, v ...interface{}) { l.log(DEBUG, format, v...) } // Info logs an info message func (l *Logger) Info(format string, v ...interface{}) { l.log(INFO, format, v...) } // Warn logs a warning message func (l *Logger) Warn(format string, v ...interface{}) { l.log(WARN, format, v...) } // Error logs an error message func (l *Logger) Error(format string, v ...interface{}) { l.log(ERROR, format, v...) } // HTTPRequest logs an HTTP request func (l *Logger) HTTPRequest(method, path, username string, statusCode int) { l.log(INFO, "HTTP %s %s - User: %s - Status: %d", method, path, username, statusCode, ) } // UserAction logs user actions like login, logout, etc. func (l *Logger) UserAction(username, action string) { l.log(INFO, "User Action - Username: %s - Action: %s", username, action, ) } // DatabaseAction logs database operations func (l *Logger) DatabaseAction(operation, details string) { l.log(INFO, "Database Action - Operation: %s - Details: %s", operation, details, ) }