01 背景
go-zero是一个集成了各种工程实践的 web 和 rpc 框架,其集成的gooctl生成工具,可以为我们快速生成代码,加速开发的过程。
go-zero框架有一个自己的日志包logx(logc是logx的封装)。 查阅go-zero框架的文档,日志配置的使用方法是:
go
var c logx.LogConf
logx.MustSetup(c)
logx.Info(context.Background(), "log")
// do your job
然而文档里并没有介绍如何在goctl工具生成的HTTP服务代码中配置日志,我也就在这里遇到了个小坑。以下是我开始时写的日志配置相关的代码,然而,日志配置并没有生效,输出的日志是json格式的(默认为json格式)。
go
// ./etc/serice.yaml
LogConf:
ServiceName: "http_service"
Encoding: "plain"
Level: "debug"
Path: "http_service/logs"
// ./internal/config/config.go
type Config struct {
rest.RestConf
Auth struct {
AccessSecret string
AccessExpire int64
}
LogConf logx.LogConf
}
// ./service.go
func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
server := rest.MustNewServer(c.RestConf)
defer server.Stop()
ctx := svc.NewServiceContext(c)
handler.RegisterHandlers(server, ctx)
logx.MustSetup(c.LogConf)
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
server.Start()
}
02 寻因过程
我首先尝试在google上搜索看看有没有其他同学发表过这个logx日志包的使用,然而并没有搜索到相关的信息。接着尝试了在github上搜索logx.MustSetup
,找到了一些大家是如何配置日志的,但是感觉仍然没搞清楚应该如何正确配置日志。
最后还是得自己老老实实看看源码。可以看见,go-zero为func SetUp(c LogConf) (err error)
这个log的设置函数使用了单例模式:
go
func SetUp(c LogConf) (err error) {
setupOnce.Do(func() {
setupLogLevel(c)
// ...
switch c.Mode {
case fileMode:
err = setupWithFiles(c)
case volumeMode:
err = setupWithVolume(c)
default:
setupWithConsole()
}
})
return
}
于是我猜测会不会是SetUp(c LogConf)
函数已经调用过了,所以设置并没有生效。果然,其实在server := rest.MustNewServer(c.RestConf)
中就已经调用过了这个SetUp()函数了:
go
func MustNewServer(c RestConf, opts ...RunOption) *Server {
server, err := NewServer(c, opts...)
if err != nil {
logx.Must(err)
}
return server
}
func NewServer(c RestConf, opts ...RunOption) (*Server, error) {
if err := c.SetUp(); err != nil {
return nil, err
}
// ...
return server, nil
}
func (sc ServiceConf) SetUp() error {
if len(sc.Log.ServiceName) == 0 {
sc.Log.ServiceName = sc.Name
}
if err := logx.SetUp(sc.Log); err != nil {
return err
}
// ...
return nil
}
同时,我们可以看到ServiceConf结构体中包含了日志配置结构体logx.LogConf:
go
ServiceConf struct {
Name string
Log logx.LogConf
Mode string `json:",default=pro,options=dev|test|rt|pre|pro"`
MetricsUrl string `json:",optional"`
// Deprecated: please use DevServer
Prometheus prometheus.Config `json:",optional"`
Telemetry trace.Config `json:",optional"`
DevServer DevServerConfig `json:",optional"`
}
03 解决
从源码中可以看到,logx.LogConf在ServiceConf结构体中相应的成员名为Log,所以配置文件service.yaml中与日志相关的配置应该写为:
yaml
Log:
ServiceName: "http_service"
Mode: "console"
Encoding: "plain"
Level: "debug"
Path: "http_service/logs"