OpenTelemetry链路追踪

1.概述

OpenTelemetry是一个开源项目,旨在为分布式系统提供一致的、标准化的方式来收集、传播和分析追踪数据。它的目标是提供一个通用的API和工具集,以支持各种编程语言和框架。

github原址;GitHub – open-telemetry/opentelemetry-go: OpenTelemetry Go API and SDK

官方地址:Getting Started | OpenTelemetry

使用jaeger,我们使用两个环境变量COLLECTOR_ZIPKIN_HTTP_PORT让它兼容zipkin,使用端口为9411,jaeger使用端口为16686,COLLECTOR_OTLP_ENABLED让它为true启用OpenTelemetry,

docker run -d --name jaeger -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 -e COLLECTOR_OTLP_ENABLED=true -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778 -p 16686:16686 -p 4317:4317 -p 4318:4318 -p 14250:14250 -p 14268:14268 -p 14269:14269 -p 9411:9411 jaegertracing/all-in-one:1.42

这样访问

localhost:16686

查看service

点击就可以看到详情

 

新建一个项目,删除原有的mod文件,新建目录jaeger,mod初始化

go mod init jaeger

导入

go get go.opentelemetry.io/otel

go get go.opentelemetry.io/otel/sdk

 

go get go.opentelemetry.io/otel/exporters/jaeger

 

 

2.代码演示

注意一下trace是go.opentelemetry.io/otel/sdk/trace包下的,不要导错包了

package main

import (
    "context"
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/attribute"
    "go.opentelemetry.io/otel/exporters/jaeger"
    "go.opentelemetry.io/otel/sdk/resource"
    "go.opentelemetry.io/otel/sdk/trace"
    semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
    "log"
)

func main() {
    //定义了一个名为jaeger的命令行参数,可以通过命令行参数-jaeger来指定Jaeger的地址。
    url := "http://localhost:14268/api/traces"

    provider, err := tracerProvider(url)

    if err != nil {
        log.Fatal(err)
    }
    ctx, cancelFunc := context.WithCancel(context.Background())
    defer cancelFunc()
    defer func(ctx context.Context) {
        err := provider.Shutdown(ctx)
        if err != nil {
            log.Fatal(err)
        }
    }(ctx)
    otel.SetTracerProvider(provider)

    tracer := provider.Tracer("dreams-main")
    ctx, span := tracer.Start(ctx, "foo")
    defer span.End()
    bar(ctx)

}

func bar(ctx context.Context) {
    tracer := otel.Tracer("dreams-bar")
    _, span := tracer.Start(ctx, "bar")
    defer span.End()

    //业务逻辑
    span.SetAttributes(attribute.Key("tanjy").String("value"))

}

func tracerProvider(url string) (*trace.TracerProvider, error) {
    exporter, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url)))

    if err != nil {
    log.Fatal(err)
        return nil, err
    }

    // 创建一个包含资源信息的 Resource 实例
    r := resource.NewWithAttributes(
        semconv.SchemaURL,
        semconv.ServiceName("trace-dreams"),
        semconv.ServiceVersionKey.String("1.0.0"),
        // 添加其他自定义属性
        attribute.String("environment", "production"),
    )

    // 创建一个TracerProvider实例
    provider := trace.NewTracerProvider(
        trace.WithBatcher(exporter),
        trace.WithResource(r),
    )
    return provider, nil

}

这段代码主要实现了使用 OpenTelemetry Go SDK 将数据发送到 Jaeger,并且在代码中添加了自定义属性和资源信息。

首先,在 main 函数中,代码创建了一个 TracerProvider 实例,并设置 Jaeger exporter 和资源信息。然后,它创建了一个根 Span 并将其作为父 Span 传递给 bar 函数。在 bar 函数中,代码创建了一个子 Span 并记录一些自定义属性。在这个例子中,bar 函数只是模拟了一些业务逻辑,但您可以将自己的逻辑放进去。

在 tracerProvider 函数中,代码创建了一个 Jaeger exporter 和一个包含资源信息的 resource.Resource 实例。在创建 TracerProvider 时,将这些信息传递给它。在这个例子中,resource.Resource 实例包含有关服务的名称、版本和环境等信息。

最后,代码启动了一个根 Span 并将其传递给 bar 函数。在 bar 函数中,代码创建了一个子 Span 并记录一些自定义属性。

代码解析

首先看tracerProvider 函数

将url传入tracerProvider 函数

exporter, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url)))

if err != nil {
    log.Fatal(err)
    return nil, err
}

 

这段代码使用了 OpenTelemetry Jaeger exporter,创建了一个 Jaeger exporter 的实例,并指定了收集器的端点。

在这段代码中,jaeger.New 函数用于创建一个 Jaeger exporter 的实例。jaeger.WithCollectorEndpoint 函数则用于设置 Jaeger 收集器的端点。

