面向云技术架构 - 痴者工良

  • 首页
  • 工良写的电子书
    • kubernetes 教程
    • 从 C# 入门 Kafka
    • 多线程和异步
    • 动态编程-反射、特性、AOP
    • 表达式树
  • 本站文章导航
  • 隐私政策
愿有人陪你颠沛流离
遇到能让你付出的事物或者人,都是一种运气。
能遇到,就该珍惜。或许你们最终没能在一起,但你会切实地感受到力量。
正因为这样,那段相遇才变得有价值,才没有辜负这世间的每一段相遇。
  1. 首页
  2. 编程语言
  3. Golang
  4. 正文

opentelemetry-go 的简单使用

2022年11月20日 342点热度 0人点赞 0条评论
内容纲要

建立链路

SDK 官方仓库地址:

https://github.com/open-telemetry/opentelemetry-go

设计一个这样的执行流程:

file

Run 先后执行 Run1、Run2:

    a.Run1(newCtx)
    a.Run2(newCtx)

Run1 中,还执行了另一个函数 Run1-1。

使用 opentelemetry SDK 的代码示例如下:

package main

import (
    "context"
    "go.opentelemetry.io/otel"
    "io"
    "log"
)
// 当前 Trace 的名称。
const name = "App"

type App struct {
    r io.Reader
    l *log.Logger
}

func NewApp(r io.Reader, l *log.Logger) *App {
    return &App{r: r, l: l}
}

func (a *App) Run(ctx context.Context) {
    newCtx, span := otel.Tracer(name).Start(ctx, "Run")
    defer span.End()

    a.Run1(newCtx)
    a.Run2(newCtx)
}

func (a *App) Run1(ctx context.Context) {
    newCtx, span := otel.Tracer(name).Start(ctx, "Run1")
    defer span.End()

    a.Run1_1(newCtx)
}

func (a *App) Run1_1(ctx context.Context) {
    _, span := otel.Tracer(name).Start(ctx, "Run1_1")
    defer span.End()
}

func (a *App) Run2(ctx context.Context) {
    _, span := otel.Tracer(name).Start(ctx, "Run2")
    defer span.End()
}

进程中会有多个 Tracer,每个 Tracer 都需要设置一个名称,以便定位信息。

使用 otel.Tracer(name).Start(ctx, "Run") 创建新的 Context 的时候, Trace 信息会被附加到 Context 中。

    newCtx, span := otel.Tracer(name).Start(ctx, "Run")

file

如果一个函数需要调用其他函数,那么就应该传递链路:

    newCtx, span := otel.Tracer(name).Start(ctx, "Run")
    defer span.End()

    a.Run1(newCtx)
    a.Run2(newCtx)

即将 Context 传递给下一个函数。

如果要从当前 Context 获取 Span,可以这样:

span := trace.SpanFromContext(ctx)

导出链路

在上面的例子中,调用函数的过程中,生成了 Trace、Span 信息。

但是还需要导出这些信息才能显示出来。

官方 SDK 或者说中间件支持以下可观测性数据:

Exporter Metrics Traces
Jaeger ✓
OTLP ✓ ✓
Prometheus ✓
stdout ✓ ✓
Zipkin ✓

在下面的例子中,将使用 stdout 将链路信息导出到文件中。

package main

import (
    "context"
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/attribute"
    "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
    "go.opentelemetry.io/otel/sdk/resource"
    "go.opentelemetry.io/otel/sdk/trace"
    semconv "go.opentelemetry.io/otel/semconv/v1.10.0"
    "io"
    "log"
    "os"
)

// 创建 Exporter
func newExporter(w io.Writer) (trace.SpanExporter, error) {
    return stdouttrace.New(
        stdouttrace.WithWriter(w),
        // Use human readable output.
        stdouttrace.WithPrettyPrint(),
        // Do not print timestamps for the demo.
        stdouttrace.WithoutTimestamps(),
    )
}

