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"
相关推荐
凤山老林3 小时前
Spring Boot 启动冲刺:耗时剖析、懒加载策略与事件驱动初始化优化
spring boot·后端·python
Thinker QAQ4 小时前
并发编程(九):BlockingQueue 与 Channel——语言层的原子性、可见性与有序性
java·python·go·并发编程·channel·blockingqueue·message passing
朱涛的自习室4 小时前
我给 Gemini 4 和 DeepSeek 搞了套「末位淘汰」,AI 干活会更猛吗?(Day 3)
android·前端·后端
woniu_maggie7 小时前
SAP MDG主数据治理实战:从架构原理到项目实施全解析
后端
xiaoqiMikko7 小时前
Redis 实战(一):内存满了 —— 拒写、淘汰、被系统杀掉,以及删了 key 内存为什么不降(6.2.4 实测)
redis·后端
工程师小爱7 小时前
电芯尺寸合格,不等于电池包尺寸合格
后端
geovindu7 小时前
rust:Memento Pattern(续)
开发语言·后端·设计模式·rust·行为模式·备忘录模
闲云lazycloud7 小时前
第 1 课:Harness 与 Agent 运行时
人工智能·后端
熊哈哈O_o8 小时前
260+异构同步链路:DDL语法自动翻译在大规模数据同步中的实现原理
后端