code.gitea.io/gitea@v1.19.3/modules/log/log.go (about)

     1  // Copyright 2014 The Gogs Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package log
     5  
     6  import (
     7  	"fmt"
     8  	"os"
     9  	"runtime"
    10  	"strings"
    11  	"sync"
    12  
    13  	"code.gitea.io/gitea/modules/process"
    14  )
    15  
    16  type loggerMap struct {
    17  	sync.Map
    18  }
    19  
    20  func (m *loggerMap) Load(k string) (*MultiChannelledLogger, bool) {
    21  	v, ok := m.Map.Load(k)
    22  	if !ok {
    23  		return nil, false
    24  	}
    25  	l, ok := v.(*MultiChannelledLogger)
    26  	return l, ok
    27  }
    28  
    29  func (m *loggerMap) Store(k string, v *MultiChannelledLogger) {
    30  	m.Map.Store(k, v)
    31  }
    32  
    33  func (m *loggerMap) Delete(k string) {
    34  	m.Map.Delete(k)
    35  }
    36  
    37  var (
    38  	// DEFAULT is the name of the default logger
    39  	DEFAULT = "default"
    40  	// NamedLoggers map of named loggers
    41  	NamedLoggers loggerMap
    42  	prefix       string
    43  )
    44  
    45  // NewLogger create a logger for the default logger
    46  func NewLogger(bufLen int64, name, provider, config string) *MultiChannelledLogger {
    47  	err := NewNamedLogger(DEFAULT, bufLen, name, provider, config)
    48  	if err != nil {
    49  		CriticalWithSkip(1, "Unable to create default logger: %v", err)
    50  		panic(err)
    51  	}
    52  	l, _ := NamedLoggers.Load(DEFAULT)
    53  	return l
    54  }
    55  
    56  // NewNamedLogger creates a new named logger for a given configuration
    57  func NewNamedLogger(name string, bufLen int64, subname, provider, config string) error {
    58  	logger, ok := NamedLoggers.Load(name)
    59  	if !ok {
    60  		logger = newLogger(name, bufLen)
    61  		NamedLoggers.Store(name, logger)
    62  	}
    63  
    64  	return logger.SetLogger(subname, provider, config)
    65  }
    66  
    67  // DelNamedLogger closes and deletes the named logger
    68  func DelNamedLogger(name string) {
    69  	l, ok := NamedLoggers.Load(name)
    70  	if ok {
    71  		NamedLoggers.Delete(name)
    72  		l.Close()
    73  	}
    74  }
    75  
    76  // DelLogger removes the named sublogger from the default logger
    77  func DelLogger(name string) error {
    78  	logger, _ := NamedLoggers.Load(DEFAULT)
    79  	found, err := logger.DelLogger(name)
    80  	if !found {
    81  		Trace("Log %s not found, no need to delete", name)
    82  	}
    83  	return err
    84  }
    85  
    86  // GetLogger returns either a named logger or the default logger
    87  func GetLogger(name string) *MultiChannelledLogger {
    88  	logger, ok := NamedLoggers.Load(name)
    89  	if ok {
    90  		return logger
    91  	}
    92  	logger, _ = NamedLoggers.Load(DEFAULT)
    93  	return logger
    94  }
    95  
    96  // GetLevel returns the minimum logger level
    97  func GetLevel() Level {
    98  	l, _ := NamedLoggers.Load(DEFAULT)
    99  	return l.GetLevel()
   100  }
   101  
   102  // GetStacktraceLevel returns the minimum logger level
   103  func GetStacktraceLevel() Level {
   104  	l, _ := NamedLoggers.Load(DEFAULT)
   105  	return l.GetStacktraceLevel()
   106  }
   107  
   108  // Trace records trace log
   109  func Trace(format string, v ...interface{}) {
   110  	Log(1, TRACE, format, v...)
   111  }
   112  
   113  // IsTrace returns true if at least one logger is TRACE
   114  func IsTrace() bool {
   115  	return GetLevel() <= TRACE
   116  }
   117  
   118  // Debug records debug log
   119  func Debug(format string, v ...interface{}) {
   120  	Log(1, DEBUG, format, v...)
   121  }
   122  
   123  // IsDebug returns true if at least one logger is DEBUG
   124  func IsDebug() bool {
   125  	return GetLevel() <= DEBUG
   126  }
   127  
   128  // Info records info log
   129  func Info(format string, v ...interface{}) {
   130  	Log(1, INFO, format, v...)
   131  }
   132  
   133  // IsInfo returns true if at least one logger is INFO
   134  func IsInfo() bool {
   135  	return GetLevel() <= INFO
   136  }
   137  
   138  // Warn records warning log
   139  func Warn(format string, v ...interface{}) {
   140  	Log(1, WARN, format, v...)
   141  }
   142  
   143  // IsWarn returns true if at least one logger is WARN
   144  func IsWarn() bool {
   145  	return GetLevel() <= WARN
   146  }
   147  
   148  // Error records error log
   149  func Error(format string, v ...interface{}) {
   150  	Log(1, ERROR, format, v...)
   151  }
   152  
   153  // ErrorWithSkip records error log from "skip" calls back from this function
   154  func ErrorWithSkip(skip int, format string, v ...interface{}) {
   155  	Log(skip+1, ERROR, format, v...)
   156  }
   157  
   158  // IsError returns true if at least one logger is ERROR
   159  func IsError() bool {
   160  	return GetLevel() <= ERROR
   161  }
   162  
   163  // Critical records critical log
   164  func Critical(format string, v ...interface{}) {
   165  	Log(1, CRITICAL, format, v...)
   166  }
   167  
   168  // CriticalWithSkip records critical log from "skip" calls back from this function
   169  func CriticalWithSkip(skip int, format string, v ...interface{}) {
   170  	Log(skip+1, CRITICAL, format, v...)
   171  }
   172  
   173  // IsCritical returns true if at least one logger is CRITICAL
   174  func IsCritical() bool {
   175  	return GetLevel() <= CRITICAL
   176  }
   177  
   178  // Fatal records fatal log and exit process
   179  func Fatal(format string, v ...interface{}) {
   180  	Log(1, FATAL, format, v...)
   181  	Close()
   182  	os.Exit(1)
   183  }
   184  
   185  // FatalWithSkip records fatal log from "skip" calls back from this function
   186  func FatalWithSkip(skip int, format string, v ...interface{}) {
   187  	Log(skip+1, FATAL, format, v...)
   188  	Close()
   189  	os.Exit(1)
   190  }
   191  
   192  // IsFatal returns true if at least one logger is FATAL
   193  func IsFatal() bool {
   194  	return GetLevel() <= FATAL
   195  }
   196  
   197  // Pause pauses all the loggers
   198  func Pause() {
   199  	NamedLoggers.Range(func(key, value interface{}) bool {
   200  		logger := value.(*MultiChannelledLogger)
   201  		logger.Pause()
   202  		logger.Flush()
   203  		return true
   204  	})
   205  }
   206  
   207  // Resume resumes all the loggers
   208  func Resume() {
   209  	NamedLoggers.Range(func(key, value interface{}) bool {
   210  		logger := value.(*MultiChannelledLogger)
   211  		logger.Resume()
   212  		return true
   213  	})
   214  }
   215  
   216  // ReleaseReopen releases and reopens logging files
   217  func ReleaseReopen() error {
   218  	var accumulatedErr error
   219  	NamedLoggers.Range(func(key, value interface{}) bool {
   220  		logger := value.(*MultiChannelledLogger)
   221  		if err := logger.ReleaseReopen(); err != nil {
   222  			if accumulatedErr == nil {
   223  				accumulatedErr = fmt.Errorf("Error reopening %s: %w", key.(string), err)
   224  			} else {
   225  				accumulatedErr = fmt.Errorf("Error reopening %s: %v & %w", key.(string), err, accumulatedErr)
   226  			}
   227  		}
   228  		return true
   229  	})
   230  	return accumulatedErr
   231  }
   232  
   233  // Close closes all the loggers
   234  func Close() {
   235  	l, ok := NamedLoggers.Load(DEFAULT)
   236  	if !ok {
   237  		return
   238  	}
   239  	NamedLoggers.Delete(DEFAULT)
   240  	l.Close()
   241  }
   242  
   243  // Log a message with defined skip and at logging level
   244  // A skip of 0 refers to the caller of this command
   245  func Log(skip int, level Level, format string, v ...interface{}) {
   246  	l, ok := NamedLoggers.Load(DEFAULT)
   247  	if ok {
   248  		l.Log(skip+1, level, format, v...)
   249  	}
   250  }
   251  
   252  // LoggerAsWriter is a io.Writer shim around the gitea log
   253  type LoggerAsWriter struct {
   254  	ourLoggers []*MultiChannelledLogger
   255  	level      Level
   256  }
   257  
   258  // NewLoggerAsWriter creates a Writer representation of the logger with setable log level
   259  func NewLoggerAsWriter(level string, ourLoggers ...*MultiChannelledLogger) *LoggerAsWriter {
   260  	if len(ourLoggers) == 0 {
   261  		l, _ := NamedLoggers.Load(DEFAULT)
   262  		ourLoggers = []*MultiChannelledLogger{l}
   263  	}
   264  	l := &LoggerAsWriter{
   265  		ourLoggers: ourLoggers,
   266  		level:      FromString(level),
   267  	}
   268  	return l
   269  }
   270  
   271  // Write implements the io.Writer interface to allow spoofing of chi
   272  func (l *LoggerAsWriter) Write(p []byte) (int, error) {
   273  	for _, logger := range l.ourLoggers {
   274  		// Skip = 3 because this presumes that we have been called by log.Println()
   275  		// If the caller has used log.Output or the like this will be wrong
   276  		logger.Log(3, l.level, string(p))
   277  	}
   278  	return len(p), nil
   279  }
   280  
   281  // Log takes a given string and logs it at the set log-level
   282  func (l *LoggerAsWriter) Log(msg string) {
   283  	for _, logger := range l.ourLoggers {
   284  		// Set the skip to reference the call just above this
   285  		_ = logger.Log(1, l.level, msg)
   286  	}
   287  }
   288  
   289  func init() {
   290  	process.Trace = func(start bool, pid process.IDType, description string, parentPID process.IDType, typ string) {
   291  		if start && parentPID != "" {
   292  			Log(1, TRACE, "Start %s: %s (from %s) (%s)", NewColoredValue(pid, FgHiYellow), description, NewColoredValue(parentPID, FgYellow), NewColoredValue(typ, Reset))
   293  		} else if start {
   294  			Log(1, TRACE, "Start %s: %s (%s)", NewColoredValue(pid, FgHiYellow), description, NewColoredValue(typ, Reset))
   295  		} else {
   296  			Log(1, TRACE, "Done %s: %s", NewColoredValue(pid, FgHiYellow), NewColoredValue(description, Reset))
   297  		}
   298  	}
   299  	_, filename, _, _ := runtime.Caller(0)
   300  	prefix = strings.TrimSuffix(filename, "modules/log/log.go")
   301  	if prefix == filename {
   302  		// in case the source code file is moved, we can not trim the suffix, the code above should also be updated.
   303  		panic("unable to detect correct package prefix, please update file: " + filename)
   304  	}
   305  }