OpenTelemetry Go Auto Instrumentation

414
下载
opentelemetry-go-auto-instrumentation 是阿里巴巴开源的基于OpenTelemetry规范的Golang应用无侵入编译时注入监控方案,可以在用户完全不修改业务代码的情况下对用户的Golang应用进行监控。

如何为插件编写测试代码


如何为插件编写测试代码

一旦你按照 how-to-add-a-new-rule.md 添加了新的插桩规则,你需要添加测试来验证你的规则。

添加插件测试用例

将目录更改为 /test,并为要测试的插件(例如redis)新建一个目录。在 redis 目录中,有一些子目录,每个子目录的名称代表该插件的最低支持版本。如果要为 redis 添加测试,应执行以下操作:

为你的插桩规则添加最低版本的依赖

例如,如果添加一条支持从 <font style="color:rgb(31, 35, 40);">v9.0.5</font> 到最新版本的 <font style="color:rgb(31, 35, 40);">redis</font> 的规则,则应首先验证最低的 <font style="color:rgb(31, 35, 40);">redis</font> 版本,即 <font style="color:rgb(31, 35, 40);">v9.0.5</font>。您可以创建一个名为 <font style="color:rgb(31, 35, 40);">v9.0.5</font> 的子目录,并添加以下 <font style="color:rgb(31, 35, 40);">go.mod</font>

Terminal window
module redis/v9.0.5
go 1.22
replace github.com/alibaba/opentelemetry-go-auto-instrumentation => ../../../../opentelemetry-go-auto-instrumentation
replace github.com/alibaba/opentelemetry-go-auto-instrumentation/test/verifier => ../../../../opentelemetry-go-auto-instrumentation/test/verifier
require (
// import this dependency to use verifier
github.com/alibaba/opentelemetry-go-auto-instrumentation/test/verifier v0.0.0-00010101000000-000000000000
github.com/redis/go-redis/v9 v9.0.5
go.opentelemetry.io/otel v1.30.0
go.opentelemetry.io/otel/sdk v1.30.0
)

编写该插件相关的业务逻辑

然后,你需要编写一些基于 redis 插件的业务逻辑,例如 test_executing_commands.goredis 中执行基本的 getset 操作。你的测试应尽可能涵盖该插件的所有使用场景。

编写验证代码

如果您编写的业务代码与规则相匹配,就会产生一些观测数据(如 span)。例如,test_executing_commands.go 会产生两个 span,一个代表 set redis 操作,另一个代表 get redis 操作。你应该使用校验器来验证其正确性:

Terminal window
import "github.com/alibaba/opentelemetry-go-auto-instrumentation/test/verifier"
verifier.WaitAndAssertTraces(func (stubs []tracetest.SpanStubs) {
verifier.VerifyDbAttributes(stubs[0][0], "set", "", "redis", "", "localhost", "set a b ex 5 ", "set")
verifier.VerifyDbAttributes(stubs[1][0], "get", "", "redis", "", "localhost", "get a ", "get")
})

验证器的 WaitAndAssertTraces 会接受一个回调函数,该函数会提供生成的所有跟踪信息。您应在所有跟踪中验证每个跨度的属性、父上下文和所有其他关键信息。

如果要验证观测数据,也可以像下面的代码一样使用验证器:

Terminal window
verifier.WaitAndAssertMetrics(map[string]func(metricdata.ResourceMetrics) {
"http.server.request.duration": func(mrs metricdata.ResourceMetrics) {
if len(mrs.ScopeMetrics) <= 0 {
panic("No http.server.request.duration metrics received!")
}
point := mrs.ScopeMetrics[0].Metrics[0].Data.(metricdata.Histogram[float64])
if point.DataPoints[0].Count != 1 {
panic("http.server.request.duration metrics count is not 1")
}
verifier.VerifyHttpServerMetricsAttributes(point.DataPoints[0].Attributes.ToSlice(), "GET", "/a", "", "http", "1.1", "http", 200)
},
"http.client.request.duration": func(mrs metricdata.ResourceMetrics) {
if len(mrs.ScopeMetrics) <= 0 {
panic("No http.client.request.duration metrics received!")
}
point := mrs.ScopeMetrics[0].Metrics[0].Data.(metricdata.Histogram[float64])
if point.DataPoints[0].Count != 1 {
panic("http.client.request.duration metrics count is not 1")
}
verifier.VerifyHttpClientMetricsAttributes(point.DataPoints[0].Attributes.ToSlice(), "GET", "127.0.0.1:"+strconv.Itoa(port), "", "http", "1.1", port, 200)
},
})

