U:调整项目目录
This commit is contained in:
1 parent
6decd94b1c
commit
d7e7a973f5
158 files changed
No files matched your search
@@ -0,0 +1,353 @@
|
||||
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
|
||||
)
|
||||
|
||||
// LogConfig 日志配置
|
||||
type LogConfig 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 *LogConfig
|
||||
}
|
||||
|
||||
// DefaultConfig 默认配置
|
||||
func DefaultConfig() *LogConfig {
|
||||
return &LogConfig{
|
||||
Level: InfoLevel,
|
||||
LogPath: "./logs",
|
||||
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 ...*LogConfig) (*Logger, error) {
|
||||
var cfg *LogConfig
|
||||
if len(config) > 0 && config[0] != nil {
|
||||
cfg = config[0]
|
||||
} else {
|
||||
cfg = DefaultConfig()
|
||||
}
|
||||
cfg.LogPath = filepath.Join(cfg.LogPath, "app.log")
|
||||
|
||||
// 确保日志目录存在
|
||||
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 ...*LogConfig) 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
|
||||
}
|
||||
Reference in new issue
Block a user