.NET 上 gRPC 中的日志记录和诊断Logging and diagnostics in gRPC on .NET

本文内容

作者:James Newton-King

本文提供从 gRPC 应用收集诊断以帮助解决问题的指南。涵盖的主题包括:

  • 日志记录 - 写入 .NET Core 日志记录的结​​构化日志。应用框架使用 ILogger 来编写日志,用户使用它在应用中进行用户自己的日志记录。
  • 跟踪 - 与使用 DiaganosticSourceActivity 进行编写的操作相关的事件。来自诊断源的跟踪通常用于通过库(如 Application InsightsOpenTelemetry)收集应用遥测数据。
  • 指标 - 一段时间间隔内数据度量值的表示形式,例如每秒请求数。指标是使用 EventCounter 发出的,可以使用 dotnet-counters 命令行工具或 Application Insights 进行观察。

LoggingLogging

gRPC 服务和 gRPC 客户端使用 .NET Core 日志记录编写日志。当你需要调试应用中的意外行为时,日志是一个不错的起点。

gRPC 服务日志记录gRPC services logging

警告

服务器端日志可能包含来自应用的敏感信息。切勿将来自生产应用的原始日志发布到 GitHub 等公共论坛 。

由于 gRPC 服务托管在 ASP.NET Core 上,因此它使用 ASP.NET Core 日志记录系统。在默认配置中,gRPC 只记录很少的信息,但这可以进行配置。有关配置 ASP.NET Core 日志记录的详细信息,请参阅 ASP.NET Core 日志记录上的文档。

gRPC 在 Grpc 类别下添加日志。若要启用来自 gRPC 的详细日志,请通过在 Logging 中的 LogLevel 子节中添加以下项目,将 Grpc 前缀配置为 appsettings.json 文件中的 Debug 级别 :

  1. {
  2. "Logging": {
  3. "LogLevel": {
  4. "Default": "Debug",
  5. "System": "Information",
  6. "Microsoft": "Information",
  7. "Grpc": "Debug"
  8. }
  9. }
  10. }

你也可以在具有 ConfigureLogging 的 Startup.cs 中配置此项 :

  1. public static IHostBuilder CreateHostBuilder(string[] args) =>
  2. Host.CreateDefaultBuilder(args)
  3. .ConfigureLogging(logging =>
  4. {
  5. logging.AddFilter("Grpc", LogLevel.Debug);
  6. })
  7. .ConfigureWebHostDefaults(webBuilder =>
  8. {
  9. webBuilder.UseStartup<Startup>();
  10. });

如果不使用基于 JSON 的配置,请在配置系统中设置以下配置值:

  • Logging:LogLevel:Grpc = Debug

查看配置系统的文档以确定如何指定嵌套的配置值。例如,使用环境变量时,使用两个 _ 而不是 : 字符(例如 LoggingLogLevelGrpc)。

建议在为应用收集更详细的诊断时使用 Debug 级别。Trace 级别产生的诊断级别很低,且很少需要它来诊断应用中的问题。

日志记录输出示例Sample logging output

下面是 Debug 级别的 gRPC 服务控制台输出示例:

  1. info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
  2. Request starting HTTP/2 POST https://localhost:5001/Greet.Greeter/SayHello application/grpc
  3. info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
  4. Executing endpoint 'gRPC - /Greet.Greeter/SayHello'
  5. dbug: Grpc.AspNetCore.Server.ServerCallHandler[1]
  6. Reading message.
  7. info: GrpcService.GreeterService[0]
  8. Hello World
  9. dbug: Grpc.AspNetCore.Server.ServerCallHandler[6]
  10. Sending message.
  11. info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
  12. Executed endpoint 'gRPC - /Greet.Greeter/SayHello'
  13. info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
  14. Request finished in 1.4113ms 200 application/grpc

访问服务器端日志Access server-side logs

访问服务器端日志的方式取决于在其中运行的环境。

作为控制台应用As a console app

如果在控制台应用中运行,则默认情况下应启用控制台记录器gRPC 日志将在控制台中显示。

其他环境Other environments

如果将应用部署到另一个环境(例如 Docker、Kubernetes 或 Windows 服务),请参阅 .NET Core 和 ASP.NET Core 中的日志记录,了解有关如何配置适用于环境的日志记录提供程序的详细信息。

