package main import ( "fmt" "io" "log" "os" "strings" ) const ( ERROR = iota WARNING INFO DEBUG TRACE ) const ( LoggerCreated int = iota // return code if the logger creates a new logger LoggerExists // retun cde in the case that there is already a logger ErrorCreatingLogger // in case of error creating the logger ) var logLevelStringMap = map[string]int{ "error": ERROR, "warning": WARNING, "info": INFO, "debug": DEBUG, "trace": TRACE, } type logOutput interface { Printf(format string, a ...interface{}) // Println(format string, a ...interface{}) init(m *io.Writer, s string, ll int) } type logStream struct { s *log.Logger logLevel int } var ( Trace logStream Debug logStream Info logStream Warning logStream Error logStream DefaultLogger logStream LogLevel int ) func (l *logStream) Printf(format string, a ...interface{}) { // describe(a) if LogLevel > l.logLevel { return } if l.s == nil { fmt.Printf(format, a...) return } l.s.Printf(format, a...) } func (l *logStream) init(m io.Writer, s string, ll int) { l.s = log.New(m, s, log.Ldate|log.Ltime|log.Lshortfile) l.logLevel = ll } // function to parse string representation of log level into integer - if there // is no match of the string, it will return 0 which maps to error only // logging...perhaps this could be made more explicit func determineLogLevel(lstr string) int { lstrLowerCase := strings.ToLower(lstr) return logLevelStringMap[lstrLowerCase] } func initLogger(logFile string, logLevelStr string, logToConsole bool) { LogLevel = determineLogLevel(logLevelStr) file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) var multi io.Writer if err != nil { log.Println("Failed to open log file:", logFile, ":", err) multi = io.MultiWriter(os.Stdout) } else { if logToConsole { multi = io.MultiWriter(file, os.Stdout) } else { multi = io.MultiWriter(file) } } // Trace = log.New(multi, " TRACE: ", log.Ldate|log.Ltime|log.Lshortfile) // Debug = log.New(multi, " DEBUG: ", log.Ldate|log.Ltime|log.Lshortfile) // Info = log.New(multi, " INFO: ", log.Ldate|log.Ltime|log.Lshortfile) // Warning = log.New(multi, "WARNING: ", log.Ldate|log.Ltime|log.Lshortfile) // Error = log.New(multi, " ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) // Trace = logStream{} Trace.init(multi, " TRACE: ", TRACE) Debug.init(multi, " DEBUG: ", DEBUG) Info.init(multi, " INFO: ", INFO) Warning.init(multi, "WARNING: ", WARNING) Error.init(multi, " ERROR: ", ERROR) } // Printf prints output to the logger if the DefaultLogger is non nil // - otherwise it does nothing func Printf(format string, a ...interface{}) { // describe(a) if DefaultLogger == nil { fmt.Printf(format, a...) return } DefaultLogger.Printf(format, a...) }