正如我们已经分享的那样,Elastic 致力于帮助 OpenTelemetry (OTel) 取得成功,这意味着在某些情况下,需要构建语言 SDK 的发行版。
Elastic 在战略上将 OTel 标准化用于可观测性和安全数据收集。此外,Elastic 致力于与 OTel 社区合作,成为可观测性生态系统的最佳数据收集基础设施。Elastic 正在深化与 OTel 的关系,这超越了最近对 Elastic Common Schema (ECS) 对 OpenTelemetry 的贡献、OTel Java 代理中的 invokedynamic,以及 即将进行的分析代理捐赠。
自 Elastic 7.14 版本起,Elastic 通过能够直接摄取基于 OpenTelemetry 协议 (OTLP) 的跟踪、指标和日志,从而原生支持 OTel。
Go SDK 与其他语言 SDK 有些不同,因为 Go 语言本身缺乏允许构建非 fork 发行版的动态性。
尽管如此,缺少发行版并不意味着您不应该使用 OTel 从具有 Elastic Stack 的 Go 应用程序收集数据。
Elastic 目前有一个 APM Go 代理,但我们建议切换到 OTel Go SDK。在这篇文章中,我们将介绍两种您可以进行迁移的方式
-
通过替换应用程序代码中的所有遥测(“大爆炸式迁移”)并发布更改
-
通过将迁移拆分为原子更改,以降低回归风险
大爆炸式迁移
从我们的 APM Go 代理迁移到 OTel SDK 的最简单方法可能是删除代理提供的所有遥测,并将其全部替换为新的遥测。
自动检测
您的大部分检测可能会自动提供,因为它属于您正在使用的框架或库的一部分。
例如,如果您使用 Elastic Go 代理,您可能正在使用我们的 net/http 自动检测模块,如下所示
import (
"net/http"
"go.elastic.co/apm/module/apmhttp/v2"
)
func handler(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "Hello World!")
}
func main() {
http.ListenAndServe(
":8080",
apmhttp.Wrap(http.HandlerFunc(handler)),
)
}
使用 OpenTelemetry,您将改为使用 otelhttp 模块
import (
"net/http"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)
func handler(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "Hello World!")
}
func main() {
http.ListenAndServe(
":8080",
otelhttp.NewHandler(http.HandlerFunc(handler), "http"),
)
}
您应该对您从我们的代理使用的每个其他模块执行相同的更改。
手动检测
您的应用程序也可能具有手动检测,这包括通过调用 Elastic APM 代理 API 直接在应用程序代码中创建跟踪和 span。
您可以使用 Elastic 的 APM SDK 创建事务和 span,如下所示
import (
"go.elastic.co/apm/v2"
)
func main() {
// Create a transaction, and assign it to the context.
tx := apm.DefaultTracer().StartTransaction("GET /", "request")
defer tx.End()
ctx = apm.ContextWithTransaction(ctx, tx)
// Create a span
span, ctx := apm.StartSpan(ctx, "span")
defer span.End()
}
OpenTelemetry 对事务和 span 使用相同的 API——Elastic 认为的“事务”在 OTel 中只是没有父级的 span(“根 span”)。
因此,您的检测变为以下内容
import (
"go.opentelemetry.io/otel/trace"
)
func main() {
tracer := otel.Tracer("my library")
// Create a root span.
// It is assigned to the returned context automatically.
ctx, span := tracer.Start(ctx, "GET /")
defer span.End()
// Create a child span (as the context has a parent).
ctx, span := tracer.Start(ctx, "span")
defer span.End()
}
通过大爆炸式迁移,您需要在发布到生产环境之前迁移所有内容。您无法将迁移拆分为更小的块。
对于小型应用程序或仅使用自动检测的应用程序,这种约束可能没问题。它可以让您快速验证迁移并继续前进。
但是,如果您正在处理复杂的服务集、大型应用程序或具有大量手动检测的应用程序,您可能希望能够在迁移期间多次发布代码,而不是一次全部发布。
原子迁移
原子迁移是指您可以逐步发布原子更改,并让您的应用程序正常运行。然后,您可以在最后,一旦您准备好这样做,才能够拔下最终的插头。
为了帮助进行原子迁移,我们提供了我们的 APM Go 代理和 OpenTelemetry 之间的桥梁。
此桥梁允许您同时运行我们的代理和 OTel,并在同一进程中使用两个库进行检测,数据以相同的格式传输到相同的位置。
您可以使用我们的代理配置 OTel 桥梁,如下所示
import (
"go.elastic.co/apm/v2"
"go.elastic.co/apm/module/apmotel/v2"
"go.opentelemetry.io/otel"
)
func main() {
provider, err := apmotel.NewTracerProvider()
if err != nil {
log.Fatal(err)
}
otel.SetTracerProvider(provider)
}
设置此配置后,OTel 创建的每个 span 都将传输到 Elastic APM 代理。
使用此桥梁,您可以通过以下过程使迁移更加安全
-
将桥梁添加到您的应用程序。
-
将一项检测(自动或手动)从代理切换到 OpenTelemetry,就像您在上面的大爆炸式迁移中一样,但一次只切换一项。
-
删除桥梁和我们的代理,并配置 OpenTelemetry 以通过其 SDK 传输数据。
这些步骤中的每一个都可以在您的应用程序中进行单次更改,并立即投入生产。
如果在迁移过程中出现任何问题,您应该能够立即看到并修复它,然后再继续。
使用 OTel 构建的可观测性优势
由于 OTel 正在快速成为行业标准,并且 Elastic 致力于使其变得更好,因此迁移到 OTel 对您的工程团队来说非常有益。
在 Go 中,无论您是通过大爆炸式迁移还是使用 Elastic 的 OTel 桥梁来完成此操作,这样做都将使您能够从全球社区维护的检测中受益,从而使您的可观测性更加有效,并更好地了解应用程序中正在发生的事情。
本帖子中描述的任何特性或功能的发布和时间安排均由 Elastic 自行决定。任何目前不可用的特性或功能可能不会按时或根本不交付。