gRPC 客户端日志记录gRPC client logging

警告

客户端日志可能包含来自应用的敏感信息。切勿将来自生产应用的原始日志发布到 GitHub 等公共论坛 。

若要从 .NET 客户端获取日志,可以在创建客户端通道时设置 GrpcChannelOptions.LoggerFactory 属性。如果要从 ASP.NET Core 的应用调用 gRPC 服务,则可以通过依赖关系注入 (DI) 来解析记录器工厂:

  1. [ApiController]
  2. [Route("[controller]")]
  3. public class GreetingController : ControllerBase
  4. {
  5. private ILoggerFactory _loggerFactory;
  6. public GreetingController(ILoggerFactory loggerFactory)
  7. {
  8. _loggerFactory = loggerFactory;
  9. }
  10. [HttpGet]
  11. public async Task<ActionResult<string>> Get(string name)
  12. {
  13. var channel = GrpcChannel.ForAddress("https://localhost:5001",
  14. new GrpcChannelOptions { LoggerFactory = _loggerFactory });
  15. var client = new Greeter.GreeterClient(channel);
  16. var reply = await client.SayHelloAsync(new HelloRequest { Name = name });
  17. return Ok(reply.Message);
  18. }
  19. }

启用客户端日志记录的另一种方法是使用 gRPC 客户端工厂创建客户端。已向客户端工厂注册且解析自 DI 的 gRPC 客户端将自动使用应用的已配置日志记录。

如果应用未使用 DI,则可以使用 LoggerFactory.Create 创建新的 ILoggerFactory 实例。若要访问此方法,请将 Microsoft.Extensions.Logging 包添加到应用。

  1. var loggerFactory = LoggerFactory.Create(logging =>
  2. {
  3. logging.AddConsole();
  4. logging.SetMinimumLevel(LogLevel.Debug);
  5. });
  6. var channel = GrpcChannel.ForAddress("https://localhost:5001",
  7. new GrpcChannelOptions { LoggerFactory = loggerFactory });
  8. var client = Greeter.GreeterClient(channel);

gRPC 客户端日志作用域gRPC client log scopes

gRPC 客户端可将日志记录作用域添加到在 gRPC 调用期间创建的日志。作用域具有与 gRPC 调用相关的元数据:

  • GrpcMethodType - gRPC 方法类型。可能的值为来自 Grpc.Core.MethodType 枚举的名称,如一元
  • GrpcUri - gRPC 方法的相对 URI,例如 /greet.Greeter/SayHellos

日志记录输出示例Sample logging output

下面是 Debug 级别的 gRPC 客户端控制台输出示例:

  1. dbug: Grpc.Net.Client.Internal.GrpcCall[1]
  2. Starting gRPC call. Method type: 'Unary', URI: 'https://localhost:5001/Greet.Greeter/SayHello'.
  3. dbug: Grpc.Net.Client.Internal.GrpcCall[6]
  4. Sending message.
  5. dbug: Grpc.Net.Client.Internal.GrpcCall[1]
  6. Reading message.
  7. dbug: Grpc.Net.Client.Internal.GrpcCall[4]
  8. Finished gRPC call.

跟踪Tracing

gRPC 服务和 gRPC 客户端使用 DiagnosticSourceActivity 提供有关 gRPC 调用的信息。

  • .NET gRPC 使用活动来表示 gRPC 调用。
  • 跟踪事件将在 gRPC 调用活动开始和结束时写入到诊断源。
  • 跟踪不会捕获有关在 gRPC 流调用的生存期内消息何时发送的信息。

gRPC 服务跟踪gRPC service tracing

gRPC 服务托管在会报告有关传入 HTTP 请求事件的 ASP.NET Core 上。特定于 gRPC 的元数据将添加到 ASP.NET Core 提供的现有 HTTP 请求诊断。

  • 诊断源名称为 Microsoft.AspNetCore
  • 活动名称为 Microsoft.AspNetCore.Hosting.HttpRequestIn
    • gRPC 调用所调用的 gRPC 方法的名称将添加为标记,标记名称为 grpc.method
    • gRPC 调用完成后,其状态代码将添加为标记,标记名称为 grpc.status_code

gRPC 客户端跟踪gRPC client tracing

