Kratos的http服务日志增加traceId

一、背景和意义

kratos是go语言中常用的微服务框架,该框架自带有log组件。在打印日志时如果输出traceId就可以方便地追踪同一请求的日志,kratos官方的traceId相关示例比较复杂,对于一个简单的、不涉及大量上下游服务的提供给前端页面调用的http服务,文本提供一个更简单使用示例。

二、创建运行简单的kratos应用

执行如下命令安装kratos工具:

bash 复制代码
go install github.com/go-kratos/kratos/cmd/kratos/v2@latest

接下来创建一个简单项目:

bash 复制代码
kratos new kratos-demo -r https://gitee.com/go-kratos/kratos-layout.git

将相关依赖下载到本地:

bash 复制代码
go mod download

生成代码:

bash 复制代码
go generate ./...

运行代码:

bash 复制代码
kratos run

用浏览器打开链接:http://localhost:8000/helloworld/kratos'。正常情况下会返回:{"message":"Hello kratos"}

同时,服务器上会输出如下一行日志:

log 复制代码
INFO ts=2024-03-03T18:10:58+08:00 caller=biz/greeter.go:43 service.id=xxxxxx service.name= service.version= trace.id= span.id= msg=CreateGreeter: kratos

对应的打印日志的代码是在internal/biz/greeter.go这个文件中的如下代码:

go 复制代码
// CreateGreeter creates a Greeter, and returns the new Greeter.
func (uc *GreeterUsecase) CreateGreeter(ctx context.Context, g *Greeter) (*Greeter, error) {
   uc.log.WithContext(ctx).Infof("CreateGreeter: %v", g.Hello)
   return uc.repo.Save(ctx, g)
}

在前面输出的日志中,trace.id还是空的。

三、增加traceId输出

修改internal/server/http.go文件,添加一个增加traceid的中间件方法simpleTraceHandler

go 复制代码
func simpleTraceHandler(handler middleware.Handler) middleware.Handler {
   return func(ctx context.Context, req interface{}) (reply interface{}, err error) {
      ctx = context.WithValue(ctx, "simpleTraceId", uuid.NewString())
      return handler(ctx, req)
   }
}

// NewHTTPServer new an HTTP server.
func NewHTTPServer(c *conf.Server, greeter *service.GreeterService, logger log.Logger) *http.Server {
   var opts = []http.ServerOption{
      http.Middleware(
         recovery.Recovery(),
         simpleTraceHandler,
      ),
   }
   if c.Http.Network != "" {
      opts = append(opts, http.Network(c.Http.Network))
   }
   if c.Http.Addr != "" {
      opts = append(opts, http.Address(c.Http.Addr))
   }
   if c.Http.Timeout != nil {
      opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration()))
   }
   srv := http.NewServer(opts...)
   v1.RegisterGreeterHTTPServer(srv, greeter)
   return srv
}

simpleTraceHandler方法使用uuid作为traceId。

接下来修改cmd/kratos-demo/main.go的代码,增加一个traceId函数用于获取前面中间件设置的traceId,另外简单应用暂时不需要输出spanId,将其去掉:

go 复制代码
func traceId() log.Valuer {
   return func(ctx context.Context) interface{} {
      traceId := ctx.Value("simpleTraceId")
      if traceId == nil {
         return ""
      } else {
         return traceId
      }
   }
}

func main() {
   flag.Parse()
   logger := log.With(log.NewStdLogger(os.Stdout),
      "ts", log.DefaultTimestamp,
      "caller", log.DefaultCaller,
      "service.id", id,
      "service.name", Name,
      "service.version", Version,
      "trace.id", traceId(),
   )
   c := config.New(
      config.WithSource(
         file.NewSource(flagconf),
      ),
   )
   defer c.Close()

   if err := c.Load(); err != nil {
      panic(err)
   }

   var bc conf.Bootstrap
   if err := c.Scan(&bc); err != nil {
      panic(err)
   }

   app, cleanup, err := wireApp(bc.Server, bc.Data, logger)
   if err != nil {
      panic(err)
   }
   defer cleanup()

   // start and wait for stop signal
   if err := app.Run(); err != nil {
      panic(err)
   }
}

