# logger **Repository Path**: gousing/logger ## Basic Information - **Project Name**: logger - **Description**: 开箱即用的 Golang Logger, 基于标准库 slog 封装的 Logger, 兼容标准库,提供日志等级、状态控制接口。 - **Primary Language**: Go - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2025-03-14 - **Last Updated**: 2025-10-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Gousing Logger ## 介绍 开箱即用的 Golang Logger, 基于标准库 slog 封装的 Logger, 兼容标准库,提供日志等级、状态控制接口。 - 支持自定义默认CallerSkip, 默认为3, 通过 Wrap/WrapAttrs 支持单条日志临时自定义CallerSkip - 支持存储到自定义 Writer, 支持多写入, 支持日志记录中间件和事件回调 - 支持存储到指定文件, 支持自定义日志文件滚动(基于 lumberjack) - 提供 Grom Logger 适配工具 - 提供 Gin Logger 适配工具 ## 安装 ```golang go get -u github.com/gousing/logger ``` ## 使用 ```golang import "github.com/gousing/logger" // 使用默认日志实例 // 开箱即用, 默认打印到控制台,日志等级为slog.LevelInfo // Logger包全局默认日志,首次使用时如未自定义则自动初始化为: // logDefault = NewText(NewStorage(os.Stdout), &Options{ // Level: defaultLogLevel, // false // AddSource: defaultAddSource, // slog.LevelInfo // CallerSkip: defaultCallerSkip, // 3 // ReplaceAttr: nil, // }) logger.Debug("hello world",slog.String("name","gousing"),slog.Int("age",18)) logger.Info("hello world",slog.String("name","gousing"),slog.Int("age",18)) logger.Warn("hello world",slog.String("name","gousing"),slog.Int("age",18)) logger.Error("hello world",slog.String("name","gousing"),slog.Int("age",18)) // 更多方法见日志接口 // 用户自定义全局日志实例 // SetDefault 设置全局默认日志实例 // logger.SetDefault(log *logger.Logger) // 自定义全局日志实例 // 单个 Storage 写入 myLog := logger.NewJson(logger.NewStorage(os.Stdout),&Options{Level: LevelDebug, AddSource: true}) // 多个 Storage 写入 storage01, _ := logger.NewFileStorage("app-1.log", &FileOptions{SavePath: "__runtime/logs"}) storage02, _ := logger.NewFileStorage("app-2.log", &FileOptions{SavePath: "__runtime/logs"}) myLog := logger.NewJson(logger.NewMultiStorage(storage01,storage02),&Options{Level: LevelDebug, AddSource: true}) // 设置全局默认日志实例 // 项目初始化时设置一次,在项目中其他代码即可直接使用全局默认日志实例 logger.SetDefault(myLog) ``` ### 全局接口 ```golang // 全局默认日志 记录接口(兼容slog) // Error 记录错误日志(全局默认日志) logger.Error(msg string, args ...any) // ErrorContext 记录错误日志(全局默认日志) logger.ErrorContext(ctx context.Context, msg string, args ...any) // Warn 记录警告日志(全局默认日志) logger.Warn(msg string, args ...any) // WarnContext 记录警告日志(全局默认日志) logger.WarnContext(ctx context.Context, msg string, args ...any) // Info 记录普通日志(全局默认日志) logger.Info(msg string, args ...any) // InfoContext 记录普通日志(全局默认日志) logger.InfoContext(ctx context.Context, msg string, args ...any) // Debug 记录调试日志(全局默认日志) logger.Debug(msg string, args ...any) // DebugContext 记录调试日志(全局默认日志) logger.DebugContext(ctx context.Context, msg string, args ...any) // Log 记录自定义日志(全局默认日志) logger.Log(ctx context.Context, level slog.Level, msg string, args ...any) // LogAttrs 记录自定义日志(全局默认日志) logger.LogAttrs(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) // Handler 获取全局默认日志实例处理器 logger.Handler() slog.Handler // With 基于全局默认日志实例, 返回一个包含给定属性的子日志实例副本 // 如果 args 为空,则返回默认日志 logger.With(args ...any) *Logger // WithGroup 基于全局默认日志实例, 返回一个包含给定分组名的日志实例副本 // 如果 name 为空,则返回默认日志 // 如果 name 不为空,则返回一个WithGroup的实例副本 logger.WithGroup(name string) *Logger // Use 全局默认日志实例使用中间件, 返回一个包含给定中间件(含继承的中间件)的日志实例副本 logger.Use(fns ...logger.Middleware) *Logger // Wrap slog.log(...) 全局默认日志实例 Wrap 日志入口, 支持临时自定义callerSkip logger.Wrap(skip int, ctx context.Context, level slog.Level, msg string, args ...any) // WrapAttrs slog.logAttrs(...) 全局默认日志实例 WrapAttrs 日志入口, 支持临时自定义callerSkip logger.WrapAttrs(skip int, ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) // GetOptions 获取全局默认日志实例配置选项 logger.GetOptions() Options // OnClose 注册全局默认日志实例关闭事件处理器 logger.OnClose(fn logger.Event) // OnError 注册全局默认日志实例错误事件处理器 logger.OnError(fn logger.Event) // SetDefault 设置全局默认日志实例 logger.SetDefault(log *logger.Logger) // GetDefault 获取全局默认日志实例 logger.GetDefault() *logger.Logger // GetLevel 获取全局默认日志实例的日志级别 logger.GetLevel() slog.Level // SetLevel 设置全局默认日志实例的日志级别(支持动态调整) logger.SetLevel(level slog.Level) // RegisterLevel 注册一个自定义的日志等级(全局可用,仅需注册一次) // - level: 日志等级 // - name: 日志等级名称 // - slog内置 slog.Level(LevelDebug < LevelInfo < LevelWarn < LevelError) // - const LevelTrace = slog.Level(-8) // < LevelDebug // - const LevelFatal = slog.Level(12) // > LevelError // - 例: // - 注册等级 RegisterLevel(LevelTrace,"TRACE") 或 logger.RegisterLevel(slog.Level(-8),"TRACE") // - 注册后使用 logger.Log(ctx,LevelTrace,"hello world") 或 logger.Log(ctx,slog.Level(-8),"hello world") logger.RegisterLevel(level slog.Level, name string) error // SetCallerSkip 设置全局默认日志 callerSkip logger.SetCallerSkip(skip int) // GetCallerSkip 获取全局默认日志 callerSkip logger.GetCallerSkip() int // Sync 同步全局默认日志文件 (仅同步/不关闭) // - 仅对文件日志或实现了Sync()接口的 storage 有效 logger.Sync() (errs error) // SyncAll 同步所有日志文件 (仅同步/不关闭), 关闭后将不再接受日志记录 // - 仅对文件日志或实现了Sync()接口的 storage 有效 logger.SyncAll() (errs error) // Close 关闭全局默认日志实例(先同步/在关闭), 关闭后将不再接受日志记录 // - 仅对文件日志或实现了Close()接口的 storage 有效 logger.Close() (errs error) // CloseAll 关闭所有日志实例(先同步/在关闭), 关闭后将不再接受日志记录 // - 仅对文件日志或实现了Close()接口的 storage 有效 logger.CloseAll() (errs error) // LastErrors 获取全局默认日志实例 Logger.handler 最近的错误信息 logger.LastErrors() error // LastErrorsAll 获取所有日志实例 Logger.handler 最近的错误信息 logger.LastErrorsAll() (errs error) // ToSlog 转换 logger.Logger 为 *slog.Logger // - 注意:原 log 自定义等级/调整等级/中间件/同步/关闭行为均为影响转换后的 *slog.Logger logger.ToSlog(log *logger.Logger) *slog.Logger // ToGinLogger 转换logger.Logger为gin.LoggerWriter // - 注意:原 log 自定义等级/调整等级/中间件/同步/关闭行为均为影响转换后的 *ginLogger // - Use: // - ginLog := logger.ToGinLogger(youLogger) // - gin.DefaultWriter = ginLog // - gin.DefaultErrorWriter = ginLog // - gin.DebugPrintRouteFunc = ginLog.DebugPrintRouteFunc // - gin.DebugPrintFunc = ginLog.DebugPrintFunc // - gin.DisableConsoleColor() logger.ToGinLogger(log *logger.Logger) *ginLogger // ToGormLogger 转换logger.Logger为gormlog.Interface // - 注意:原 log 自定义等级/调整等级/中间件/同步/关闭行为均为影响转换后的 gormlog // - Use: // - db, err := gorm.Open(...) // - gormLog := logger.ToGormLogger(logger.GetDefault()) // - db.Logger = gormLog logger.ToGormLogger(log *logger.Logger) gormlog.Interface // 全局默认日志记录接口见日 [日志实例接口] ``` ### 日志实例接口 ```golang // Error 记录错误日志 func (l *Logger) Error(msg string, args ...any) // ErrorContext 记录错误日志 func (l *Logger) ErrorContext(ctx context.Context, msg string, args ...any) // Warn 记录警告日志 func (l *Logger) Warn(msg string, args ...any) // WarnContext 记录警告日志 func (l *Logger) WarnContext(ctx context.Context, msg string, args ...any) // Info 记录普通日志 func (l *Logger) Info(msg string, args ...any) // InfoContext 记录普通日志 func (l *Logger) InfoContext(ctx context.Context, msg string, args ...any) // Debug 记录调试日志 func (l *Logger) Debug(msg string, args ...any) // DebugContext 记录调试日志 func (l *Logger) DebugContext(ctx context.Context, msg string, args ...any) // Log 记录自定义日志 func (l *Logger) Log(ctx context.Context, level slog.Level, msg string, args ...any) // LogAttrs 记录自定义日志 func (l *Logger) LogAttrs(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) // Handler 获取日志实例Handler处理器 func (l *Logger) Handler() slog.Handler // With 从现有的 handler 创建一个新的 handler,并将新增属性附加到新的 handler // 如果 args 为空,则返回默认日志 func (l *Logger) With(args ...any) *Logger // WithGroup 从现有的 handler 创建一个新的 handler,并将指定分组附加到新的 handler func (l *Logger) WithGroup(name string) *Logger // Use 添加中间件, 返回新的日志实例 func (l *Logger) Use(fns ...logger.Middleware) *Logger // Wrap slog.log(...) Wrap日志入口, 支持临时自定义callerSkip func (l *Logger) Wrap(skip int, ctx context.Context, level slog.Level, msg string, args ...any) error // WrapAttrs slog.logAttrs(...) Wrap日志入口, 支持临时自定义callerSkip func (l *Logger) WrapAttrs(skip int, ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) error // GetOptions 获取日志选项 func (l *Logger) GetOptions() Options // OnClose 注册关闭事件处理器 func (l *Logger) OnClose(fn logger.Event) // OnError 注册错误事件处理器 func (l *Logger) OnError(fn logger.Event) // GetLevel 获取日志等级 func (l *Logger) GetLevel() slog.Level // SetLevel 设置日志等级(支持动态切换日志等级) func (l *Logger) SetLevel(level slog.Level) // SetCallerSkip 设置日志记录 callerSkip func (l *Logger) SetCallerSkip(skip int) // GetCallerSkip 获取日志记录 callerSkip func (l *Logger) GetCallerSkip() int // Sync 同步数据 Logger.storage (仅同步/不关闭) // - 仅对文件日志或实现了Sync()接口的 storage 有效 func (l *Logger) Sync() (errs error) // Close 关闭 Logger.storage (先同步/在关闭), 关闭后将不再接受日志记录 // - 仅对文件日志或实现了Close()接口的 storage 有效 func (l *Logger) Close() (errs error) // IsClose 日志实例是否已关闭 func (l *Logger) IsClose() bool // LastErrors 获取 Handler 最近的错误信息 func (l *Logger) LastErrors() error // ToSlog 转换 Logger 为 *slog.Logger // - 注意:原 log 自定义等级/调整等级/中间件/同步/关闭行为均为影响转换后的 *slog.Logger func (l *Logger) ToSlog() *slog.Logger // ToGinLogger 转换 Logger 为 gin.LoggerWriter // - 注意:原 log 自定义等级/调整等级/中间件/同步/关闭行为均为影响转换后的 *ginLogger // - Use: // - ginLog := logger.ToGinLogger(youLogger) // - gin.DefaultWriter = ginLog // - gin.DefaultErrorWriter = ginLog // - gin.DebugPrintRouteFunc = ginLog.DebugPrintRouteFunc // - gin.DebugPrintFunc = ginLog.DebugPrintFunc // - gin.DisableConsoleColor() func (l *Logger) ToGinLogger() *ginLogger // ToGormLogger 转换slog.Logger为 gormlog.Interface // - 注意:原 log 自定义等级/调整等级/中间件/同步/关闭行为均为影响转换后的 gormlog // - Use: // - db, err := gorm.Open(...) // - gormLog := logger.ToGormLogger(logger.GetDefault()) // - db.Logger = gormLog func (l *Logger) ToGormLogger() gormlog.Interface ``` ### 自定义日志实例 ```golang // NewJson 创建Json格式的日志实例 // - s: Storager 存储接口 // - opts: Options 日志处理选项 func NewJson(s Storager, opts *Options) *Logger // NewText 创建Text格式的日志实例 // - s: Storager 存储接口 // - opts: Options 日志处理选项 func NewText(s Storager, opts *Options) *Logger // NewStorage 将单个 io.Writer 转换为 Storager 对象 func NewStorage(writer io.Writer) Storager // NewMultiStorage 将多个 io.Writer 转换为 Storager 对象 func NewMultiStorage(writers ...io.Writer) Storager // NewFileStorage 依据文件名及选项创建Lumberjack文件实例 ( 通过 lumberjack 管理日志文件的写入及滚动 ) func NewFileStorage(fileName string, options *FileOptions) (Storager, error) ``` ### 配置选项 ```golang // Options like slog.Options type Options struct { Level slog.Level // 日志记录级别, 默认 slog.LevelInfo AddSource bool // 是否记录日志来源Source信息(1条runtime.Callers), 默认 true CallerSkip int // 日志来源Source信息 跳过Callers的层数, 默认 3(与slog保持一致), 如不为3, Handler.Handle()接口会依据Skip层数重写覆盖 Record.PC 埋点 ReplaceAttr func(groups []string, a slog.Attr) slog.Attr // 自定义日志 Attr 键值对内容(即日志记录中附加的 key/value), 默认 nil } const ( defaultAddSource = false // 默认 false ( 保持与 slog 一致 ) defaultCallerSkip = 3 // 默认 3 ( 最小3, 保持与 slog 一致 ) defaultLogLevel = slog.LevelInfo // 默认 slog.LevelInfo ( 保持与 slog 一致 ) ) type FileOptions struct { MaxSize int // 文件最大尺寸(以MB为单位), 默认 2 MaxBackups int // 保留的最大旧文件数量, 默认 15 MaxAge int // 保留旧文件的最大天数,默认 30 Compress bool // 是否压缩/归档旧文件,默认 false LocalTime bool // 使用本地时间创建时间戳,默认 true SavePath string // 日志文件存放的位置, 基于WorkPath工作目录, 默认为"logs" } const ( defaultMaxSize int = 2 defaultMaxBackups int = 15 defaultMaxAge int = 30 defaultCompress bool = false defaultLocalTime bool = true defaultAddSource bool = true defaultSavePath string = "logs" ) // Middleware 日志记录中间件, 返回不为nil的错误,终止后续中间件处理及丢弃此条日志的记录 type Middleware func(ctx *context.Context, record *slog.Record) error ``` ### Benchmark ```shell go.exe test -benchmem -run=^$ -bench ^Benchmark_slog* gitee.com/gousing/logger -v goos: windows goarch: amd64 pkg: gitee.com/gousing/gerror cpu: 12th Gen Intel(R) Core(TM) i5-12400F ``` | Benchmark | - | - | - | - | | :--------------------------------- | :------ | :---------- | :-------- | :---------- | | Benchmark_slog_agent/TextWriter-12 | 1082922 | 1068 ns/op | 911 B/op | 7 allocs/op | | Benchmark_slog_agent/JsonWriter-12 | 1000000 | 1215 ns/op | 1420 B/op | 8 allocs/op | | Benchmark_slog_std/TextWriter-12 | 1466792 | 851.8 ns/op | 543 B/op | 5 allocs/op | | Benchmark_slog_std/JsonWriter-12 | 1241985 | 1014 ns/op | 1016 B/op | 6 allocs/op |