From 993d40a7b62b78ec06c454527f9f586027de098c Mon Sep 17 00:00:00 2001 From: hans Date: Tue, 2 Apr 2019 13:55:41 +0800 Subject: [PATCH] init --- .gitignore | 1 + README.md | 15 ++++ filelog.go | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 3 + gokit.go | 181 +++++++++++++++++++++++++++++++++++++++++++ gokit_test.go | 55 ++++++++++++++ kafka.go | 1 + syslog.go | 69 +++++++++++++++++ 8 files changed, 532 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 filelog.go create mode 100644 go.mod create mode 100644 gokit.go create mode 100644 gokit_test.go create mode 100644 kafka.go create mode 100644 syslog.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..62c8935 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..0ded5fb --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +#### Usage +``` + + import git.qietv.work/public/logkit + + + logkit.Init(FIlE, "test", logkit.LevelDebug) + defer logkit.Exit() + + logkit.Info("this is a log") + + logkit.Infof("this is log %s", "arg") + + +``` \ No newline at end of file diff --git a/filelog.go b/filelog.go new file mode 100644 index 0000000..438f2a8 --- /dev/null +++ b/filelog.go @@ -0,0 +1,207 @@ +package logkit + +import ( + "bufio" + "bytes" + "fmt" + "os" + "path/filepath" + "sync" + "time" +) + +type bufferNode struct { + bytes.Buffer + next *bufferNode +} + +type mFileLogger struct { + writer *bufferWriter + mu sync.Mutex + + filepath string + name string + freeList *bufferNode + freeListMu sync.Mutex + flushInterval time.Duration + fileSplitSize uint64 + bufferSize int +} + +type bufferWriter struct { + *bufio.Writer + logPath string + logName string + file *os.File + slot int + startTime time.Time + byteSize uint64 // The number of bytes written to this file + maxFileSize uint64 + bufferSize int +} + +func (w *mFileLogger) getBuffer() *bufferNode { + w.freeListMu.Lock() + b := w.freeList + if b != nil { + w.freeList = b.next + } + w.freeListMu.Unlock() + if b == nil { + b = new(bufferNode) + } else { + b.next = nil + b.Reset() + } + return b +} + +func (w *mFileLogger) putBuffer(b *bufferNode) { + if b.Len() >= 256 { + // Let big buffers die with gc. + return + } + w.freeListMu.Lock() + b.next = w.freeList + w.freeList = b + w.freeListMu.Unlock() +} + +func (w *mFileLogger) Exit() { + w.flush() +} + +func NewFileLogger(path, name string, flushInterval time.Duration, fileSplitSize uint64, bufferSize int) Writer { + writer := &mFileLogger{ + filepath: path, + name: name, + flushInterval: flushInterval, + fileSplitSize: fileSplitSize, + bufferSize: bufferSize, + } + go writer.flushDaemon() + return writer +} + +func (w *mFileLogger) flushDaemon() { + //for _ = range time.NewTicker(w.flushInterval).C { + // w.flush() + //} +} + +func (w *mFileLogger) flush() { + w.writer.Flush() + w.writer.Sync() +} + +func (w *mFileLogger) Write(level Level, msg string) { + + buf := w.getBuffer() + buf.WriteString(msg) + w.mu.Lock() + defer w.mu.Unlock() + + writer := w.writer + + if writer == nil { + w.writer = &bufferWriter{ + logPath: w.filepath, + logName: w.name, + maxFileSize: w.fileSplitSize, + bufferSize: w.bufferSize, + } + writer = w.writer + } + + if err := writer.checkRotate(time.Now()); err != nil { + fmt.Println("[logkit] check rotate err: " + err.Error()) + return + } + + writer.Write(buf.Bytes()) + w.putBuffer(buf) + +} + +func (bufferW *bufferWriter) Write(p []byte) (int, error) { + n, err := bufferW.Writer.Write(p) + bufferW.byteSize += uint64(n) + return n, err +} + +func (bufferW *bufferWriter) Sync() error { + return bufferW.file.Sync() +} + +func (bufferW *bufferWriter) checkRotate(now time.Time) error { + if bufferW.file == nil { + return bufferW.rotate(now, 0) + } + sYear, sMonth, sDay := bufferW.startTime.Date() + year, month, day := now.Date() + if year != sYear || month != sMonth || day != sDay { + return bufferW.rotate(now, 0) + } + if bufferW.byteSize >= bufferW.maxFileSize { + return bufferW.rotate(now, bufferW.slot+1) + } + return nil +} + +func (bufferW *bufferWriter) write(p []byte) (int, error) { + n, err := bufferW.Writer.Write(p) + bufferW.byteSize += uint64(n) + return n, err +} + +func (bufferW *bufferWriter) rotate(oldTime time.Time, slot int) error { + if bufferW.file != nil { + bufferW.Flush() + bufferW.file.Close() + var newFileName string + + year, month, day := oldTime.Date() + + if slot > 0 { + newFileName = fmt.Sprintf("%s-%02d%02d%02d.%02d", bufferW.logPath, year, month, day, slot-1) + } else { + newFileName = fmt.Sprintf("%s-%02d%02d%02d", bufferW.logPath, year, month, day) + } + os.Rename(bufferW.logPath, newFileName) + } + + if err := bufferW.openFile(bufferW.logPath, bufferW.logName); err != nil { + return fmt.Errorf("rotate file error: %#v", err) + } + fileInfo, _ := bufferW.file.Stat() + bufferW.byteSize = uint64(fileInfo.Size()) + bufferW.Writer = bufio.NewWriterSize(bufferW.file, bufferW.bufferSize) + bufferW.slot = slot + bufferW.startTime = time.Now() + bufferW.byteSize = 0 + + return nil +} + +func (bufferW *bufferWriter) openFile(fileName, logName string) error { + var file *os.File + var err error + for { + file, err = os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err == nil { + break + } + // try to create all the parent directories for specified log file + // if it doesn't exist + if os.IsNotExist(err) { + err2 := os.MkdirAll(filepath.Dir(fileName), 0755) + if err2 != nil { + return err + } + continue + } + return err + } + bufferW.file = file + return nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..dfa1989 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module log-kit + +go 1.12 diff --git a/gokit.go b/gokit.go new file mode 100644 index 0000000..7742569 --- /dev/null +++ b/gokit.go @@ -0,0 +1,181 @@ +package logkit + +import ( + "fmt" + "time" +) + +var ( + inited bool + + logWriter Writer + + logLevel = LevelInfo + + logLevelName string + + logName string + + alsoStdout bool + + levelToNames = map[Level]string{ + LevelFatal: "FATAL", + LevelError: "ERROR", + LevelWarn: "WARN", + LevelInfo: "INFO", + LevelDebug: "DEBUG", + LevelTrace: "TRACE", + } +) + +//Level 日志等级 +type Level byte + +const ( + Default Level = iota + LevelTrace + LevelDebug + LevelInfo + LevelWarn + LevelError + LevelFatal +) +type Channel byte +const ( + FIlE Channel = iota + SYSLOG + KAFKA +) +type Writer interface { + //Write 写日志 + Write(Level, string) + //Exit 日志退出 + Exit() +} + +func Exit() { + logWriter.Exit() + +} + +func Init(channel Channel,name string, level Level) error { + if inited { + return fmt.Errorf("logkit has been inited") + } + + if name != "" { + logName = name + } else { + fmt.Errorf("log name must not be empty") + } + + logLevel = level + logLevelName = getLevelName(level) + + if logWriter == nil && channel == FIlE { + logWriter = NewFileLogger(logName+".log", logName, time.Second * 5, 1204 * 1024 * 1800, 256 * 1024 ) + inited = true + } + if logWriter == nil && channel == SYSLOG { + logWriter ,_ = NewSyslogWriter("", "", level, name) + } + return nil +} + +func getLevelName(level Level) string { + levelName, _ := levelToNames[level] + return levelName +} + +func format(msg string) string { + return fmt.Sprintf("%s [%s] %s \n", time.Now().Format("2006-01-02 15:04:05.999"), logLevelName, msg) +} + +func write(level Level, msg string) { + if !inited { + fmt.Println(time.Now().Format("2006-01-02 15:04:05") + " [" + logLevelName + "] " + msg) + return + } + logWriter.Write(level, format(msg)) + if alsoStdout { + fmt.Println(time.Now().Format("2006-01-02 15:04:05") + " [" + logLevelName + "] " + msg) + } +} + +func level() Level { + return logLevel +} + + +func Debug(str string) { + if level() <= LevelDebug { + write(LevelDebug, str) + } +} + +func Debugs(args ...interface{}) { + if level() <= LevelDebug { + write(LevelDebug, fmt.Sprintln(args...)) + } +} + +func Debugf(format string, args ...interface{}) { + if level() <= LevelDebug { + write(LevelDebug, fmt.Sprintf(format, args...)) + } +} + +func Info(str string) { + if level() <= LevelInfo { + write(LevelInfo, str) + } +} + +func Infos(args ...interface{}) { + if level() <= LevelInfo { + write(LevelInfo, fmt.Sprintln(args...)) + } +} + +func Infof(format string, args ...interface{}) { + if level() <= LevelInfo { + write(LevelInfo, fmt.Sprintf(format, args...)) + } +} + +func Warn(str string) { + if level() <= LevelWarn { + write(LevelWarn, str) + } +} + +func Warns(args ...interface{}) { + if level() <= LevelWarn { + write(LevelWarn, fmt.Sprintln(args...)) + } +} + +func Warnf(format string, args ...interface{}) { + if level() <= LevelWarn { + write(LevelWarn, fmt.Sprintf(format, args...)) + } +} + +func Error(str string) { + if level() <= LevelError { + write(LevelError, str) + } +} + +func Errors(args ...interface{}) { + if level() <= LevelError { + write(LevelError, fmt.Sprintln(args...)) + } +} + +func Errorf(format string, args ...interface{}) { + if level() <= LevelError { + write(LevelError, fmt.Sprintf(format, args...)) + } +} + diff --git a/gokit_test.go b/gokit_test.go new file mode 100644 index 0000000..6dbe8c4 --- /dev/null +++ b/gokit_test.go @@ -0,0 +1,55 @@ +package logkit + +import ( + "fmt" + "strconv" + "testing" + "time" +) + +func init() { + Init(SYSLOG,"test", LevelInfo) + +} +func TestGoKit(t *testing.T) { + Init(FIlE, "test", LevelDebug) +} +func BenchmarkGoKit(b *testing.B) { + defer Exit() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + Info("test " + strconv.FormatInt(int64(i), 10)) + } +} + +func TestInfo(t *testing.T) { + defer Exit() + fmt.Println("start") + for i := 0; i< 10 ; i++ { + go func(i int) { + Info("test "+ strconv.FormatInt(int64(i), 10)) + }(i) + } + fmt.Println("end") + time.Sleep(time.Second * 2) + // + //for i := 0; i< 1000 ; i++ { + // Info("test "+ strconv.FormatInt(int64(i), 10)) + //} + + time.Sleep(time.Second * 1) + Info("test 2") + time.Sleep(time.Second * 1) + Info("test 3") +} + +func TestBuffer(t *testing.T) { + defer Exit() + + //for i := 0 ; i < 1024; i++ { + // str += strconv.FormatInt(int64(i),10) + //} + Infof("test %s --- %s", "1", "23") + //Exit() +} diff --git a/kafka.go b/kafka.go new file mode 100644 index 0000000..9333d03 --- /dev/null +++ b/kafka.go @@ -0,0 +1 @@ +package logkit diff --git a/syslog.go b/syslog.go new file mode 100644 index 0000000..af52257 --- /dev/null +++ b/syslog.go @@ -0,0 +1,69 @@ +package logkit + +import "log/syslog" + +type SyslogWriter struct { + network string + raddr string + priority syslog.Priority + tag string + writer *syslog.Writer +} + +func NewSyslogWriter(network, raddr string, level Level, tag string) (Writer, error) { + var priority syslog.Priority + switch level { + case LevelDebug: + priority = syslog.LOG_DEBUG + break + case LevelInfo: + priority = syslog.LOG_INFO + break + case LevelWarn: + priority = syslog.LOG_WARNING + break + case LevelError: + priority = syslog.LOG_ERR + break + case LevelFatal: + priority = syslog.LOG_ALERT + break + default: + priority = syslog.LOG_INFO + } + writer, err := syslog.Dial(network, raddr,priority, tag) + if err != nil { + return nil, err + } + object := &SyslogWriter{ + network: network, + raddr: raddr, + priority: priority, + tag: tag, + writer: writer, + } + return object, nil +} + +func (self *SyslogWriter) Write(level Level, msg string) { + + switch level { + case LevelFatal: + self.writer.Crit(msg) + case LevelError: + self.writer.Err(msg) + case LevelWarn: + self.writer.Warning(msg) + case LevelInfo: + self.writer.Info(msg) + case LevelDebug: + self.writer.Debug(msg) + default: + self.writer.Write([]byte(msg)) + } +} + +func (self *SyslogWriter) Exit() { + // ignore the error return code + self.writer.Close() +}