为了验证,我们在internal/service/greeter.go中也增加一行日志输入,以确认同一请求的traceId是一致的:

go 复制代码
// GreeterService is a greeter service.
type GreeterService struct {
   v1.UnimplementedGreeterServer

   uc  *biz.GreeterUsecase
   log *log.Helper
}

// NewGreeterService new a greeter service.
func NewGreeterService(uc *biz.GreeterUsecase, logger log.Logger) *GreeterService {
   return &GreeterService{uc: uc, log: log.NewHelper(logger)}
}

// SayHello implements helloworld.GreeterServer.
func (s *GreeterService) SayHello(ctx context.Context, in *v1.HelloRequest) (*v1.HelloReply, error) {
   g, err := s.uc.CreateGreeter(ctx, &biz.Greeter{Hello: in.Name})
   if err != nil {
      return nil, err
   }
   s.log.WithContext(ctx).Info("Say Hello get Greeter: %v", g)
   return &v1.HelloReply{Message: "Hello " + g.Hello}, nil
}

改好上述代码之后,运行go generate ./...kratos run,访问http://localhost:8000/helloworld/kratos'两次,可看到如下日志输出:

log 复制代码
INFO ts=2024-03-03T18:24:01+08:00 caller=biz/greeter.go:43 service.id=xxxxxx service.name= service.version= trace.id=91ad483f-d724-4055-906d-34d255c93b01 msg=CreateGreeter: kratos
INFO ts=2024-03-03T18:24:01+08:00 caller=service/greeter.go:30 service.id=xxxxxx service.name= service.version= trace.id=91ad483f-d724-4055-906d-34d255c93b01 msg=Say Hello get Greeter: %v&{kratos}
INFO ts=2024-03-03T18:24:09+08:00 caller=biz/greeter.go:43 service.id=xxxxxx service.name= service.version= trace.id=c52f4d91-6a7d-4c6d-a69b-7c3f496bc8fe msg=CreateGreeter: kratos
INFO ts=2024-03-03T18:24:09+08:00 caller=service/greeter.go:30 service.id=xxxxxx service.name= service.version= trace.id=c52f4d91-6a7d-4c6d-a69b-7c3f496bc8fe msg=Say Hello get Greeter: %v&{kratos}

第一次请求的traceId为91ad483f-d724-4055-906d-34d255c93b01,而第二次为c52f4d91-6a7d-4c6d-a69b-7c3f496bc8fe

相关推荐
星就前端叭36 分钟前
【开源】一款基于Vue3 + WebRTC + Node + SRS + FFmpeg搭建的直播间项目
前端·后端·开源·webrtc
小林coding2 小时前
阿里云 Java 后端一面,什么难度?
java·后端·mysql·spring·阿里云
AI理性派思考者2 小时前
【保姆教程】手把手教你在Linux系统搭建早期alpha项目cysic的验证者&证明者
后端·github·gpu
从善若水2 小时前
【2024】Merry Christmas!一起用Rust绘制一颗圣诞树吧
开发语言·后端·rust
机器之心2 小时前
终于等来能塞进手机的文生图模型!十分之一体量,SnapGen实现百分百的效果
人工智能·后端
机器之心2 小时前
首次!大模型自动搜索人工生命,做出AI科学家的Sakana AI又放大招
人工智能·后端
运维&陈同学2 小时前
【模块一】kubernetes容器编排进阶实战之基于velero及minio实现etcd数据备份与恢复
数据库·后端·云原生·容器·kubernetes·etcd·minio·velero
waterme1onY3 小时前
Spring AOP 中记录日志
java·开发语言·笔记·后端
全栈开发帅帅4 小时前
基于springboot+vue实现的博物馆游客预约系统 (源码+L文+ppt)4-127
java·spring boot·后端
zyh_0305215 小时前
GIN中间件
后端·golang·gin