diff --git a/config/loadAuto/auto.go b/config/loadAuto/auto.go index 9e42e3f..01b1a2d 100644 --- a/config/loadAuto/auto.go +++ b/config/loadAuto/auto.go @@ -1,12 +1,14 @@ package loadAuto import ( + "fmt" + "log" + "path/filepath" + "helay.net/go/utils/v3/config" loadIni2 "helay.net/go/utils/v3/config/loadIni" loadJson2 "helay.net/go/utils/v3/config/loadJson" "helay.net/go/utils/v3/config/loadYaml" - "helay.net/go/utils/v3/logger/ulogs" - "path/filepath" ) var ( @@ -27,7 +29,7 @@ func Load[T any](i T) { if err = loadFirst(i); err == nil { return } - ulogs.Error(err, "配置文件默认解析器计息失败,开始尝试其他解析器") + log.Printf("默认配置解析器解析失败,尝试其他解析器 %v\n", err) } for _, v := range loadFunc { err = v(i) @@ -35,5 +37,5 @@ func Load[T any](i T) { return } } - ulogs.DieCheckerr(err, "载入配置文件失败") + panic(fmt.Errorf("解析配置文件失败 %v", err)) } diff --git a/config/loadIni/load.go b/config/loadIni/load.go index fe86c79..961984c 100644 --- a/config/loadIni/load.go +++ b/config/loadIni/load.go @@ -1,14 +1,17 @@ package loadIni import ( + "fmt" + "gopkg.in/ini.v1" "helay.net/go/utils/v3/config" - "helay.net/go/utils/v3/logger/ulogs" "helay.net/go/utils/v3/tools" ) func LoadIni(i any) { - ulogs.DieCheckerr(LoadIniBase(i), "载入配置文件失败") + if err := LoadIniBase(i); err != nil { + panic(fmt.Errorf("解析配置文件失败 %v", err)) + } } // LoadIniBase 载入配置基础功能 diff --git a/config/loadJson/load.go b/config/loadJson/load.go index f78fcc8..1e94080 100644 --- a/config/loadJson/load.go +++ b/config/loadJson/load.go @@ -3,15 +3,17 @@ package loadJson import ( "encoding/json" "fmt" + "os" + "helay.net/go/utils/v3/close/osClose" "helay.net/go/utils/v3/config" - "helay.net/go/utils/v3/logger/ulogs" "helay.net/go/utils/v3/tools" - "os" ) func LoadJson(i any) { - ulogs.DieCheckerr(LoadJsonBase(i), "解析配置文件失败") + if err := LoadJsonBase(i); err != nil { + panic(fmt.Errorf("解析配置文件失败 %v", err)) + } } func LoadJsonBase(i any) error { diff --git a/config/loadYaml/load.go b/config/loadYaml/load.go index 7ca8e35..5067442 100644 --- a/config/loadYaml/load.go +++ b/config/loadYaml/load.go @@ -9,13 +9,14 @@ import ( "gopkg.in/yaml.v3" "helay.net/go/utils/v3/close/osClose" "helay.net/go/utils/v3/config" - "helay.net/go/utils/v3/logger/ulogs" "helay.net/go/utils/v3/tools" "helay.net/go/utils/v3/tools/fileinclude" ) func LoadYaml(i any) { - ulogs.DieCheckerr(LoadYamlBase(i), "解析配置文件失败") + if err := LoadYamlBase(i); err != nil { + panic(fmt.Errorf("解析配置文件失败 %v", err)) + } } func LoadYamlBase(i any) error { diff --git a/config/parseCmd/parse.go b/config/parseCmd/parse.go index 4576acb..74673b7 100644 --- a/config/parseCmd/parse.go +++ b/config/parseCmd/parse.go @@ -3,6 +3,7 @@ package parseCmd import ( "flag" "fmt" + "log" "os" "helay.net/go/utils/v3" @@ -57,7 +58,7 @@ func Parseparams(f ...func()) { // noinspection all if config.EnableParseParamsLog { - fmt.Println("日志级别", logLevel, ulogs.Level) - ulogs.Log("运行参数解析完成...") + log.Printf("日志级别 %s %d\n", logLevel, ulogs.Level) + log.Println("运行参数解析完成...") } } diff --git a/logger/ulogs/log.go b/logger/ulogs/log.go index e7dfc8c..4799ff3 100644 --- a/logger/ulogs/log.go +++ b/logger/ulogs/log.go @@ -40,21 +40,32 @@ func Log(i ...interface{}) { func Trace(i ...any) { if Level <= LogLevelTrace { - traceLogger.Println(i...) + entry := globalLogger.getEntry() + entry.logger = globalLogger.traceLogger + entry.args = i + globalLogger.stdoutChan <- entry } } // noinspection all func Tracef(format string, a ...any) { if Level <= LogLevelTrace { - traceLogger.Printf(format, a...) + entry := globalLogger.getEntry() + entry.logger = globalLogger.traceLogger + entry.isFormatted = true + entry.format = format + entry.args = a + globalLogger.stdoutChan <- entry } } // Debug 用于记录调试信息 func Debug(i ...any) { if Level <= LogLevelDebug { - debugLogger.Println(i...) + entry := globalLogger.getEntry() + entry.logger = globalLogger.debugLogger + entry.args = i + globalLogger.stdoutChan <- entry } } @@ -62,21 +73,34 @@ func Debug(i ...any) { // noinspection all func Debugf(format string, a ...any) { if Level <= LogLevelDebug { - debugLogger.Printf(format, a...) + entry := globalLogger.getEntry() + entry.logger = globalLogger.debugLogger + entry.isFormatted = true + entry.format = format + entry.args = a + globalLogger.stdoutChan <- entry } } // Info 用于记录信息 func Info(i ...interface{}) { if Level <= LogLevelInfo { - infoLogger.Println(i...) + entry := globalLogger.getEntry() + entry.logger = globalLogger.infoLogger + entry.args = i + globalLogger.stdoutChan <- entry } } // noinspection all func Infof(format string, a ...any) { if Level <= LogLevelInfo { - infoLogger.Printf(format, a...) + entry := globalLogger.getEntry() + entry.logger = globalLogger.infoLogger + entry.isFormatted = true + entry.format = format + entry.args = a + globalLogger.stdoutChan <- entry } } @@ -84,41 +108,65 @@ func Infof(format string, a ...any) { // Warn 用于记录警告信息 func Warn(i ...interface{}) { if Level <= LogLevelWarn { - warnLogger.Println(i...) + entry := globalLogger.getEntry() + entry.logger = globalLogger.warnLogger + entry.args = i + globalLogger.stderrChan <- entry } } // noinspection all func Warnf(format string, a ...any) { if Level <= LogLevelWarn { - warnLogger.Printf(format, a...) + entry := globalLogger.getEntry() + entry.logger = globalLogger.warnLogger + entry.isFormatted = true + entry.format = format + entry.args = a + globalLogger.stderrChan <- entry } } // Error 用于记录错误信息 func Error(i ...interface{}) { if Level <= LogLevelError { - errorLogger.Println(i...) + entry := globalLogger.getEntry() + entry.logger = globalLogger.errorLogger + entry.args = i + globalLogger.stderrChan <- entry } } func Errorf(format string, a ...any) { if Level <= LogLevelError { - errorLogger.Printf(format, a...) + entry := globalLogger.getEntry() + entry.logger = globalLogger.errorLogger + entry.isFormatted = true + entry.format = format + entry.args = a + globalLogger.stderrChan <- entry } } // Fatal 用于记录致命错误信息 func Fatal(i ...interface{}) { if Level <= LogLevelFatal { - fatalLogger.Println(i...) + entry := globalLogger.getEntry() + entry.logger = globalLogger.fatalLogger + entry.args = i + globalLogger.stderrChan <- entry } } // noinspection all func Fatalf(format string, a ...any) { if Level <= LogLevelFatal { - fatalLogger.Printf(format, a...) + entry := globalLogger.getEntry() + entry.logger = globalLogger.fatalLogger + entry.isFormatted = true + entry.format = format + entry.args = a + globalLogger.stderrChan <- entry } } diff --git a/logger/ulogs/types.go b/logger/ulogs/types.go new file mode 100644 index 0000000..37bc53c --- /dev/null +++ b/logger/ulogs/types.go @@ -0,0 +1,204 @@ +/* +Package ulogs 提供一个高性能的异步日志库 + +# 设计哲学 + +1. 简单可靠:不添加多余的检查,相信开发者会正确初始化 +2. 高性能:使用channel缓冲 + 对象池,减少GC压力 +3. 双输出:stdout/stderr分离,符合Unix哲学 +4. Fail Fast:未初始化直接panic,开发阶段暴露问题 + +# 快速开始 + + package main + + import ( + "time" + "yourmodule/ulogs" + ) + + func main() { + // 1. 必须初始化,否则panic + ulogs.New(&ulogs.Config{ + BufferSize: 20000, // stdout缓冲区大小 + ErrorBufSize: 10000, // stderr缓冲区大小 + }) + + // 2. 设置日志级别(可选) + ulogs.SetLevel(ulogs.LogLevelDebug) + + // 3. 启动处理器 + ulogs.Start() + defer ulogs.Shutdown() + + // 4. 正常使用 + ulogs.Info("Server started") + ulogs.Debugf("Config loaded: %v", config) + ulogs.Errorf("Failed to connect: %v", err) + } + +# 性能特性 + +- 无锁设计:每个级别独立channel +- 对象池复用:减少内存分配和GC压力 +- 异步处理:日志写入不阻塞业务逻辑 +- 批量缓冲:log.Logger内置缓冲,无需额外批量 + +# 许可证 + +Copyright (c) 2024 helays +MIT License +*/ +package ulogs + +import ( + "log" + "os" + "sync" +) + +const ( + defaultBufferSize = 10000 // 标准输出缓冲区 + defaultErrorBufSize = 5000 // 错误输出缓冲区(可以小一些) +) + +type Config struct { + BufferSize int `json:"buffer_size" yaml:"buffer_size" ini:"buffer_size"` // 标准输出缓冲区 + ErrorBufSize int `json:"error_buf_size" yaml:"error_buf_size" ini:"error_buf_size"` // 错误输出缓冲区 +} +type logEntry struct { + logger *log.Logger + isFormatted bool + format string + args []any +} + +func (l *logEntry) reset() { + l.logger = nil + l.isFormatted = false + l.format = "" + l.args = nil +} + +type FastLogger struct { + stdoutChan chan *logEntry + stderrChan chan *logEntry + done chan struct{} + wg sync.WaitGroup + + traceLogger *log.Logger + debugLogger *log.Logger + infoLogger *log.Logger + warnLogger *log.Logger + errorLogger *log.Logger + fatalLogger *log.Logger + + // 对象池 + entryPool *sync.Pool +} + +var ( + globalLogger *FastLogger + once sync.Once +) + +func init() { + globalLogger = &FastLogger{ + stdoutChan: make(chan *logEntry, defaultBufferSize), + stderrChan: make(chan *logEntry, defaultErrorBufSize), + done: make(chan struct{}), + traceLogger: log.New(os.Stdout, "【TRACE】", log.LstdFlags), + debugLogger: log.New(os.Stdout, "【DEBUG】", log.LstdFlags), + infoLogger: log.New(os.Stdout, "【INFO】", log.LstdFlags), + warnLogger: log.New(os.Stderr, "【WARN】", log.LstdFlags), + errorLogger: log.New(os.Stderr, "【ERROR】", log.LstdFlags), + fatalLogger: log.New(os.Stderr, "【FATAL】", log.LstdFlags), + } + // 初始化对象池 + globalLogger.entryPool = &sync.Pool{ + New: func() any { + return &logEntry{} + }, + } +} + +// SetBufferSize 设置缓冲区大小 +// 注意:必须在 Start 之前调用,否则不会生效 +func SetBufferSize(stdoutSize, stderrSize int) { + if stdoutSize > 0 { + globalLogger.stdoutChan = make(chan *logEntry, stdoutSize) + } + + if stderrSize > 0 { + globalLogger.stderrChan = make(chan *logEntry, stderrSize) + } +} + +func SetLogger(level int, l *log.Logger) { + switch level { + case LogLevelTrace: + globalLogger.traceLogger = l + case LogLevelDebug: + globalLogger.debugLogger = l + case LogLevelInfo: + globalLogger.infoLogger = l + case LogLevelWarn: + globalLogger.warnLogger = l + case LogLevelError: + globalLogger.errorLogger = l + case LogLevelFatal: + globalLogger.fatalLogger = l + + } +} +func Start() { + globalLogger.wg.Add(2) + go globalLogger.processor(globalLogger.stdoutChan) // 标准输出日志处理 + go globalLogger.processor(globalLogger.stderrChan) // 错误输出日志处理 +} + +func Shutdown() { + close(globalLogger.done) + globalLogger.wg.Wait() +} + +func (f *FastLogger) processor(ch <-chan *logEntry) { + defer f.wg.Done() + for { + select { + case entry := <-ch: + f.writeEntry(entry) + case <-f.done: + // 退出前处理完所有日志 + for { + select { + case entry := <-ch: + f.writeEntry(entry) + default: + return + } + } + } + } +} + +func (f *FastLogger) writeEntry(entry *logEntry) { + defer f.putEntry(entry) + if entry.isFormatted { + entry.logger.Printf(entry.format, entry.args...) + } else { + entry.logger.Println(entry.args...) + } +} + +// getEntry 从对象池获取entry +func (f *FastLogger) getEntry() *logEntry { + return f.entryPool.Get().(*logEntry) +} + +// putEntry 归还entry到池中(会自动reset) +func (f *FastLogger) putEntry(entry *logEntry) { + // 重要:先reset再归还 + entry.reset() + f.entryPool.Put(entry) +}