在以前的文章中,我们创建了一个HTTP REST API server,一个CLI,一个Bot for Discord,甚至是game for Nintendo Game Boy Advance。
今天,我们将学习如何使用opentelemetry go库来创建仪器应用程序并将轨迹发送到jaeger实例。
opentelemetry
OpenTelemetry是工具,API和SDK的集合。对仪器,生成,收集和导出遥测数据(指标,日志和痕迹)有用,可帮助您分析软件的性能和行为。
opentelemetry与流行的库和框架(例如春季,express,quarkus和with a lot of languages)集成,包括: - )。
如果您曾经听说过OpenTracing或习惯了使用它,请知道现在已经弃用了opentracing,因此最好使用opentelemetryð。
如果您想migrate from OpenTracing to OpenTelemetry,则存在官方指南。
Jaeger
Jaeger是一个开源分布式跟踪平台。
它可用于监视基于微服务的分布式系统:
- 分布式上下文传播
- 分布式交易监控
- 根本原因分析
- 服务依赖分析
- 性能 /延迟优化< / li>
jaeger包含多个组件:
本地运行Jaeger
我们将使用Docker运行Jaeger UI,收集器,查询和代理,并具有内存存储组件:
$ docker run -d --name jaeger \
-e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
-p 5775:5775/udp \
-p 6831:6831/udp \
-p 6832:6832/udp \
-p 5778:5778 \
-p 16686:16686 \
-p 14268:14268 \
-p 9411:9411 \
jaegertracing/all-in-one:1.6
Jaeger UI将在16686
端口上可用,您将向14268
发送跟踪。
打开浏览器,输入url http://localhost:16686
以显示jaeger ui:
初始化
我们在上一篇文章中创建了GIT存储库,因此现在我们只需要在本地检索它:
$ git clone https://github.com/scraly/learning-go-by-examples.git
$ cd learning-go-by-examples
我们将为我们的CLI应用程序创建一个文件夹go-gopher-opentelemetry
,然后进入:
$ mkdir go-gopher-opentelemetry
$ cd go-gopher-opentelemetry
现在,我们必须初始化GO模块(依赖关系管理):
$ go mod init github.com/scraly/learning-go-by-examples/go-gopher-opentelemetry
go: creating new go.mod: module github.com/scraly/learning-go-by-examples/go-gopher-opentelemetry
这将创建一个这样的go.mod
文件:
module github.com/scraly/learning-go-by-examples/go-gopher-opentelemetry
go 1.19
在开始我们的超级仪器应用程序之前,我们将创建一个简单的代码组织。
创建以下文件夹组织:
.
├── README.md
├── bin
└── go.mod
就是这样吗?是的,我们的其余代码组织将很快创建; - )。
创建我们的应用程序
opentelemetry分为两个部分:与仪器代码的API,以及实现API的SDK。
让我们安装OpenTelemetry Trace API,以便在我们的代码中使用它:
$ go get go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp
$ go get go.opentelemetry.io/otel/exporters/jaeger
$ go get go.opentelemetry.io/otel/sdk/resource
$ go get go.opentelemetry.io/otel/sdk/trace
好,现在我们可以创建一个main.go
文件并将以下代码复制到其中。
GO代码被组织成软件包。因此,首先,我们初始化了称为main的软件包,以及我们需要在主文件中导入和使用的所有依赖关系/库:
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"time"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/jaeger"
"go.opentelemetry.io/otel/sdk/resource"
tracesdk "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
)
添加了进口,您可以启动仪器。
OpentElemetry Tracing API提供了创建痕迹的示踪剂。这些示踪剂的设计与一个仪表库相关联。要唯一地识别示踪剂的应用程序,我们将使用main.go
文件中的软件包名称创建常数。
所以,我们定义const:
const (
service = "go-gopher-opentelemetry"
environment = "development"
id = 1
)
然后,我们创建一个称为tracerProvider()
的函数,该函数启动了与示踪剂提供商的连接,例如Jaeger
实例。
func tracerProvider(url string) (*tracesdk.TracerProvider, error) {
// Create the Jaeger exporter
exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url)))
if err != nil {
return nil, err
}
tp := tracesdk.NewTracerProvider(
// Always be sure to batch in production.
tracesdk.WithBatcher(exp),
// Record information about this application in a Resource.
tracesdk.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String(service),
attribute.String("environment", environment),
attribute.Int64("ID", id),
)),
)
return tp, nil
}
和main()
函数:
- 连接到您先前部署的Jaeger Collector
- 创建在port
8080
上侦听的HTTP服务器 - 并每次调用 / http路由时都会创建并发送跨度:
func main() {
// Tracer
tp, err := tracerProvider("http://localhost:14268/api/traces")
if err != nil {
log.Fatal(err)
}
// Register our TracerProvider as the global so any imported
// instrumentation in the future will default to using it.
otel.SetTracerProvider(tp)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Cleanly shutdown and flush telemetry when the application exits.
defer func(ctx context.Context) {
// Do not make the application hang when it is shutdown.
ctx, cancel = context.WithTimeout(ctx, time.Second*5)
defer cancel()
if err := tp.Shutdown(ctx); err != nil {
log.Fatal(err)
}
}(ctx)
tr := tp.Tracer("component-main")
ctx, span := tr.Start(ctx, "hello")
defer span.End()
// HTTP Handlers
helloHandler := func(w http.ResponseWriter, r *http.Request) {
// Use the global TracerProvider
tr := otel.Tracer("hello-handler")
_, span := tr.Start(ctx, "hello")
span.SetAttributes(attribute.Key("mykey").String("value"))
defer span.End()
yourName := os.Getenv("MY_NAME")
fmt.Fprintf(w, "Hello %q!", yourName)
}
otelHandler := otelhttp.NewHandler(http.HandlerFunc(helloHandler), "Hello")
http.Handle("/", otelHandler)
log.Println("Listening on localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
当调用http路由时,我们在“ my_name”环境变量中打印一条消息,并用“ hello”和您的名字。
让我们在本地测试
首先,在本地,我们必须定义环境变量并运行您的应用程序:
$ export MY_NAME=scraly ; go run main.go
2022/11/08 19:07:54 Listening on localhost:8080
在我们的HTTP服务器中拨打电话:
$ curl localhost:8080
Hello "scraly"!
让我们再次观看Jaeger UI。很酷,出现了新的go-gopher-opentelemetry
服务。选择它,然后单击Find Traces
按钮:
您现在可以单击跟踪并可视化有用的信息。
在跟踪中,您可以在痕迹中看到我们定义的environement
和id
常数。
结论
正如您在本文和以前的文章中所看到的那样,可以在GO中创建应用程序:CLI,REST API ...以及有用的应用程序,可以使用分布式跟踪,您可以链接到其他工具。
我们的仪器应用程序的所有代码均提供:https://github.com/scraly/learning-go-by-examples/tree/main/go-gopher-opentelemetry
在以下文章中,我们将在GO中创建其他应用程序/类型的应用程序。
希望您会喜欢的。