在.NET中使用OpenTelemetry实现链路追踪(一)之详细教程与指南
概述
本篇文章介绍如何使在.Net中使用OpenTelemetry把链路数据包括:服务与服务之间,服务与数据库之间,服务与第三方中间件(Redis)之间的数据调用链路都链接起来,并且同时导出Jaeger和Zipkin这2个开源的链路追踪工具中。
创建项目以及插件
如果还没有配置OpenTelemetry Collector,按照之前的文章去配置OpenTelemetry Collector的配置
使用docker安装redis:
1
docker run --name redis -p 6379:6379 -d redis
创建2个Asp.Net Core Web Api:
ServiceA :在链路中主要是发送Http请求到ServiceB,扮演发生请求的服务角色。
安装如下几个包
- OpenTelemetry.Exporter.OpenTelemetryProtocol
- OpenTelemetry.Extensions.Hosting
- OpenTelemetry.Instrumentation.AspNetCore
- OpenTelemetry.Instrumentation.Http
在容器中注入如下几个服务:
1
2
3
4
5
6
7
8
9
10
11services.AddOpenTelemetry()
.ConfigureResource(resource => resource.AddService("ServiceA", serviceVersion: "1.0.0"))
.WithTracing(builder => builder
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddOtlpExporter());
services.AddHttpClient("ServiceB", client =>
{
client.BaseAddress = new Uri("http://localhost:5062");
});
ServiceB : 在链路中接收ServiceA发送过来的请求,并且在之后依次请求数据库和Redis
安装如下几个包:
- Microsoft.EntityFrameworkCore.SqlServer
- Microsoft.EntityFrameworkCore.Tools
- OpenTelemetry.Exporter.OpenTelemetryProtocol
- OpenTelemetry.Extensions.Hosting
- OpenTelemetry.Instrumentation.AspNetCore
- OpenTelemetry.Instrumentation.EntityFrameworkCore
- OpenTelemetry.Instrumentation.Http
- OpenTelemetry.Instrumentation.StackExchangeRedis
- StackExchange.Redis
在容器中注入如下几个服务:
1
2
3
4
5
6
7
8
9
10services.AddDbContext<ServiceADBContext>(options =>options.UseSqlServer(configuration.GetConnectionString("OpenTelemetryTestServiceBContext")));
services.AddSingleton<IConnectionMultiplexer>(sp => ConnectionMultiplexer.Connect("localhost:6379"));
services.AddOpenTelemetry()
.WithTracing(builder => builder
.ConfigureResource(resource => resource.AddService("ServiceB", serviceVersion: "1.0.0"))
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddEntityFrameworkCoreInstrumentation()
.AddRedisInstrumentation()
.AddOtlpExporter());
然后分别在两个服务中添加如下代码
ServiceA中在ValueController中添加如下代码
1
2
3
4
5
6[HttpGet]
public async Task<List<DBValueEntity>> Get([FromServices]IHttpClientFactory httpClientFactory)
{
var list = await httpClientFactory.CreateClient("ServiceB").GetFromJsonAsync<List<DBValueEntity>>("/api/dbvalues");
return list;
}ServiceB中DBValueController中添加如下代码:
1
2
3
4
5
6
7[HttpGet]
public IEnumerable<DBValueEntity> Get([FromServices]ServiceADBContext context, [FromServices] IConnectionMultiplexer connectionMultiplexer)
{
var list =context.DBValues.Take(10).ToList(); // Ensure the context is used to trigger DB access
connectionMultiplexer.GetDatabase(0).StringSet("testKey", "testValue"); // Example Redis operation
return list;
}
最后调用ServiceA中/api/value就会产生如下的链路调用
Timeline
Graph
添加自定义的Span
上面的例子演示了一些官方和社区开发和维护的一些采集器,能够大大提升我们的开发效率,但是有些时候,我们也需要在业务中增加一些我们自己的链路块,接下来我们就演示一下如何增加自己的链路块。我们主要是改动在ServiceA,
在构建Trace的代码中增加一个.AddSource("ServiceA")
,不然无法把产生的数据导出。
1 |
|
另外修改一下ServiceA中ValueController
1 |
|
最终产生的链路如下:
好了基本上掌握以上几点,就可以完成我们应用程序中的链路追踪了,记得在采集某一个中间件或者服务的数据时,可以先去社区寻找是否有现成的采集器帮助我们,加快我们的开发效率。下一节我们会进一步讲解其中的原理,以及如何优雅的实现数据采集。