gookit / slog

📑 Lightweight, configurable, extensible logging library written in Go. Support multi level, multi outputs and built-in multi file logger, buffers, clean, rotate-file handling.一个易于使用的,轻量级、可配置、可扩展的日志库。支持多个级别,输出到多文件;内置文件日志处理、自动切割、清理、压缩等增强功能
https://pkg.go.dev/github.com/gookit/slog
MIT License
383 stars 24 forks source link

自定义模板报 invalid memory address or nil pointer dereference #139

Closed chanyipiaomiao closed 5 months ago

chanyipiaomiao commented 6 months ago

System (please complete the following information):

Describe the bug

自定义模板报空指针 invalid memory address or nil pointer dereference

To Reproduce

func TestLog(t *testing.T) {
    myTemplate := "[{{datetime}}] [{{requestid}}] [{{level}}] {{message}}"
    textFormatter := &slog.TextFormatter{TimeFormat: "2006-01-02 15:04:05.000"}
    textFormatter.SetTemplate(myTemplate)
    h1 := handler.NewConsoleHandler(slog.AllLevels)
    h1.SetFormatter(textFormatter)
    L := slog.New()
    L.AddHandlers(h1)
    L.WithField("requestid", "11111").Info("testst")
}

Expected behavior

A clear and concise description of what you expected to happen.

Screenshots

image

Additional context

Add any other context about the problem here.

chanyipiaomiao commented 6 months ago

func TestLog(t *testing.T) { myTemplate := "[{{datetime}}] [{{requestid}}] [{{level}}] {{message}}" textFormatter := &slog.TextFormatter{TimeFormat: "2006-01-02 15:04:05.000"} textFormatter.SetTemplate(myTemplate) h1 := handler.NewConsoleHandler(slog.AllLevels) h1.SetFormatter(textFormatter) ctx := context.WithValue(context.Background(), "requestid", "111111") L := slog.New() L.AddHandlers(h1) L.WithCtx(ctx).Info("test") } 请问这样使用是否有问题,模板中的requestid没有被替换 image

inhere commented 6 months ago

改成这样:

    myTemplate := "[{{datetime}}] [{{requestid}}] [{{level}}] {{message}}\n"
    // textFormatter := &slog.TextFormatter{TimeFormat: "2006-01-02 15:04:05.000"}
    // textFormatter.SetTemplate(myTemplate)
    // CHANGE 1 ....
    textFormatter :=slog.NewTextFormatter(myTemplate).Configure(func(f *slog.TextFormatter) {
        f.TimeFormat = "2006-01-02 15:04:05.000"
    })
    h1 := handler.NewConsoleHandler(slog.AllLevels)
    h1.SetFormatter(textFormatter)
    ctx := context.WithValue(context.Background(), "requestid", "111111")

    L := slog.New()
    L.AddHandlers(h1)
    // add processor <==== CHANGE 2
    L.AddProcessor(slog.ProcessorFunc(func(r *slog.Record) {
        r.Fields["requestid"] = r.Ctx.Value("requestid")
    }))
    L.WithCtx(ctx).Info("test")
chanyipiaomiao commented 5 months ago

请帮忙看看 遇到 panic: assignment to entry in nil map 也不是必现,偶现 具体的错误堆栈信息如下:


panic: assignment to entry in nil map

goroutine 1165 [running]:
devops-alertcenter/internal/pkg/logger.Setup.func2(0xc0003eeb60)
    /app/devops_alertcenter/internal/pkg/logger/logger.go:64 +0x65
github.com/gookit/slog.ProcessorFunc.Process(0x9dd6fb?, 0x19b3328?)
    /gopath/pkg/mod/github.com/gookit/slog@v0.5.5/processor.go:27 +0x19
github.com/gookit/slog.(*Record).beforeHandle(0xc0003eeb60, 0xc00013e000)
    /gopath/pkg/mod/github.com/gookit/slog@v0.5.5/logger_write.go:55 +0x1d5
