Merge remote-tracking branch 'github/yun'

This commit is contained in:
Yun
2025-05-11 18:44:47 +08:00
7 changed files with 130 additions and 29 deletions
+13 -6
View File
@@ -14,13 +14,20 @@ func main() {
loggerx.SetToConsole(), loggerx.SetToConsole(),
// loggerx.SetTimeZone(time.UTC), // loggerx.SetTimeZone(time.UTC),
loggerx.SetTimeZone(time.FixedZone("CST", 8*3600)), loggerx.SetTimeZone(time.FixedZone("CST", 8*3600)),
loggerx.SetEscapeHTML(false),
) )
log.WriteAsync().Info(ctx, "{ \"a\": 1, \"b\": 2 }")
log.Info(ctx, "哈哈哈2") log.Info(ctx, "哈哈哈2")
log.Info(ctx, "哈哈哈2") log.Info(ctx, "哈哈哈2")
log.Info(ctx, "哈哈哈2") log.Info(ctx, "哈哈哈2\r")
log.Info(ctx, "哈哈哈2") log.Info(ctx, "哈哈哈2\r\n")
log.Info(ctx, "哈哈哈2") log.Info(ctx, "哈哈哈2<b>")
log.Info(ctx, "哈哈哈2") 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)
} }
+14 -2
View File
@@ -1,6 +1,7 @@
package loggerx package loggerx
import ( import (
"bytes"
"context" "context"
"encoding/json" "encoding/json"
"fmt" "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" // 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 { if _, ok := val.(error); ok {
v[idx] = fmt.Sprintf("%+v", val) 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()) // 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 + "]") ff := []byte("\n[" + event + "]")
fdb = append(ff, fdb...) fdb = append(ff, fdb...)
+2 -1
View File
@@ -2,7 +2,8 @@ package loggerx
import "context" import "context"
type Loggerx interface { // 简单使用的日志接口
type LoggerInterface interface {
Info(ctx context.Context, args ...any) Info(ctx context.Context, args ...any)
Infof(ctx context.Context, format string, args ...any) Infof(ctx context.Context, format string, args ...any)
Error(ctx context.Context, args ...any) Error(ctx context.Context, args ...any)
+14
View File
@@ -26,6 +26,7 @@ type Logger struct {
mu *sync.Mutex mu *sync.Mutex
option loggerOption option loggerOption
channel string channel string
writeType writeType // 是否异步落盘,这里作用范围是本条,优先判断这里
} }
type filePath struct { type filePath struct {
@@ -49,6 +50,7 @@ func NewLogger(ctx context.Context, opts ...Option) *Logger {
filePath: &sync.Map{}, filePath: &sync.Map{},
mu: &sync.Mutex{}, mu: &sync.Mutex{},
option: opt, option: opt,
writeType: writeTypeDefault,
} }
log.SetOutput(l) log.SetOutput(l)
@@ -87,6 +89,18 @@ func (l *Logger) Channel(ch string) (r *Logger) {
return &rr 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的字段 // 获取TraceField的字段
func (l *Logger) GetTraceField() string { func (l *Logger) GetTraceField() string {
return l.option.traceField return l.option.traceField
+26
View File
@@ -13,6 +13,7 @@ type loggerOption struct {
isGinLog bool isGinLog bool
isGid bool isGid bool
isPrintFile bool isPrintFile bool
writeType writeType // 是否异步罗盘
traceField string // trace字段 traceField string // trace字段
errorToInfo bool // 错误日志是否写入info日志 errorToInfo bool // 错误日志是否写入info日志
days int // 日志保存天数 days int // 日志保存天数
@@ -20,19 +21,31 @@ type loggerOption struct {
fileSplit FileSplit // 文件切割规则 fileSplit FileSplit // 文件切割规则
sizeSplit int // 根据文件大小切割 sizeSplit int // 根据文件大小切割
timeZone *time.Location // 时区 timeZone *time.Location // 时区
escapeHTML bool
} }
type writeType uint8
const (
// 0.默认(同步) 1.指定同步 2.指定异步
writeTypeDefault writeType = iota
writeTypeSync
writeTypeAsync
)
func defaultOptions() loggerOption { func defaultOptions() loggerOption {
return loggerOption{ return loggerOption{
isGinLog: true, isGinLog: true,
isGid: true, isGid: true,
isPrintFile: true, isPrintFile: true,
writeType: writeTypeDefault, // 默认同步
format: "json", format: "json",
dir: "./log", dir: "./log",
traceField: "trace_id", traceField: "trace_id",
days: 7, days: 7,
fileSplit: FileSplitTimeE, fileSplit: FileSplitTimeE,
timeZone: time.Local, timeZone: time.Local,
escapeHTML: true,
} }
} }
@@ -45,6 +58,13 @@ func SetTraceField(traceField string) Option {
} }
} }
// 是否异步写入
func SetWriteAsync() Option {
return func(o *loggerOption) {
o.writeType = writeTypeAsync
}
}
// 打印到控制台 // 打印到控制台
func SetToConsole() Option { func SetToConsole() Option {
return func(o *loggerOption) { return func(o *loggerOption) {
@@ -158,3 +178,9 @@ func SetSizeSplit(m int) Option {
o.sizeSplit = m o.sizeSplit = m
} }
} }
func SetEscapeHTML(b bool) Option {
return func(o *loggerOption) {
o.escapeHTML = b
}
}
+12 -11
View File
@@ -1,4 +1,3 @@
# 简介 # 简介
这个是基于原生log实现的日志存储。 这个是基于原生log实现的日志存储。
@@ -11,15 +10,17 @@ log.Println("ddddd")
# 用法 # 用法
# 开发计划 # 开发计划
1. 自动清除过期的日志文件 1. [ ] 自动清除过期的日志文件
2. 支持日志文件压缩 2. [ ] 支持日志文件压缩
3. 支持日志文件切割 3. [X] 支持日志文件切割
4. 支持日志文件归档 4. [ ] 支持日志文件归档
5. 支持多种文件分割类型 5. [ ] 支持多种文件分割类型
1. 按照时间分割 1. [ ] 按照时间分割
2. 按照文件大小分割 2. [ ] 按照文件大小分割
3. 按照日志行数分割 3. [ ] 按照日志行数分割
6. 支持debug 模式 6. [ ] 支持debug 模式
7. [X] 添加异步落库,支持全局和单次
1. [ ] 优化:异步应该跟实例不应该全局,多实例异步落库将会有BUG
8. [X] 添加支持是否转义html
+40
View File
@@ -2,9 +2,20 @@ package loggerx
import ( import (
"io" "io"
"sync"
) )
// 写入,需要判断同步还是异步
func (l *Logger) write(event string, b []byte) (n int, err error) { 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 { if l.option.isPrintFile {
f, err := l.getFile(event, false) 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 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
}