Files
argus-go/rear/pkg/logger/logger.go
T
2025-06-12 22:22:36 +08:00

353 lines
8.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package logger
import (
"fmt"
"os"
"path/filepath"
"time"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
)
// LogLevel 日志级别
type LogLevel int
const (
DebugLevel LogLevel = iota
InfoLevel
WarnLevel
ErrorLevel
FatalLevel
)
// Config 日志配置
type Config struct {
Level LogLevel `json:"level"` // 日志级别
LogPath string `json:"log_path"` // 日志文件路径
MaxSize int `json:"max_size"` // 单个日志文件最大大小(MB)
MaxBackups int `json:"max_backups"` // 保留的旧日志文件个数
MaxAge int `json:"max_age"` // 保留旧日志文件的最大天数
Compress bool `json:"compress"` // 是否压缩旧日志文件
EnableConsole bool `json:"enable_console"` // 是否同时输出到控制台
EnableCaller bool `json:"enable_caller"` // 是否显示调用者信息(文件名和行号)
TimeFormat string `json:"time_format"` // 时间格式
AsyncBufferSize int `json:"async_buffer_size"` // 异步缓冲区大小
}
// Logger 日志器结构体
type Logger struct {
zap *zap.Logger
sugar *zap.SugaredLogger
config *Config
}
// defaultConfig 默认配置
func defaultConfig() *Config {
return &Config{
Level: InfoLevel,
LogPath: "./logs/app.log",
MaxSize: 1, // 1MB
MaxBackups: 30, // 保留30个备份
MaxAge: 7, // 保留7天
Compress: true, // 压缩旧文件
EnableConsole: true,
EnableCaller: true,
TimeFormat: "2006-01-02 15:04:05.000",
AsyncBufferSize: 1000,
}
}
// NewLogger 创建新的日志器
func NewLogger(skipCaller int, config ...*Config) (*Logger, error) {
var cfg *Config
if len(config) > 0 && config[0] != nil {
cfg = config[0]
} else {
cfg = defaultConfig()
}
// 确保日志目录存在
logDir := filepath.Dir(cfg.LogPath)
if err := os.MkdirAll(logDir, 0755); err != nil {
return nil, fmt.Errorf("failed to create log directory: %w", err)
}
// 配置日志轮转
hook := &lumberjack.Logger{
Filename: cfg.LogPath,
MaxSize: cfg.MaxSize,
MaxBackups: cfg.MaxBackups,
MaxAge: cfg.MaxAge,
Compress: cfg.Compress,
LocalTime: true,
}
// 创建编码器配置
encoderConfig := zapcore.EncoderConfig{
TimeKey: "time",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller",
MessageKey: "msg",
StacktraceKey: "stacktrace",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: getTimeEncoder(cfg.TimeFormat),
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
// 创建文件写入器
var fileWriter zapcore.WriteSyncer
if cfg.AsyncBufferSize > 0 {
// 使用异步缓冲写入器
fileWriter = &zapcore.BufferedWriteSyncer{
WS: zapcore.AddSync(hook),
Size: cfg.AsyncBufferSize,
FlushInterval: time.Second,
}
} else {
fileWriter = zapcore.AddSync(hook)
}
// 创建控制台写入器
consoleWriter := zapcore.AddSync(os.Stdout)
// 设置日志级别
var level zapcore.Level
switch cfg.Level {
case DebugLevel:
level = zapcore.DebugLevel
case InfoLevel:
level = zapcore.InfoLevel
case WarnLevel:
level = zapcore.WarnLevel
case ErrorLevel:
level = zapcore.ErrorLevel
case FatalLevel:
level = zapcore.FatalLevel
default:
level = zapcore.InfoLevel
}
// 创建核心组件
var cores []zapcore.Core
// 文件输出核心
fileCore := zapcore.NewCore(
zapcore.NewJSONEncoder(encoderConfig),
fileWriter,
level,
)
cores = append(cores, fileCore)
// 控制台输出核心
if cfg.EnableConsole {
consoleEncoderConfig := encoderConfig
consoleEncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
// zapcore.NewJSONEncoder(...) → 输出 JSON 格式日志(机器友好、可解析)
// zapcore.NewConsoleEncoder(...) → 输出彩色文本日志(人类友好)
consoleCore := zapcore.NewCore(
zapcore.NewConsoleEncoder(consoleEncoderConfig),
consoleWriter,
level,
)
cores = append(cores, consoleCore)
}
// 创建tee核心(同时写入多个目标)
core := zapcore.NewTee(cores...)
// 配置选项
var options []zap.Option
if cfg.EnableCaller {
// 向上寻找调用者【1 或 2 即可】
options = append(options, zap.AddCaller(), zap.AddCallerSkip(skipCaller))
}
options = append(options, zap.AddStacktrace(zapcore.ErrorLevel))
// 创建zap logger
zapLogger := zap.New(core, options...)
logger := &Logger{
zap: zapLogger,
sugar: zapLogger.Sugar(),
config: cfg,
}
return logger, nil
}
// getTimeEncoder 获取时间编码器
func getTimeEncoder(format string) zapcore.TimeEncoder {
return func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(t.Format(format))
}
}
// Debug 调试级别日志
func (l *Logger) Debug(msg string, fields ...zap.Field) {
l.zap.Debug(msg, fields...)
}
// Debugf 格式化调试日志
func (l *Logger) Debugf(template string, args ...interface{}) {
l.sugar.Debugf(template, args...)
}
// Info 信息级别日志
func (l *Logger) Info(msg string, fields ...zap.Field) {
l.zap.Info(msg, fields...)
}
// Infof 格式化信息日志
func (l *Logger) Infof(template string, args ...interface{}) {
l.sugar.Infof(template, args...)
}
// Warn 警告级别日志
func (l *Logger) Warn(msg string, fields ...zap.Field) {
l.zap.Warn(msg, fields...)
}
// Warnf 格式化警告日志
func (l *Logger) Warnf(template string, args ...interface{}) {
l.sugar.Warnf(template, args...)
}
// Error 错误级别日志
func (l *Logger) Error(msg string, fields ...zap.Field) {
l.zap.Error(msg, fields...)
}
// Errorf 格式化错误日志
func (l *Logger) Errorf(template string, args ...interface{}) {
l.sugar.Errorf(template, args...)
}
// Fatal 致命错误日志(会调用os.Exit(1))
func (l *Logger) Fatal(msg string, fields ...zap.Field) {
l.zap.Fatal(msg, fields...)
}
// Fatalf 格式化致命错误日志
func (l *Logger) Fatalf(template string, args ...interface{}) {
l.sugar.Fatalf(template, args...)
}
// With 添加字段到日志上下文
func (l *Logger) With(fields ...zap.Field) *Logger {
return &Logger{
zap: l.zap.With(fields...),
sugar: l.zap.With(fields...).Sugar(),
config: l.config,
}
}
// WithFields 使用映射添加字段
func (l *Logger) WithFields(fields map[string]interface{}) *Logger {
var zapFields []zap.Field
for k, v := range fields {
zapFields = append(zapFields, zap.Any(k, v))
}
return l.With(zapFields...)
}
// Sync 同步缓冲区(确保所有日志都被写入)
func (l *Logger) Sync() error {
return l.zap.Sync()
}
// Close 关闭日志器
func (l *Logger) Close() error {
return l.Sync()
}
// GetZapLogger 获取原始的zap logger(用于高级用法)
func (l *Logger) GetZapLogger() *zap.Logger {
return l.zap
}
// GetSugarLogger 获取sugar logger(用于更简单的API)
func (l *Logger) GetSugarLogger() *zap.SugaredLogger {
return l.sugar
}
// 全局默认日志器
var defaultLogger *Logger
// InitDefaultLogger 初始化默认日志器
func InitDefaultLogger(config ...*Config) error {
var err error
defaultLogger, err = NewLogger(2, config...)
return err
}
// 自动初始化
func ensureDefaultLogger() {
if defaultLogger == nil {
_ = InitDefaultLogger() // 忽略错误或打印到stderr
}
}
// Debug 全局日志函数
func Debug(msg string, fields ...zap.Field) {
ensureDefaultLogger()
defaultLogger.Debug(msg, fields...)
}
func Debugf(template string, args ...interface{}) {
ensureDefaultLogger()
defaultLogger.Debugf(template, args...)
}
func Info(msg string, fields ...zap.Field) {
ensureDefaultLogger()
defaultLogger.Info(msg, fields...)
}
func Infof(template string, args ...interface{}) {
ensureDefaultLogger()
defaultLogger.Infof(template, args...)
}
func Warn(msg string, fields ...zap.Field) {
ensureDefaultLogger()
defaultLogger.Warn(msg, fields...)
}
func Warnf(template string, args ...interface{}) {
ensureDefaultLogger()
defaultLogger.Warnf(template, args...)
}
func Error(msg string, fields ...zap.Field) {
ensureDefaultLogger()
defaultLogger.Error(msg, fields...)
}
func Errorf(template string, args ...interface{}) {
ensureDefaultLogger()
defaultLogger.Errorf(template, args...)
}
func Fatal(msg string, fields ...zap.Field) {
ensureDefaultLogger()
defaultLogger.Fatal(msg, fields...)
}
func Fatalf(template string, args ...interface{}) {
ensureDefaultLogger()
defaultLogger.Fatalf(template, args...)
}
// Sync 确保所有日志都被写入
func Sync() error {
if defaultLogger != nil {
return defaultLogger.Sync()
}
return nil
}