153 lines
3.2 KiB
Go
153 lines
3.2 KiB
Go
package log
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"time"
|
|
|
|
"github.com/rs/zerolog"
|
|
"gopkg.in/natefinch/lumberjack.v2"
|
|
)
|
|
|
|
type LogType string
|
|
|
|
const (
|
|
TypeAccess LogType = "access"
|
|
TypeBusiness LogType = "business"
|
|
TypeError LogType = "error"
|
|
)
|
|
|
|
var (
|
|
logger zerolog.Logger
|
|
)
|
|
|
|
// Setup 初始化日志配置
|
|
func Setup(conf LogConfig) error {
|
|
// 确保日志目录存在
|
|
if err := os.MkdirAll(filepath.Dir(conf.OutputPath), 0755); err != nil {
|
|
return fmt.Errorf("create log directory failed: %v", err)
|
|
}
|
|
|
|
// 配置日志轮转
|
|
writer := &lumberjack.Logger{
|
|
Filename: conf.OutputPath,
|
|
MaxSize: conf.MaxSize, // MB
|
|
MaxAge: conf.MaxAge, // days
|
|
MaxBackups: conf.MaxBackups,
|
|
Compress: conf.Compress,
|
|
}
|
|
|
|
// 设置日志级别
|
|
level, err := zerolog.ParseLevel(conf.Level)
|
|
if err != nil {
|
|
level = zerolog.InfoLevel
|
|
}
|
|
zerolog.SetGlobalLevel(level)
|
|
|
|
// 初始化logger 并添加 app_name
|
|
logger = zerolog.New(writer).With().
|
|
Timestamp().
|
|
Str("app_name", conf.AppName). // 添加 app_name
|
|
Logger()
|
|
|
|
return nil
|
|
}
|
|
|
|
// log 统一的日志记录函数
|
|
func log(ctx context.Context, level zerolog.Level, logType LogType, kv ...interface{}) {
|
|
if len(kv)%2 != 0 {
|
|
kv = append(kv, "MISSING")
|
|
}
|
|
|
|
event := logger.WithLevel(level)
|
|
|
|
// 添加日志类型
|
|
event.Str("type", string(logType))
|
|
|
|
// 添加请求ID
|
|
if reqID, exists := ctx.Value("request_id").(string); exists {
|
|
event.Str("request_id", reqID)
|
|
}
|
|
|
|
// 添加调用位置
|
|
if pc, file, line, ok := runtime.Caller(2); ok {
|
|
event.Str("caller", fmt.Sprintf("%s:%d %s", filepath.Base(file), line, runtime.FuncForPC(pc).Name()))
|
|
}
|
|
|
|
// 处理key-value对
|
|
for i := 0; i < len(kv); i += 2 {
|
|
key, ok := kv[i].(string)
|
|
if !ok {
|
|
continue
|
|
}
|
|
value := kv[i+1]
|
|
|
|
switch v := value.(type) {
|
|
case error:
|
|
event.AnErr(key, v)
|
|
case int:
|
|
event.Int(key, v)
|
|
case int64:
|
|
event.Int64(key, v)
|
|
case float64:
|
|
event.Float64(key, v)
|
|
case bool:
|
|
event.Bool(key, v)
|
|
case time.Duration:
|
|
event.Dur(key, v)
|
|
case time.Time:
|
|
event.Time(key, v)
|
|
case []byte:
|
|
event.Bytes(key, v)
|
|
case string:
|
|
event.Str(key, v)
|
|
default:
|
|
event.Interface(key, v)
|
|
}
|
|
}
|
|
|
|
event.Send()
|
|
}
|
|
|
|
// Debug 记录调试日志
|
|
func Debug(ctx context.Context, kv ...interface{}) {
|
|
log(ctx, zerolog.DebugLevel, TypeBusiness, kv...)
|
|
}
|
|
|
|
// Info 记录信息日志
|
|
func Info(ctx context.Context, kv ...interface{}) {
|
|
log(ctx, zerolog.InfoLevel, TypeBusiness, kv...)
|
|
}
|
|
|
|
// Warn 记录警告日志
|
|
func Warn(ctx context.Context, kv ...interface{}) {
|
|
log(ctx, zerolog.WarnLevel, TypeError, kv...)
|
|
}
|
|
|
|
// Error 记录错误日志
|
|
func Error(ctx context.Context, kv ...interface{}) {
|
|
log(ctx, zerolog.ErrorLevel, TypeError, kv...)
|
|
}
|
|
|
|
func Fatal(ctx context.Context, kv ...interface{}) {
|
|
// 获取错误堆栈
|
|
buf := make([]byte, 4096)
|
|
n := runtime.Stack(buf, false)
|
|
|
|
// 添加堆栈信息到kv
|
|
newKv := make([]interface{}, 0, len(kv)+2)
|
|
newKv = append(newKv, kv...)
|
|
newKv = append(newKv, "stack", string(buf[:n]))
|
|
|
|
log(ctx, zerolog.FatalLevel, TypeError, newKv...)
|
|
}
|
|
|
|
// Access 记录访问日志
|
|
func Access(ctx context.Context, kv ...interface{}) {
|
|
log(ctx, zerolog.InfoLevel, TypeAccess, kv...)
|
|
}
|
|
|