使用 OpenTelemetry 构建可观测性 02 - 埋点

news2025/1/18 4:46:01

这是讲解 OpenTelemetry 系列博客的第二篇。在上一篇博客中,我们介绍了 OpenTelemetry 是什么以及由什么组成。现在我们将讨论如何使用 OTel 准确收集遥测数据和链路追踪数据。

手动埋点

我们这里谈论“埋点”(代码插桩),是指通过技术手段采集链路追踪数据的行为。通常有两种方式:手动和自动(下面讨论)。顾名思义,手动埋点需要在软件中显式的选择要暴露哪些数据。

手动埋点被认为是更高级和定制的遥测方法。手动和自动埋点分别有各自的使用场景,我们将在下文介绍。

一个请求进入系统并通过多个后端服务时,OpenTelemetry 能够记录该请求在系统中调用流程和经过的完整路径,这个路径被称为 链路追踪(trace) 。请求可能触发多个操作,每个操作都被记录在一个 跨度(span) 中,表示具体操作的实例。

每个跨度都有一个父跨度,除非它是链路追踪中的第一个跨度,在这种情况下,其父跨度 ID 为零(形成树状结构)。

注:示例应用程序主要是用 Go 和一些 Python 编写的。我将使用 Go 语言展示代码示例,但其中原理和概念同样适用于 OTel 支持的其他编程语言。

我们可以通过 API 将跨度添加到现有链路追踪中(或启动新链路追踪)。对于 Go 语言,这意味着我们将引用 go.opentelemetry.io/otel 库,它包含了手动埋点所需的所有函数方法。我们可以通过函数调用,使用全局链路追踪生产者来创建跨度:

import "go.opentelemetry.io/otel"

// ... other code ...

ctx, span := otel.Tracer("my-telemetry-library").Start(r.Context(), "get_user_cart")
defer span.End()

这里有几点需要注意。首先,我们先获取全局链路追踪的实例,使用这个实例创建一个新的跨度。

我们将在下一篇博客文章中更深入地讨论链路追踪生产者,它是 SDK 的一个组件,负责决定和管理这些遥测数据的流向和传输方式。

链路追踪生产者既可以通过调用 otel.Tracer 也可以显式地使用参数传递。此示例应用程序依赖于全局跟踪器提供程序。当我们调用 otel.Tracer 时,我们传入埋点对象名称,该名称通常是处理埋点库名。在示例应用中,它被设置为“ github.com/trstringer/otel-shopping-cart ”。

一旦我们得到了链路追踪生产者,就可以调用 Start 函数并向其传递两个参数:上下文对象( context ,允许我们在不同的执行环境中共享数据,并且可以跨多函数调用、请求处理或线程之间)和跨度的名称。上下文对象可以被新建(例如 context.Background() )或从它的父上下文传递(在本例中我使用的是 HTTP 请求上下文)。跨度名称可以是任何字符串,但在这个项目中,使用了一种标准化的命名方式,即选择描述标识符来命名并且使用下划线将不同标识符分隔。

Start 函数的返回值之一是上下文对象,我们可以把它传递给代码不同执行分支或路径(例如创建子跨度),以满足那些需要使用相同上下文的调用;而另一个返回值跨度对象,可以用来处理其他操作。

正如在此示例中所示,首先是通过 defer 关键字声明对函数 span.End 的调用,以便可以将此跨度标记为完成。我们还可以为 span 对象添加属性。

还需要注意的是,跨度是可以被嵌套使用的。通常一个新跨度是进入了一个代码执行分支或路径并且包含一个父跨度。这样就形成了跨度的嵌套关系,准确地反映了请求所经历的代码调用路径。

属性

在链路追踪系统中,我们采集各种与系统行为相关的数据,并将这些数据与特定的跨度进行关联,以便更好地理解系统行为。通过利用具有多样取值的高基数数据,我们能够获取更加详细和全面的上下文信息,从而更好地观测和分析系统的运行情况。

可以像下面给跨度设置属性:

span.SetAttributes(attribute.String("user.name", userName))

创建了一个名为 user.name 的字符串类型的属性并赋值。跨度的记录就会变成下面这样:

Span #4
    Trace ID       : d6b58718e2d607f2a881e55200b387d5
    Parent ID      : ef6c51753d66f227
    ID             : 95dcb2657f5bca91
    Name           : get_user_cart
    Kind           : SPAN_KIND_INTERNAL
    Start time     : 2022-08-07 16:37:51.184919236 +0000 UTC
    End time       : 2022-08-07 16:37:51.231164398 +0000 UTC
    Status code    : STATUS_CODE_UNSET
    Status message :
Attributes:
     -> user.name: STRING(tlasagna)

太棒了!现在名为 get_user_cart 的跨度就包含这个新属性 user.name 。还可以在 Jaeger 中同样看到这个属性:

20230727111919

事件

在许多情况下,当使用链路追踪时,您可能希望记录一些文本或发生在跨度期间的事件。通过调用 span.AddEvent,可以实现这一点:

span.AddEvent(
    "Successfully retrieved rows from database",
    trace.WithAttributes(attribute.Int("row.count", rowCount)),
)