.NET gRPC 客户端使用 HttpClient 进行 gRPC 调用。尽管 HttpClient 可编写诊断事件,但 .NET gRPC 客户端提供自定义诊断源、活动和事件,以便可以收集有关 gRPC 调用的完整信息。

  • 诊断源名称为 Grpc.Net.Client
  • 活动名称为 Grpc.Net.Client.GrpcOut
    • gRPC 调用所调用的 gRPC 方法的名称将添加为标记,标记名称为 grpc.method
    • gRPC 调用完成后,其状态代码将添加为标记,标记名称为 grpc.status_code

收集跟踪Collecting tracing

使用 DiagnosticSource 的最简单方法是在应用中配置遥测库,如 Application InsightsOpenTelemetry该库将与其他应用遥测一起处理有关 gRPC 调用的信息。

可以在托管服务(如 Application Insights)中查看跟踪,也可以选择运行自己的分布式跟踪系统。OpenTelemetry 支持将跟踪数据导出到 JaegerZipkin

DiagnosticSource 可以使用 DiagnosticListener 在代码中使用跟踪事件。有关使用代码侦听诊断源的信息,请参阅 DiagnosticSource 用户指南

备注

遥测库当前不捕获特定于 gRPC 的 Grpc.Net.Client.GrpcOut 遥测。改进捕获此跟踪的遥测库的工作正在进行。

指标Metrics

指标是一段时间间隔内数据度量值的表示形式,例如每秒请求数。使用指标数据可以在高级别观察应用的状态。.NET gRPC 指标是使用 EventCounter 发出的。

gRPC 服务指标gRPC service metrics

gRPC 服务器指标在 Grpc.AspNetCore.Server 事件源上报告。

“属性”描述
total-calls总调用数
current-calls当前调用
calls-failed失败调用总数
calls-deadline-exceeded超出截止时间的调用总数
messages-sent已发送消息总数
messages-received已接收消息总数
calls-unimplemented总未实现调用数

ASP.NET Core 还在 Microsoft.AspNetCore.Hosting 事件源上提供其自己的指标。

gRPC 客户端指标gRPC client metrics

gRPC 客户端指标在 Grpc.Net.Client 事件源上报告。

“属性”描述
total-calls总调用数
current-calls当前调用
calls-failed失败调用总数
calls-deadline-exceeded超出截止时间的调用总数
messages-sent已发送消息总数
messages-received已接收消息总数

观察指标Observe metrics

dotnet-counters 是一个性能监视工具,用于临时运行状况监视和初级性能调查。使用 Grpc.AspNetCore.ServerGrpc.Net.Client 作为提供程序名称监视 .NET 应用。

  1. > dotnet-counters monitor --process-id 1902 Grpc.AspNetCore.Server
  2. Press p to pause, r to resume, q to quit.
  3. Status: Running
  4. [Grpc.AspNetCore.Server]
  5. Total Calls 300
  6. Current Calls 5
  7. Total Calls Failed 0
  8. Total Calls Deadline Exceeded 0
  9. Total Messages Sent 295
  10. Total Messages Received 300
  11. Total Calls Unimplemented 0

观察 gRPC 指标的另一种方法是使用 Application Insights 的 捕获计数器数据。设置完成后,Application Insights 可在运行时收集常见的 .NET 计数器。默认情况下,不收集 gRPC 的计数器,但可以自定义 App Insights 以包括其他计数器

为 Application Insight 指定 gRPC 计数器以在 Startup.cs 中收集 :

  1. using Microsoft.ApplicationInsights.Extensibility.EventCounterCollector;
  2. public void ConfigureServices(IServiceCollection services)
  3. {
  4. //... other code...
  5. services.ConfigureTelemetryModule<EventCounterCollectionModule>(
  6. (module, o) =>
  7. {
  8. // Configure App Insights to collect gRPC counters gRPC services hosted in an ASP.NET Core app
  9. module.Counters.Add(new EventCounterCollectionRequest("Grpc.AspNetCore.Server", "current-calls"));
  10. module.Counters.Add(new EventCounterCollectionRequest("Grpc.AspNetCore.Server", "total-calls"));
  11. module.Counters.Add(new EventCounterCollectionRequest("Grpc.AspNetCore.Server", "calls-failed"));
  12. }
  13. );
  14. }

其他资源Additional resources