gogf / gf

GoFrame is a modular, powerful, high-performance and enterprise-class application development framework of Golang.
https://goframe.org
MIT License
11.76k stars 1.6k forks source link

os/glog: Does GoFrame support for logging fields? #3869

Open RyoJerryYu opened 1 month ago

RyoJerryYu commented 1 month ago

What do you want to ask?

We are using logrus and logging like this:

log.Info("A simple log")
log.WithFields(log.Fields{
  "event": event,
  "user_id": userId,
}).Info("A log with fields")

And it produce json logs like below:

{
  "log": "A simple log"
}
{
  "event": "event",
  "user_id": "user_id",
  "log": "A log with fields"
}

So we can use the fields to filter our logs such as:

select log
where  user_id = 1 and event = "event"

Do GoFrame support this? Or how can I implement something like this in GoFrame?

RyoJerryYu commented 1 month ago

I do have read this issue: https://github.com/gogf/gf/issues/553

But the answer in that issue do not fit my situation.

The point is the log message is a field in JSON, both logging in a simple way and logging with fields. We don't want to make the simple logging being so complex.

gqcn commented 1 month ago

@RyoJerryYu Hello, we does not support WithFields like logrus, but you can try function SetPrefix or submit a PR adding Fields/SetFields function to support this.

github-actions[bot] commented 1 month ago

Hello @RyoJerryYu. We like your proposal/feedback and would appreciate a contribution via a Pull Request by you or another community member. We thank you in advance for your contribution and are looking forward to reviewing it! 你好 @RyoJerryYu。我们喜欢您的提案/反馈,并希望您或其他社区成员通过拉取请求做出贡献。我们提前感谢您的贡献,并期待对其进行审查。

RyoJerryYu commented 1 month ago

@RyoJerryYu Hello, we does not support WithFields like logrus, but you can try function SetPrefix or submit a PR adding Fields/SetFields function to support this.

@gqcn Thank you for answering. But I don't seem to have made my real needs clear.

What we really want is the ability of structured logging, and the simple logging should remain simple and work well with structured logging. We do not care how the codes look like. The logrus-like WithFields method is not important at all.

In fact, we all know there's a bunch of libraries that support structured logging in different styles.

// zap styles
sugar.Infow("failed to fetch URL",
  // Structured context as loosely typed key-value pairs.
  "url", url,
  "attempt", 3,
  "backoff", time.Second,
)

logger.Info("failed to fetch URL",
  // Structured context as strongly typed Field values.
  zap.String("url", url),
  zap.Int("attempt", 3),
  zap.Duration("backoff", time.Second),
)

// zerolog styles
log.Debug().
        Str("Scale", "833 cents").
        Float64("Interval", 833.09).
        Msg("Fibonacci is everywhere")

Obviously we can easily convert to each style by adding a simple adapter layer.

But it seems glog does not provide any method to log with fields? We tried to log with g.Map , but the logs it produced were not what we want. I found a Chinese comment here also complaining about this: https://goframe.org/pages/viewpage.action?pageId=1114186

RyoJerryYu commented 1 month ago

BTW, we finally found that it seems could be implemented by providing a self-defined Handler, then log fields in zap style. However, since HandlerInput do not provide any support for custom fields, we can only parse the fields from HandlerInput.Values one by one.

It would be much better if glog support structured logging as a first-class feature.

gqcn commented 1 month ago

BTW, we finally found that it seems could be implemented by providing a self-defined Handler, then log fields in zap style. However, since HandlerInput do not provide any support for custom fields, we can only parse the fields from HandlerInput.Values one by one.

It would be much better if glog support structured logging as a first-class feature.

Hello, if your root requirement is just structure logging feature, it is already supported in glogcomponent. You can refer the document here: https://goframe.org/pages/viewpage.action?pageId=17207121 Here's a simple example:

package main

import (
    "context"
    "net"

    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/os/glog"
)

func main() {
    ctx := context.TODO()
    glog.SetDefaultHandler(glog.HandlerStructure)

    g.Log().Info(ctx, "caution", "name", "admin")
    glog.Error(ctx, "oops", net.ErrClosed, "status", 500)
}

When you run it, it outputs like this:

Time="2023-11-23 21:00:08.671" Level=INFO Content=caution name=admin
Time="2023-11-23 21:00:08.671" Level=ERRO oops="use of closed network connection" status=500 Stack="1.  main.main\n    /Users/txqiangguo/Workspace/gogf/gf/example/.test/main.go:16\n"