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"
相关推荐
黄俊懿2 分钟前
【深入理解SpringCloud微服务】手写实现各种限流算法——固定时间窗、滑动时间窗、令牌桶算法、漏桶算法
java·后端·算法·spring cloud·微服务·架构
2401_8574396929 分钟前
“衣依”服装销售平台:Spring Boot技术应用与优化
spring boot·后端·mfc
Jerry.ZZZ1 小时前
系统设计,如何设计一个秒杀功能
后端
27669582922 小时前
京东e卡滑块 分析
java·javascript·python·node.js·go·滑块·京东
九圣残炎2 小时前
【springboot】简易模块化开发项目整合Redis
spring boot·redis·后端
.生产的驴3 小时前
Electron Vue框架环境搭建 Vue3环境搭建
java·前端·vue.js·spring boot·后端·electron·ecmascript
爱学的小涛3 小时前
【NIO基础】基于 NIO 中的组件实现对文件的操作(文件编程),FileChannel 详解
java·开发语言·笔记·后端·nio
爱学的小涛3 小时前
【NIO基础】NIO(非阻塞 I/O)和 IO(传统 I/O)的区别,以及 NIO 的三大组件详解
java·开发语言·笔记·后端·nio
北极无雪3 小时前
Spring源码学习:SpringMVC(4)DispatcherServlet请求入口分析
java·开发语言·后端·学习·spring
爱码少年3 小时前
springboot工程中使用tcp协议
spring boot·后端·tcp/ip