diff --git a/log.go b/log.go index 9ae2709..76f2136 100644 --- a/log.go +++ b/log.go @@ -3,13 +3,10 @@ package log import ( - "bytes" "encoding/json" "fmt" "log" "os" - "path/filepath" - "runtime" "runtime/debug" "strings" "sync" @@ -18,73 +15,38 @@ import ( "qoobing.com/gomod/str" ) -var ( - glogger *log.Logger = nil - once sync.Once = sync.Once{} - mylogger *Logger = nil - modulelogs map[string]*Logger = map[string]*Logger{} - logidSetter func(string) = nil - logidGetter func() string = nil +const ( + PANIC logLevel = 0 + FATAL logLevel = 1 + ERROR logLevel = 2 + NOTICE logLevel = 3 + WARNING logLevel = 4 + INFO logLevel = 5 + DEBUG logLevel = 9 + ErrLogPanic = "~~~~panic~~~~~~" ) -const ErrLogPanic = "~~~~panic~~~~~~" - -//////////////global log//////////////////begin/////////////////// -func SetLogLevel(newlv logLevel) (oldlv logLevel) { - return mylogger.SetLogLevel(newlv) -} -func PrintPretty(prefix string, v interface{}) { - mylogger.PrintPretty(prefix, v) -} -func DebugfWithDepth(calldepth int, format string, v ...interface{}) { - mylogger.DebugfWithDepth(calldepth, format, v...) -} -func Debugf(format string, v ...interface{}) { - mylogger.Debugf(format, v...) -} -func Noticef(format string, v ...interface{}) { - mylogger.Noticef(format, v...) -} -func NoticefWithDepth(calldepth int, format string, v ...interface{}) { - mylogger.NoticefWithDepth(calldepth, format, v...) -} -func Infof(format string, v ...interface{}) { - mylogger.Infof(format, v...) -} -func Warningf(format string, v ...interface{}) { - mylogger.Warningf(format, v...) -} -func Errorf(format string, v ...interface{}) { - mylogger.Warningf(format, v...) -} -func Panicf(format string, v ...interface{}) { - mylogger.Panicf(format, v...) -} -func Fatalf(format string, v ...interface{}) { - mylogger.Fatalf(format, v...) -} - -////////////////////////////////////////////////////////////////// +var ( + golog *log.Logger = nil + mylog *Logger = nil + logidCreator LogidCreator = nil + modulelogs map[string]*Logger = map[string]*Logger{} +) type logLevel int - -const ( - PANIC logLevel = 0 - FATAL logLevel = 1 - ERROR logLevel = 2 - NOTICE logLevel = 3 - WARNING logLevel = 4 - INFO logLevel = 5 - DEBUG logLevel = 9 -) - type Logger struct { module string + golog *log.Logger loglevel logLevel - logger *log.Logger } -func New(module string) (logger *Logger) { +type LogidCreator interface { + Cleanup() + GetLogid() string + SetLogid(logid string) +} + +func New(module string) *Logger { if module == "" { module = "undefine" } @@ -93,13 +55,14 @@ func New(module string) (logger *Logger) { } else { modulelogs[module] = &Logger{ module: module, - logger: glogger, + golog: golog, loglevel: DEBUG, } return modulelogs[module] } } +////////////////////////////////////////////////////////////////// func (log *Logger) SetLogLevel(newlv logLevel) (oldlv logLevel) { oldlv = log.loglevel log.loglevel = newlv @@ -155,7 +118,10 @@ func (log *Logger) Panicf(format string, v ...interface{}) { } func (log *Logger) GetLogidStr(format string) string { - return fmt.Sprintf(format, GetLogid()) + if logidCreator != nil { + return fmt.Sprintf(format, logidCreator.GetLogid()) + } + return "" } func (log *Logger) logwrite(typ logLevel, calldepth int, format string, v ...interface{}) { @@ -167,152 +133,79 @@ func (log *Logger) logwrite(typ logLevel, calldepth int, format string, v ...int format = strings.Trim(format, "\n") switch typ { case PANIC: - log.logger.SetPrefix("\x1b[31m" + "PANIC " + idstr + "[" + log.module + "] ") + log.golog.SetPrefix("\x1b[31m" + "PANIC " + idstr + "[" + log.module + "] ") case FATAL: - log.logger.SetPrefix("\x1b[31m" + "FATAL " + idstr + "[" + log.module + "] ") + log.golog.SetPrefix("\x1b[31m" + "FATAL " + idstr + "[" + log.module + "] ") case WARNING: - log.logger.SetPrefix("\x1b[32m" + "WARNING " + idstr + "[" + log.module + "] ") + log.golog.SetPrefix("\x1b[32m" + "WARNING " + idstr + "[" + log.module + "] ") case ERROR: - log.logger.SetPrefix("\x1b[32m" + "ERROR " + idstr + "[" + log.module + "] ") + log.golog.SetPrefix("\x1b[32m" + "ERROR " + idstr + "[" + log.module + "] ") case INFO: - log.logger.SetPrefix("INFO " + idstr + "[" + log.module + "] ") + log.golog.SetPrefix("INFO " + idstr + "[" + log.module + "] ") case NOTICE: - log.logger.SetPrefix("NOTICE " + idstr + "[" + log.module + "] ") + log.golog.SetPrefix("NOTICE " + idstr + "[" + log.module + "] ") case DEBUG: - log.logger.SetPrefix("DEBUG " + idstr + "[" + log.module + "] ") + log.golog.SetPrefix("DEBUG " + idstr + "[" + log.module + "] ") default: - log.logger.SetPrefix("UNKNOWN " + idstr + "[" + log.module + "] ") + log.golog.SetPrefix("UNKNOWN " + idstr + "[" + log.module + "] ") } - if mylogger == log { + if mylog == log { calldepth = calldepth + 1 } if typ == FATAL || typ == WARNING || typ == ERROR { - log.logger.Output(calldepth, fmt.Sprintf(format+"\x1b[0m\n", v...)) + log.golog.Output(calldepth, fmt.Sprintf(format+"\x1b[0m\n", v...)) } else if typ == NOTICE { calldepth = calldepth + 2 - log.logger.Output(calldepth, fmt.Sprintf(format+"\n", v...)) + log.golog.Output(calldepth, fmt.Sprintf(format+"\n", v...)) } else if typ == PANIC { stack := strings.Replace(string(debug.Stack()), "\n", "\n== ", -1) stack = str.SkipLine(stack, calldepth*2+1) v = append(v, stack) panicstr := fmt.Sprintf(format+"\x1b[0m. Panic stack:\n%s\n", v...) - log.logger.Output(calldepth, panicstr) + log.golog.Output(calldepth, panicstr) panic(ErrLogPanic) } else { - log.logger.Output(calldepth, fmt.Sprintf(format+"\n", v...)) + log.golog.Output(calldepth, fmt.Sprintf(format+"\n", v...)) } } -//////////////global log trace//////////////////begin/////////////////// - -func TRACE_INTO(format string, v ...interface{}) string { - _, fn, line, _ := runtime.Caller(1) - strfn := fmt.Sprintf("%s:%d", fn, line) - Debugf("TRACE into ["+strfn+"]"+format+"...\r\n", v...) - - return strfn -} - -func TRACE_EXIT(strfn string, format string, v ...interface{}) { - Debugf("TRACE exit ["+strfn+"]"+format+"...\r\n", v...) -} - -type mWriter struct { - logw *os.File - stdw *os.File -} - -func (w mWriter) Write(p []byte) (n int, err error) { - if flagcachelog { - logCache.Write(p) - } - w.stdw.Write(p) - return w.logw.Write(p) -} - -var cacheLogLock = new(sync.Mutex) -var flagcachelog = false -var logCache = bytes.Buffer{} - -func StartCacheLog() { - cacheLogLock.Lock() - flagcachelog = true - logCache.Reset() -} -func StopCacheLog() { - cacheLogLock.Unlock() - flagcachelog = false -} -func GetCacheLog() string { - if flagcachelog != true { - panic("GetCacheLog MUST call after StartCacheLog called") - } - return logCache.String() -} - //////////////////////////////////////////////////////////////////////////////////// /////////////////////////Initialize///////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// +var once sync.Once = sync.Once{} + +// init func init() { once.Do(initlog) } +// initlog func initlog() { - var mwriter mWriter - var openlog = func(logname string) *log.Logger { - fp, err := os.OpenFile(logname, os.O_APPEND|os.O_CREATE|os.O_WRONLY, os.ModePerm) - if err != nil { - panic("open log file failed:" + err.Error()) - } - mwriter.logw.Close() - mwriter.logw = fp - mwriter.stdw = os.Stdout - glogger = log.New(mwriter, "", log.Ldate|log.Lmicroseconds|log.Lshortfile) - return glogger - } + // Step 1. create base writer & cache writer for ALL log + var ( + logDir = "./logs/" + logName = getExeFilename() + logDirsOptional = []string{"./log", "/var/log"} + logSplitTag = "20060102" //20060102150405 + baseWriter = NewBaseWriter(nil, os.Stdout, nil) + cacheWriter = NewCacheWriter(baseWriter) + gologFlags = log.Ldate | log.Lmicroseconds | log.Lshortfile + goSystemLog = log.New(cacheWriter, "", gologFlags) + ) - _, logfilename := filepath.Split(os.Args[0]) - LOGSPLITTIME := "20060102" //20060102150405 - LOGFILENAME := logfilename + ".log" - if _, err := os.Stat("log/"); err == nil { - LOGFILENAME = "log/" + LOGFILENAME - } else if _, err := os.Stat("logs/"); err == nil { - LOGFILENAME = "logs/" + LOGFILENAME - } else { - LOGFILENAME = "logs/" + LOGFILENAME - } - - glogger = openlog(LOGFILENAME) - mylogger = New("system") - curhourtime := time.Now().Local().Format(LOGSPLITTIME) - prehourtime := curhourtime + // Step 2. init golog(golang std logger) & mylog(myself defined logger) + golog = goSystemLog + mylog = New("system") + baseWriter.OpenLogFile(logDir, logName, logDirsOptional) + // Step 3. backgroud split log (log rotate) go func() { - intva := 2 * time.Minute - timer := time.NewTimer(1 * time.Second) - for { - select { - case <-timer.C: - curhourtime := time.Now().Local().Format(LOGSPLITTIME) - //Debugf("check logfile: prehourtime:%s,curhourtime:%s", prehourtime, curhourtime) - if prehourtime != curhourtime { - // close old logger & move log to backup file. - PREFILENAME := LOGFILENAME + "." + prehourtime - os.Rename(LOGFILENAME, PREFILENAME) - prehourtime = curhourtime - - glogger = openlog(LOGFILENAME) - mylogger = New("system") - for _, l := range modulelogs { - l.logger = glogger - } - } - - timer.Reset(intva) - } + tag := time.Now().Local().Format(logSplitTag) + baseWriter.TryBackupLogFile(tag) + time.Sleep(2 * time.Minute) } }() } diff --git a/logid+glslogid.go b/logid+glslogid.go index 072d4b5..fcdd74e 100644 --- a/logid+glslogid.go +++ b/logid+glslogid.go @@ -1,18 +1,38 @@ +// +build glslogid package log -import( - "github.com/jtolds/gls" - ) +import ( + "fmt" + "github.com/tylerb/gls" +) -type glsLogid struct { - mgr *gls.ContextManager - idkey gls.ContextKey +type glsLogidCreator struct { + idkey string } -func GetLogid() string { - return "" +func (creator *glsLogidCreator) GetLogid() string { + id := gls.Get(creator.idkey) + if id == nil { + return "" + } + if logid, ok := id.(string); ok { + return logid + } else { + return fmt.Sprintf("%s", id) + } } -func SetLogid(logid string) { - +func (creator *glsLogidCreator) SetLogid(logid string) { + gls.Set(creator.idkey, logid) +} + +func (creator *glsLogidCreator) Cleanup() { + gls.Cleanup() +} + +func init() { + idc := &glsLogidCreator{ + idkey: "logidkey", + } + RegisterLogidCreator(idc) } diff --git a/logid+nologid.go b/logid+nologid.go deleted file mode 100644 index e54eef9..0000000 --- a/logid+nologid.go +++ /dev/null @@ -1,9 +0,0 @@ -package log - - -func GetLogid() string { - return "" -} - -func SetLogid(logid string) { -} diff --git a/logid+runtimelogid.go b/logid+runtimelogid.go index 4abb076..1a43844 100644 --- a/logid+runtimelogid.go +++ b/logid+runtimelogid.go @@ -1,45 +1,21 @@ +// +build runtimelogid package log -func GetLogid() string { - if logidGetter != nil { - return logidGetter() - } - return "" -} - -func SetLogid(logid string) { - if logidSetter != nil { - logidSetter(logid) - } -} -// +build logid - -package yk_logger - -import ( - "bytes" - "runtime" - "strconv" -) - -// LogidFormatPart is a FormatPart of the full source code placeholder. -type LogidFormatPart struct{} - -// Format writes the source file path and line number of the record to the buf. -func (p *LogidFormatPart) Format(r *Record, buf *bytes.Buffer) { - logid := p.GetLogid() - logidstr := strconv.FormatInt(logid, 10) - buf.WriteString(logidstr) -} - -func (p *LogidFormatPart) GetLogid() int64 { - return runtime.GetLogid() -} - -func (p *LogidFormatPart) SetLogid(newid int64) (oldid int64) { - return runtime.SetLogid(newid) -} - -func init() { - LogidSupporter = &LogidFormatPart{} -} +//// Format writes the source file path and line number of the record to the buf. +//func (p *LogidFormatPart) Format(r *Record, buf *bytes.Buffer) { +// logid := p.GetLogid() +// logidstr := strconv.FormatInt(logid, 10) +// buf.WriteString(logidstr) +//} +// +//func (p *LogidFormatPart) GetLogid() int64 { +// return runtime.GetLogid() +//} +// +//func (p *LogidFormatPart) SetLogid(newid int64) (oldid int64) { +// return runtime.SetLogid(newid) +//} +// +//func init() { +// LogidSupporter = &LogidFormatPart{} +//}