gomog/pkg/logger/logger.go

394 lines
7.3 KiB
Go

package logger
import (
"context"
"fmt"
"io"
"os"
"runtime"
"sync"
"time"
)
// Level 日志级别
type Level int
const (
DEBUG Level = iota
INFO
WARN
ERROR
FATAL
)
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"
}
}
// Fields 日志字段的类型别名
type Fields map[string]interface{}
// Logger 结构化日志器
type Logger struct {
mu sync.Mutex
level Level
output io.Writer
prefix string
fields Fields
hooks []Hook
}
// Hook 日志钩子接口
type Hook interface {
Fire(entry *Entry) error
Levels() []Level
}
// Entry 日志条目
type Entry struct {
Logger *Logger
Time time.Time
Level Level
Message string
Fields Fields
Caller string
Context context.Context
}
// New 创建新的日志器
func New() *Logger {
return &Logger{
level: INFO,
output: os.Stdout,
fields: make(Fields),
}
}
// SetLevel 设置日志级别
func (l *Logger) SetLevel(level Level) {
l.mu.Lock()
defer l.mu.Unlock()
l.level = level
}
// GetLevel 获取日志级别
func (l *Logger) GetLevel() Level {
l.mu.Lock()
defer l.mu.Unlock()
return l.level
}
// SetOutput 设置输出目标
func (l *Logger) SetOutput(w io.Writer) {
l.mu.Lock()
defer l.mu.Unlock()
l.output = w
}
// WithPrefix 设置前缀
func (l *Logger) WithPrefix(prefix string) *Logger {
return &Logger{
level: l.level,
output: l.output,
prefix: prefix,
fields: make(Fields),
}
}
// WithField 添加单个字段
func (l *Logger) WithField(key string, value interface{}) *Logger {
l.mu.Lock()
defer l.mu.Unlock()
newFields := make(Fields, len(l.fields)+1)
for k, v := range l.fields {
newFields[k] = v
}
newFields[key] = value
return &Logger{
level: l.level,
output: l.output,
prefix: l.prefix,
fields: newFields,
hooks: l.hooks, // 复制钩子
}
}
// WithFields 添加多个字段
func (l *Logger) WithFields(fields Fields) *Logger {
l.mu.Lock()
defer l.mu.Unlock()
newFields := make(Fields, len(l.fields)+len(fields))
for k, v := range l.fields {
newFields[k] = v
}
for k, v := range fields {
newFields[k] = v
}
return &Logger{
level: l.level,
output: l.output,
prefix: l.prefix,
fields: newFields,
hooks: l.hooks, // 复制钩子
}
}
// WithContext 添加上下文
func (l *Logger) WithContext(ctx context.Context) *Logger {
return &Logger{
level: l.level,
output: l.output,
prefix: l.prefix,
fields: l.fields,
}
}
// AddHook 添加钩子
func (l *Logger) AddHook(hook Hook) {
l.mu.Lock()
defer l.mu.Unlock()
l.hooks = append(l.hooks, hook)
}
// newEntry 创建新的日志条目
func (l *Logger) newEntry(level Level, msg string) *Entry {
l.mu.Lock()
defer l.mu.Unlock()
entry := &Entry{
Logger: l,
Time: time.Now(),
Level: level,
Message: msg,
Fields: make(Fields, len(l.fields)),
}
// 复制字段
for k, v := range l.fields {
entry.Fields[k] = v
}
// 添加调用者信息
if _, file, line, ok := runtime.Caller(2); ok {
entry.Caller = fmt.Sprintf("%s:%d", file, line)
}
return entry
}
// Debug 记录 DEBUG 级别日志
func (l *Logger) Debug(msg string) {
if l.level <= DEBUG {
l.newEntry(DEBUG, msg).Log()
}
}
// Info 记录 INFO 级别日志
func (l *Logger) Info(msg string) {
if l.level <= INFO {
l.newEntry(INFO, msg).Log()
}
}
// Warn 记录 WARN 级别日志
func (l *Logger) Warn(msg string) {
if l.level <= WARN {
l.newEntry(WARN, msg).Log()
}
}
// Error 记录 ERROR 级别日志
func (l *Logger) Error(msg string) {
if l.level <= ERROR {
l.newEntry(ERROR, msg).Log()
}
}
// Fatal 记录 FATAL 级别日志
func (l *Logger) Fatal(msg string) {
if l.level <= FATAL {
l.newEntry(FATAL, msg).Log()
os.Exit(1)
}
}
// Debugf 记录带格式化的 DEBUG 级别日志
func (l *Logger) Debugf(format string, args ...interface{}) {
l.Debug(fmt.Sprintf(format, args...))
}
// Infof 记录带格式化的 INFO 级别日志
func (l *Logger) Infof(format string, args ...interface{}) {
l.Info(fmt.Sprintf(format, args...))
}
// Warnf 记录带格式化的 WARN 级别日志
func (l *Logger) Warnf(format string, args ...interface{}) {
l.Warn(fmt.Sprintf(format, args...))
}
// Errorf 记录带格式化的 ERROR 级别日志
func (l *Logger) Errorf(format string, args ...interface{}) {
l.Error(fmt.Sprintf(format, args...))
}
// Fatalf 记录带格式化的 FATAL 级别日志
func (l *Logger) Fatalf(format string, args ...interface{}) {
l.Fatal(fmt.Sprintf(format, args...))
}
// Log 记录日志条目
func (e *Entry) Log() {
formatted := e.format()
e.Logger.mu.Lock()
_, _ = e.Logger.output.Write([]byte(formatted))
e.Logger.mu.Unlock()
// 触发钩子
for _, hook := range e.Logger.hooks {
for _, level := range hook.Levels() {
if e.Level == level {
_ = hook.Fire(e)
}
}
}
}
// format 格式化日志条目
func (e *Entry) format() string {
timestamp := e.Time.Format("2006-01-02 15:04:05.000")
var callerStr string
if e.Caller != "" {
callerStr = fmt.Sprintf("[%s] ", e.Caller)
}
var prefixStr string
if e.Logger.prefix != "" {
prefixStr = fmt.Sprintf("[%s] ", e.Logger.prefix)
}
// 格式化字段
fieldsStr := ""
for k, v := range e.Fields {
fieldsStr += fmt.Sprintf("%s=%v ", k, v)
}
return fmt.Sprintf("%s %s%s%s%s%s\n",
timestamp,
e.Level.String(),
callerStr,
prefixStr,
e.Message,
fieldsStr,
)
}
// 性能追踪相关
// TimingEntry 性能计时条目
type TimingEntry struct {
logger *Logger
start time.Time
operation string
fields Fields
}
// BeginTiming 开始性能追踪
func (l *Logger) BeginTiming(operation string) *TimingEntry {
return &TimingEntry{
logger: l.WithField("operation", operation),
start: time.Now(),
operation: operation,
fields: make(Fields),
}
}
// WithField 添加追踪字段
func (t *TimingEntry) WithField(key string, value interface{}) *TimingEntry {
t.fields[key] = value
return t
}
// End 结束性能追踪并记录
func (t *TimingEntry) End(msg string) {
duration := time.Since(t.start)
t.logger.WithFields(t.fields).WithField("duration_ms", float64(duration.Nanoseconds())/1e6).Info(msg)
}
// 全局默认日志器
var defaultLogger = New()
// Default 获取默认日志器
func Default() *Logger {
return defaultLogger
}
// SetDefault 设置默认日志器
func SetDefault(logger *Logger) {
defaultLogger = logger
}
// 便捷函数
func Debug(msg string) {
defaultLogger.Debug(msg)
}
func Info(msg string) {
defaultLogger.Info(msg)
}
func Warn(msg string) {
defaultLogger.Warn(msg)
}
func Error(msg string) {
defaultLogger.Error(msg)
}
func Fatal(msg string) {
defaultLogger.Fatal(msg)
}
func Debugf(format string, args ...interface{}) {
defaultLogger.Debugf(format, args...)
}
func Infof(format string, args ...interface{}) {
defaultLogger.Infof(format, args...)
}
func Warnf(format string, args ...interface{}) {
defaultLogger.Warnf(format, args...)
}
func Errorf(format string, args ...interface{}) {
defaultLogger.Errorf(format, args...)
}
func Fatalf(format string, args ...interface{}) {
defaultLogger.Fatalf(format, args...)
}
func WithField(key string, value interface{}) *Logger {
return defaultLogger.WithField(key, value)
}
func WithFields(fields Fields) *Logger {
return defaultLogger.WithFields(fields)
}