github.com/gookit/slog.(*Logger).writeRecord(0xc00013e000, 0x258, 0xc0003eeb60)
    /gopath/pkg/mod/github.com/gookit/slog@v0.5.5/logger_write.go:71 +0x15a
github.com/gookit/slog.(*Record).logf(0xc0003eeb60, 0x258, {0xc71ea9?, 0x0?}, {0xc000024a80?, 0x2?, 0xc000600400?})
    /gopath/pkg/mod/github.com/gookit/slog@v0.5.5/record.go:360 +0xd7
github.com/gookit/slog.(*Record).Infof(...)
    /gopath/pkg/mod/github.com/gookit/slog@v0.5.5/record.go:377
devops-alertcenter/internal/app/v1/logic.(*alertSender).send(0xc0001e1260)
    /app/devops_alertcenter/internal/app/v1/logic/alert.go:141 +0xb65
devops-alertcenter/internal/app/v1/logic.GeneralAlert({0x1589160?, 0xc000304180}, 0xc000102150)
    /app/devops_alertcenter/internal/app/v1/logic/general_alert.go:39 +0x268
devops-alertcenter/internal/app/v1/controller.(*GeneralAlertController).Alert(0xc0001e1340)
    /app/devops_alertcenter/internal/app/v1/controller/general_alert.go:40 +0x12f
devops-alertcenter/internal/app/v1/controller.AlertDispatchController(0xc00035cc00)
    /app/devops_alertcenter/internal/app/v1/controller/alert_dispatch.go:26 +0x14d
github.com/gofiber/fiber/v2.(*App).next(0xc0003b0f00, 0xc00035cc00)
    /gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.2/router.go:145 +0x1b2
github.com/gofiber/fiber/v2.(*Ctx).Next(0xc0003c08a0?)
    /gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.2/ctx.go:1030 +0x4d
github.com/gofiber/fiber/v2/middleware/logger.New.func3(0xc00035cc00)
    /gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.2/middleware/logger/logger.go:119 +0x316
github.com/gofiber/fiber/v2.(*Ctx).Next(0xc00057a330?)
    /gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.2/ctx.go:1027 +0x3d
github.com/gofiber/fiber/v2/middleware/cors.New.func1(0xc00035cc00)
    /gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.2/middleware/cors/cors.go:191 +0x326
github.com/gofiber/fiber/v2.(*Ctx).Next(0xc0000687d0?)
    /gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.2/ctx.go:1027 +0x3d
github.com/gofiber/fiber/v2/middleware/healthcheck.New.func1(0xc00035cc00)
    /gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.2/middleware/healthcheck/healthcheck.go:41 +0x154
github.com/gofiber/fiber/v2.(*Ctx).Next(0xc00057a4e0?)
    /gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.2/ctx.go:1027 +0x3d
devops-alertcenter/internal/app/server.StartHttpServer.func2(0xc00035cc00)
    /app/devops_alertcenter/internal/app/server/httpserver.go:78 +0xaf
github.com/gofiber/fiber/v2.(*Ctx).Next(0xc00032a000?)
    /gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.2/ctx.go:1027 +0x3d
devops-alertcenter/internal/app/server.StartHttpServer.New.func6(0xb7ec20?)
    /gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.2/middleware/requestid/requestid.go:31 +0xe5
github.com/gofiber/fiber/v2.(*App).next(0xc0003b0f00, 0xc00035cc00)
    /gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.2/router.go:145 +0x1b2
github.com/gofiber/fiber/v2.(*App).handler(0xc0003b0f00, 0x4cb24f?)
    /gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.2/router.go:172 +0x78
github.com/valyala/fasthttp.(*Server).serveConn(0xc00036bc00, {0x158c0f0?, 0xc000482008})
    /gopath/pkg/mod/github.com/valyala/fasthttp@v1.51.0/server.go:2359 +0x11d4
