mirror of https://github.com/cloudreve/Cloudreve
206 lines
4.6 KiB
Go
206 lines
4.6 KiB
Go
package logging
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"github.com/fatih/color"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/gofrs/uuid"
|
|
"runtime"
|
|
"time"
|
|
)
|
|
|
|
// Logger interface for logging messages.
|
|
type Logger interface {
|
|
Panic(format string, v ...any)
|
|
Error(format string, v ...any)
|
|
Warning(format string, v ...any)
|
|
Info(format string, v ...any)
|
|
Debug(format string, v ...any)
|
|
// Copy a new logger with a prefix.
|
|
CopyWithPrefix(prefix string) Logger
|
|
|
|
// SupportColor returns if current logger support outputting colors.
|
|
SupportColor() bool
|
|
}
|
|
|
|
// LoggerCtx defines keys for logger with correlation ID
|
|
type LoggerCtx struct{}
|
|
|
|
// CorrelationIDCtx defines keys for correlation ID
|
|
type CorrelationIDCtx struct{}
|
|
type LogLevel string
|
|
|
|
const (
|
|
// LevelError 错误
|
|
LevelError LogLevel = "error"
|
|
// LevelWarning 警告
|
|
LevelWarning LogLevel = "warning"
|
|
// LevelInformational 提示
|
|
LevelInformational LogLevel = "info"
|
|
// LevelDebug 除错
|
|
LevelDebug LogLevel = "debug"
|
|
)
|
|
|
|
// NewConsoleLogger initializes a new logging that prints logs to Stdout.
|
|
func NewConsoleLogger(level LogLevel) Logger {
|
|
logFunc := func(level string) loggingFunc {
|
|
return func(logger *consoleLogger, s string, a ...any) {
|
|
msg := fmt.Sprintf(s, a...)
|
|
logger.println(level, msg)
|
|
}
|
|
}
|
|
|
|
logger := &consoleLogger{
|
|
warning: logFunc("Warn"),
|
|
panic: func(logger *consoleLogger, s string, a ...any) {
|
|
msg := fmt.Sprintf(s, a...)
|
|
logger.println("Panic", msg)
|
|
panic(msg)
|
|
},
|
|
error: logFunc("Error"),
|
|
info: logFunc("Info"),
|
|
debug: logFunc("Debug"),
|
|
}
|
|
|
|
switch level {
|
|
case LevelError:
|
|
logger.warning = noopLoggingFunc
|
|
logger.info = noopLoggingFunc
|
|
logger.debug = noopLoggingFunc
|
|
case LevelWarning:
|
|
logger.info = noopLoggingFunc
|
|
logger.debug = noopLoggingFunc
|
|
case LevelInformational:
|
|
logger.debug = noopLoggingFunc
|
|
case LevelDebug:
|
|
|
|
}
|
|
|
|
return logger
|
|
}
|
|
|
|
// FromContext retrieves a logger from context.
|
|
func FromContext(ctx context.Context) Logger {
|
|
v, ok := ctx.Value(LoggerCtx{}).(Logger)
|
|
if !ok {
|
|
v = NewConsoleLogger(LevelDebug)
|
|
}
|
|
return v
|
|
}
|
|
|
|
// CorrelationID retrieves a correlation ID from context.
|
|
func CorrelationID(ctx context.Context) uuid.UUID {
|
|
v, ok := ctx.Value(CorrelationIDCtx{}).(uuid.UUID)
|
|
if !ok {
|
|
v = uuid.Nil
|
|
}
|
|
return v
|
|
}
|
|
|
|
type consoleLogger struct {
|
|
warning loggingFunc
|
|
panic loggingFunc
|
|
error loggingFunc
|
|
info loggingFunc
|
|
debug loggingFunc
|
|
prefix string
|
|
}
|
|
|
|
func (ll *consoleLogger) Panic(format string, v ...any) {
|
|
ll.panic(ll, format, v...)
|
|
}
|
|
|
|
func (ll *consoleLogger) Error(format string, v ...any) {
|
|
ll.error(ll, format, v...)
|
|
}
|
|
|
|
func (ll *consoleLogger) Warning(format string, v ...any) {
|
|
ll.warning(ll, format, v...)
|
|
}
|
|
|
|
func (ll *consoleLogger) Info(format string, v ...any) {
|
|
ll.info(ll, format, v...)
|
|
}
|
|
|
|
func (ll *consoleLogger) Debug(format string, v ...any) {
|
|
ll.debug(ll, format, v...)
|
|
}
|
|
|
|
// println 打印
|
|
func (ll *consoleLogger) println(level string, msg string) {
|
|
c := color.New()
|
|
_, filename, line, _ := runtime.Caller(3)
|
|
|
|
_, _ = c.Printf(
|
|
"%s\t %s [%s:%d]%s %s\n",
|
|
colors[level]("["+level+"]"),
|
|
time.Now().Format("2006-01-02 15:04:05"),
|
|
filename,
|
|
line,
|
|
ll.prefix,
|
|
msg,
|
|
)
|
|
}
|
|
|
|
func (ll *consoleLogger) CopyWithPrefix(prefix string) Logger {
|
|
return &consoleLogger{
|
|
warning: ll.warning,
|
|
panic: ll.panic,
|
|
error: ll.error,
|
|
info: ll.info,
|
|
debug: ll.debug,
|
|
prefix: ll.prefix + " " + prefix,
|
|
}
|
|
}
|
|
|
|
func (ll *consoleLogger) SupportColor() bool {
|
|
return !color.NoColor
|
|
}
|
|
|
|
type loggingFunc func(*consoleLogger, string, ...any)
|
|
|
|
func noopLoggingFunc(*consoleLogger, string, ...any) {}
|
|
|
|
var colors = map[string]func(a ...interface{}) string{
|
|
"Warn": color.New(color.FgYellow).Add(color.Bold).SprintFunc(),
|
|
"Panic": color.New(color.BgRed).Add(color.Bold).SprintFunc(),
|
|
"Error": color.New(color.FgRed).Add(color.Bold).SprintFunc(),
|
|
"Info": color.New(color.FgCyan).Add(color.Bold).SprintFunc(),
|
|
"Debug": color.New(color.FgWhite).Add(color.Bold).SprintFunc(),
|
|
}
|
|
|
|
// Request helper fund to log request.
|
|
func Request(l Logger, incoming bool, code int, method, clientIP, path, err string, start time.Time) {
|
|
param := gin.LogFormatterParams{
|
|
StatusCode: code,
|
|
Method: method,
|
|
}
|
|
param.StatusCode = code
|
|
|
|
var statusColor, methodColor, resetColor string
|
|
if l.SupportColor() {
|
|
statusColor = param.StatusCodeColor()
|
|
methodColor = param.MethodColor()
|
|
resetColor = param.ResetColor()
|
|
}
|
|
|
|
category := "Incoming"
|
|
if !incoming {
|
|
category = "Outgoing"
|
|
}
|
|
|
|
l.Info(
|
|
"[%s] %s %3d %s| %13v | %15s |%s %-7s %s %#v",
|
|
category,
|
|
statusColor, param.StatusCode, resetColor,
|
|
time.Now().Sub(start),
|
|
clientIP,
|
|
methodColor, method, resetColor,
|
|
path,
|
|
)
|
|
if err != "" {
|
|
l.Error("%s", err)
|
|
}
|
|
}
|