通过Jaeger上报.NET应用数据

通过Jaeger上报.NET应用数据

更新时间:

通过 Jaeger 为应用埋点并上报链路数据至 可观测链路 OpenTelemetry 版 后, 可观测链路 OpenTelemetry 版 即可开始监控应用,您可以查看应用拓扑、调用链路、异常事务、慢事务和 SQL 分析等一系列监控数据。本文介绍如何使用 OpenTracing/NetCore/gRPC 组件进行自动埋点或通过手动埋点并上报.NET 应用数据。

重要

为获得更丰富的功能、更先进的链路追踪能力,以及最佳使用体验,建议您使用 OpenTelemetry 协议将应用接入 可观测链路 OpenTelemetry 版

我们为您提供了详细的 OpenTelemetry 接入指南和最佳实践,帮助您快速上手 可观测链路 OpenTelemetry 版 。更多信息,请参见 接入应用

重要

目前 Jaeger Client C#已不再维护,建议您使用 OpenTelemetry .NET 上报数据。具体操作,请参见 通过 OpenTelemetry 上报.NET 应用数据

前提条件

获取接入点信息

  1. 登录 ARMS 控制台 ,在左侧导航栏单击 接入中心

  2. 服务端应用 区域单击 Jaeger 卡片。

  3. 在弹出的 Jaeger 面板中选择数据需要上报的地域。

    说明

    初次接入的地域将会自动进行资源初始化。

  4. 选择 连接方式 上报方式 ,然后复制接入点信息。

    • 连接方式:若您的服务部署在阿里云上,且所属地域与选择的接入地域一致,推荐使用阿里云内网方式,否则选择公网方式。

    • 上报方式:根据客户端支持的协议类型选择 HTTP gRPC 协议上报数据。

    image.png

背景信息

Jaeger Uber 推出的一款开源分布式追踪系统,兼容 OpenTracing API,已在 Uber 大规模使用,且已加入 CNCF 开源组织 。其主要功能是聚合来自各个异构系统的实时监控数据。

目前 OpenTracing 社区已有许多组件可支持各种.NET 框架,例如:

数据是如何上报的?

  • 不通过 Jaeger Agent 而直接上报数据的原理如下图所示。

    image
  • 通过 Jaeger Agent 上报数据的原理如下图所示。

    image

示例 Demo

示例代码仓库: dotnet-demo

.NET 6.0 埋点

通过 OpenTracing 组件自动埋点

Demo 源码的运行版本要求:

  • Jaeger:1.0.2 版本

  • .NET:6.0 版本

  1. 在示例项目的 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;
    }
  2. 进入项目目录 dotnet-demo/net6.0/CustomersApi ,然后运行以下命令。

    dotnet run --framework:net6.0
  3. 启动本地服务,并访问以下地址。

    http://localhost:5001/health
  4. 登录 ARMS 控制台 后,在 应用监控 > 应用列表 页面通过自定义的 serviceName 搜索应用,查看上报的数据。

    说明

    语言 列显示 image 图标的应用为接入应用监控的应用,显示 - 图标的应用为接入可观测链路 OpenTelemetry 版的应用。

NET Core 3.1 埋点

Demo 源码的运行版本要求:

  • Jaeger:1.0.2 版本

  • .NET:3.1 版本

通过 NetCore 组件自动埋点

  1. 在项目的 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;
    }
  2. 进入项目目录 dotnet-demo/netcoreapp3.1/Shared ,然后运行以下命令。

    // 添加aspnetcore中间件
    dotnet add  package OpenTracing.Contrib.NetCore
  3. 进入项目目录 dotnet-demo/netcoreapp3.1/CustomersApi ,然后运行以下命令。

    // 添加aspnetcore中间件
    dotnet add  package OpenTracing.Contrib.NetCore
    // 运行示例程序
    dotnet run --framework:netcoreapp3.1
  4. 启动本地服务,并访问以下地址。

    http://localhost:5001/health
  5. 登录 ARMS 控制台 后,在 应用监控 > 应用列表 页面通过自定义的 serviceName 搜索应用,查看上报的数据。

    说明

    语言 列显示 image 图标的应用为接入应用监控的应用,显示 - 图标的应用为接入可观测链路 OpenTelemetry 版的应用。

通过 gRPC 组件自动埋点

  1. 安装 NuGet 包。

    // 添加以下组件。
    // OpenTracing.Contrib.Grpc(gRPC中间件)
    // Jaeger(OpenTracing的实现组件)
    // Microsoft.Extensions.Logging.Console(日志组件)
    dotnet add  package OpenTracing.Contrib.grpc
    dotnet add  package Jaeger
  2. 初始化 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();
            }
  3. 在服务端埋点。构建用于埋点的 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) }
     };
  4. 在客户端埋点。构建用于埋点的 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));
  5. 进入项目目录 dotnet-demo/netcoreapp3.1/GreeterServer ,然后在终端运行以下命令开启 gRPC 的服务端。

    dotnet run --framework:netcoreapp3.1
  6. 进入项目目录 dotnet-demo/netcoreapp3.1/GreeterClient ,然后在另一个终端运行以下命令开启 gRPC 的客户端。

    dotnet run --framework:netcoreapp3.1

    如果终端输出 Greeting: Hello you ,说明服务端和客户端之间通信成功,在控制台可以看到示例应用 dotnetGrpcServer dotnetGrpcClient 上报的数据。

手动埋点

除了利用各种现有插件实现埋点外,还可以使用手动埋点的方法通过 Jaeger 将.NET 应用数据上报至 可观测链路 OpenTelemetry 版 控制台。

  1. 安装 NuGet 包。

    // Jaeger(OpenTracing的实现组件)
    // Microsoft.Extensions.Logging.Console(日志组件)
    dotnet add  package Microsoft.Extensions.Logging.Console
    dotnet add  package Jaeger
  2. 构建 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();
    }
  3. ITracer 注册到 GlobalTracer 中,方便调用代码。

    GlobalTracer.Register(InitTracer("dotnetManualDemo", loggerFactory ));
  4. 记录请求数据。

    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();
  5. 可选: 为了快速排查问题,您可以为某个记录添加一些自定义标签,例如记录是否发生错误、请求的返回值等。

    tracer.activeSpan().setTag("http.status_code", "200");
  6. 在分布式系统中发送 RPC 请求时会带上 Tracing 数据,包括 TraceId、ParentSpanId、SpanId、Sampled 等。您可以在 HTTP 请求中使用 Extract/Inject 方法在 HTTP Request Headers 上透传数据。总体流程如下:

    流程图

    1. 在客户端调用 Inject 方法传入 Context 信息。

      Tracer.Inject(span.Context, BuiltinFormats.HttpHeaders, new HttpHeadersInjectAdapter(request.Headers));
    2. 在服务端调用 Extract 方法解析 Context 信息。

      ISpanContext extractedSpanContext = _tracer.Extract(BuiltinFormats.HttpHeaders, new RequestHeadersExtractAdapter(request.Headers));
      ISpan childSpan = _tracer.BuildSpan(operationName).AsChildOf(extractedSpanContext);
  7. 进入项目目录 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 采样率文档