乐趣区

关于go-zero:微服务框架-gozero-logx-日志组件剖析

addTenant api 和 rpc 的实现

上一篇咱们说到咱们还剩下 addTenant 性能还未实现,不晓得有没有兄弟感兴趣去试验一波的,本篇文章进行简要补充

依据上一篇文章剖析,其实咱们只须要执行如下几步即可:

  1. 编写 tenant.api,提供内部 addTenant 的 http 接口
  • 编写 tenant.api

提供一个 POST http 的接口 / api /tenant/addtenant

type (
        AddTenantReq {
                Name string `json:"name"`
                Addr string `json:"addr"`
        }
        AddTenantRsp {Id string `json:"id"`}
)
service tenant {
        @handler addTenant
        post /api/tenant/addtenant(AddTenantReq) returns (AddTenantRsp)
  • goctl 生成 api 代码
goctl api go -api tenant.api  -dir .
  1. 批改 api 的配置和逻辑层,让 api 层去调用之前写好的 rpc 接口 即可

对于配置能够模拟上一篇文章 order.api 的配置进行批改,另外只须要调整 addTenant 的 logic 层即可

func (l *AddTenantLogic) AddTenant(req *types.AddTenantReq) (*types.AddTenantRsp, error) {
   // todo: add your logic here and delete this line
   rsp,err :=l.svcCtx.TenantRpc.AddTenant(l.ctx, &tenant.AddTenantReq{
      Name: req.Name,
      Addr: req.Addr,
   })
   if err !=nil{return nil,err}
   return &types.AddTenantRsp{Id: rsp.Id},nil
}

具体的代码案例能够拜访地址:https://github.com/qingconglaixueit/my_test_Demo

上面咱们来看是 go-zero 中 日志组件 logx 的分析

logx 日志组件分析

对于 logx 日志组件,别离从如下几个方面来聊一聊我的了解,如果形容有不当的中央,还请多加评论多加交换

  • Go-zero 中 logx 是如何应用的?

<!—->

  • Logx 根本的数据结构

<!—->

  • Logx 的默认接口实现

<!—->

  • Logx 日志存储地位,以及自定义存储日志地位的实现

<!—->

  • Logx 实现自定义接口的形式

Go-zero 中 logx 是如何应用的?

咱们以之前的 demo,对于 tenant 的 rpc 局部作为例子,追踪一下代码,是如何走到日志局部的逻辑的

能够看到在 tenant.go 的文件中,做的是服务的启动

zrpc.MustNewServer 实际上是调用 go-zero 的 zrpc 包 的 NewServer 函数,传入的参数是

  • c RpcServerConf,咱们 rpc 服务的配置,就是咱们我的项目中的 etc/tenant.yaml

明天不聊对于 RpcServerConf 的构造,咱们重点说说 logx

  • register internal.RegisterFn 注册服务的回调函数

NewServer 函数做了如下几件事件:

  • RpcServerConf 配置数据的有效性查看

<!—->

  • 初始化 metrics 的 options

<!—->

  • 设置服务名,注册 etcd 服务,服务名就是上述配置文件中的 Name 字段

<!—->

  • c.SetUp() 启动整个服务

对于 logx 日志组件的启动就是在 c.SetUp() 中实现

Logx 根本的数据结构

持续看到 logx.SetUp() 中的具体实现,函数须要传入的数据结构是这样的 LogConf

type LogConf struct {
   ServiceName         string `json:",optional"`
   Mode                string `json:",default=console,options=[console,file,volume]"`
   Encoding            string `json:",default=json,options=[json,plain]"`
   TimeFormat          string `json:",optional"`
   Path                string `json:",default=logs"`
   Level               string `json:",default=info,options=[info,error,severe]"`
   Compress            bool   `json:",optional"`
   KeepDays            int    `json:",optional"`
   StackCooldownMillis int    `json:",default=100"`
}
  • ServiceName:设置服务名称,可选。在 volume 模式下,该名称用于生成日志文件。在 rest/zrpc 服务中,名称将被主动设置为 restzrpc 的名称。

<!—->

  • Mode:输入日志的模式,默认是 console

    • console 模式将日志写到 stdout/stderr
    • file 模式将日志写到 Path 指定目录的文件中
    • volume 模式在 docker 中应用,将日志写入挂载的卷中

<!—->

  • Encoding: 批示如何对日志进行编码,默认是 json

    • json模式以 json 格局写日志
    • plain模式用纯文本写日志,并带有终端色彩显示

<!—->

  • TimeFormat:自定义工夫格局,可选。默认是 2006-01-02T15:04:05.000Z07:00

<!—->

  • Path:设置日志门路,默认为 logs

<!—->

  • Level: 用于过滤日志的日志级别。默认为 info

    • info,所有日志都被写入
    • error, info 的日志被抛弃
    • severe, infoerror 日志被抛弃,只有 severe 日志被写入

<!—->

  • Compress: 是否压缩日志文件,只在 file 模式下工作

<!—->

  • KeepDays:日志文件被保留多少天,在给定的天数之后,过期的文件将被主动删除。对 console 模式没有影响

<!—->

  • StackCooldownMillis:多少毫秒后再次写入堆栈跟踪。用来防止堆栈跟踪日志过多

另外对于 SetUp 函数做了如下几件事:

  • 设定日志等级

<!—->

  • 初始化工夫格局

<!—->

  • 依据编码方式初始化存储日志编码类型

<!—->

  • 依据设定的模式来初始化 Writer 句柄

Logx 的默认接口实现

对于 logx 打印日志的具体接口定义在:logx 包的 logger.go 文件中

对于上述接口,依据须要传递的参数咱们能够分为如下几类:

  • Error, Info, Slow: 将任何类型的信息写进日志,应用 fmt.Sprint(...) 来转换为 string

<!—->

  • Errorf, Infof, Slowf: 将指定格局的信息写入日志

<!—->

  • Errorv, Infov, Slowv: 将任何类型的信息写入日志,用 json marshal 编码

<!—->

  • Errorw, Infow, Sloww: 写日志,并带上给定的 key:value 字段

<!—->

  • WithContext:将给定的 ctx 注入日志信息,例如用于记录 trace-idspan-id

<!—->

  • WithDuration: 将指定的工夫写入日志信息中,字段名为 duration

例如接口名后缀带有 w 的,是须要咱们传入 key:value 的,例如传入的构造是这样的:

实际上咱们能够看到在 logx 源码中,其实有很多文件都曾经依据本人的应用状况去实现了上述 Logger 接口

举一个 traceLogger 的例子

实际上咱们能够间接看到,咱们之前实现的 GetTenant rpc 办法

咱们能够看到当调用了NewGetTenantLogic 办法之后,实际上是会调用 logx.WithContext(ctx) 初始化一个 traceLogger 的句柄

traceLogger 实现了上述 Logger 接口, 因而,当咱们须要在 rpc 中打印日志的时候,咱们能够这样来应用

这个时候,实际上是调用的 traceLogger 对应的实现代码

咱们能够看到,打印进去的日志,是咱们所冀望的信息

此处的字段对应含意是这样的:

  • Timestamp

工夫戳

  • Level

日志等级

  • Duration

工夫距离

  • Caller

日志调用者

  • Content

具体的日志信息

认真查看上述日志,咱们能够发现还有 trace 和 span 字段也打印进去了,然而 logEntry 为什么没有定义呢

咱们略微追一下代码,不难看出,是 traceLogger 外部的 info 函数进行日志信息的拼接

Logx 自定义存储日志地位 和 实现自定义接口的形式

Logx 自定义存储日志地位 和 实现自定义接口的形式其实我在这里就不须要过多的解释了,简略阐明一下实现伎俩就能够了,有必要的话咱们能够查看 go-zero 官网文档 https://go-zero.dev/cn/docs/component/logx/

自定义存储日志地位

对于咱们须要批改日志的输入地位,实际上咱们能够认真思考一下,对于日志的数据,go-zero 还是应用的 golang io 包中的 Writer 接口

咱们只须要定义对象,去实现 Writer 接口 中的 Write(p []byte) (n int, err error) 办法就能够了

官网也给了咱们例子,例如咱们实现输入的日志往 kafka 外面吐,咱们就能够这样

实现自定义接口

实现自定义接口,咱们其实方才看 traceLogger 的实现形式,咱们就能领悟到,traceLogger 去实现 Logger 接口中的办法,并且退出本人自定义的逻辑,例如加上了 trace 和 span

那么对于咱们自定义接口,其实也是非常容易的,照葫芦画瓢即可了

\

感激浏览,欢送交换,点个赞,关注一波 再走吧

欢送点赞,关注,珍藏

敌人们,你的反对和激励,是我保持分享,提高质量的能源

好了,本次就到这里

技术是凋谢的,咱们的心态,更应是凋谢的。拥抱变动,背阴而生,致力向前行。

我是 阿兵云原生,欢送点赞关注珍藏,下次见~

\

退出移动版