// 创建表示当前进程的 Resource 对象
func newResource() *resource.Resource {
    r, _ := resource.Merge(
        resource.Default(),
        resource.NewWithAttributes(
            semconv.SchemaURL,
            semconv.ServiceNameKey.String("example1"),
            semconv.ServiceVersionKey.String("v0.1.0"),
            attribute.String("environment", "demo"), // 添加 attribute
        ),
    )
    return r
}

func main() {
    l := log.New(os.Stdout, "", 0)

    // trace 导出到文件
    f, err := os.Create("traces.txt")
    if err != nil {
        l.Fatal(err)
    }
    defer f.Close()

    // 创建一个 Exporter
    exp, err := newExporter(f)
    if err != nil {
        l.Fatal(err)
    }

    // 创建 TracerProvider
    tp := trace.NewTracerProvider(
        trace.WithBatcher(exp),
        trace.WithResource(newResource()),
    )
    defer func() {
        if err := tp.Shutdown(context.Background()); err != nil {
            l.Fatal(err)
        }
    }()
    otel.SetTracerProvider(tp)

    app := NewApp(os.Stdin, l)
    app.Run(context.Background())
}

首先是为了标识当前程序,需要创建一个 Resource。

// 创建表示当前进程的 Resource 对象
func newResource() *resource.Resource {
    r, _ := resource.Merge(
        resource.Default(),
        resource.NewWithAttributes(
            semconv.SchemaURL,
            semconv.ServiceNameKey.String("example1"),
            semconv.ServiceVersionKey.String("v0.1.0"),
            attribute.String("environment", "demo"), // 添加 attribute
        ),
    )
    return r
}

创建一个 Exporter,当前使用了文件 IO 。

// 创建 Exporter
func newExporter(w io.Writer) (trace.SpanExporter, error) {
    return stdouttrace.New(
        stdouttrace.WithWriter(w),
        // Use human readable output.
        stdouttrace.WithPrettyPrint(),
        // Do not print timestamps for the demo.
        stdouttrace.WithoutTimestamps(),
    )
}
func newExporter(ctx context.Context)  /* (someExporter.Exporter, error) */ {
  // Your preferred exporter: console, jaeger, zipkin, OTLP, etc.
}

创建 TracerProvider:

    // 创建 trace
    tp := trace.NewTracerProvider(
        trace.WithBatcher(exp), // exporter
        trace.WithResource(newResource()),
    )

设置全局 TracerProvider:

    otel.SetTracerProvider(tp)

启动后,生成的 Trace:

