394 lines
7.3 KiB
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)
|
|
}
|