记录的事件中还可以设置属性变量,如下例所示:

Span #1
    Trace ID       : 2d77674bf5bee80afcaf0df064f961ed
    Parent ID      : 5989852864910844
    ID             : f47e44dd5e23f016
    Name           : db_get_cart
    Kind           : SPAN_KIND_INTERNAL
    Start time     : 2022-08-07 18:37:39.167046809 +0000 UTC
    End time       : 2022-08-07 18:37:39.168098188 +0000 UTC
    Status code    : STATUS_CODE_UNSET
    Status message :
Events:
SpanEvent #0
     -> Name: Successfully retrieved rows from database
     -> Timestamp: 2022-08-07 18:37:39.16803511 +0000 UTC
     -> DroppedAttributesCount: 0
     -> Attributes:
         -> row.count: INT(2)

20230727112818

自动埋点

在前面的例子中,我们展示了如何手动在跨度中进行埋点操作。然而,OpenTelemetry 具有一个非常强大的特性,即支持广泛的自动埋点。

自动埋点适用于以下情况:

  • 对于 OpenTelemetry (OTel) 的新手,他们希望能够快速利用 OTel 收集与应用程序性能相关的指标和日志信息。
  • 在现有代码库的基础上尝试集成和使用 OTel 的功能。
  • 对于一些常用的组件或服务,在对遥测数据没有特殊要求的情况下,使用默认的自动埋点机制能够自动处理数据收集。

在购物应用的示例程序中,在 Python 服务(定价服务)中使用自动埋点来处理了两个事情:

  • Flask web 服务
  • MySQL 连接服务
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.instrumentation.mysql import MySQLInstrumentor

app = Flask(__name__)

FlaskInstrumentor().instrument_app(app)
MySQLInstrumentor().instrument()

自动埋点的神奇之处就在于,它所需要的仅仅是启用自动埋点功能!然后,不需要任何额外的工作或编写代码,就能够获得一些关于 Flask 路由和 MySQL 查询的非常有用的数据。这是 Flask 框架自动埋点的跨度:

20230727114336

记录中可以看到大量与请求相关的信息,例如 http.target 、 net.peer.ip 、 http.method 等等。

MySQL 自动埋点有很多有价值的信息:

20230727114419

这太棒了。通过零代码开发,仅自动获取跨度,它就已经告诉我一个关键的数据:查询的持续时间。此外,还可以看到运行中的查询以及运行该查询的用户。

这些数据提供了足够的信息,用于对慢查询进行故障排除,并帮助我们识别可能发生在数据库侧的意外情况。这一切都是因为一行代码启用了 MySQL 自动埋点!

总结

埋点是 OpenTelemetry 的核心。它定义了如何去收集哪些遥测数据,我们既可以选择手动埋点还可以利用现成的自动埋点代码库。在下一篇博文中,我们将了解 OTel SDK 是如何处理这些数据!

本文翻译自:Observability with OpenTelemetry Part 2 - Instrumentation | Thomas Stringer

扩展阅读:

  • 方法论:面向故障处理的可观测性体系建设
  • 白皮书:事件 OnCall 中心建设方法
  • 好工具:FlashDuty - 一站式告警处理平台:告警降噪、排班OnCall

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/896287.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络协议详解之BGP

目录 BGP(边界网关路由协议) 一、基础知识囊括: 1.1 IGP协议追求: 1.2 EGP协议的追求: 二、BGP特点: 2.1 BGP数据包 2.2 BGP的工作过程 2.3 结构突变** 2.4 名词解析 2.5 BGP的路由黑洞问题 2.6 …

Plecs电力电子仿真专业教程-第一季 第四节 C语言脚本模块介绍

Plecs电力电子仿真专业教程-第一季 目录 第一章 Plecs是什么 第二节 Plecs 的功能介绍 第三节 Plecs界面介绍 补充课程 Plecs的安装教程与软件下载 第四节 Plecs C语言脚本模块介绍 鉴于很多学习的小伙伴私信我要安装软件,特此添加如下链接: Plecs4.6…

我记不住的Linux那些时间及区别

背景:总是搞不明白Linux系统中这些相关的时间及区别,通过查看网上的资料发现很多都是人云亦云,没有任何新意,所以这里根据自己的试验及资料,再次总结一下,在这里记录一下。 一、介绍 标准的POSIX文件有三…

spring如何进行依赖注入,通过set方法把Dao注入到serves

1、选择Generate右键鼠标 你在service层后面方法的这些: 2、UserService配置文件的写法是怎样的: 3、我们在UserController中执行一下具体写法: 最后我们执行一下 : 4、这里可能出现空指针,因为你当前web层,因为你new这个对象根…

计算机竞赛 医学大数据分析 - 心血管疾病分析

文章目录 1 前言1 课题背景2 数据处理3 数据可视化4 最后 1 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 基于大数据的心血管疾病分析 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! &#x1f9…

神经网络为什么可以学习

本资料转载于B站up主:大模型成长之路,仅用于学习和讨论,如有侵权请联系 动画解析神经网络为什么可以学习_哔哩哔哩_bilibilis 1、一个神经网络是由很多神经元形成的 1.1 也可以是一层,也可以是多层 2 层和层之间的连接就跟一张网一样 2.1 每…

