author | Alberto Bertogli
<albertito@blitiri.com.ar> 2020-05-22 16:16:52 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2020-05-22 16:53:51 UTC |
parent | dba4a5e2fa67674862122fcac488378b49ee5abc |
log.go | +44 | -21 |
log_test.go | +40 | -5 |
diff --git a/log.go b/log.go index 2c6a226..87bca24 100644 --- a/log.go +++ b/log.go @@ -81,11 +81,25 @@ type Logger struct { // could change in the future. Level Level + // Include timestamp in the log message. + // The use of this field should be considered EXPERIMENTAL, the API for it + // could change in the future. + LogTime bool + + // Include the log level in the log message. + // The use of this field should be considered EXPERIMENTAL, the API for it + // could change in the future. + LogLevel bool + + // Include the caller in the log message. + // The use of this field should be considered EXPERIMENTAL, the API for it + // could change in the future. + LogCaller bool + // File name, if this logger is backed by a file. It's used to implement // reopening. fname string - logTime bool callerSkip int w io.WriteCloser sync.Mutex @@ -97,7 +111,9 @@ func New(w io.WriteCloser) *Logger { w: w, callerSkip: 0, Level: Info, - logTime: true, + LogTime: true, + LogLevel: true, + LogCaller: true, } } @@ -116,7 +132,6 @@ func NewFile(path string) (*Logger, error) { } l := New(f) - l.logTime = true l.fname = path return l, nil } @@ -130,7 +145,7 @@ func NewSyslog(priority syslog.Priority, tag string) (*Logger, error) { } l := New(w) - l.logTime = false + l.LogTime = false return l, nil } @@ -182,25 +197,29 @@ func (l *Logger) Log(level Level, skip int, format string, a ...interface{}) err msg := fmt.Sprintf(format, a...) // Caller. - _, file, line, ok := runtime.Caller(1 + l.callerSkip + skip) - if !ok { - file = "unknown" - } - fl := fmt.Sprintf("%s:%-4d", filepath.Base(file), line) - if len(fl) > 18 { - fl = fl[len(fl)-18:] + if l.LogCaller { + _, file, line, ok := runtime.Caller(1 + l.callerSkip + skip) + if !ok { + file = "unknown" + } + fl := fmt.Sprintf("%s:%-4d", filepath.Base(file), line) + if len(fl) > 18 { + fl = fl[len(fl)-18:] + } + msg = fmt.Sprintf("%-18s", fl) + " " + msg } - msg = fmt.Sprintf("%-18s", fl) + " " + msg // Level. - letter, ok := levelToLetter[level] - if !ok { - letter = strconv.Itoa(int(level)) + if l.LogLevel { + letter, ok := levelToLetter[level] + if !ok { + letter = strconv.Itoa(int(level)) + } + msg = letter + " " + msg } - msg = letter + " " + msg // Time. - if l.logTime { + if l.LogTime { msg = time.Now().Format("2006-01-02 15:04:05.000000 ") + msg } @@ -241,10 +260,14 @@ func (l *Logger) Fatalf(format string, a ...interface{}) { // The default logger, used by the top-level functions below. var Default = &Logger{ - w: os.Stderr, + w: os.Stderr, + + Level: Info, + callerSkip: 1, - Level: Info, - logTime: false, + LogCaller: true, + LogLevel: true, + LogTime: false, } // Initialize the default logger, based on the command-line flags. @@ -271,7 +294,7 @@ func Init() { Default.callerSkip = 1 Default.Level = Level(*vLevel) - Default.logTime = *logTime + Default.LogTime = *logTime } // V is a convenient wrapper to Default.V. diff --git a/log_test.go b/log_test.go index 7d235cb..1ce9883 100644 --- a/log_test.go +++ b/log_test.go @@ -36,7 +36,7 @@ func checkContentsMatch(t *testing.T, name, path, expected string) { } func testLogger(t *testing.T, fname string, l *Logger) { - l.logTime = false + l.LogTime = false l.Infof("message %d", 1) checkContentsMatch(t, "info-no-time", fname, "^_ log_test.go:.... message 1\n") @@ -47,13 +47,13 @@ func testLogger(t *testing.T, fname string, l *Logger) { "^_ log_test.go:.... message 1\n") os.Truncate(fname, 0) - l.logTime = true + l.LogTime = true l.Infof("message %d", 1) checkContentsMatch(t, "info-with-time", fname, `^....-..-.. ..:..:..\.\d{6} _ log_test.go:.... message 1\n`) os.Truncate(fname, 0) - l.logTime = false + l.LogTime = false l.Errorf("error %d", 1) checkContentsMatch(t, "error", fname, `^E log_test.go:.... error 1\n`) @@ -62,7 +62,7 @@ func testLogger(t *testing.T, fname string, l *Logger) { } os.Truncate(fname, 0) - l.logTime = false + l.LogTime = false l.Debugf("debug %d", 1) checkContentsMatch(t, "debug-no-log", fname, `^$`) @@ -87,6 +87,41 @@ func testLogger(t *testing.T, fname string, l *Logger) { l.Log(Fatal, 0, "log fatal %d", 1) checkContentsMatch(t, "log", fname, `^☠ log_test.go:.... log fatal 1\n`) + + // Test some combinations of options. + cases := []struct { + name string + logTime bool + logLevel bool + logCaller bool + expected string + }{ + { + "show everything", + true, true, true, + `^....-..-.. ..:..:..\.\d{6} _ log_test.go:.... message 1\n`, + }, { + "caller+level", + false, true, true, + `^_ log_test.go:.... message 1\n`, + }, { + "time", + true, false, false, + `^....-..-.. ..:..:..\.\d{6} message 1\n`, + }, { + "none", + false, false, false, + `message 1\n`, + }, + } + for _, c := range cases { + os.Truncate(fname, 0) + l.LogTime = c.logTime + l.LogLevel = c.logLevel + l.LogCaller = c.logCaller + l.Infof("message %d", 1) + checkContentsMatch(t, c.name, fname, c.expected) + } } func TestBasic(t *testing.T) { @@ -113,7 +148,7 @@ func TestReopen(t *testing.T) { fname, l := mustNewFile(t) defer l.Close() defer os.Remove(fname) - l.logTime = false + l.LogTime = false l.Infof("pre rename") checkContentsMatch(t, "r", fname, `^_ log_test.go:.... pre rename\n`)