diff --git a/aspnetcore/grpc/configuration.md b/aspnetcore/grpc/configuration.md index 7227e03b52..7967fcdebb 100644 --- a/aspnetcore/grpc/configuration.md +++ b/aspnetcore/grpc/configuration.md @@ -1,18 +1,18 @@ --- -title: gRPC for ASP.NET Core configuration +title: gRPC for .NET configuration author: jamesnk -description: Learn how to configure gRPC for ASP.NET Core apps. +description: Learn how to configure gRPC for .NET apps. monikerRange: '>= aspnetcore-3.0' ms.author: jamesnk ms.custom: mvc ms.date: 09/05/2019 uid: grpc/configuration --- -# gRPC for ASP.NET Core configuration +# gRPC for .NET configuration ## Configure services options -The following table describes options for configuring gRPC services: +gRPC services are configured with `AddGrpc` in *Startup.cs*. The following table describes options for configuring gRPC services: | Option | Default Value | Description | | ------ | ------------- | ----------- | @@ -33,13 +33,13 @@ Options for a single service override the global options provided in `AddGrpc` a ## Configure client options -The following table describes options for configuring gRPC channels: +gRPC client configuration is set on `GrpcChannelOptions`. The following table describes options for configuring gRPC channels: | Option | Default Value | Description | | ------ | ------------- | ----------- | | `HttpClient` | New instance | The `HttpClient` used to make gRPC calls. A client can be set to configure a custom `HttpClientHandler`, or add additional handlers to the HTTP pipeline for gRPC calls. If no `HttpClient` is specified, then a new `HttpClient` instance is created for the channel. It will automatically be disposed. | | `DisposeHttpClient` | `false` | If `true`, and an `HttpClient` is specified, then the `HttpClient` instance will be disposed when the `GrpcChannel` is disposed. | -| `LoggerFactory` | `null` | The `LoggerFactory` used by the client to log information about gRPC calls. A `LoggerFactory` instance can be resolved from dependency injection or created using `LoggerFactory.Create`. For examples of configuring logging, see . | +| `LoggerFactory` | `null` | The `LoggerFactory` used by the client to log information about gRPC calls. A `LoggerFactory` instance can be resolved from dependency injection or created using `LoggerFactory.Create`. For examples of configuring logging, see . | | `MaxSendMessageSize` | `null` | The maximum message size in bytes that can be sent from the client. Attempting to send a message that exceeds the configured maximum message size results in an exception. | | `MaxReceiveMessageSize` | 4 MB | The maximum message size in bytes that can be received by the client. If the client receives a message that exceeds this limit, it throws an exception. Increasing this value allows the client to receive larger messages, but can negatively impact memory consumption. | | `Credentials` | `null` | A `ChannelCredentials` instance. Credentials are used to add authentication metadata to gRPC calls. | @@ -56,4 +56,5 @@ The following code: * * +* * diff --git a/aspnetcore/grpc/configuration/sample/Program.cs b/aspnetcore/grpc/configuration/sample/Program.cs index 2487a83d10..538dc6448c 100644 --- a/aspnetcore/grpc/configuration/sample/Program.cs +++ b/aspnetcore/grpc/configuration/sample/Program.cs @@ -21,9 +21,6 @@ namespace GrpcGreeterClient var reply = await client.SayHelloAsync( new HelloRequest { Name = "GreeterClient" }); Console.WriteLine("Greeting: " + reply.Message); - await channel.ShutdownAsync(); - Console.WriteLine("Press any key to exit..."); - Console.ReadKey(); } #endregion } diff --git a/aspnetcore/grpc/diagnostics.md b/aspnetcore/grpc/diagnostics.md new file mode 100644 index 0000000000..43c7844995 --- /dev/null +++ b/aspnetcore/grpc/diagnostics.md @@ -0,0 +1,106 @@ +--- +title: Logging and diagnostics in gRPC on .NET +author: jamesnk +description: Learn how to gather diagnostics from your gRPC app on .NET. +monikerRange: '>= aspnetcore-3.0' +ms.author: jamesnk +ms.date: 09/23/2019 +uid: grpc/diagnostics +--- +# Logging and diagnostics in gRPC on .NET + +By [James Newton-King](https://twitter.com/jamesnk) + +This article provides guidance for gathering diagnostics from your gRPC app to help troubleshoot issues. + +## gRPC services logging + +> [!WARNING] +> Server-side logs may contain sensitive information from your app. **Never** post raw logs from production apps to public forums like GitHub. + +Since gRPC services are hosted on ASP.NET Core, it uses the ASP.NET Core logging system. In the default configuration, gRPC logs very little information, but this can configured. See the documentation on [ASP.NET Core logging](xref:fundamentals/logging/index#configuration) for details on configuring ASP.NET Core logging. + +gRPC adds logs under the `Grpc` category. To enable detailed logs from gRPC, configure the `Grpc` prefixes to the `Debug` level in your *appsettings.json* file by adding the following items to the `LogLevel` sub-section in `Logging`: + +[!code-json[](diagnostics/logging-config.json?highlight=7)] + +You can also configure this in *Startup.cs* with `ConfigureLogging`: + +[!code-csharp[](diagnostics/logging-config-code.cs?highlight=5)] + +If you aren't using JSON-based configuration, set the following configuration value in your configuration system: + +* `Logging:LogLevel:Grpc` = `Debug` + +Check the documentation for your configuration system to determine how to specify nested configuration values. For example, when using environment variables, two `_` characters are used instead of the `:` (for example, `Logging__LogLevel__Grpc`). + +We recommend using the `Debug` level when gathering more detailed diagnostics for your app. The `Trace` level produces very low-level diagnostics and is rarely needed to diagnose issues in your app. + +### Sample logging output + +Here is an example of console output at the `Debug` level of a gRPC service: + +``` +info: Microsoft.AspNetCore.Hosting.Diagnostics[1] + Request starting HTTP/2 POST https://localhost:5001/Greet.Greeter/SayHello application/grpc +info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0] + Executing endpoint 'gRPC - /Greet.Greeter/SayHello' +dbug: Grpc.AspNetCore.Server.ServerCallHandler[1] + Reading message. +info: GrpcService.GreeterService[0] + Hello World +dbug: Grpc.AspNetCore.Server.ServerCallHandler[6] + Sending message. +info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] + Executed endpoint 'gRPC - /Greet.Greeter/SayHello' +info: Microsoft.AspNetCore.Hosting.Diagnostics[2] + Request finished in 1.4113ms 200 application/grpc +``` + +## Access server-side logs + +How you access server-side logs depends on the environment in which you're running. + +### As a console app + +If you're running in a console app, the [Console logger](xref:fundamentals/logging/index#console-provider) should be enabled by default. gRPC logs will appear in the console. + +### Other environments + +If the app is deployed to another environment (for example, Docker, Kubernetes, or Windows Service), see for more information on how to configure logging providers suitable for the environment. + +## gRPC client logging + +> [!WARNING] +> Client-side logs may contain sensitive information from your app. **Never** post raw logs from production apps to public forums like GitHub. + +To get logs from the .NET client, you can set the `GrpcChannelOptions.LoggerFactory` property when the client's channel is created. If you are calling a gRPC service from an ASP.NET Core app then the logger factory can be resolved from dependency injection (DI): + +[!code-csharp[](diagnostics/net-client-dependency-injection.cs?highlight=7,16)] + +An alternative way to enable client logging is to use the [gRPC client factory](xref:grpc/clientfactory) to create the client. A gRPC client registered with the client factory and resolved from DI will automatically use the app's configured logging. + +If your app isn't using DI then you can create a new `ILoggerFactory` instance with [LoggerFactory.Create](xref:Microsoft.Extensions.Logging.LoggerFactory.Create*). To access this method add the [Microsoft.Extensions.Logging](https://www.nuget.org/packages/microsoft.extensions.logging/) package to your app. + +[!code-csharp[](diagnostics/net-client-loggerfactory-create.cs?highlight=1,8)] + +### Sample logging output + +Here is an example of console output at the `Debug` level of a gRPC client: + +``` +dbug: Grpc.Net.Client.Internal.GrpcCall[1] + Starting gRPC call. Method type: 'Unary', URI: 'https://localhost:5001/Greet.Greeter/SayHello'. +dbug: Grpc.Net.Client.Internal.GrpcCall[6] + Sending message. +dbug: Grpc.Net.Client.Internal.GrpcCall[1] + Reading message. +dbug: Grpc.Net.Client.Internal.GrpcCall[4] + Finished gRPC call. +``` + +## Additional resources + +* +* +* diff --git a/aspnetcore/grpc/diagnostics/logging-config-code.cs b/aspnetcore/grpc/diagnostics/logging-config-code.cs new file mode 100644 index 0000000000..a2b0b2ac1a --- /dev/null +++ b/aspnetcore/grpc/diagnostics/logging-config-code.cs @@ -0,0 +1,10 @@ +public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureLogging(logging => + { + logging.AddFilter("Grpc", LogLevel.Debug); + }) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); \ No newline at end of file diff --git a/aspnetcore/grpc/diagnostics/logging-config.json b/aspnetcore/grpc/diagnostics/logging-config.json new file mode 100644 index 0000000000..aa0297e59b --- /dev/null +++ b/aspnetcore/grpc/diagnostics/logging-config.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information", + "Grpc": "Debug" + } + } +} \ No newline at end of file diff --git a/aspnetcore/grpc/diagnostics/net-client-dependency-injection.cs b/aspnetcore/grpc/diagnostics/net-client-dependency-injection.cs new file mode 100644 index 0000000000..5c7902edb2 --- /dev/null +++ b/aspnetcore/grpc/diagnostics/net-client-dependency-injection.cs @@ -0,0 +1,22 @@ +[ApiController] +[Route("[controller]")] +public class GreetingController : ControllerBase +{ + private ILoggerFactory _loggerFactory; + + public GreetingController(ILoggerFactory loggerFactory) + { + _loggerFactory = loggerFactory; + } + + [HttpGet] + public async Task> Get(string name) + { + var channel = GrpcChannel.ForAddress("https://localhost:5001", + new GrpcChannelOptions { LoggerFactory = _loggerFactory }); + var client = new Greeter.GreeterClient(channel); + + var reply = await client.SayHelloAsync(new HelloRequest { Name = name }); + return Ok(reply.Message); + } +} \ No newline at end of file diff --git a/aspnetcore/grpc/diagnostics/net-client-loggerfactory-create.cs b/aspnetcore/grpc/diagnostics/net-client-loggerfactory-create.cs new file mode 100644 index 0000000000..a98fb8bbf3 --- /dev/null +++ b/aspnetcore/grpc/diagnostics/net-client-loggerfactory-create.cs @@ -0,0 +1,10 @@ +var loggerFactory = LoggerFactory.Create(logging => +{ + logging.AddConsole(); + logging.SetMinimumLevel(LogLevel.Debug); +}); + +var channel = GrpcChannel.ForAddress("https://localhost:5001", + new GrpcChannelOptions { LoggerFactory = loggerFactory }); + +var client = Greeter.GreeterClient(channel); \ No newline at end of file diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 20c4c97ad6..4822064d00 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -570,6 +570,8 @@ uid: grpc/configuration - name: Authentication and authorization uid: grpc/authn-and-authz + - name: Logging and diagnostics + uid: grpc/diagnostics - name: Security considerations uid: grpc/security - name: Migrate gRPC services from C Core