Golang 接入 OpenTelemetry 完整过程和思路(附源码)
建议点击 查看原文 查看最新内容。
原文链接: https://typonotes.com/posts/2023/08/14/golang-opentelemetry-notes/
为了更方便的查看代码, 建议直接跳转到 Github 仓库:https://github.com/tangx/opentelemetry-gin-demo
这里使用 app -> collector-contrib
进行转发, 应用不直接对后端的存储。适配性 更高。
collector-contrib
最常见的两种协议 grpc / http(s)
。传入 endpoint 地址进行初始化 Provider, 参考代码 grpcExporter 和 httpExporter
c.Set(k,v)
将 provider 放入了 gin 自己实现的 Context 中。tracer.Start
启动了第一个 Span, 并将生成的 ctx 放入 Request 中向下传递。之后我们将从 Request 中取 tracer provider。httpconv.XXXXX
方法进行 span 状态设置。httpconv
是一个 OpenTelemetry 实现的 标准/模版 方法, 用于处理 http 请求中的各种情况。可以多跟一下。在使用的时候, 需要使用 Context 在不同的 函数/方法 之间传递 Provider。每个 函数/方法 创建自己的 Span, 以此实现 调用的父子关系。
Span(xxxx)
提出 context 中的 provider 并启动 tracer.Start(xxx)
。在 #L21 中, 对 ctx
进行了判断, 如果 ctx 是 gin.Context
的话, 就需要从 Request 中携带的 context, 这一点在上诉的 2.4. 中已经说明原因。
额外的进行了一些 公共属性 的设置, 例如运行的主机名。
Span(xxx)
跟踪当前情况。当有需求的时候(例如出现访问错误), 需要把 TraceID 返回给用户。这样用户在报错的时候提供 TraceID 可以快速 debug。
在 otel/response_traceid.go 创建了一个 Gin Middleware, 将 TraceID 从 Context 中提取出来, 并放到 Response Header 中。
其中用到了 propagation
标准库, 简单快捷。
在上图 App2 中, 能够拿到 App 传递的 Traceparent header, 这样就保证了接收侧的 TraceID 连贯性。
otelgin
中, 提供了一个 Option 注入, otel/propagation, 使用 otelgin.WithPropagators(pptc)
为了保证 TraceID 的连贯性, 除了接收侧(App2)。在 发送侧 App1 也需要做对应的操作。
从 Context 中读取 TraceParent 并注入到 HTTP Request Header 中。
propagation
标准库将 Header 字段找出来。标准 API 用法。
span.RecordError
提交错误日志span.SetStatus
设置 trace span 状态。氛围 error 和 okspan.SetAttributes
设置属性,可以通过属性搜索。(所有属性被 索引)。在 Tracer 启动的时候传入。启动之后 Span 不能设置。可以通过 Kind 类型, 表明当前步骤类型, 以后在 检索/查询 的时候更直观。
internal, server, client, producer, consumer
可以在代码中看到。trace.WithSpanKind
, 在 trace.Start
时作为 opt 传入。之后不能通过 span 设置。nginx/web -> app1----> app2(get balance) -----> app3 (check db)
\
\-> app4(get cellphone) ----> app5 (check redis)
正常图示
有 Error 图示
[1]
gin-gonic/gin/otelgin: https://github.com/open-telemetry/opentelemetry-go-contrib/blob/849072ef827b4abab754253e1e63e7b410a31084/instrumentation/github.com/gin-gonic/gin/otelgin/gintrace.go#L42