/* A package that provides advanced logging facilities. */ package monolog import ( "fmt" "os" "path/filepath" "runtime" "strings" "time" "unicode" ) type Logger interface { Log(level string, file string, line int, format string, args ...interface{}) Close() } func GetCallerName(depth int) { pc := make([]uintptr, depth+1) runtime.Callers(depth, pc) for i, v := range pc { fun := runtime.FuncForPC(v) if fun != nil { fmt.Printf("GetCallerName %d %s\n", i, fun.Name()) } else { fmt.Printf("GetCallerName %d nil\n", i) } } } func (me *FileLogger) WriteLog(depth int, level string, format string, args ...interface{}) { _, file, line, ok := runtime.Caller(depth) if !ok { file = "unknown" line = 0 } me.Log(level, file, line, format, args...) } func (me *FileLogger) NamedLog(name string, format string, args ...interface{}) { me.WriteLog(2, name, format, args...) } func (me *FileLogger) Info(format string, args ...interface{}) { me.WriteLog(2, "INFO", format, args...) } func (me *FileLogger) Warning(format string, args ...interface{}) { me.WriteLog(2, "WARNING", format, args...) } func (me *FileLogger) Error(format string, args ...interface{}) { me.WriteLog(2, "ERROR", format, args...) } func (me *FileLogger) Fatal(format string, args ...interface{}) { me.WriteLog(2, "FATAL", format, args...) } func (me *FileLogger) Debug(format string, args ...interface{}) { me.WriteLog(2, "DEBUG", format, args...) } type FileLogger struct { filename string file *os.File } func (me *FileLogger) Close() { if me.file != nil { me.file.Close() } me.file = nil } func (me *FileLogger) Log(level string, file string, line int, format string, args ...interface{}) { fileshort := filepath.Base(file) now := time.Now().Format(time.RFC3339) fmt.Fprintf(me.file, "%s: %s: %s: %d: ", now, level, fileshort, line) if args != nil && len(args) > 0 { fmt.Fprintf(me.file, format, args...) } else { fmt.Fprint(me.file, format) } fmt.Fprint(me.file, "\n") } func NewFileLogger(filename string) (logger Logger, err error) { file, err := os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660) if err != nil { return nil, err } return &FileLogger{filename, file}, nil } func NewStderrLogger() (logger Logger, err error) { return &FileLogger{"/dev/stderr", os.Stderr}, nil } func NewStdoutLogger() (logger Logger, err error) { return &FileLogger{"/dev/stderr", os.Stdout}, nil } type Logbook struct { loggers []Logger levels map[string]bool } func NewLog() *Logbook { loggers := make([]Logger, 32) levels := make(map[string]bool) return &Logbook{loggers, levels} } func (me *Logbook) AddLogger(logger Logger) { me.loggers = append(me.loggers, logger) } func (me *Logbook) EnableLevel(level string) { me.levels[level] = true } func (me *Logbook) DisableLevel(level string) { me.levels[level] = false } func (me * Logbook) GetLevels() map[string] bool { return me.levels } func enableDisableSplitter(c rune) bool { ok := (!unicode.IsLetter(c)) ok = ok && (!unicode.IsNumber(c)) ok = ok && (c != '_') return ok } func (me *Logbook) EnableLevels(list string) { to_enable := strings.FieldsFunc(list, enableDisableSplitter) for _, level := range to_enable { me.EnableLevel(level) } } func (me *Logbook) DisableLevels(list string) { to_disable := strings.FieldsFunc(list, enableDisableSplitter) for _, level := range to_disable { me.DisableLevel(level) } } func (me *Logbook) LogVa(name string, file string, line int, format string, args ...interface{}) { enabled, ok := me.levels[name] if (!ok) || (!enabled) { return } for _, logger := range me.loggers { if logger != nil { logger.Log(name, file, line, format, args...) } } } func (me *Logbook) Close() { for index, logger := range me.loggers { if logger != nil { logger.Close() me.loggers[index] = nil } } } func (lb *Logbook) EnabledLevels() []string { var res []string for name, ll := range lb.levels { if ll { res = append(res, name) } } return res } var DefaultLog *Logbook func init() { DefaultLog = NewLog() // runtime.SetFinalizer(DefaultLog, DefaultLog.Close) } func EnableLevel(level string) { DefaultLog.EnableLevel(level) } func DisableLevel(level string) { DefaultLog.DisableLevel(level) } func EnableLevels(list string) { DefaultLog.EnableLevels(list) } func DisableLevels(list string) { DefaultLog.DisableLevels(list) } func GetLevels() map[string] bool { return DefaultLog.GetLevels(); } func AddLogger(logger Logger, err error) { if err == nil { DefaultLog.AddLogger(logger) } } func Setup(name string, stderr bool, stdout bool) { if name != "" { AddLogger(NewFileLogger(name)) } if stderr { AddLogger(NewStderrLogger()) } if stdout { AddLogger(NewStdoutLogger()) } EnableLevel("INFO") EnableLevel("WARNING") EnableLevel("ERROR") EnableLevel("FATAL") } func Close() { DefaultLog.Close() } func WriteLog(depth int, name string, format string, args ...interface{}) { _, file, line, ok := runtime.Caller(depth) if !ok { file = "unknown" line = 0 } DefaultLog.LogVa(name, file, line, format, args...) } func Log(name string, format string, args ...interface{}) { WriteLog(2, name, format, args) } func Printf(format string, args ...interface{}) { WriteLog(2, "INFO", format, args...) } func Info(format string, args ...interface{}) { WriteLog(2, "INFO", format, args...) } func Warning(format string, args ...interface{}) { WriteLog(2, "WARNING", format, args...) } func Error(format string, args ...interface{}) { WriteLog(2, "ERROR", format, args...) } func Fatal(format string, args ...interface{}) { WriteLog(2, "FATAL", format, args...) } func Debug(format string, args ...interface{}) { WriteLog(2, "DEBUG", format, args...) } func エラ(err error) { WriteLog(2, "ERROR", "%s", err.Error()) } func WriteError(err error) { WriteLog(2, "ERROR", "%s", err.Error()) }