通过 Jaeger 为应用埋点并上报链路数据至 可观测链路 OpenTelemetry 版 后, 可观测链路 OpenTelemetry 版 即可开始监控应用,您可以查看应用拓扑、调用链路、异常事务、慢事务和 SQL 分析等一系列监控数据。本文介绍如何使用 OpenTracing/NetCore/gRPC 组件进行自动埋点或通过手动埋点并上报.NET 应用数据。
为获得更丰富的功能、更先进的链路追踪能力,以及最佳使用体验,建议您使用 OpenTelemetry 协议将应用接入 可观测链路 OpenTelemetry 版 。
我们为您提供了详细的 OpenTelemetry 接入指南和最佳实践,帮助您快速上手 可观测链路 OpenTelemetry 版 。更多信息,请参见 接入应用 。
目前 Jaeger Client C#已不再维护,建议您使用 OpenTelemetry .NET 上报数据。具体操作,请参见 通过 OpenTelemetry 上报.NET 应用数据 。
前提条件
背景信息
Jaeger 是 Uber 推出的一款开源分布式追踪系统,兼容 OpenTracing API,已在 Uber 大规模使用,且已加入 CNCF 开源组织 。其主要功能是聚合来自各个异构系统的实时监控数据。
目前 OpenTracing 社区已有许多组件可支持各种.NET 框架,例如:
示例 Demo
示例代码仓库: dotnet-demo
.NET 6.0 埋点
通过 OpenTracing 组件自动埋点
Demo 源码的运行版本要求:
-
Jaeger:1.0.2 版本
-
.NET:6.0 版本
-
在示例项目的 dotnet-demo/net6.0/Shared/JaegerServiceCollectionExtensions.cs 文件中填写上报数据端口并修改上报服务名,用于实现 ITracer 对象的初始化和注册逻辑。
public static class JaegerServiceCollectionExtensions // 参考前提条件获取Jaeger Endpoint并填入参数 private static readonly Uri _jaegerUri = new Uri("http://tracing-analysis-dc-sz.aliyuncs.com/adapt_your_token/api/traces"); public static IServiceCollection AddJaeger(this IServiceCollection services) if (services == null) throw new ArgumentNullException(nameof(services)); services.AddSingleton<ITracer>(serviceProvider => // 可以将其修改为自定义的服务名 string serviceName = Assembly.GetEntryAssembly().GetName().Name; ILoggerFactory loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>(); ISampler sampler = new ConstSampler(sample: true); IReporter reporter = new RemoteReporter.Builder() .WithSender(new HttpSender.Builder(_jaegerUri.ToString()).Build()) .Build(); ITracer tracer = new Tracer.Builder(serviceName) .WithLoggerFactory(loggerFactory) .WithSampler(sampler) .WithReporter(reporter) .Build(); GlobalTracer.Register(tracer); return tracer; // Prevent endless loops when OpenTracing is tracking HTTP requests to Jaeger. services.Configure<HttpHandlerDiagnosticOptions>(options => options.IgnorePatterns.Add(request => _jaegerUri.IsBaseOf(request.RequestUri)); return services; }
-
进入项目目录 dotnet-demo/net6.0/CustomersApi ,然后运行以下命令。
dotnet run --framework:net6.0
-
启动本地服务,并访问以下地址。
http://localhost:5001/health
-
登录 ARMS 控制台 后,在 页面通过自定义的 serviceName 搜索应用,查看上报的数据。
说明语言 列显示 图标的应用为接入应用监控的应用,显示 - 图标的应用为接入可观测链路 OpenTelemetry 版的应用。
NET Core 3.1 埋点
Demo 源码的运行版本要求:
-
Jaeger:1.0.2 版本
-
.NET:3.1 版本
通过 NetCore 组件自动埋点
-
在项目的 dotnet-demo/netcoreapp3.1/Shared/JaegerServiceCollectionExtensions.cs 中填写上报数据端口并修改上报服务名,用于实现 ITracer 对象的初始化和注册逻辑。
public static class JaegerServiceCollectionExtensions // 参考前提条件获取Jaeger Endpoint并填入参数 private static readonly Uri _jaegerUri = new Uri("http://tracing-analysis-dc-sz.aliyuncs.com/adapt_your_token/api/traces"); public static IServiceCollection AddJaeger(this IServiceCollection services) if (services == null) throw new ArgumentNullException(nameof(services)); services.AddSingleton<ITracer>(serviceProvider => // 可以将其修改为自定义的服务名 string serviceName = Assembly.GetEntryAssembly().GetName().Name; ILoggerFactory loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>(); ISampler sampler = new ConstSampler(sample: true); IReporter reporter = new RemoteReporter.Builder() .WithSender(new HttpSender.Builder(_jaegerUri.ToString()).Build()) .Build(); ITracer tracer = new Tracer.Builder(serviceName) .WithLoggerFactory(loggerFactory) .WithSampler(sampler) .WithReporter(reporter) .Build(); GlobalTracer.Register(tracer); return tracer; // Prevent endless loops when OpenTracing is tracking HTTP requests to Jaeger. services.Configure<HttpHandlerDiagnosticOptions>(options => options.IgnorePatterns.Add(request => _jaegerUri.IsBaseOf(request.RequestUri)); return services; }
-
进入项目目录 dotnet-demo/netcoreapp3.1/Shared ,然后运行以下命令。
// 添加aspnetcore中间件 dotnet add package OpenTracing.Contrib.NetCore
-
进入项目目录 dotnet-demo/netcoreapp3.1/CustomersApi ,然后运行以下命令。
// 添加aspnetcore中间件 dotnet add package OpenTracing.Contrib.NetCore // 运行示例程序 dotnet run --framework:netcoreapp3.1
-
启动本地服务,并访问以下地址。
http://localhost:5001/health
-
登录 ARMS 控制台 后,在 页面通过自定义的 serviceName 搜索应用,查看上报的数据。
说明语言 列显示 图标的应用为接入应用监控的应用,显示 - 图标的应用为接入可观测链路 OpenTelemetry 版的应用。
通过 gRPC 组件自动埋点
-
安装 NuGet 包。
// 添加以下组件。 // OpenTracing.Contrib.Grpc(gRPC中间件) // Jaeger(OpenTracing的实现组件) // Microsoft.Extensions.Logging.Console(日志组件) dotnet add package OpenTracing.Contrib.grpc dotnet add package Jaeger
-
初始化 ITracer 对象。
public static Tracer InitTracer(string serviceName, ILoggerFactory loggerFactory) Configuration.SamplerConfiguration samplerConfiguration = new Configuration.SamplerConfiguration(loggerFactory) .WithType(ConstSampler.Type) .WithParam(1); Configuration.SenderConfiguration senderConfiguration = new Configuration.SenderConfiguration(loggerFactory) // 参考前提条件获取Jaeger Endpoint并填入参数 .WithEndpoint("http://tracing-analysis-dc-sz.aliyuncs.com/adapt_your_token/api/traces"); Configuration.ReporterConfiguration reporterConfiguration = new Configuration.ReporterConfiguration(loggerFactory) .WithSender(senderConfiguration); return (Tracer)new Configuration(serviceName, loggerFactory) .WithSampler(samplerConfiguration) .WithReporter(reporterConfiguration) .GetTracer(); }
-
在服务端埋点。构建用于埋点的 ServerTracingInterceptor 对象,并将 ServerTracingInterceptor 绑定到服务上。
ILoggerFactory loggerFactory = new LoggerFactory().AddConsole(); ITracer tracer = TracingHelper.InitTracer("dotnetGrpcServer", loggerFactory); ServerTracingInterceptor tracingInterceptor = new ServerTracingInterceptor(tracer); Server server = new Server Services = { Greeter.BindService(new GreeterImpl()).Intercept(tracingInterceptor) }, Ports = { new ServerPort("localhost", Port, ServerCredentials.Insecure) } };
-
在客户端埋点。构建用于埋点的 ClientTracingInterceptor 对象,并将 ClientTracingInterceptor 绑定到 Channel 上。
ILoggerFactory loggerFactory = new LoggerFactory().AddConsole(); ITracer tracer = TracingHelper.InitTracer("dotnetGrpcClient", loggerFactory); ClientTracingInterceptor tracingInterceptor = new ClientTracingInterceptor(tracer); Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure); var client = new Greeter.GreeterClient(channel.Intercept(tracingInterceptor));
-
进入项目目录 dotnet-demo/netcoreapp3.1/GreeterServer ,然后在终端运行以下命令开启 gRPC 的服务端。
dotnet run --framework:netcoreapp3.1
-
进入项目目录 dotnet-demo/netcoreapp3.1/GreeterClient ,然后在另一个终端运行以下命令开启 gRPC 的客户端。
dotnet run --framework:netcoreapp3.1
如果终端输出
Greeting: Hello you
,说明服务端和客户端之间通信成功,在控制台可以看到示例应用 dotnetGrpcServer 和 dotnetGrpcClient 上报的数据。
手动埋点
除了利用各种现有插件实现埋点外,还可以使用手动埋点的方法通过 Jaeger 将.NET 应用数据上报至 可观测链路 OpenTelemetry 版 控制台。
-
安装 NuGet 包。
// Jaeger(OpenTracing的实现组件) // Microsoft.Extensions.Logging.Console(日志组件) dotnet add package Microsoft.Extensions.Logging.Console dotnet add package Jaeger
-
构建 ITracer 对象。ITracer 是 OpenTracing 定义的对象,我们用 Jaeger 来构建该对象(配置网关、采样率等)。
public static ITracer InitTracer(string serviceName, ILoggerFactory loggerFactory) Configuration.SamplerConfiguration samplerConfiguration = new Configuration.SamplerConfiguration(loggerFactory) .WithType(ConstSampler.Type) .WithParam(1); Configuration.SenderConfiguration senderConfiguration = new Configuration.SenderConfiguration(loggerFactory) // 在可观测链路 OpenTelemetry 版控制台获取Jaeger Endpoint。 .WithEndpoint("http://tracing-analysis-dc-sz.aliyuncs.com/adapt_your_token/api/traces"); Configuration.ReporterConfiguration reporterConfiguration = new Configuration.ReporterConfiguration(loggerFactory) .WithSender(senderConfiguration); return (Tracer)new Configuration(serviceName, loggerFactory) .WithSampler(samplerConfiguration) .WithReporter(reporterConfiguration) .GetTracer(); }
-
将 ITracer 注册到 GlobalTracer 中,方便调用代码。
GlobalTracer.Register(InitTracer("dotnetManualDemo", loggerFactory ));
-
记录请求数据。
ITracer tracer = GlobalTracer.Instance; ISpan span = tracer.BuildSpan("parentSpan").WithTag("mytag","parentSapn").Start(); tracer.ScopeManager.Activate(span, false); // ... do something span.Finish();
说明以上代码用于记录请求的根操作,如果需要记录请求的上一步和下一步操作,则需要调用 AsChildOf 方法。
示例:
ITracer tracer = GlobalTracer.Instance; ISpan parentSpan = tracer.ActiveSpan; ISpan childSpan =tracer.BuildSpan("childSpan").AsChildOf(parentSpan).WithTag("mytag", "spanSecond").Start(); tracer.ScopeManager.Activate(childSpan, false); // ... do something childSpan.Finish();
-
可选: 为了快速排查问题,您可以为某个记录添加一些自定义标签,例如记录是否发生错误、请求的返回值等。
tracer.activeSpan().setTag("http.status_code", "200");
-
在分布式系统中发送 RPC 请求时会带上 Tracing 数据,包括 TraceId、ParentSpanId、SpanId、Sampled 等。您可以在 HTTP 请求中使用 Extract/Inject 方法在 HTTP Request Headers 上透传数据。总体流程如下:
-
在客户端调用 Inject 方法传入 Context 信息。
Tracer.Inject(span.Context, BuiltinFormats.HttpHeaders, new HttpHeadersInjectAdapter(request.Headers));
-
在服务端调用 Extract 方法解析 Context 信息。
ISpanContext extractedSpanContext = _tracer.Extract(BuiltinFormats.HttpHeaders, new RequestHeadersExtractAdapter(request.Headers)); ISpan childSpan = _tracer.BuildSpan(operationName).AsChildOf(extractedSpanContext);
-
-
进入项目目录 dotnet-demo/netcoreapp3.1/ManualDemo ,然后运行以下命令,示例程序将会上报数据。
dotnet run --framework:netcoreapp3.1
在控制台可以查看手动埋点的示例应用 dotnetManualDemo 上报的数据。
常见问题
Q1:Demo 程序执行成功,为什么控制台上没有上报数据?
A1:请检查 senderConfiguration 配置中的 Endpoint 是否填写正确。
Configuration.SenderConfiguration senderConfiguration = new Configuration.SenderConfiguration(loggerFactory)
// 在可观测链路 OpenTelemetry 版控制台获取Jaeger Endpoint。
.WithEndpoint("http://tracing-analysis-dc-sz.aliyuncs.com/adapt_your_token/api/traces");
Q2:如何设置采样率?
A2:具体详情,请参见 Jaeger 采样率文档 。