]> source.dussan.org Git - gitea.git/commitdiff
Refactor Logger (#13294)
authorzeripath <art27@cantab.net>
Sat, 31 Oct 2020 05:36:46 +0000 (05:36 +0000)
committerGitHub <noreply@github.com>
Sat, 31 Oct 2020 05:36:46 +0000 (01:36 -0400)
Refactor Logger to make a logger interface and make it possible to
wrap loggers for specific purposes.

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
models/log.go
modules/indexer/code/elastic_search.go
modules/indexer/issues/elastic_search.go
modules/log/colors.go
modules/log/level.go
modules/log/log.go
modules/log/log_test.go
modules/log/logger.go
modules/log/multichannel.go [new file with mode: 0644]

index 1cfddd90a19cb9d4daf65d6d0fb9a7927a7987e3..942dbc744a467db9d187cd834184c10de5df1133 100644 (file)
@@ -15,7 +15,7 @@ import (
 // XORMLogBridge a logger bridge from Logger to xorm
 type XORMLogBridge struct {
        showSQL bool
-       logger  *log.Logger
+       logger  log.Logger
 }
 
 // NewXORMLogger inits a log bridge for xorm
index 08b20b80a08ff5e6ab83fab9a2254ae4a1546550..0f61c4e59202d02c4bfb6779ba5fce3b136817bb 100644 (file)
@@ -40,7 +40,7 @@ type ElasticSearchIndexer struct {
 }
 
 type elasticLogger struct {
-       *log.Logger
+       log.Logger
 }
 
 func (l elasticLogger) Printf(format string, args ...interface{}) {
index 1f9c59965c07d5c61e5a8690b9c74250fa7e49c0..4cdeff53dc17ca9e38277f44e08dd3427ba7c4b8 100644 (file)
@@ -27,11 +27,11 @@ type ElasticSearchIndexer struct {
 }
 
 type elasticLogger struct {
-       *log.Logger
+       log.LevelLogger
 }
 
 func (l elasticLogger) Printf(format string, args ...interface{}) {
-       _ = l.Logger.Log(2, l.Logger.GetLevel(), format, args...)
+       _ = l.Log(2, l.GetLevel(), format, args...)
 }
 
 // NewElasticSearchIndexer creates a new elasticsearch indexer
index d8e57767353a2859753822fe1c0171a23cdc42be..5d56fd739077e397e8d810fc92665151959a81c8 100644 (file)
@@ -158,15 +158,15 @@ func ColorBytes(attrs ...ColorAttribute) []byte {
        return bytes
 }
 
-var levelToColor = map[Level]string{
-       TRACE:    ColorString(Bold, FgCyan),
-       DEBUG:    ColorString(Bold, FgBlue),
-       INFO:     ColorString(Bold, FgGreen),
-       WARN:     ColorString(Bold, FgYellow),
-       ERROR:    ColorString(Bold, FgRed),
-       CRITICAL: ColorString(Bold, BgMagenta),
-       FATAL:    ColorString(Bold, BgRed),
-       NONE:     ColorString(Reset),
+var levelToColor = map[Level][]byte{
+       TRACE:    ColorBytes(Bold, FgCyan),
+       DEBUG:    ColorBytes(Bold, FgBlue),
+       INFO:     ColorBytes(Bold, FgGreen),
+       WARN:     ColorBytes(Bold, FgYellow),
+       ERROR:    ColorBytes(Bold, FgRed),
+       CRITICAL: ColorBytes(Bold, BgMagenta),
+       FATAL:    ColorBytes(Bold, BgRed),
+       NONE:     ColorBytes(Reset),
 }
 
 var resetBytes = ColorBytes(Reset)
index 4b89385fe2f9423cf51c23494ea55d3bf333e879..ab231bd1bd0908b7a74ba19ee06ef0b720114271 100644 (file)
@@ -73,6 +73,16 @@ func (l Level) String() string {
        return "info"
 }
 
+// Color returns the color string for this Level
+func (l Level) Color() *[]byte {
+       color, ok := levelToColor[l]
+       if ok {
+               return &(color)
+       }
+       none := levelToColor[NONE]
+       return &none
+}
+
 // MarshalJSON takes a Level and turns it into text
 func (l Level) MarshalJSON() ([]byte, error) {
        buffer := bytes.NewBufferString(`"`)
index 2a35b5752c92886aef9577b63b6fc76716ad94fd..16a6efb75b9a8fc78afcce615de1548221876a9a 100644 (file)
@@ -16,16 +16,16 @@ type loggerMap struct {
        sync.Map
 }
 
-func (m *loggerMap) Load(k string) (*Logger, bool) {
+func (m *loggerMap) Load(k string) (*MultiChannelledLogger, bool) {
        v, ok := m.Map.Load(k)
        if !ok {
                return nil, false
        }
-       l, ok := v.(*Logger)
+       l, ok := v.(*MultiChannelledLogger)
        return l, ok
 }
 
-func (m *loggerMap) Store(k string, v *Logger) {
+func (m *loggerMap) Store(k string, v *MultiChannelledLogger) {
        m.Map.Store(k, v)
 }
 
@@ -42,7 +42,7 @@ var (
 )
 
 // NewLogger create a logger for the default logger
-func NewLogger(bufLen int64, name, provider, config string) *Logger {
+func NewLogger(bufLen int64, name, provider, config string) *MultiChannelledLogger {
        err := NewNamedLogger(DEFAULT, bufLen, name, provider, config)
        if err != nil {
                CriticalWithSkip(1, "Unable to create default logger: %v", err)
@@ -83,7 +83,7 @@ func DelLogger(name string) error {
 }
 
 // GetLogger returns either a named logger or the default logger
-func GetLogger(name string) *Logger {
+func GetLogger(name string) *MultiChannelledLogger {
        logger, ok := NamedLoggers.Load(name)
        if ok {
                return logger
@@ -196,7 +196,7 @@ func IsFatal() bool {
 // Pause pauses all the loggers
 func Pause() {
        NamedLoggers.Range(func(key, value interface{}) bool {
-               logger := value.(*Logger)
+               logger := value.(*MultiChannelledLogger)
                logger.Pause()
                logger.Flush()
                return true
@@ -206,7 +206,7 @@ func Pause() {
 // Resume resumes all the loggers
 func Resume() {
        NamedLoggers.Range(func(key, value interface{}) bool {
-               logger := value.(*Logger)
+               logger := value.(*MultiChannelledLogger)
                logger.Resume()
                return true
        })
@@ -216,7 +216,7 @@ func Resume() {
 func ReleaseReopen() error {
        var accumulatedErr error
        NamedLoggers.Range(func(key, value interface{}) bool {
-               logger := value.(*Logger)
+               logger := value.(*MultiChannelledLogger)
                if err := logger.ReleaseReopen(); err != nil {
                        if accumulatedErr == nil {
                                accumulatedErr = fmt.Errorf("Error reopening %s: %v", key.(string), err)
@@ -250,15 +250,15 @@ func Log(skip int, level Level, format string, v ...interface{}) {
 
 // LoggerAsWriter is a io.Writer shim around the gitea log
 type LoggerAsWriter struct {
-       ourLoggers []*Logger
+       ourLoggers []*MultiChannelledLogger
        level      Level
 }
 
 // NewLoggerAsWriter creates a Writer representation of the logger with setable log level
-func NewLoggerAsWriter(level string, ourLoggers ...*Logger) *LoggerAsWriter {
+func NewLoggerAsWriter(level string, ourLoggers ...*MultiChannelledLogger) *LoggerAsWriter {
        if len(ourLoggers) == 0 {
                l, _ := NamedLoggers.Load(DEFAULT)
-               ourLoggers = []*Logger{l}
+               ourLoggers = []*MultiChannelledLogger{l}
        }
        l := &LoggerAsWriter{
                ourLoggers: ourLoggers,
index 0e7583081ceca49b49d397f70afb0d9eff7f3b3b..810505dea5b473d08775e00a56209196518fdca4 100644 (file)
@@ -11,7 +11,7 @@ import (
        "github.com/stretchr/testify/assert"
 )
 
-func baseConsoleTest(t *testing.T, logger *Logger) (chan []byte, chan bool) {
+func baseConsoleTest(t *testing.T, logger *MultiChannelledLogger) (chan []byte, chan bool) {
        written := make(chan []byte)
        closed := make(chan bool)
 
index 9704ffd3d88a6e65112a6aede55c2cae177aeb41..75f361ccdba43cbd63b018fb64cfd9d08c37ed30 100644 (file)
 
 package log
 
-import (
-       "fmt"
-       "os"
-       "runtime"
-       "strings"
-       "time"
-)
-
-// Logger is default logger in the Gitea application.
-// it can contain several providers and log message into all providers.
-type Logger struct {
-       *MultiChannelledLog
-       bufferLength int64
-}
-
-// newLogger initializes and returns a new logger.
-func newLogger(name string, buffer int64) *Logger {
-       l := &Logger{
-               MultiChannelledLog: NewMultiChannelledLog(name, buffer),
-               bufferLength:       buffer,
-       }
-       return l
-}
-
-// SetLogger sets new logger instance with given logger provider and config.
-func (l *Logger) SetLogger(name, provider, config string) error {
-       eventLogger, err := NewChannelledLog(name, provider, config, l.bufferLength)
-       if err != nil {
-               return fmt.Errorf("Failed to create sublogger (%s): %v", name, err)
-       }
-
-       l.MultiChannelledLog.DelLogger(name)
-
-       err = l.MultiChannelledLog.AddLogger(eventLogger)
-       if err != nil {
-               if IsErrDuplicateName(err) {
-                       return fmt.Errorf("Duplicate named sublogger %s %v", name, l.MultiChannelledLog.GetEventLoggerNames())
-               }
-               return fmt.Errorf("Failed to add sublogger (%s): %v", name, err)
-       }
-
-       return nil
-}
-
-// DelLogger deletes a sublogger from this logger.
-func (l *Logger) DelLogger(name string) (bool, error) {
-       return l.MultiChannelledLog.DelLogger(name), nil
-}
-
-// Log msg at the provided level with the provided caller defined by skip (0 being the function that calls this function)
-func (l *Logger) Log(skip int, level Level, format string, v ...interface{}) error {
-       if l.GetLevel() > level {
-               return nil
-       }
-       caller := "?()"
-       pc, filename, line, ok := runtime.Caller(skip + 1)
-       if ok {
-               // Get caller function name.
-               fn := runtime.FuncForPC(pc)
-               if fn != nil {
-                       caller = fn.Name() + "()"
-               }
-       }
-       msg := format
-       if len(v) > 0 {
-               msg = ColorSprintf(format, v...)
-       }
-       stack := ""
-       if l.GetStacktraceLevel() <= level {
-               stack = Stack(skip + 1)
-       }
-       return l.SendLog(level, caller, strings.TrimPrefix(filename, prefix), line, msg, stack)
-}
-
-// SendLog sends a log event at the provided level with the information given
-func (l *Logger) SendLog(level Level, caller, filename string, line int, msg string, stack string) error {
-       if l.GetLevel() > level {
-               return nil
-       }
-       event := &Event{
-               level:      level,
-               caller:     caller,
-               filename:   filename,
-               line:       line,
-               msg:        msg,
-               time:       time.Now(),
-               stacktrace: stack,
-       }
-       l.LogEvent(event)
-       return nil
+import "os"
+
+// Logger is the basic interface for logging
+type Logger interface {
+       LevelLogger
+       Trace(format string, v ...interface{})
+       IsTrace() bool
+       Debug(format string, v ...interface{})
+       IsDebug() bool
+       Info(format string, v ...interface{})
+       IsInfo() bool
+       Warn(format string, v ...interface{})
+       IsWarn() bool
+       Error(format string, v ...interface{})
+       ErrorWithSkip(skip int, format string, v ...interface{})
+       IsError() bool
+       Critical(format string, v ...interface{})
+       CriticalWithSkip(skip int, format string, v ...interface{})
+       IsCritical() bool
+       Fatal(format string, v ...interface{})
+       FatalWithSkip(skip int, format string, v ...interface{})
+       IsFatal() bool
+}
+
+// LevelLogger is the simplest logging interface
+type LevelLogger interface {
+       Flush()
+       Close()
+       GetLevel() Level
+       Log(skip int, level Level, format string, v ...interface{}) error
+}
+
+// SettableLogger is the interface of loggers which have subloggers
+type SettableLogger interface {
+       SetLogger(name, provider, config string) error
+       DelLogger(name string) (bool, error)
+}
+
+// StacktraceLogger is a logger that can log stacktraces
+type StacktraceLogger interface {
+       GetStacktraceLevel() Level
+}
+
+// LevelLoggerLogger wraps a LevelLogger as a Logger
+type LevelLoggerLogger struct {
+       LevelLogger
 }
 
 // Trace records trace log
-func (l *Logger) Trace(format string, v ...interface{}) {
+func (l *LevelLoggerLogger) Trace(format string, v ...interface{}) {
        l.Log(1, TRACE, format, v...)
 }
 
+// IsTrace returns true if the logger is TRACE
+func (l *LevelLoggerLogger) IsTrace() bool {
+       return l.GetLevel() <= TRACE
+}
+
 // Debug records debug log
-func (l *Logger) Debug(format string, v ...interface{}) {
+func (l *LevelLoggerLogger) Debug(format string, v ...interface{}) {
        l.Log(1, DEBUG, format, v...)
 
 }
 
+// IsDebug returns true if the logger is DEBUG
+func (l *LevelLoggerLogger) IsDebug() bool {
+       return l.GetLevel() <= DEBUG
+}
+
 // Info records information log
-func (l *Logger) Info(format string, v ...interface{}) {
+func (l *LevelLoggerLogger) Info(format string, v ...interface{}) {
        l.Log(1, INFO, format, v...)
 }
 
+// IsInfo returns true if the logger is INFO
+func (l *LevelLoggerLogger) IsInfo() bool {
+       return l.GetLevel() <= INFO
+}
+
 // Warn records warning log
-func (l *Logger) Warn(format string, v ...interface{}) {
+func (l *LevelLoggerLogger) Warn(format string, v ...interface{}) {
        l.Log(1, WARN, format, v...)
 }
 
+// IsWarn returns true if the logger is WARN
+func (l *LevelLoggerLogger) IsWarn() bool {
+       return l.GetLevel() <= WARN
+}
+
 // Error records error log
-func (l *Logger) Error(format string, v ...interface{}) {
+func (l *LevelLoggerLogger) Error(format string, v ...interface{}) {
        l.Log(1, ERROR, format, v...)
 }
 
 // ErrorWithSkip records error log from "skip" calls back from this function
-func (l *Logger) ErrorWithSkip(skip int, format string, v ...interface{}) {
+func (l *LevelLoggerLogger) ErrorWithSkip(skip int, format string, v ...interface{}) {
        l.Log(skip+1, ERROR, format, v...)
 }
 
+// IsError returns true if the logger is ERROR
+func (l *LevelLoggerLogger) IsError() bool {
+       return l.GetLevel() <= ERROR
+}
+
 // Critical records critical log
-func (l *Logger) Critical(format string, v ...interface{}) {
+func (l *LevelLoggerLogger) Critical(format string, v ...interface{}) {
        l.Log(1, CRITICAL, format, v...)
 }
 
 // CriticalWithSkip records critical log from "skip" calls back from this function
-func (l *Logger) CriticalWithSkip(skip int, format string, v ...interface{}) {
+func (l *LevelLoggerLogger) CriticalWithSkip(skip int, format string, v ...interface{}) {
        l.Log(skip+1, CRITICAL, format, v...)
 }
 
+// IsCritical returns true if the logger is CRITICAL
+func (l *LevelLoggerLogger) IsCritical() bool {
+       return l.GetLevel() <= CRITICAL
+}
+
 // Fatal records fatal log and exit the process
-func (l *Logger) Fatal(format string, v ...interface{}) {
+func (l *LevelLoggerLogger) Fatal(format string, v ...interface{}) {
        l.Log(1, FATAL, format, v...)
        l.Close()
        os.Exit(1)
 }
 
 // FatalWithSkip records fatal log from "skip" calls back from this function and exits the process
-func (l *Logger) FatalWithSkip(skip int, format string, v ...interface{}) {
+func (l *LevelLoggerLogger) FatalWithSkip(skip int, format string, v ...interface{}) {
        l.Log(skip+1, FATAL, format, v...)
        l.Close()
        os.Exit(1)
 }
+
+// IsFatal returns true if the logger is FATAL
+func (l *LevelLoggerLogger) IsFatal() bool {
+       return l.GetLevel() <= FATAL
+}
diff --git a/modules/log/multichannel.go b/modules/log/multichannel.go
new file mode 100644 (file)
index 0000000..d28071c
--- /dev/null
@@ -0,0 +1,98 @@
+// Copyright 2020 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package log
+
+import (
+       "fmt"
+       "runtime"
+       "strings"
+       "time"
+)
+
+// MultiChannelledLogger is default logger in the Gitea application.
+// it can contain several providers and log message into all providers.
+type MultiChannelledLogger struct {
+       LevelLoggerLogger
+       *MultiChannelledLog
+       bufferLength int64
+}
+
+// newLogger initializes and returns a new logger.
+func newLogger(name string, buffer int64) *MultiChannelledLogger {
+       l := &MultiChannelledLogger{
+               MultiChannelledLog: NewMultiChannelledLog(name, buffer),
+               bufferLength:       buffer,
+       }
+       l.LevelLogger = l
+       return l
+}
+
+// SetLogger sets new logger instance with given logger provider and config.
+func (l *MultiChannelledLogger) SetLogger(name, provider, config string) error {
+       eventLogger, err := NewChannelledLog(name, provider, config, l.bufferLength)
+       if err != nil {
+               return fmt.Errorf("Failed to create sublogger (%s): %v", name, err)
+       }
+
+       l.MultiChannelledLog.DelLogger(name)
+
+       err = l.MultiChannelledLog.AddLogger(eventLogger)
+       if err != nil {
+               if IsErrDuplicateName(err) {
+                       return fmt.Errorf("Duplicate named sublogger %s %v", name, l.MultiChannelledLog.GetEventLoggerNames())
+               }
+               return fmt.Errorf("Failed to add sublogger (%s): %v", name, err)
+       }
+
+       return nil
+}
+
+// DelLogger deletes a sublogger from this logger.
+func (l *MultiChannelledLogger) DelLogger(name string) (bool, error) {
+       return l.MultiChannelledLog.DelLogger(name), nil
+}
+
+// Log msg at the provided level with the provided caller defined by skip (0 being the function that calls this function)
+func (l *MultiChannelledLogger) Log(skip int, level Level, format string, v ...interface{}) error {
+       if l.GetLevel() > level {
+               return nil
+       }
+       caller := "?()"
+       pc, filename, line, ok := runtime.Caller(skip + 1)
+       if ok {
+               // Get caller function name.
+               fn := runtime.FuncForPC(pc)
+               if fn != nil {
+                       caller = fn.Name() + "()"
+               }
+       }
+       msg := format
+       if len(v) > 0 {
+               msg = ColorSprintf(format, v...)
+       }
+       stack := ""
+       if l.GetStacktraceLevel() <= level {
+               stack = Stack(skip + 1)
+       }
+       return l.SendLog(level, caller, strings.TrimPrefix(filename, prefix), line, msg, stack)
+}
+
+// SendLog sends a log event at the provided level with the information given
+func (l *MultiChannelledLogger) SendLog(level Level, caller, filename string, line int, msg string, stack string) error {
+       if l.GetLevel() > level {
+               return nil
+       }
+       event := &Event{
+               level:      level,
+               caller:     caller,
+               filename:   filename,
+               line:       line,
+               msg:        msg,
+               time:       time.Now(),
+               stacktrace: stack,
+       }
+       l.LogEvent(event)
+       return nil
+}