diff --git a/log.go b/log.go index 48e7a8e..9954119 100644 --- a/log.go +++ b/log.go @@ -61,6 +61,7 @@ type Logger struct { module string golog *log.Logger loglevel LogLevel + skipfunc func(string) bool calldepth int } @@ -108,6 +109,11 @@ func (log *Logger) SetCalldepth(calldepth int) { log.calldepth = calldepth } +// SetSkipfunc set skip func to skip stack filename +func (log *Logger) SetSkipfunc(skipfunc func(string) bool) { + log.skipfunc = skipfunc +} + func (log *Logger) Print(prefix string, v interface{}) { var str = "" if pkg, err := json.Marshal(v); err != nil { @@ -198,7 +204,7 @@ func (log *Logger) logwrite(typ LogLevel, calldepth int, format string, v ...int calldepth += log.calldepth var ( idstr = log.GetLogidStr(" [%s]") - header = formatHeader(calldepth) + "$" + idstr + header = formatHeader(calldepth, log.skipfunc) + "$" + idstr ) format = strings.Trim(format, "\n") @@ -238,7 +244,7 @@ func (log *Logger) logwrite(typ LogLevel, calldepth int, format string, v ...int } } -func formatHeader(calldepth int) string { +func formatHeader(calldepth int, skipfunc func(string) bool) string { const MAX_LENGTH = 35 /* + 22 */ // log time now := time.Now() @@ -248,10 +254,17 @@ func formatHeader(calldepth int) string { year, month, day, hour, min, sec, now.Nanosecond()/1e6) // log position - _, file, line, ok := runtime.Caller(calldepth) - if !ok { - file = "???" - line = 0 + pcs := [13]uintptr{} + cnt := runtime.Callers(calldepth+1, pcs[:]) + frames := runtime.CallersFrames(pcs[:cnt]) + file, line := "???", 0 + for i := 0; i < cnt; i++ { + frame, more := frames.Next() + fmt.Println(i, "\t", frame.File, frame.Line) + if !more || skipfunc == nil || !skipfunc(frame.File) { + file, line = frame.File, frame.Line + break + } } // Case 1: too short path, return directly diff --git a/util.go b/util.go index 0290adc..c46938d 100644 --- a/util.go +++ b/util.go @@ -21,9 +21,19 @@ func tryOptLogDirs(optLogDirs []string) (string, error) { for i, d := range optLogDirs { dir := fmt.Sprintf("%s/", d) optionDirsStr += fmt.Sprintf("%d.[%s];", i, dir) - if _, err := os.Stat(dir); err == nil { + if ok := canWriteByTest(dir); ok { return dir, nil } } - return "", fmt.Errorf("all optional dir are not exist: %s", optionDirsStr) + return "", fmt.Errorf("all optional dir are not exist or writeable: %s", optionDirsStr) +} + +// canWriteByTest +func canWriteByTest(dir string) bool { + testFile := filepath.Join(dir, ".write_test.log.tmp") + if err := os.WriteFile(testFile, []byte("test"), 0644); err != nil { + return false + } + os.Remove(testFile) + return true } diff --git a/writer.go b/writer.go index 83df903..982fa9e 100644 --- a/writer.go +++ b/writer.go @@ -35,22 +35,23 @@ func NewBaseWriter(logw, stdw, errw *os.File) *baseWriter { // OpenLogFile func (w *baseWriter) OpenLogFile(logDir, logName string, optLogDirs []string) { + realDir := "" // Step 1. try get available log dir - if _, err := os.Stat(logDir); err == nil { - logDir = logDir - } else if dir, err := tryOptLogDirs(optLogDirs); err == nil { - logDir = dir + if _, err := os.Stat(logDir); err == nil && canWriteByTest(logDir) { + realDir = logDir + } else if dir, tryOptErr := tryOptLogDirs(optLogDirs); tryOptErr == nil { + realDir = dir } else if err := os.Mkdir(logDir, 0755); err == nil { - logDir = logDir + realDir = logDir } else { - errstr := fmt.Sprintf("all path not exist:\n "+ - "a.[%s]\n b.[%s]\n c.[%s]\n", - logDir, "./log/", "./logs/") + errstr := fmt.Sprintf("all path not exist or writeable:\n "+ + "logDir = %s, optLogDirs = %v\n", + logDir, optLogDirs) panic("failed initlog:" + errstr) } // Step 2. open base writer logfile - filename := filepath.Join(logDir, logName+".log") + filename := filepath.Join(realDir, logName+".log") w.logFilename = filename w.logPreBackupTag = "" w.ReopenLogFile()