乐趣区

关于运维:使用-OpenTelemetry-构建可观测性-03-导出

上一个博文中,我提到如何应用 OpenTelemery 的特定语言 API 来收集遥测数据,蕴含手动和主动的埋点技术,这很重要!然而,收集遥测数据只是解决方案的第一步。

你须要把遥测数据路由转发到其余中央,同时增加额定的元数据信息。这时就轮到 SDK 发挥作用了。

链路追踪生产者(Tracer Provider)

链路追踪生产者是 SDK 中一个要害概念。用于将通过 API 收集的遥测数据与其余组件分割起来。在 Go 语言中,TracerProvider 对象只有一个 Tracer 办法的接口,办法签名如下:

Tracer(instrumentationName string, opts ...TracerOption) Tracer

Tracer 办法返回一个实现 Tracer 接口的对象,这个接口也只有一个办法 Start, 其办法签名如下:

Start(ctx context.Context, spanName string, opts ...spanStartOption) (context.Context, Span)

样例我的项目中通过链路追踪生产者创立了跨度 (span):

import "go.opentelemetry.io/otel"

// ...

ctx, span := otel.Tracer(telemetry.TelemetryLibrary).Start(ctx, "get_product_price")

能够发现通过 otel.Tracer 查找并创立全局的链路追踪生产者最终返回 Tracer 对象,须要留神要应用链路追踪生产者,其初始化设置是不可短少的。

Note: 在文中提及是获取‘全局’链路追踪生产者的办法。应用全局链路追踪最简略的一种形式就是调用 otel.Tracer 的 API。不过理论应用中如果下面计划不满足,还能够通过链路追踪生产者传递给消费者以代替全局查找的办法。

Note:trace 代表整个申请的门路信息、span 代表链路中的具体节点信息

资源(Resource)

链路追踪生产者还须要配置‘资源’对象,它是元数据信息的一部分。资源是遥测数据产生形容过程或者服务的信息,形容了服务自身的元数据,有助于解析遥测数据。

这是样例我的项目中购物车服务的‘资源’对象定义:

import (
    "go.opentelemetry.io/otel/sdk/resource"
    semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)

// ...

res, err := resource.New(
    ctx,
    resource.WithAttributes(semconv.ServiceNameKey.String("cart"),
        semconv.ServiceVersionKey.String("v1.0.0"),
    ),
)

资源对象定义的要害是设置属性参数,OpenTelemetry 曾经定义了一些资源属性的键值对,能够参考这篇文档 OTel’s 资源语义约定。例如,你能够通过下面例子看到,如何定义服务名称和版本号信息。然而可能还有更多信息你须要配置,比方服务本身依赖的资源有哪些;服务运行在云上吗?须要约定不同的属性给不同的云服务供应商;服务运行在 Kubernetes 吗?是的话,这里有份领导手册 Kubernetes 的资源语义约定。

最终样例我的项目中, 链路追踪数据中 span 都蕴含这样的‘资源’数据:

Resource labels:
     -> service.name: STRING(cart)
     -> service.version: STRING(v1.0.0)

导出器(Exporter)

既然咱们曾经创立了资源对象,咱们接下来定义一下遥测数据的目的地。

导出器的抉择范畴很广,能够依据本人的需要抉择不同的导出器,不过在以后我的项目例子中我应用 OpenTelemetry 控制器(会在下一篇细聊),它反对 HTTP 和 gRPC 协定。我抉择应用 gRPC 协定和 OTLP 导出器:

import (
    "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
    "google.golang.org/grpc"
)

// ...

hostIP := os.Getenv("HOST_IP")
if hostIP == "" {return nil, fmt.Errorf("unexpected no host IP address for receiver")
}
receiverAddress := fmt.Sprintf("%s:%d", hostIP, 4317)

conn, err := grpc.DialContext(
    ctx,
    receiverAddress,
    grpc.WithTransportCredentials(insecure.NewCredentials()),
    grpc.WithBlock(),)
if err != nil {return nil, fmt.Errorf("error creating client connection to collector: %w", err)
}

