/* A package that provides advanced logging facilities. */ package monolog import ( "os" "fmt" "time" "runtime" "path/filepath" "unicode" "strings" ) 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 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 } } } 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 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 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()) }