Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
390 lines
8.6 KiB
390 lines
8.6 KiB
// 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 |
|
|
|
// LoggerAsWriter is a io.Writer shim around the gitea log |
|
type LoggerAsWriter struct { |
|
level int |
|
} |
|
|
|
// NewLoggerAsWriter creates a Writer representation of the logger with setable log level |
|
func NewLoggerAsWriter(level string) *LoggerAsWriter { |
|
l := &LoggerAsWriter{} |
|
switch strings.ToUpper(level) { |
|
case "TRACE": |
|
l.level = TRACE |
|
case "DEBUG": |
|
l.level = DEBUG |
|
case "INFO": |
|
l.level = INFO |
|
case "WARN": |
|
l.level = WARN |
|
case "ERROR": |
|
l.level = ERROR |
|
case "CRITICAL": |
|
l.level = CRITICAL |
|
case "FATAL": |
|
l.level = FATAL |
|
default: |
|
l.level = INFO |
|
} |
|
return l |
|
} |
|
|
|
// Write implements the io.Writer interface to allow spoofing of macaron |
|
func (l *LoggerAsWriter) Write(p []byte) (int, error) { |
|
l.Log(string(p)) |
|
return len(p), nil |
|
} |
|
|
|
// Log takes a given string and logs it at the set log-level |
|
func (l *LoggerAsWriter) Log(msg string) { |
|
for _, logger := range loggers { |
|
logger.writerMsg(0, l.level, msg) |
|
} |
|
} |
|
|
|
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) |
|
}
|
|
|