go-zero的日志配置——logx

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"
相关推荐
monkey_meng25 分钟前
【遵守孤儿规则的External trait pattern】
开发语言·后端·rust
Estar.Lee40 分钟前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
新知图书1 小时前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust
盛夏绽放2 小时前
Node.js 和 Socket.IO 实现实时通信
前端·后端·websocket·node.js
Ares-Wang2 小时前
Asp.net Core Hosted Service(托管服务) Timer (定时任务)
后端·asp.net
Rverdoser3 小时前
RabbitMQ的基本概念和入门
开发语言·后端·ruby
Tech Synapse4 小时前
Java根据前端返回的字段名进行查询数据的方法
java·开发语言·后端
.生产的驴4 小时前
SpringCloud OpenFeign用户转发在请求头中添加用户信息 微服务内部调用
spring boot·后端·spring·spring cloud·微服务·架构
微信-since811924 小时前
[ruby on rails] 安装docker
后端·docker·ruby on rails
代码吐槽菌6 小时前
基于SSM的毕业论文管理系统【附源码】
java·开发语言·数据库·后端·ssm