在 WithCollectorEndpoint 函数中,您可以通过传递 WithEndpoint 选项来指定收集器的端点。WithEndpoint 函数接受一个 URL 参数,用于指定 Jaeger 收集器的地址。

然后处理异常

// 创建一个包含资源信息的 Resource 实例
r := resource.NewWithAttributes(
    semconv.SchemaURL,
    semconv.ServiceName("trace-dreams"),
    semconv.ServiceVersionKey.String("1.0.0"),
    // 添加其他自定义属性
    attribute.String("environment", "production"),
)

// 创建一个TracerProvider实例
provider := trace.NewTracerProvider(
    trace.WithBatcher(exporter),
    trace.WithResource(r),
)

trace.NewTracerProvider: 用于创建一个新的跟踪提供者的实例。该方法接受一个或多个选项参数,用于配置提供者的行为。在这里,通过 trace.WithBatcher 和 trace.WithResource 选项来配置批处理器和资源属性。

trace.WithBatcher: 该方法用于设置批处理器,用于将跟踪数据批量发送给远程后端。在这里,传入了之前创建的 Jaeger exporter 作为批处理器。

trace.WithResource: 该方法用于设置资源属性,包括服务名称、版本以及其他自定义属性等。在这里,通过 resource.NewWithAttributes 方法设置了服务名称、版本以及一个自定义的环境属性。resource.NewWithAttributes: 用于创建一个新的资源对象,并设置属性。该方法接受一个或多个键值对作为参数,其中键表示属性名称,值表示属性值。在这里,通过 semconv.ServiceName 和 semconv.ServiceVersionKey.String 方法设置了服务名称和版本属性,并通过 attribute.String 方法添加了一个自定义的环境属性。

 

main函数

tracerProvider 函数返回一个TracerProvider实例到main函数

main函数如下

provider, err := tracerProvider(url)

if err != nil {
    log.Fatal(err)
}

接下来使用 OpenTelemetry 进行跟踪

ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
defer func(ctx context.Context) {
    err := provider.Shutdown(ctx)
    if err != nil {
        log.Fatal(err)
    }
}(ctx)
otel.SetTracerProvider(provider)

tracer := provider.Tracer("dreams-main")
ctx, span := tracer.Start(ctx, "foo")
defer span.End()
bar(ctx)
  • ctx, cancelFunc := context.WithCancel(context.Background()): 创建一个带有取消函数的上下文,以便在需要时取消操作。
  • defer cancelFunc(): 使用 defer 关键字延迟调用 cancelFunc,以确保在函数执行结束时取消上下文。
  • defer func(ctx context.Context) {…}(ctx): 延迟调用一个匿名函数,并在其中执行 provider 的 Shutdown 操作。这样可以确保在函数执行结束时执行 Shutdown 操作。
  • otel.SetTracerProvider(provider): 设置全局的跟踪提供者,以便在整个应用程序中都能使用该提供者进行跟踪操作。
  • tracer := provider.Tracer(“dreams-main”): 通过提供者创建一个具体的跟踪器实例,这里命名为 “dreams-main”。
  • ctx, span := tracer.Start(ctx, “foo”): 使用跟踪器开始一个名为 “foo” 的跟踪操作,并得到一个跟踪 span 对象,同时返回一个新的上下文。
  • defer span.End(): 延迟调用 span 的 End 方法,以确保在函数执行结束时结束当前的跟踪 span。
  • bar(ctx): 调用另一个函数 bar,并将上下文传递给它,以确保在该函数中也能继续进行跟踪操作。

 

func bar(ctx context.Context) {
    tracer := otel.Tracer("dreams-bar")
    _, span := tracer.Start(ctx, "bar")
    defer span.End()

    //业务逻辑
    span.SetAttributes(attribute.Key("tanjy").String("value"))

}

这段代码是一个名为 bar 的函数,它接受一个上下文对象作为参数,并使用 OpenTelemetry 进行跟踪操作。

  • tracer := otel.Tracer(“dreams-bar”): 创建了一个名为 “dreams-bar” 的跟踪器实例,用于在函数内部进行跟踪操作。
  • _, span := tracer.Start(ctx, “bar”): 使用创建的跟踪器开始一个名为 “bar” 的跟踪操作,并得到一个跟踪 span 对象。这将会创建一个新的子 span,该子 span 会成为当前跟踪的一部分,继承父 span 的上下文信息。
  • defer span.End(): 延迟调用 span 的 End 方法,以确保在函数执行结束时结束当前的跟踪 span。
  • span.SetAttributes(attribute.Key(“tanjy”).String(“value”)): 在当前的跟踪 span 上设置了一个自定义的属性,键为 “tanjy”,值为 “value”。

代码使用了 OpenTelemetry 创建了一个新的子 span,然后在子 span 中设置了一个自定义的属性。

 

运行,产生一个新的链路

点击Find Traces

果然出现了两个链路

点击查看,这是我们定义的名称

 

 

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