AutoCompany模型的概念设计,涵盖了AI智能公司的各个角色

AutoCompany模型的概念设计,涵盖了AI智能公司的各个角色 自动化企业概念设计与设想,文本将介绍AutoCompany模型的概念设计,涵盖了AI智能公司的各个角色,并结合了GPT-4接口来实现各个角色的功能,设置中央控制器&#xf…

【Redis】Redis哨兵模式

【Redis】Redis哨兵模式 Redis主从模式当主服务器宕机后,需要手动把一台从服务器切换为主服务器,需要人工干预费事费力,为了解决这个问题出现了哨兵模式。 哨兵模式是是一个管理多个 Redis 实例的工具,它可以实现对 Redis 的监控…

动力电池系统介绍(十三)——高压互锁(HVIL)

动力电池系统介绍(十三) 一、高压互锁梗概1.1 高压互锁原理1.1 高压互锁内部结构1.2 高压互锁分类1.3 高压互锁原则 二、高压互锁常见故障2.1 高压互锁开关失效2.2 端子退针导致开路2.3 互锁端子对地短路2.4 动力电池内部故障 三、高压互锁故障排查 一、…

孟德尔随机化:Steiger Test避免反向因果关系

Steiger Test避免反向因果关系 以下steiger test方法是一个新的方法学,增加后提升提取工具变量的稳健性,没有的话也不影响文章内容。 看自己的需要。跑分析过程中,如果是GWAS数据没有samplesize,自己又需要这个内容,…

musl libc ldso 动态加载研究笔记:01

前言 musl 是一个轻量级的标准C库,建立在系统调用之上,可以认为是【用户态】的C 库,与 glibc 或者 uClibc 属于同一类。 基于 musl 的 gcc 工具链包括交叉编译工具链,可以用于编译 Linux 或者其他的操作系统,如当前 L…

kubesphere 集成 sonar

文章目录 安装 helm通过 helm 安装 sonar配置 SonarQube 服务器创建 SonarQube 管理员令牌SonarQube 配置添加到 ks-installer创建 Webhook 服务器将 SonarQube 服务器添加至 Jenkins将 sonarqubeURL 添加到 KubeSphere 控制台重启服务 为新项目创建 SonarQube Token 官方文档&…

蓝蓝设计-ui设计公司-界面设计案例作品

泛亚高科-光伏电站控制系统界面设计 html前端 | 交互设计 | 视觉设计 | 图标设计 泛亚高科(北京)科技有限公司(以下简称“泛亚高科”),一个以实时监控、高精度数值计算为基础的科技公司, 自成立以来,组成了以博士、硕…

同样都是找工作,为什么你的简历没人看?

上次的文章分享了自己软件测试面试时的一些经历,今天我想分享一下自己当时写简历以及投简历方面的经历,本文内容纯粹是个人简单分享,如果有写得不好的地方还请读者包涵与指正。 我是去年的九月初开始投递简历的,貌似各行各业的人…

μCOS-Ⅲ_简介

μCOS-Ⅲ简介 文章目录 μCOS-Ⅲ简介前言一、什么是 C/OS-III?二、C/OS-III的特点三、C/OS-III的版本和参考资料1、C/OS-III版本2、C/OS-III源码获取3、C/OS-III参考资料 四、C/OS-III源码简介总结 前言 μcos-III是一个可以基于ROM运行的、可裁剪的、抢占式、实时…

第五章.编辑资料

5.1.添加编辑页面 <template><div class="users-show"><div class="col-md-3 main-col"><div class="box"><div class="padding-md"><div class="list-group text-center"><rou…

k8s v1.27.4 部署metrics-serverv:0.6.4,kube-prometheus

只有一个问题&#xff0c;原来的httpGet存活、就绪检测一直不通过&#xff0c;于是改为tcpSocket后pod正常。 wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml修改后的yaml文件&#xff0c;镜像修改为阿里云 apiVersion: …

9.处理this和防抖、节流

9.1 this指向-普通函数 普通函数的调用方式决定了this的值&#xff0c;即【谁调用this的值 指向谁】 普通函数没有明确调用者时this值为window&#xff0c;严格模式下没有调用者时this的值为undefined 9.2 this指向-箭头函数 箭头函数中的this与普通函数完全不同&#xff0…

uni——遍历循环替换值

案例展示 const fraction_json ref([]) //星级数组最终我们需要的格式是&#xff1a; [{“num”: “5”, “evaluate_id”: “2”}, {“num”: “5”, “evaluate_id”: “3”}] 参考的方法&#xff1a; 【 .map() 】方法 map() 方法返回一个新数组&#xff0c;数组中的元素…

究竟什么是位图

引言 为什么要写这篇博文呢&#xff0c;是因为之前面试的时候遇到这样一个问题&#xff1a; 有一款数十亿级别的用户产品&#xff0c;如何统计一周内连续活跃的用户数&#xff1f; 这个问题的特征其实很明显&#xff1a;数据量大&#xff0c;需要交并操作&#xff0c;而且还有…