用户需要使用验证器中的 WaitAndAssertMetrics 方法来验证度量数据的正确性。WaitAndAssertMetrics 接收一个映射,映射的键是指标的名称,值是该指标数据的验证函数。用户可以在回调函数中编写自己的验证逻辑。

注册测试

最后,你应该注册测试。您应该在测试目录下编写一个_tests.go 文件来完成注册:

Terminal window
const redis_dependency_name = "github.com/redis/go-redis/v9"
const redis_module_name = "redis"
func init() {
TestCases = append(TestCases, NewGeneralTestCase("redis-9.0.5-executing-commands-test", redis_module_name, "v9.0.5", "v9.5.1", "1.18", "", TestExecutingCommands)
}
func TestExecutingCommands(t *testing.T, env ...string) {
redisC, redisPort := initRedisContainer()
defer clearRedisContainer(redisC)
UseApp("redis/v9.0.5")
RunGoBuild(t, "go", "build", "test_executing_commands.go")
env = append(env, "REDIS_PORT="+redisPort.Port())
RunApp(t, "test_executing_commands", env...)
}

在 init 函数中,您需要用 NewGeneralTestCase 封装您的测试用例,它将接收以下参数:

testName, moduleName, minVersion, maxVersion, minGoVersion, maxGoVersion string, testFunc func(t *testing.T, env …string)

  1. testName:测试用例名称。
  2. moduleName:测试目录中的子目录名。
  3. minVersion:插件的最低支持版本。
  4. maxVersion:插件支持的最高版本
  5. minGoVersion:插件支持的最低 Go 版本。
  6. maxGoVersion:插件支持的最高 Go 版本。
  7. testFunc:要执行的测试函数。

您应使用 opentelemetry-go-auto-instrumentation 构建测试用例,使您的测试用例能够生成观测数据。首先,应调用 UseApp 方法将目录更改为测试用例目录,然后调用 RunGoBuild 进行混合编译。最后,使用 RunApp 运行仪器化的测试用例二进制文件,以验证观测数据。

为插件添加muzzle测试用例

muzzle检查的灵感来自 safety-mechanisms.md。我们不可能对每个版本都进行通用插件测试,因为这会耗费大量时间。因此,opentelemetry-go-auto-instrumentation 会随机挑选一些版本进行混合编译,以验证不同版本之间的 API 兼容性。如果muzzle check发现某些 API 在某个版本中发生了变化,社区就会创建新的规则对其进行调整。

用户可以通过调用 NewMuzzleTestCase 来添加muzzle检查案例,NewMuzzleTestCase 使用的参数与 NewGeneralTestCase 几乎相同。此外,您还需要指定插件的依赖名称和需要进行muzzle检查的类列表。

添加插件最新测试用例

测试通常是针对我们支持的最低版本的库运行的,以确保针对使用旧版本依赖库的用户的基线,但是Agent可能会在新发布的库版本上失败。、我们会针对从远端获取的最新版本库额外运行仪器测试。如果新版本的库无法与Agent一起运行,我们会通过这次构建发现问题,并在下一次发布Agent时加以解决。

用户可以通过调用 NewLatestDepthTestCase 来添加最新测试案例,NewLatestDepthTestCase 使用的参数与 NewGeneralTestCase 几乎相同。您还需要指定插件的依赖名称和需要进行最新深度检查的类列表。


observability.cn Authors 2024 | Documentation Distributed under CC-BY-4.0
Copyright © 2017-2024, Alibaba. All rights reserved. Alibaba has registered trademarks and uses trademarks.
浙ICP备2021005855号-32