2024-01-22 18:05:51 +08:00
|
|
|
package loggerx
|
|
|
|
|
|
|
|
|
|
// author:黄新云
|
2024-04-03 21:18:44 +08:00
|
|
|
// lastTime:2024年4月3日21:18:05
|
2024-01-22 18:05:51 +08:00
|
|
|
// desc: 日志封装类
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"log"
|
|
|
|
|
"os"
|
|
|
|
|
"runtime"
|
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
|
|
// "sync_log/global"
|
|
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// 需要实现io.Writer接口
|
|
|
|
|
type Logger struct {
|
2024-11-22 20:08:25 +08:00
|
|
|
ctx context.Context
|
|
|
|
|
filePath *sync.Map // filePath
|
|
|
|
|
mu *sync.Mutex
|
|
|
|
|
option loggerOption
|
|
|
|
|
channel string
|
|
|
|
|
writeType writeType // 是否异步落盘,这里作用范围是本条,优先判断这里
|
2024-01-23 00:12:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type filePath struct {
|
2024-01-22 18:05:51 +08:00
|
|
|
file *os.File
|
|
|
|
|
fileName string
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-15 23:40:55 +08:00
|
|
|
func NewLogger(ctx context.Context, opts ...Option) *Logger {
|
2024-01-22 18:05:51 +08:00
|
|
|
opt := defaultOptions()
|
|
|
|
|
for _, apply := range opts {
|
|
|
|
|
apply(&opt)
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-03 21:18:44 +08:00
|
|
|
// 验证文件夹权限
|
|
|
|
|
if !checkDir(opt.dir) {
|
|
|
|
|
panic("文件夹权限不足")
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-23 00:12:08 +08:00
|
|
|
l := &Logger{
|
2024-11-22 20:08:25 +08:00
|
|
|
ctx: ctx,
|
|
|
|
|
filePath: &sync.Map{},
|
|
|
|
|
mu: &sync.Mutex{},
|
|
|
|
|
option: opt,
|
|
|
|
|
writeType: writeTypeDefault,
|
2024-01-22 18:05:51 +08:00
|
|
|
}
|
2024-01-23 00:12:08 +08:00
|
|
|
|
2024-01-22 18:05:51 +08:00
|
|
|
log.SetOutput(l)
|
|
|
|
|
log.SetFlags(log.LstdFlags | log.Llongfile | log.Lmicroseconds) // log.Lshortfile | log.LUTC
|
|
|
|
|
|
|
|
|
|
// 保存Gin日志写入到文件+控制台
|
2024-01-23 00:12:08 +08:00
|
|
|
if opt.isGinLog {
|
|
|
|
|
gin.DefaultWriter = io.MultiWriter(l, os.Stdout)
|
|
|
|
|
gin.DefaultErrorWriter = io.MultiWriter(l, os.Stdout)
|
2024-01-22 18:05:51 +08:00
|
|
|
}
|
2024-01-23 13:37:51 +08:00
|
|
|
|
|
|
|
|
// 日志删除
|
|
|
|
|
go l.delete()
|
|
|
|
|
|
2024-04-15 23:40:55 +08:00
|
|
|
// 强制刷盘
|
|
|
|
|
go func() {
|
|
|
|
|
<-ctx.Done()
|
|
|
|
|
l.MustSync()
|
|
|
|
|
}()
|
|
|
|
|
|
2024-01-22 18:05:51 +08:00
|
|
|
return l
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-23 00:12:08 +08:00
|
|
|
// 强制刷盘
|
|
|
|
|
func (l *Logger) MustSync() {
|
|
|
|
|
l.filePath.Range(func(key, value any) bool {
|
|
|
|
|
f := value.(*filePath)
|
|
|
|
|
f.file.Sync()
|
|
|
|
|
return true
|
|
|
|
|
})
|
|
|
|
|
}
|
2024-01-22 18:05:51 +08:00
|
|
|
|
2024-01-23 00:12:08 +08:00
|
|
|
func (l *Logger) Channel(ch string) (r *Logger) {
|
|
|
|
|
rr := *l
|
|
|
|
|
rr.channel = ch
|
|
|
|
|
return &rr
|
|
|
|
|
}
|
2024-01-22 18:05:51 +08:00
|
|
|
|
2024-11-22 20:08:25 +08:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-03 16:58:14 +08:00
|
|
|
// 获取TraceField的字段
|
|
|
|
|
func (l *Logger) GetTraceField() string {
|
|
|
|
|
return l.option.traceField
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-23 00:12:08 +08:00
|
|
|
// 实现io.Writer接口
|
2024-01-22 18:05:51 +08:00
|
|
|
func (l *Logger) Write(b []byte) (n int, err error) {
|
2024-01-23 00:12:08 +08:00
|
|
|
return l.write("info", b)
|
2024-01-22 18:05:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *Logger) Info(ctx context.Context, v ...any) {
|
|
|
|
|
l.logger(ctx, "info", v...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *Logger) Infof(ctx context.Context, format string, v ...any) {
|
|
|
|
|
s := fmt.Sprintf(format, v...)
|
|
|
|
|
l.logger(ctx, "info", s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *Logger) Error(ctx context.Context, v ...any) {
|
|
|
|
|
l.logger(ctx, "error", v...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *Logger) Errorf(ctx context.Context, format string, v ...any) {
|
|
|
|
|
s := fmt.Sprintf(format, v...)
|
|
|
|
|
l.logger(ctx, "error", s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 添加固定的内容
|
|
|
|
|
// func (l *Logger) ContextWithFields(ctx context.Context, v ...any) {
|
|
|
|
|
// l.logger(ctx, "add", v...)
|
|
|
|
|
// }
|
|
|
|
|
// func (l *Logger) Field(key,val string) {
|
|
|
|
|
// l.logger(nil, "add", key,val)
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
func getGID() string {
|
|
|
|
|
b := make([]byte, 64)
|
|
|
|
|
b = b[:runtime.Stack(b, false)]
|
|
|
|
|
b = bytes.TrimPrefix(b, []byte("goroutine "))
|
|
|
|
|
b = b[:bytes.IndexByte(b, ' ')]
|
|
|
|
|
return string(b)
|
|
|
|
|
}
|
2024-04-03 21:18:44 +08:00
|
|
|
|
|
|
|
|
// 验证文件夹权限
|
|
|
|
|
// 根文件夹如果不存在则创建
|
|
|
|
|
func checkDir(dir string) bool {
|
|
|
|
|
if _, err := os.Stat(dir); err != nil {
|
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
|
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
|
|
|
|
|
log.Println("创建文件夹失败", err)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|