otpm/logger/logger.go
“xHuPo” bcd986e3f7 beta
2025-05-23 18:57:11 +08:00

204 lines
4.4 KiB
Go

package logger
import (
"context"
"fmt"
"io"
"os"
"runtime"
"strings"
"time"
"github.com/google/uuid"
)
// Level represents a log level
type Level int
const (
// DEBUG level
DEBUG Level = iota
// INFO level
INFO
// WARN level
WARN
// ERROR level
ERROR
// FATAL level
FATAL
)
// String returns the string representation of the log level
func (l Level) String() string {
switch l {
case DEBUG:
return "DEBUG"
case INFO:
return "INFO"
case WARN:
return "WARN"
case ERROR:
return "ERROR"
case FATAL:
return "FATAL"
default:
return "UNKNOWN"
}
}
// Logger represents a logger
type Logger struct {
level Level
output io.Writer
}
// contextKey is a type for context keys
type contextKey string
// requestIDKey is the key for request ID in context
const requestIDKey = contextKey("request_id")
// New creates a new logger
func New(level Level, output io.Writer) *Logger {
if output == nil {
output = os.Stdout
}
return &Logger{
level: level,
output: output,
}
}
// WithLevel creates a new logger with the specified level
func (l *Logger) WithLevel(level Level) *Logger {
return &Logger{
level: level,
output: l.output,
}
}
// WithOutput creates a new logger with the specified output
func (l *Logger) WithOutput(output io.Writer) *Logger {
return &Logger{
level: l.level,
output: output,
}
}
// log logs a message with the specified level
func (l *Logger) log(ctx context.Context, level Level, format string, args ...interface{}) {
if level < l.level {
return
}
// Get request ID from context
requestID := getRequestID(ctx)
// Get caller information
_, file, line, ok := runtime.Caller(2)
if !ok {
file = "unknown"
line = 0
}
// Extract just the filename
if idx := strings.LastIndex(file, "/"); idx >= 0 {
file = file[idx+1:]
}
// Format message
message := fmt.Sprintf(format, args...)
// Format log entry
timestamp := time.Now().Format(time.RFC3339)
logEntry := fmt.Sprintf("%s [%s] %s:%d [%s] %s\n",
timestamp, level.String(), file, line, requestID, message)
// Write log entry
_, _ = l.output.Write([]byte(logEntry))
// Exit if fatal
if level == FATAL {
os.Exit(1)
}
}
// Debug logs a debug message
func (l *Logger) Debug(ctx context.Context, format string, args ...interface{}) {
l.log(ctx, DEBUG, format, args...)
}
// Info logs an info message
func (l *Logger) Info(ctx context.Context, format string, args ...interface{}) {
l.log(ctx, INFO, format, args...)
}
// Warn logs a warning message
func (l *Logger) Warn(ctx context.Context, format string, args ...interface{}) {
l.log(ctx, WARN, format, args...)
}
// Error logs an error message
func (l *Logger) Error(ctx context.Context, format string, args ...interface{}) {
l.log(ctx, ERROR, format, args...)
}
// Fatal logs a fatal message and exits
func (l *Logger) Fatal(ctx context.Context, format string, args ...interface{}) {
l.log(ctx, FATAL, format, args...)
}
// WithRequestID adds a request ID to the context
func WithRequestID(ctx context.Context) context.Context {
requestID := uuid.New().String()
return context.WithValue(ctx, requestIDKey, requestID)
}
// GetRequestID gets the request ID from the context
func GetRequestID(ctx context.Context) string {
return getRequestID(ctx)
}
// getRequestID gets the request ID from the context
func getRequestID(ctx context.Context) string {
if ctx == nil {
return "-"
}
requestID, ok := ctx.Value(requestIDKey).(string)
if !ok {
return "-"
}
return requestID
}
// Default logger
var defaultLogger = New(INFO, os.Stdout)
// SetDefaultLogger sets the default logger
func SetDefaultLogger(logger *Logger) {
defaultLogger = logger
}
// Debug logs a debug message using the default logger
func Debug(ctx context.Context, format string, args ...interface{}) {
defaultLogger.Debug(ctx, format, args...)
}
// Info logs an info message using the default logger
func Info(ctx context.Context, format string, args ...interface{}) {
defaultLogger.Info(ctx, format, args...)
}
// Warn logs a warning message using the default logger
func Warn(ctx context.Context, format string, args ...interface{}) {
defaultLogger.Warn(ctx, format, args...)
}
// Error logs an error message using the default logger
func Error(ctx context.Context, format string, args ...interface{}) {
defaultLogger.Error(ctx, format, args...)
}
// Fatal logs a fatal message and exits using the default logger
func Fatal(ctx context.Context, format string, args ...interface{}) {
defaultLogger.Fatal(ctx, format, args...)
}