From 8152713ad22f94abee40b3c6bf18e4f54e10f7fa Mon Sep 17 00:00:00 2001 From: kenshinx Date: Tue, 13 Oct 2015 18:44:42 +0800 Subject: [PATCH] Log Module support file and console handler --- log.go | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++ log_test.go | 60 ++++++++++++++++++ 2 files changed, 233 insertions(+) create mode 100644 log.go create mode 100644 log_test.go diff --git a/log.go b/log.go new file mode 100644 index 0000000..a355bf9 --- /dev/null +++ b/log.go @@ -0,0 +1,173 @@ +package main + +import ( + "fmt" + "log" + "os" +) + +const LOG_OUTPUT_BUFFER = 1024 + +const ( + LevelDebug = iota + LevelInfo + LevelNotice + LevelWarn + LevelError +) + +type logMesg struct { + Level int + Mesg string +} + +type LoggerHandler interface { + Setup(config map[string]interface{}) error + Write(mesg *logMesg) +} + +type GoDNSLogger struct { + level int + mesgs chan *logMesg + outputs map[string]LoggerHandler +} + +func NewLogger() *GoDNSLogger { + logger := &GoDNSLogger{ + mesgs: make(chan *logMesg, LOG_OUTPUT_BUFFER), + outputs: make(map[string]LoggerHandler), + } + go logger.Run() + return logger +} + +func (l *GoDNSLogger) SetLogger(handlerType string, config map[string]interface{}) { + var handler LoggerHandler + switch handlerType { + case "console": + handler = NewConsoleHandler() + case "file": + handler = NewFileHandler() + default: + panic("Unknown log handler.") + } + + handler.Setup(config) + l.outputs[handlerType] = handler +} + +func (l *GoDNSLogger) SetLevel(level int) { + l.level = level +} + +func (l *GoDNSLogger) Run() { + for { + select { + case mesg := <-l.mesgs: + for _, handler := range l.outputs { + handler.Write(mesg) + } + } + } +} + +func (l *GoDNSLogger) writeMesg(mesg string, level int) { + if l.level > level { + return + } + + lm := &logMesg{ + Level: level, + Mesg: mesg, + } + + l.mesgs <- lm +} + +func (l *GoDNSLogger) Debug(format string, v ...interface{}) { + mesg := fmt.Sprintf("[DEBUG] "+format, v...) + l.writeMesg(mesg, LevelDebug) +} + +func (l *GoDNSLogger) Info(format string, v ...interface{}) { + mesg := fmt.Sprintf("[INFO] "+format, v...) + l.writeMesg(mesg, LevelInfo) +} + +func (l *GoDNSLogger) Notice(format string, v ...interface{}) { + mesg := fmt.Sprintf("[NOTICE] "+format, v...) + l.writeMesg(mesg, LevelNotice) +} + +func (l *GoDNSLogger) Warn(format string, v ...interface{}) { + mesg := fmt.Sprintf("[WARN] "+format, v...) + l.writeMesg(mesg, LevelWarn) +} + +func (l *GoDNSLogger) Error(format string, v ...interface{}) { + mesg := fmt.Sprintf("[ERROR] "+format, v...) + l.writeMesg(mesg, LevelError) +} + +type ConsoleHandler struct { + level int + logger *log.Logger +} + +func NewConsoleHandler() LoggerHandler { + return new(ConsoleHandler) +} + +func (h *ConsoleHandler) Setup(config map[string]interface{}) error { + if _level, ok := config["level"]; ok { + level := _level.(int) + h.level = level + } + h.logger = log.New(os.Stdout, "", log.Ldate|log.Ltime) + return nil + +} + +func (h *ConsoleHandler) Write(lm *logMesg) { + if h.level <= lm.Level { + h.logger.Println(lm.Mesg) + } +} + +type FileHandler struct { + level int + file string + logger *log.Logger +} + +func NewFileHandler() LoggerHandler { + return new(FileHandler) +} + +func (h *FileHandler) Setup(config map[string]interface{}) error { + if level, ok := config["level"]; ok { + h.level = level.(int) + } + + if file, ok := config["file"]; ok { + h.file = file.(string) + output, err := os.Create(h.file) + if err != nil { + return err + } + + h.logger = log.New(output, "", log.Ldate|log.Ltime) + } + + return nil +} + +func (h *FileHandler) Write(lm *logMesg) { + if h.logger == nil { + return + } + + if h.level <= lm.Level { + h.logger.Println(lm.Mesg) + } +} diff --git a/log_test.go b/log_test.go new file mode 100644 index 0000000..ca7eb26 --- /dev/null +++ b/log_test.go @@ -0,0 +1,60 @@ +package main + +import ( + "bufio" + "os" + "testing" + "time" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestConsole(t *testing.T) { + logger := NewLogger() + logger.SetLogger("console", nil) + logger.SetLevel(LevelInfo) + + logger.Debug("debug") + logger.Info("info") + logger.Notice("notiece") + logger.Warn("warn") + logger.Error("error") +} + +func TestFile(t *testing.T) { + logger := NewLogger() + logger.SetLogger("file", map[string]interface{}{"file": "test.log"}) + logger.SetLevel(LevelInfo) + + logger.Debug("debug") + logger.Info("info") + logger.Notice("notiece") + logger.Warn("warn") + logger.Error("error") + + time.Sleep(time.Second) + + f, err := os.Open("test.log") + if err != nil { + t.Fatal(err) + } + b := bufio.NewReader(f) + linenum := 0 + for { + line, _, err := b.ReadLine() + if err != nil { + break + } + if len(line) > 0 { + linenum++ + } + } + + Convey("Test Log File Handler", t, func() { + Convey("file line nums should be 4", func() { + So(linenum, ShouldEqual, 4) + }) + }) + + os.Remove("test.log") +}