otlpTraceExporter, err := otlptracegrpc.New(
    ctx,
    otlptracegrpc.WithGRPCConn(conn),
)

Note: 文中例子是演示的程序,应用的非平安的连贯形式来获取数据, 不过生产环境中你最起码应该要应用带鉴权的连贯形式。

就导出器而言,有多种形式输入后果渠道供你抉择,例如:控制台输入(输入到 stdout), Jaeger (间接发送数据给它), Prometheus 等。应用 OTLP 导出器并将数据发送到 OTel Collector 的益处是,您能够创立数据正本、并行处理数据,并领有更多控制权(将在下一篇文章中介绍)。

因为应用 OTLP 导出器非常灵活,咱们能够依据须要在 Collector 中应用遥测数据(输入到 stdout、发送到 Jaeger 等)。下一篇文章将具体介绍这一点!

整合(Tying it all together)

当初咱们有了资源(生成遥测数据)和导出器(遥测数据的目的地),咱们将它们放在一起造成链路追踪生产者:

tp := trace.NewTracerProvider(trace.WithSampler(trace.AlwaysSample()),
    trace.WithResource(res),
    trace.WithSpanProcessor(trace.NewBatchSpanProcessor(otlpTraceExporter)),
)

当链路追踪生产者创立后,咱们须要将其设置为全局链路追踪生产者:

import ("go.opentelemetry.io/otel")

// ...

otel.SetTracerProvider(tp)

接下来咱们须要设置‘流传’。在后续博文中,将深刻探讨流传和附加数据(baggage,整个链路中传递业务自定义 KV 属性),但当初只须要晓得‘流传’能够将 OTel 链路追踪的上下文信息跨多个服务进行传递。让‘分布式’概念在‘分布式链路追踪’中实现。

import ("go.opentelemetry.io/otel/propagation")

// ...

otel.SetTextMapPropagator(
    propagation.NewCompositeTextMapPropagator(propagation.TraceContext{},
        propagation.Baggage{}),
)

最初,咱们须要调用 TracerProvider.Shutdown 来清理并敞开跨度处理器(在例子中,咱们应用批量 span 处理器,按批次将 span 数据进行聚合和批量解决,而后将残缺的批处理后果发送给导出器):

defer func() {if err := tp.Shutdown(context.Background()); err != nil {fmt.Printf("Error shutting down tracer provider: %v", err)
        os.Exit(1)
    }
}()

Note: 为了可靠性和可读性,仅通过调用 defer tp.Shutdown(context.Background()) 是不够的,须要处理函数返回的一些谬误。

链路追踪生产者 Python 版(Python tracer provider)

样例我的项目中大部分服务都用 Go 语言来编写,用 Python 写了一个服务(定价服务)。为了残缺起见,以下是如何在 Python 中创立和设置相似的链路追踪生产者的例子:

from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource, SERVICE_NAME, SERVICE_VERSION
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

resource = Resource(attributes={
    SERVICE_NAME: "price",
    SERVICE_VERSION: "v1.0.0"
})
tracer_provider = TracerProvider(resource=resource)

host_ip = os.environ.get("HOST_IP")
if host_ip is None:
    print("Must pass in environment var HOST_IP")
    sys.exit(1)

tracer_provider.add_span_processor(span_processor=BatchSpanProcessor(OTLPSpanExporter(endpoint=f"{host_ip}:4317", insecure=True)
))
trace.set_tracer_provider(tracer_provider)

其中资源、span 处理器和设置全局链路追踪生产者的实现与 Go 形容雷同。

总结

很棒后退了一步!依照下面步骤实现了,通过 API 获取了遥测数据,并将其从以后组件中被发送到一个导出器,并向其中增加了一些元数据(资源)!接下来咱们将理解如何应用 OpenTelemetry 收集器来解决这来数据。

本文翻译自:https://trstringer.com/otel-part3-export/

扩大浏览:

  • 方法论:面向故障解决的可观测性体系建设
  • 白皮书:事件 OnCall 核心建设办法
  • 好工具:FlashDuty – 一站式告警解决平台:告警降噪、排班 OnCall
退出移动版