package utils import ( "bufio" "fmt" "os" "strings" "sync" "time" ) const ( LOG_LEVEL_DEBUG = iota LOG_LEVEL_INFO LOG_LEVEL_WARNING LOG_LEVEL_ERROR LOG_LEVEL_FATAL ) const rfc3339milli = "2006-01-02T15:04:05.000Z07:00" const Seperator = " | " var log_level_msg = [...]string{"DEBUG", "INFO", "WARN", "ERROR", "FATAL"} var ( once sync.Once stdout *bufio.Writer stderr *bufio.Writer ) // Logger includes the module name and an output destination. type Logger struct { mu sync.Mutex Module string Symbol string } // NewLogger creates a new Logger with output set to os.Stdout by default. func NewLogger(module, symbol string) *Logger { once.Do(func() { stdout = bufio.NewWriter(os.Stdout) stderr = bufio.NewWriter(os.Stderr) }) ret := &Logger{ Module: module, Symbol: symbol, } if ret.Symbol == "" { ret.Symbol = "-" } return ret } // logMessage logs a message with the given severity. func (l *Logger) logMessage(severity int, format string, a ...any) { timestamp := time.Now().Format(rfc3339milli) formattedMessage := fmt.Sprintf(format, a...) var out *bufio.Writer if severity < LOG_LEVEL_ERROR { out = stdout } else { out = stderr } l.mu.Lock() defer l.mu.Unlock() out.WriteString(strings.Join([]string{ timestamp, l.Module, l.Symbol, log_level_msg[severity], formattedMessage}, Seperator)) out.WriteByte('\n') out.Flush() } // Debug logs an debug message. func (l *Logger) Debug(format string, a ...any) { l.logMessage(LOG_LEVEL_DEBUG, format, a...) } // Info logs an info message. func (l *Logger) Info(format string, a ...any) { l.logMessage(LOG_LEVEL_INFO, format, a...) } // Warn logs an warn message. func (l *Logger) Warn(format string, a ...any) { l.logMessage(LOG_LEVEL_WARNING, format, a...) } // Error logs an error message. func (l *Logger) Error(format string, a ...any) { l.logMessage(LOG_LEVEL_ERROR, format, a...) } // Fatal logs an fatal message and exit. func (l *Logger) Fatal(format string, a ...any) { l.logMessage(LOG_LEVEL_FATAL, format, a...) os.Exit(125) }