package logging import ( "fmt" "io" "log" "os" "strings" ) // higher log level means more logging... const ( ERROR = iota WARNING INFO DEBUG TRACE ) 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 = WARNING ) func (l *logStream) Printf(format string, a ...interface{}) { // describe(a) if LogLevel < l.logLevel { return } // if no specific logger is configured for this logstrea, write to stdout... 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.init(multi, " TRACE: ", TRACE) Debug.init(multi, " DEBUG: ", DEBUG) Info.init(multi, " INFO: ", INFO) Warning.init(multi, "WARNING: ", WARNING) Error.init(multi, " ERROR: ", ERROR) }