一、概念介绍
1、什么是OpenTelemetry
OpenTelemetry 是一个可观测性框架和工具包,旨在创建和管理遥测数据,如链路、、指标和日志。OpenTelemetry 对供应商和工具是中立的,这意味着它可以与各种可观测性后端一起使用,包括 Jaeger 和 Prometheus 这类开源工具以及商业化产品。
OpenTelemetry 不是像 Jaeger、Prometheus 或其他商业供应商那样的可观测性后端。OpenTelemetry 专注于遥测数据的生成、采集、管理和导出。OpenTelemetry 的一个主要目标是,无论应用程序或系统采用何种编程语言、基础设施或运行时环境,你都可以轻松地将其仪表化。重要的是,遥测数据的存储和可视化是有意留给其他工具处理的。
2、什么是aspire-dashboard
Aspire-dashboard 是一个用于实时监控和调试应用程序的工具,特别适用于 ASP.NETCore 和其他支持 OpenTelemetry 的应用。它提供了一个用户界面来跟踪日志、指标数据,帮助开发者在本地环境中快速诊断问题。
二、安装OpenTelemetry环境
如下图所示安装所需的 nuget 包,如果想监测本项目的 MongoDB 性能,必须安装 MongoDB.Driver.Core.Extensions.DiagnosticSources 包。

