Preface

OpenTelemetry 是一个可观测性工具,通过标准化的 API 和 SDK,提供了跨语言、跨平台的分布式追踪、日志和指标收集和分析能力。OpenTelemetry 的目标是让开发者更容易地维护和监测他们的应用程序。

本文将介绍 OpenTelemetry 的一些基本概念和用法,帮助读者快速入门。

1. 安装 OpenTelemetry

首先,需要安装 OpenTelemetry 的 SDK。这里以 Golang 为例,介绍如何安装 OpenTelemetry Go SDK。

1
go get go.opentelemetry.io/otel

通过运行上述命令,可以下载并安装 OpenTelemetry Go SDK。

2. 配置 OpenTelemetry Collector

OpenTelemetry Collector 是一个数据收集器,它可以收集不同类型的数据并发送到指定的目的地。在使用 OpenTelemetry 进行分布式追踪时,通常需要将追踪数据发送到 Zipkin 或 Jaeger 等追踪系统中。

安装并配置 OpenTelemetry Collector 的详细步骤可以参考官方文档 Installation

3. 创建 Span

在 Go 语言中,可以通过调用 OpenTelemetry SDK 的 TracerProvider 对象来创建 Span。Span 表示从应用程序中发出的命名工作单元,比如一个函数调用、一次网络请求等。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
    "context"

    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/trace"
)

func main() {
    // 初始化 TracerProvider
    provider := otel.GetTracerProvider()

    // 创建 Tracer 对象
    tracer := provider.Tracer("example-tracer")

    // 创建 Span
    ctx, span := tracer.Start(context.Background(), "example-span")
    defer span.End()

    // 执行业务逻辑
    // ...

    // 可以通过 Span 对象设置一些属性和事件
    span.SetAttribute("example-attribute", "hello world!")
    span.AddEvent("example-event")
}

通过调用 TracerProvider 对象的 Tracer 方法创建一个 Tracer 对象,然后使用 Tracer 对象的 Start 方法创建一个 Span 对象,并设置 Span 的名称。

最后,在使用完 Span 对象后需要通过 End 方法结束 Span 对象。

4. 追踪信息传递

OpenTelemetry 支持在分布式系统中传递追踪信息,以便完整地跟踪分布式系统中的请求。

在 Go 语言中,可以通过使用 OpenTelemetry 的 otelpropagation 包,将追踪信息添加到请求上下文中。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 在处理 HTTP 请求时传递追踪信息
package main

import (
    "net/http"

    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/propagation"
    "go.opentelemetry.io/otel/trace"
)

func main() {
    // 初始化 TracerProvider
    provider := otel.GetTracerProvider()

    // 创建 Tracer 对象
    tracer := provider.Tracer("example-tracer")

    // 处理 HTTP 请求
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        // 从请求中获取追踪信息
        ctx := propagation.ExtractHTTP(r.Context(), propagation.HeaderCarrier(r.Header))

        // 创建 Span
        _, span := tracer.Start(ctx, "example-span")
        defer span.End()

        // 执行业务逻辑
        // ...

        // 可以通过 Span 对象设置一些属性和事件
        span.SetAttribute("example-attribute", "hello world!")
        span.AddEvent("example-event")
    })

    // 启动 HTTP 服务
    http.ListenAndServe(":8080", nil)
}

在处理 HTTP 请求时,可以通过调用 propagation.ExtractHTTP 方法,从 HTTP 请求中获取

4.1 业务自定义 span

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import (
    "context"

    "go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/trace"
)

// WithSpan create span if sampled
func WithSpan(ctx context.Context, spanName string, key string, val interface{}) {
	if trace.SpanContextFromContext(ctx).IsSampled() {
		_, span := telemetry.Start(ctx, spanName)
		defer span.End()
		span.AddEvent("custom", trace.WithAttributes(
			attribute.Key(key).String(traces.DefaulMsgMarshaler(val)),
		))
        // 增加自定义 tags
        span.SetAttributes("自定义Key", "自定义Value")
        span.SetStatus(codes.Error, "timeout")
	}
}

4.2 在当前的 span 上追加 event

1
2
3
4
5
6
7
8
9
// AddEvent add event
func AddEvent(ctx context.Context, req interface{}, rsp interface{}) {
	if span := trace.SpanFromContext(ctx); span.SpanContext().IsSampled() {
		span.AddEvent("msg", trace.WithAttributes(
			attribute.Key("req").String(traces.DefaulMsgMarshaler(req)),
			attribute.Key("rsp").String(traces.DefaulMsgMarshaler(rsp)),
		))
	}
}