commit
993d40a7b6
@ -0,0 +1 @@ |
|||||||
|
.idea/ |
@ -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") |
||||||
|
|
||||||
|
|
||||||
|
``` |
@ -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 |
||||||
|
} |
@ -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...)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -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()
|
||||||
|
} |
@ -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() |
||||||
|
} |
Loading…
Reference in new issue