From 7c70f805db2a534940f9e2415b242da313c84565 Mon Sep 17 00:00:00 2001 From: Yun <995116474@qq.com> Date: Fri, 15 Nov 2024 17:59:35 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E7=9A=84=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- interfaces.go | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 interfaces.go diff --git a/interfaces.go b/interfaces.go new file mode 100644 index 0000000..ef0f8ec --- /dev/null +++ b/interfaces.go @@ -0,0 +1,11 @@ +package loggerx + +import "context" + +// 简单使用的日志接口 +type LoggerInterface interface { + Info(ctx context.Context, args ...any) + Infof(ctx context.Context, format string, args ...any) + Error(ctx context.Context, args ...any) + Errorf(ctx context.Context, format string, args ...any) +} From 33706c10729ba0265c9f78c38af25f84ea1f14ea Mon Sep 17 00:00:00 2001 From: Yun <995116474@qq.com> Date: Fri, 22 Nov 2024 20:08:25 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E5=86=99=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/main.go | 8 +++++++- loggerx.go | 32 +++++++++++++++++++++++--------- options.go | 18 ++++++++++++++++++ readme.md | 4 ++-- storage.go | 40 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 12 deletions(-) diff --git a/example/main.go b/example/main.go index 81859a0..1d7e6d7 100644 --- a/example/main.go +++ b/example/main.go @@ -15,6 +15,7 @@ func main() { // loggerx.SetTimeZone(time.UTC), loggerx.SetTimeZone(time.FixedZone("CST", 8*3600)), ) + log.WriteAsync().Info(ctx, "哈哈哈2异步") log.Info(ctx, "哈哈哈2") log.Info(ctx, "哈哈哈2") log.Info(ctx, "哈哈哈2") @@ -22,5 +23,10 @@ func main() { log.Info(ctx, "哈哈哈2") log.Info(ctx, "哈哈哈2") log.Info(ctx, "哈哈哈2") - log.Info(ctx, "哈哈哈2") + + for i := 0; i < 100; i++ { + log.WriteAsync().Infof(ctx, "异步 %d", i) + } + + time.Sleep(time.Second) } diff --git a/loggerx.go b/loggerx.go index cdebd9c..8e3c925 100644 --- a/loggerx.go +++ b/loggerx.go @@ -21,11 +21,12 @@ import ( // 需要实现io.Writer接口 type Logger struct { - ctx context.Context - filePath *sync.Map // filePath - mu *sync.Mutex - option loggerOption - channel string + ctx context.Context + filePath *sync.Map // filePath + mu *sync.Mutex + option loggerOption + channel string + writeType writeType // 是否异步落盘,这里作用范围是本条,优先判断这里 } type filePath struct { @@ -45,10 +46,11 @@ func NewLogger(ctx context.Context, opts ...Option) *Logger { } l := &Logger{ - ctx: ctx, - filePath: &sync.Map{}, - mu: &sync.Mutex{}, - option: opt, + ctx: ctx, + filePath: &sync.Map{}, + mu: &sync.Mutex{}, + option: opt, + writeType: writeTypeDefault, } log.SetOutput(l) @@ -87,6 +89,18 @@ func (l *Logger) Channel(ch string) (r *Logger) { return &rr } +func (l *Logger) WriteAsync() (r *Logger) { + rr := *l + rr.writeType = writeTypeAsync + return &rr +} + +func (l *Logger) WriteSync() (r *Logger) { + rr := *l + rr.writeType = writeTypeSync + return &rr +} + // 获取TraceField的字段 func (l *Logger) GetTraceField() string { return l.option.traceField diff --git a/options.go b/options.go index fb1cb9a..ce15e2d 100644 --- a/options.go +++ b/options.go @@ -13,6 +13,7 @@ type loggerOption struct { isGinLog bool isGid bool isPrintFile bool + writeType writeType // 是否异步罗盘 traceField string // trace字段 errorToInfo bool // 错误日志是否写入info日志 days int // 日志保存天数 @@ -22,11 +23,21 @@ type loggerOption struct { timeZone *time.Location // 时区 } +type writeType uint8 + +const ( + // 0.默认(同步) 1.指定同步 2.指定异步 + writeTypeDefault writeType = iota + writeTypeSync + writeTypeAsync +) + func defaultOptions() loggerOption { return loggerOption{ isGinLog: true, isGid: true, isPrintFile: true, + writeType: writeTypeDefault, // 默认同步 format: "json", dir: "./log", traceField: "trace_id", @@ -45,6 +56,13 @@ func SetTraceField(traceField string) Option { } } +// 是否异步写入 +func SetWriteAsync() Option { + return func(o *loggerOption) { + o.writeType = writeTypeAsync + } +} + // 打印到控制台 func SetToConsole() Option { return func(o *loggerOption) { diff --git a/readme.md b/readme.md index 85524a3..54a6984 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,3 @@ - # 简介 这个是基于原生log实现的日志存储。 @@ -11,7 +10,6 @@ log.Println("ddddd") # 用法 - # 开发计划 1. 自动清除过期的日志文件 @@ -23,3 +21,5 @@ log.Println("ddddd") 2. 按照文件大小分割 3. 按照日志行数分割 6. 支持debug 模式 + +* [X] 添加异步落库,支持全局和单次 diff --git a/storage.go b/storage.go index 7e8e2da..df7083f 100644 --- a/storage.go +++ b/storage.go @@ -2,9 +2,20 @@ package loggerx import ( "io" + "sync" ) +// 写入,需要判断同步还是异步 func (l *Logger) write(event string, b []byte) (n int, err error) { + if l.toAsync(event, b) { + // fmt.Println("异步写入") + return len(b), nil + } + return l.store(event, b) +} + +// 实际的存储 +func (l *Logger) store(event string, b []byte) (n int, err error) { if l.option.isPrintFile { f, err := l.getFile(event, false) @@ -30,3 +41,32 @@ func (l *Logger) write(event string, b []byte) (n int, err error) { } return n, err } + +var chanStore = make(chan cacheData, 1000) +var chanOnce = sync.Once{} + +type cacheData struct { + logger *Logger + Event string + Data []byte +} + +func (l *Logger) toAsync(event string, b []byte) bool { + chanOnce.Do(func() { + go func() { + for val := range chanStore { + val.logger.store(val.Event, val.Data) + } + }() + }) + + if l.writeType == writeTypeSync || // 指定同步模式 + (l.writeType == writeTypeDefault && l.option.writeType != writeTypeAsync) { // 默认同步模式 + return false + } + + // 为了避免丢失,还是要阻塞等待 + chanStore <- cacheData{l, event, b} + + return true +} From fad8686a73212698dc7e8d77510d22fe0878486a Mon Sep 17 00:00:00 2001 From: Yun <995116474@qq.com> Date: Wed, 15 Jan 2025 15:29:45 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E5=85=81=E8=AE=B8=E9=85=8D=E7=BD=AEjson?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E8=BD=AC=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/main.go | 13 +++++++------ format.go | 16 ++++++++++++++-- options.go | 8 ++++++++ 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/example/main.go b/example/main.go index 1d7e6d7..c6a7ab3 100644 --- a/example/main.go +++ b/example/main.go @@ -14,15 +14,16 @@ func main() { loggerx.SetToConsole(), // loggerx.SetTimeZone(time.UTC), loggerx.SetTimeZone(time.FixedZone("CST", 8*3600)), + loggerx.SetEscapeHTML(false), ) - log.WriteAsync().Info(ctx, "哈哈哈2异步") - log.Info(ctx, "哈哈哈2") - log.Info(ctx, "哈哈哈2") - log.Info(ctx, "哈哈哈2") - log.Info(ctx, "哈哈哈2") - log.Info(ctx, "哈哈哈2") + log.WriteAsync().Info(ctx, "{ \"a\": 1, \"b\": 2 }") log.Info(ctx, "哈哈哈2") log.Info(ctx, "哈哈哈2") + log.Info(ctx, "哈哈哈2\r") + log.Info(ctx, "哈哈哈2\r\n") + log.Info(ctx, "哈哈哈2") + log.Info(ctx, "哈哈哈2<") + log.Info(ctx, "哈哈哈2>") for i := 0; i < 100; i++ { log.WriteAsync().Infof(ctx, "异步 %d", i) diff --git a/format.go b/format.go index 1747b85..2894c2d 100644 --- a/format.go +++ b/format.go @@ -1,6 +1,7 @@ package loggerx import ( + "bytes" "context" "encoding/json" "fmt" @@ -32,7 +33,7 @@ func (l *Logger) logger(ctx context.Context, event string, v ...any) { // writeStr := "[" + event + "]" + nowTime + " " + file + ":" + fmt.Sprintf("%d", line) + " " + funcName + " gid:" + getGID() + " " + traceId + " @data@: " + string(by) + "\n\n" - for idx,val := range v { + for idx, val := range v { if _, ok := val.(error); ok { v[idx] = fmt.Sprintf("%+v", val) } @@ -51,7 +52,18 @@ func (l *Logger) logger(ctx context.Context, event string, v ...any) { // fd.Stack = string(debug.Stack()) } - fdb, _ := json.Marshal(fd) + var fdb []byte + if l.option.escapeHTML { + fdb, _ = json.Marshal(fd) + } else { + // 非转义 + var buf bytes.Buffer + encoder := json.NewEncoder(&buf) + encoder.SetEscapeHTML(false) + encoder.Encode(fd) + fdb = buf.Bytes() + } + fdb = bytes.TrimRight(fdb, "\n") ff := []byte("\n[" + event + "]") fdb = append(ff, fdb...) diff --git a/options.go b/options.go index ce15e2d..b927370 100644 --- a/options.go +++ b/options.go @@ -21,6 +21,7 @@ type loggerOption struct { fileSplit FileSplit // 文件切割规则 sizeSplit int // 根据文件大小切割 timeZone *time.Location // 时区 + escapeHTML bool } type writeType uint8 @@ -44,6 +45,7 @@ func defaultOptions() loggerOption { days: 7, fileSplit: FileSplitTimeE, timeZone: time.Local, + escapeHTML: true, } } @@ -176,3 +178,9 @@ func SetSizeSplit(m int) Option { o.sizeSplit = m } } + +func SetEscapeHTML(b bool) Option { + return func(o *loggerOption) { + o.escapeHTML = b + } +} From 3ca01077b675da0c307312065f07c5ab78af6dca Mon Sep 17 00:00:00 2001 From: Yun <995116474@qq.com> Date: Wed, 15 Jan 2025 15:40:55 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E8=AE=A1=E5=88=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- readme.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/readme.md b/readme.md index 54a6984..fa902b2 100644 --- a/readme.md +++ b/readme.md @@ -12,14 +12,15 @@ log.Println("ddddd") # 开发计划 -1. 自动清除过期的日志文件 -2. 支持日志文件压缩 -3. 支持日志文件切割 -4. 支持日志文件归档 -5. 支持多种文件分割类型 - 1. 按照时间分割 - 2. 按照文件大小分割 - 3. 按照日志行数分割 -6. 支持debug 模式 - -* [X] 添加异步落库,支持全局和单次 +1. [ ] 自动清除过期的日志文件 +2. [ ] 支持日志文件压缩 +3. [X] 支持日志文件切割 +4. [ ] 支持日志文件归档 +5. [ ] 支持多种文件分割类型 + 1. [ ] 按照时间分割 + 2. [ ] 按照文件大小分割 + 3. [ ] 按照日志行数分割 +6. [ ] 支持debug 模式 +7. [X] 添加异步落库,支持全局和单次 + 1. [ ] 优化:异步应该跟实例不应该全局,多实例异步落库将会有BUG +8. [X] 添加支持是否转义html