{
    "Name": "Run1_1",
    "SpanContext": {
        "TraceID": "50cf661b85718ec74a4d859f4c1aeef8",
        "SpanID": "7f51afb5a078006e",
        "TraceFlags": "01",
        "TraceState": "",
        "Remote": false
    },
    "Parent": {
        "TraceID": "50cf661b85718ec74a4d859f4c1aeef8",
        "SpanID": "11b82f4e7829ed50",
        "TraceFlags": "01",
        "TraceState": "",
        "Remote": false
    },
    "SpanKind": 1,
    "StartTime": "0001-01-01T00:00:00Z",
    "EndTime": "0001-01-01T00:00:00Z",
    "Attributes": null,
    "Events": null,
    "Links": null,
    "Status": {
        "Code": "Unset",
        "Description": ""
    },
    "DroppedAttributes": 0,
    "DroppedEvents": 0,
    "DroppedLinks": 0,
    "ChildSpanCount": 0,
    "Resource": null,
    "InstrumentationLibrary": {
        "Name": "App",
        "Version": "",
        "SchemaURL": ""
    }
}
{
    "Name": "Run1",
    "SpanContext": {
        "TraceID": "50cf661b85718ec74a4d859f4c1aeef8",
        "SpanID": "11b82f4e7829ed50",
        "TraceFlags": "01",
        "TraceState": "",
        "Remote": false
    },
    "Parent": {
        "TraceID": "50cf661b85718ec74a4d859f4c1aeef8",
        "SpanID": "bd024e7b63a2de62",
        "TraceFlags": "01",
        "TraceState": "",
        "Remote": false
    },
    "SpanKind": 1,
    "StartTime": "0001-01-01T00:00:00Z",
    "EndTime": "0001-01-01T00:00:00Z",
    "Attributes": null,
    "Events": null,
    "Links": null,
    "Status": {
        "Code": "Unset",
        "Description": ""
    },
    "DroppedAttributes": 0,
    "DroppedEvents": 0,
    "DroppedLinks": 0,
    "ChildSpanCount": 1,
    "Resource": null,
    "InstrumentationLibrary": {
        "Name": "App",
        "Version": "",
        "SchemaURL": ""
    }
}
{
    "Name": "Run2",
    "SpanContext": {
        "TraceID": "50cf661b85718ec74a4d859f4c1aeef8",
        "SpanID": "bc9c29add7a9b100",
        "TraceFlags": "01",
        "TraceState": "",
        "Remote": false
    },
    "Parent": {
        "TraceID": "50cf661b85718ec74a4d859f4c1aeef8",
        "SpanID": "bd024e7b63a2de62",
        "TraceFlags": "01",
        "TraceState": "",
        "Remote": false
    },
    "SpanKind": 1,
    "StartTime": "0001-01-01T00:00:00Z",
    "EndTime": "0001-01-01T00:00:00Z",
    "Attributes": null,
    "Events": null,
    "Links": null,
    "Status": {
        "Code": "Unset",
        "Description": ""
    },
    "DroppedAttributes": 0,
    "DroppedEvents": 0,
    "DroppedLinks": 0,
    "ChildSpanCount": 0,
    "Resource": null,
    "InstrumentationLibrary": {
        "Name": "App",
        "Version": "",
        "SchemaURL": ""
    }
}
{
    "Name": "Run",
    "SpanContext": {
        "TraceID": "50cf661b85718ec74a4d859f4c1aeef8",
        "SpanID": "bd024e7b63a2de62",
        "TraceFlags": "01",
        "TraceState": "",
        "Remote": false
    },
    "Parent": {
        "TraceID": "00000000000000000000000000000000",
        "SpanID": "0000000000000000",
        "TraceFlags": "00",
        "TraceState": "",
        "Remote": false
    },
    "SpanKind": 1,
    "StartTime": "0001-01-01T00:00:00Z",
    "EndTime": "0001-01-01T00:00:00Z",
    "Attributes": null,
    "Events": null,
    "Links": null,
    "Status": {
        "Code": "Unset",
        "Description": ""
    },
    "DroppedAttributes": 0,
    "DroppedEvents": 0,
    "DroppedLinks": 0,
    "ChildSpanCount": 2,
    "Resource": null,
    "InstrumentationLibrary": {
        "Name": "App",
        "Version": "",
        "SchemaURL": ""
    }
}

其他常用方法

Span 添加属性

可以向 Span 添加 k/v 信息:

    var myKey = attribute.Key("myCoolAttribute")
    span.SetAttributes(myKey.String("a value"))
func (a *App) Run(ctx context.Context) {
    newCtx, span := otel.Tracer(name).Start(ctx, "Run")
    defer span.End()
    var myKey = attribute.Key("myCoolAttribute")
    span.SetAttributes(myKey.String("a value"))
    a.Run1(newCtx)
    a.Run2(newCtx)
}

添加事件

添加简单的事件信息,表示在当前执行了何种操作。

span.AddEvent("Acquiring lock")
mutex.Lock()
span.AddEvent("Got lock, doing work...")
// do stuff
span.AddEvent("Unlocking")
mutex.Unlock()

Span 添加状态

如果当前函数执行有问题,可以向 Span 添加状态以及记录错误信息。

result, err := operationThatCouldFail()
if err != nil {
    span.SetStatus(codes.Error, "operationThatCouldFail failed")
    span.RecordError(err)
}
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: go opentelemetry 使用 简单
最后更新:2022年11月20日

痴者工良

高级程序员劝退师

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

文章目录
  • 建立链路
  • 导出链路
  • 其他常用方法

COPYRIGHT © 2022 whuanle.cn. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

粤ICP备18051778号

粤公网安备 44030902003257号