github.com/valyala/fasthttp.(*workerPool).workerFunc(0xc0003ad180, 0xc0003b4020)
    /gopath/pkg/mod/github.com/valyala/fasthttp@v1.51.0/workerpool.go:224 +0xa4
github.com/valyala/fasthttp.(*workerPool).getCh.func1()
    /gopath/pkg/mod/github.com/valyala/fasthttp@v1.51.0/workerpool.go:196 +0x32
created by github.com/valyala/fasthttp.(*workerPool).getCh in goroutine 1
    /gopath/pkg/mod/github.com/valyala/fasthttp@v1.51.0/workerpool.go:195 +0x1ab

/app/devops_alertcenter/internal/pkg/logger/logger.go:64 这个文件内容如下:

r.Fields[consts.RequestIDKeyName] = r.Ctx.Value(consts.RequestIDKeyName) // 第64行

// Setup 初始化日志
func Setup(cfg *config.ServiceConfig) {
    var (
        logSetting     = cfg.LogSetting
        rotation       = rotatefile.RotateTime(logSetting.Rotation)
        backupNum      = logSetting.BackupNum
        backupTime     = logSetting.BackupTime
        maxSize        = logSetting.MaxSize * rotatefile.OneMByte
        errorHandler   *handler.SyncCloseHandler
        normalHandler  *handler.SyncCloseHandler
        errorFilename  = fmt.Sprintf("%s.error%s", logSetting.ServiceLogFilename, logSetting.LogFilenamePostfix)
        errorFilepath  = path.Join(logSetting.LogDir, errorFilename)
        normalFilename = fmt.Sprintf("%s.info%s", logSetting.ServiceLogFilename, logSetting.LogFilenamePostfix)
        normalFilepath = path.Join(logSetting.LogDir, normalFilename)
        textFormatter  *slog.TextFormatter
        commonConfigs  = []handler.ConfigFn{
            handler.WithBackupNum(backupNum), handler.WithBackupTime(backupTime),
            handler.WithMaxSize(maxSize), handler.WithBuffSize(0),
        }
        errorConfigs = []handler.ConfigFn{
            handler.WithLogLevels(slog.DangerLevels),
        }
        normalConfigs = []handler.ConfigFn{
            handler.WithLogLevels(slog.NormalLevels),
        }
    )

    errorConfigs = append(errorConfigs, commonConfigs...)
    normalConfigs = append(normalConfigs, commonConfigs...)

    textFormatter = slog.NewTextFormatter(LogRecordTemplate).Configure(func(f *slog.TextFormatter) {
        f.TimeFormat = consts.LogDateTimeFormat // 自定义时间格式
    })

    // warning以上的级别写到一个文件
    errorHandler = handler.MustRotateFile(errorFilepath, rotation, errorConfigs...)
    errorHandler.SetFormatter(textFormatter)

    // info以下的级别写到一个文件
    normalHandler = handler.MustRotateFile(normalFilepath, rotation, normalConfigs...)
    normalHandler.SetFormatter(textFormatter)

    // 增加handler
    slog.AddHandlers(errorHandler, normalHandler)

    // 添加requestid
    slog.AddProcessor(slog.ProcessorFunc(func(r *slog.Record) {
        r.Fields[consts.RequestIDKeyName] = r.Ctx.Value(consts.RequestIDKeyName)     // 第64行
    }))

    // 禁用console输出,默认是启用的
    slog.SetLogLevel(slog.PanicLevel)
}
inhere commented 5 months ago

可以使用下面这个方法替代 r.Fields["requestid"] = r.Ctx.Value("requestid") 更保险,里面会做检查:


    // L.AddProcessor(slog.ProcessorFunc(func(r *slog.Record) {
    //  r.Fields["requestid"] = r.Ctx.Value("requestid")
    // }))
    L.AddProcessor(slog.AppendCtxKeys("requestid"))