三、开启监测项目本身Mongodb请求的性能
本项目使用 MongoDB 来存储数据,所以我们需要在 MongoClient 初始化之后再启用 OpenTelemetry。而且必须订阅 DiagnosticsActivityEventSubscriber 才能监测本项目的 MongoDB 性能。
cs
namespace TelemetryConsole
{
public static class StartupExtensions
{
public static void AddConfigurations(this IServiceCollection services, IConfiguration configuration)
{
}
public static void AddServices(this IServiceCollection services)
{
services.AddSingleton<IAnalyzerService, AnalyzerService>();
}
public static void AddMongoDbConnection(this IServiceCollection services, IConfiguration configuration)
{
services.Configure<DatabaseSettings>(configuration.GetSection(nameof(DatabaseSettings)));
services.AddSingleton<IDatabaseSettings>(sp => sp.GetRequiredService<IOptions<DatabaseSettings>>().Value);
//services.AddSingleton<IMongoClient, MongoClient>(x =>
// new MongoClient(((DatabaseSettings)x.GetService(typeof(DatabaseSettings)))
// .ConnectionString));
services.AddSingleton<IMongoClient, MongoClient>(x =>
{
/* If we have initialized a MongoClient, then its settings will be frozen.
* We cannot enable open telemetry at the moment.
* So we only enable open telemetry before initializing the MongoClient.
*/
var settings = MongoClientSettings
.FromConnectionString(((IDatabaseSettings)x.GetService(typeof(IDatabaseSettings)))?.ConnectionString)
.EnableOpenTelemetry();
return new MongoClient(settings);
});
services.AddSingleton<IDbConnectionPool, MongoDbConnectionPool>();
services.AddSingleton<IBaseDbService, BaseDbService>();
services.AddSingleton<IGuidWrapper, GuidWrapper>();
services.AddSingleton<IDateTimeWrapper, DateTimeWrapper>();
}
}
}
cs
namespace TelemetryConsole.Telemetry
{
public static class MongoClientExtensions
{
/// <summary>
/// 开启监测项目本身Mongodb请求的性能
/// </summary>
/// <param name="settings"></param>
/// <returns></returns>
public static MongoClientSettings EnableOpenTelemetry(this MongoClientSettings settings)
{
if (settings == null)
{
return settings;
}
var previous = settings.ClusterConfigurator;
settings.ClusterConfigurator = cb =>
{
previous?.Invoke(cb);
cb.Subscribe(new DiagnosticsActivityEventSubscriber(
new InstrumentationOptions
{
CaptureCommandText = true
}));
};
return settings;
}
}
}
四、配置启动项
使用OpenTelemetry 最重要的有两点:一是在 appsetting.json 中添加配置Otlp:Endpoint,二是 builder.Services.AddDefaultOpenTelemetry() 配置OpenTelemetry 组件。若跟下面的示例代码类似配置了 o.Tracing.Endpoint = "http://localhost:4317",那不在 appsetting.json 中添加配置也行,配置这个 URL 是为了把生成的遥测数据发过去,让其他组件为我们生成可观测的性能报告。
cs
namespace TelemetryConsole
{
[ExcludeFromCodeCoverage]
class Program
{
public static async Task<int> Main(string[] args)
{
try
{
var builder = Host.CreateApplicationBuilder();
var conventionPack = new ConventionPack { new CamelCaseElementNameConvention() };
ConventionRegistry.Register("camelCase", conventionPack, t => true);
builder.Services.AddHttpClient();
builder.Services.AddHostedService<Entry>();
builder.Services.AddConfigurations(builder.Configuration);
builder.Services.AddServices();
builder.Services.AddMongoDbConnection(builder.Configuration);
builder.Services.AddDefaultOpenTelemetry(
builder.Configuration,
o =>
{
o.Resource.Namespace = "MyNamespace"; // From configuration 'ServiceNamespace'
o.Resource.Version = "0.0.1"; // From configuration 'ServiceVersion'
o.Resource.InstanceId = "MyInstance"; // From configuration 'HOSTNAME'
o.Tracing.Endpoint = "http://localhost:4317";
});
var host = builder.Build();
await host.RunAsync();
return 0;
}
catch (Exception ex)
{
Console.WriteLine($"Error occured when running Maxwell Perf Analyzer : {ex}");
return 1;
}
}
}
}
五、改造待监测的类
AnalyzerService() 是我们要监测的主要类,构造函数中的 ITracerFactory 是改造时添加的,只要是已启动监测的类型(MongoDB、Redis、Http请求),都会生成一条同等级的记录。但我们的代码是嵌套结构,若我们想更清晰的了解某个方法及其内部子方法的性能情况,就要用到ITracerFactory。using var span = _traceFactory.CreateSpan("Main point") 会生成一条目录,using 范围内的监测类型都会在这个目录之下,若子方法内部还有 _traceFactory.CreateSpan("Sub point"),那本目录就会缩进变成子目录,这样有了层级结构报告会更清晰。
cs
namespace TelemetryConsole.Services.Impls
{
public class AnalyzerService : IAnalyzerService
{
private const string DefaultUser = "test@slb.com";
private readonly IBaseDbService _baseDbService;
private IHttpClientFactory _httpFactory;
private ITracerFactory _traceFactory;
public AnalyzerService(IBaseDbService baseDbService, IHttpClientFactory httpFactory, ITracerFactory traceFactory)
{
_baseDbService = baseDbService;
_httpFactory = httpFactory;
_traceFactory = traceFactory;
}
public async Task AnalyzeAsync()
{
try
{
using var span = _traceFactory.CreateSpan("Main point");
await QuerySomeData();
await InsertSomeData();
await ExecuteSomeHttpRequests();
}
catch (Exception EX)
{
throw;
}
}
async Task QuerySomeData()
{
using var span = _traceFactory.CreateSpan("Query some data");
var item01 = await _baseDbService.GetAsync<ModificationItem>("6a89034a-6e31-4aeb-a4f0-b36494fe7b18", "wireline-bgc-drillplan-bgc-bil", "modification");
var item02 = await _baseDbService.GetAsync<ModificationItem>("10208e50-e4aa-447f-893d-dd8a4b29c8e4", "wireline-bgc-drillplan-bgc-bil", "modification");
string str = "";
for (int i = 0; i < 10000; i++)
{
str += i;
}
}
async Task InsertSomeData()
{
using var activity = _traceFactory.CreateSpan("Insert Some Data");
for (var i = 0; i < 10; i++)
{
await _baseDbService.CreateAsync(new ModificationItem
{
Source = ParsingDataSource.Job,
ItemId = Guid.NewGuid().ToString()
}, DefaultUser, null, "modification_wireline-bgc-drillplan-bgc-bil");
}
string str = "";
for (int i = 0; i < 10000; i++)
{
str += i;
}
activity?.SetTag("RecordInserted", 10);
}
async Task ExecuteSomeHttpRequests()
{
using (var activity01 = _traceFactory.CreateSpan("Call HTTP API", ActivityKind.Client))
{
var client = _httpFactory.CreateClient();
var response = await client.GetAsync("https://httpbin.org/get");
var ret = await response.Content.ReadAsStringAsync();
}
using (var activity02 = _traceFactory.CreateSpan("Call TelemetryApi", ActivityKind.Client))
{
var client = _httpFactory.CreateClient();
var response01 = await client.GetAsync("https://localhost:7094/ParsingStep?id=d9fff557-1e08-4850-97d7-5cdb73e809e4");
var ret01 = await response01.Content.ReadAsStringAsync();
var response02 = await client.GetAsync("https://localhost:7094/ParsingStep?id=e18031b9-1ff4-4320-bfd2-e0f618356ae0");
var ret02 = await response01.Content.ReadAsStringAsync();
}
}
}
}
六、利用podman启动aspire-dashboard
我在 Windows 系统中安装了WSL2(Ubuntu22.04.5 LTS)、Podman,不熟悉可参考:安装WSL2。启动 aspire-dashboard 之前要先检查 podman 环境是否正常,然后再启动。
bash
--检查podman环境是否开启
wsl -l -v
--开启podman环境
podman machine start
--关闭podman环境
podman machine stop
--运行aspire-dashboard
podman run --rm -it -p 18888:18888 -p 4317:18889 -p 4318:18890 -d --name aspire-dashboard -e DOTNET_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS=true mcr.microsoft.com/dotnet/aspire-dashboard:9.0

七、启动aspire-dashboard
当我们启动配置了 OpenTelemetry 的项目之后,就会生成遥测数据,访问 http://localhost:18888/traces 即可浏览性能报告。
1、层级结构日志


2、数据库处理请求

3、Http请求

4、调用的API中又请求了数据库
若配置了 OpenTelemetry 的项目,调用的 API 所属的项目也配置了 OpenTelemetry,那性能监测可以穿透到 API 项目。如下图所示,api 内部调用了数据库请求,在这里也能显示出来。
