mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-11-02 23:41:05 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			348 lines
		
	
	
	
		
			7.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			348 lines
		
	
	
	
		
			7.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2014 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"
 | 
						|
	"os"
 | 
						|
	"path"
 | 
						|
	"path/filepath"
 | 
						|
	"runtime"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"golang.org/x/sync/syncmap"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	loggers []*Logger
 | 
						|
	// GitLogger logger for git
 | 
						|
	GitLogger *Logger
 | 
						|
)
 | 
						|
 | 
						|
// NewLogger create a logger
 | 
						|
func NewLogger(bufLen int64, mode, config string) {
 | 
						|
	logger := newLogger(bufLen)
 | 
						|
 | 
						|
	isExist := false
 | 
						|
	for i, l := range loggers {
 | 
						|
		if l.adapter == mode {
 | 
						|
			isExist = true
 | 
						|
			loggers[i] = logger
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if !isExist {
 | 
						|
		loggers = append(loggers, logger)
 | 
						|
	}
 | 
						|
	if err := logger.SetLogger(mode, config); err != nil {
 | 
						|
		Fatal(2, "Failed to set logger (%s): %v", mode, err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// DelLogger removes loggers that are for the given mode
 | 
						|
func DelLogger(mode string) error {
 | 
						|
	for _, l := range loggers {
 | 
						|
		if _, ok := l.outputs.Load(mode); ok {
 | 
						|
			return l.DelLogger(mode)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	Trace("Log adapter %s not found, no need to delete", mode)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// NewGitLogger create a logger for git
 | 
						|
// FIXME: use same log level as other loggers.
 | 
						|
func NewGitLogger(logPath string) {
 | 
						|
	path := path.Dir(logPath)
 | 
						|
 | 
						|
	if err := os.MkdirAll(path, os.ModePerm); err != nil {
 | 
						|
		Fatal(4, "Failed to create dir %s: %v", path, err)
 | 
						|
	}
 | 
						|
 | 
						|
	GitLogger = newLogger(0)
 | 
						|
	GitLogger.SetLogger("file", fmt.Sprintf(`{"level":0,"filename":"%s","rotate":false}`, logPath))
 | 
						|
}
 | 
						|
 | 
						|
// Trace records trace log
 | 
						|
func Trace(format string, v ...interface{}) {
 | 
						|
	for _, logger := range loggers {
 | 
						|
		logger.Trace(format, v...)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Debug records debug log
 | 
						|
func Debug(format string, v ...interface{}) {
 | 
						|
	for _, logger := range loggers {
 | 
						|
		logger.Debug(format, v...)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Info records info log
 | 
						|
func Info(format string, v ...interface{}) {
 | 
						|
	for _, logger := range loggers {
 | 
						|
		logger.Info(format, v...)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Warn records warning log
 | 
						|
func Warn(format string, v ...interface{}) {
 | 
						|
	for _, logger := range loggers {
 | 
						|
		logger.Warn(format, v...)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Error records error log
 | 
						|
func Error(skip int, format string, v ...interface{}) {
 | 
						|
	for _, logger := range loggers {
 | 
						|
		logger.Error(skip, format, v...)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Critical records critical log
 | 
						|
func Critical(skip int, format string, v ...interface{}) {
 | 
						|
	for _, logger := range loggers {
 | 
						|
		logger.Critical(skip, format, v...)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Fatal records error log and exit process
 | 
						|
func Fatal(skip int, format string, v ...interface{}) {
 | 
						|
	Error(skip, format, v...)
 | 
						|
	for _, l := range loggers {
 | 
						|
		l.Close()
 | 
						|
	}
 | 
						|
	os.Exit(1)
 | 
						|
}
 | 
						|
 | 
						|
// Close closes all the loggers
 | 
						|
func Close() {
 | 
						|
	for _, l := range loggers {
 | 
						|
		l.Close()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// .___        __                 _____
 | 
						|
// |   | _____/  |_  ____________/ ____\____    ____  ____
 | 
						|
// |   |/    \   __\/ __ \_  __ \   __\\__  \ _/ ___\/ __ \
 | 
						|
// |   |   |  \  | \  ___/|  | \/|  |   / __ \\  \__\  ___/
 | 
						|
// |___|___|  /__|  \___  >__|   |__|  (____  /\___  >___  >
 | 
						|
//          \/          \/                  \/     \/    \/
 | 
						|
 | 
						|
// LogLevel level type for log
 | 
						|
//type LogLevel int
 | 
						|
 | 
						|
// log levels
 | 
						|
const (
 | 
						|
	TRACE = iota
 | 
						|
	DEBUG
 | 
						|
	INFO
 | 
						|
	WARN
 | 
						|
	ERROR
 | 
						|
	CRITICAL
 | 
						|
	FATAL
 | 
						|
)
 | 
						|
 | 
						|
// LoggerInterface represents behaviors of a logger provider.
 | 
						|
type LoggerInterface interface {
 | 
						|
	Init(config string) error
 | 
						|
	WriteMsg(msg string, skip, level int) error
 | 
						|
	Destroy()
 | 
						|
	Flush()
 | 
						|
}
 | 
						|
 | 
						|
type loggerType func() LoggerInterface
 | 
						|
 | 
						|
var adapters = make(map[string]loggerType)
 | 
						|
 | 
						|
// Register registers given logger provider to adapters.
 | 
						|
func Register(name string, log loggerType) {
 | 
						|
	if log == nil {
 | 
						|
		panic("log: register provider is nil")
 | 
						|
	}
 | 
						|
	if _, dup := adapters[name]; dup {
 | 
						|
		panic("log: register called twice for provider \"" + name + "\"")
 | 
						|
	}
 | 
						|
	adapters[name] = log
 | 
						|
}
 | 
						|
 | 
						|
type logMsg struct {
 | 
						|
	skip, level int
 | 
						|
	msg         string
 | 
						|
}
 | 
						|
 | 
						|
// Logger is default logger in beego application.
 | 
						|
// it can contain several providers and log message into all providers.
 | 
						|
type Logger struct {
 | 
						|
	adapter string
 | 
						|
	level   int
 | 
						|
	msg     chan *logMsg
 | 
						|
	outputs syncmap.Map
 | 
						|
	quit    chan bool
 | 
						|
}
 | 
						|
 | 
						|
// newLogger initializes and returns a new logger.
 | 
						|
func newLogger(buffer int64) *Logger {
 | 
						|
	l := &Logger{
 | 
						|
		msg:  make(chan *logMsg, buffer),
 | 
						|
		quit: make(chan bool),
 | 
						|
	}
 | 
						|
	go l.StartLogger()
 | 
						|
	return l
 | 
						|
}
 | 
						|
 | 
						|
// SetLogger sets new logger instance with given logger adapter and config.
 | 
						|
func (l *Logger) SetLogger(adapter string, config string) error {
 | 
						|
	if log, ok := adapters[adapter]; ok {
 | 
						|
		lg := log()
 | 
						|
		if err := lg.Init(config); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		l.outputs.Store(adapter, lg)
 | 
						|
		l.adapter = adapter
 | 
						|
	} else {
 | 
						|
		panic("log: unknown adapter \"" + adapter + "\" (forgotten register?)")
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// DelLogger removes a logger adapter instance.
 | 
						|
func (l *Logger) DelLogger(adapter string) error {
 | 
						|
	if lg, ok := l.outputs.Load(adapter); ok {
 | 
						|
		lg.(LoggerInterface).Destroy()
 | 
						|
		l.outputs.Delete(adapter)
 | 
						|
	} else {
 | 
						|
		panic("log: unknown adapter \"" + adapter + "\" (forgotten register?)")
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (l *Logger) writerMsg(skip, level int, msg string) error {
 | 
						|
	if l.level > level {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	lm := &logMsg{
 | 
						|
		skip:  skip,
 | 
						|
		level: level,
 | 
						|
	}
 | 
						|
 | 
						|
	// Only error information needs locate position for debugging.
 | 
						|
	if lm.level >= ERROR {
 | 
						|
		pc, file, line, ok := runtime.Caller(skip)
 | 
						|
		if ok {
 | 
						|
			// Get caller function name.
 | 
						|
			fn := runtime.FuncForPC(pc)
 | 
						|
			var fnName string
 | 
						|
			if fn == nil {
 | 
						|
				fnName = "?()"
 | 
						|
			} else {
 | 
						|
				fnName = strings.TrimLeft(filepath.Ext(fn.Name()), ".") + "()"
 | 
						|
			}
 | 
						|
 | 
						|
			fileName := file
 | 
						|
			if len(fileName) > 20 {
 | 
						|
				fileName = "..." + fileName[len(fileName)-20:]
 | 
						|
			}
 | 
						|
			lm.msg = fmt.Sprintf("[%s:%d %s] %s", fileName, line, fnName, msg)
 | 
						|
		} else {
 | 
						|
			lm.msg = msg
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		lm.msg = msg
 | 
						|
	}
 | 
						|
	l.msg <- lm
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// StartLogger starts logger chan reading.
 | 
						|
func (l *Logger) StartLogger() {
 | 
						|
	for {
 | 
						|
		select {
 | 
						|
		case bm := <-l.msg:
 | 
						|
			l.outputs.Range(func(k, v interface{}) bool {
 | 
						|
				if err := v.(LoggerInterface).WriteMsg(bm.msg, bm.skip, bm.level); err != nil {
 | 
						|
					fmt.Println("ERROR, unable to WriteMsg:", err)
 | 
						|
				}
 | 
						|
				return true
 | 
						|
			})
 | 
						|
		case <-l.quit:
 | 
						|
			return
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Flush flushes all chan data.
 | 
						|
func (l *Logger) Flush() {
 | 
						|
	l.outputs.Range(func(k, v interface{}) bool {
 | 
						|
		v.(LoggerInterface).Flush()
 | 
						|
		return true
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// Close closes logger, flush all chan data and destroy all adapter instances.
 | 
						|
func (l *Logger) Close() {
 | 
						|
	l.quit <- true
 | 
						|
	for {
 | 
						|
		if len(l.msg) > 0 {
 | 
						|
			bm := <-l.msg
 | 
						|
			l.outputs.Range(func(k, v interface{}) bool {
 | 
						|
				if err := v.(LoggerInterface).WriteMsg(bm.msg, bm.skip, bm.level); err != nil {
 | 
						|
					fmt.Println("ERROR, unable to WriteMsg:", err)
 | 
						|
				}
 | 
						|
				return true
 | 
						|
			})
 | 
						|
		} else {
 | 
						|
			break
 | 
						|
		}
 | 
						|
	}
 | 
						|
	l.outputs.Range(func(k, v interface{}) bool {
 | 
						|
		v.(LoggerInterface).Flush()
 | 
						|
		v.(LoggerInterface).Destroy()
 | 
						|
		return true
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// Trace records trace log
 | 
						|
func (l *Logger) Trace(format string, v ...interface{}) {
 | 
						|
	msg := fmt.Sprintf("[T] "+format, v...)
 | 
						|
	l.writerMsg(0, TRACE, msg)
 | 
						|
}
 | 
						|
 | 
						|
// Debug records debug log
 | 
						|
func (l *Logger) Debug(format string, v ...interface{}) {
 | 
						|
	msg := fmt.Sprintf("[D] "+format, v...)
 | 
						|
	l.writerMsg(0, DEBUG, msg)
 | 
						|
}
 | 
						|
 | 
						|
// Info records information log
 | 
						|
func (l *Logger) Info(format string, v ...interface{}) {
 | 
						|
	msg := fmt.Sprintf("[I] "+format, v...)
 | 
						|
	l.writerMsg(0, INFO, msg)
 | 
						|
}
 | 
						|
 | 
						|
// Warn records warning log
 | 
						|
func (l *Logger) Warn(format string, v ...interface{}) {
 | 
						|
	msg := fmt.Sprintf("[W] "+format, v...)
 | 
						|
	l.writerMsg(0, WARN, msg)
 | 
						|
}
 | 
						|
 | 
						|
// Error records error log
 | 
						|
func (l *Logger) Error(skip int, format string, v ...interface{}) {
 | 
						|
	msg := fmt.Sprintf("[E] "+format, v...)
 | 
						|
	l.writerMsg(skip, ERROR, msg)
 | 
						|
}
 | 
						|
 | 
						|
// Critical records critical log
 | 
						|
func (l *Logger) Critical(skip int, format string, v ...interface{}) {
 | 
						|
	msg := fmt.Sprintf("[C] "+format, v...)
 | 
						|
	l.writerMsg(skip, CRITICAL, msg)
 | 
						|
}
 | 
						|
 | 
						|
// Fatal records error log and exit the process
 | 
						|
func (l *Logger) Fatal(skip int, format string, v ...interface{}) {
 | 
						|
	msg := fmt.Sprintf("[F] "+format, v...)
 | 
						|
	l.writerMsg(skip, FATAL, msg)
 | 
						|
	l.Close()
 | 
						|
	os.Exit(1)
 | 
						|
}
 |