Google.Cloud.Diagnostics.Common
Google.Cloud.Diagnostics.Common is a .NET Core instrumentation library for Google Logging,Error Reporting and Tracing. It allows for simple integration of Google observability components into .NET Standard 2.0+ applicationswith minimal custom code.
Google.Cloud.Diagnostics.AspNetCore andGoogle.Cloud.Diagnostics.AspNetCore3are the recommended instrumentation libraries if you are writing ASP.NET Core 2.1 or ASP.NET Core 3.1+ applications respectively.
Note:This documentation is for version5.3.0 of the library.Some samples may not work with other versions.
Installation
Install theGoogle.Cloud.Diagnostics.Common package from NuGet. Add it toyour project in the normal way (for example by right-clicking on theproject in Visual Studio and choosing "Manage NuGet Packages...").
Authentication
When running on Google Cloud, no action needs to be taken to authenticate.
Otherwise, the simplest way of authenticating your API calls is toset up Application Default Credentials.The credentials will automatically be used to authenticate. SeeSet up Application Default Credentials for more details.
SeeAPI Permissions forentries.writefor the permissions needed for Logging and Error Reporting.
SeeAPI Permissions for PatchTracesfor the permissions needed for Tracing.
Note
TheGoogle.Cloud.Diagnostics.Commonpackage attempts to collect the filename and line number whenerror entries are collected. However, to be able to collect this information PDBs must be included withthe deployed code.Note
Some environments limit or disable CPU usage for background activities, while some others allow you toconfigure CPU allocation for request processing only.When running on environments with limited CPU for background activities, take care not to use thetimed buffer options for any of Logging, Tracing or Error Reporting. Take into account that the timed bufferis used for the Logging and Tracing components by default so you will need to explicitly configure the buffers by usingtheGoogle.Cloud.Diagnostics.Common.LoggerOptionsandGoogle.Cloud.Diagnostics.Common.TraceOptionsclasses. The Error Reportingcomponent does not buffer entries by default.Below you'll find examples of how to configure the buffers.Here you can read more aboutCPU allocation in Google Cloud Run.NoteUsing
Google.Cloud.Diagnostics.Commonfor non ASP.NET Core applications relies heavily on.NET's Dependency Injection mechanism.You can read more about .NET dependency injection in non ASP.NET Core applications in theMicrosoft documentation.
Getting started
The easiest way to configure Google Cloud Diagnostics is using theAddGoogleDiagnostics extensionmethods onIServiceCollection.This configures the Logging, Tracing and Error Reporting components.
If your application is running on Google App Engine, Google Kubernetes Engine, Google Cloud Run or Google Compute Engine, you don't need to provide a value forProjectId,Service andVersionsince they can be automatically obtained by theAddGoogleDiagnostics methods as far as they make sense for theenvironment. (Not every environment has the concept of a "service" or "version".)The values used will be the ones associated with the running application.
If your application is running outside of GCP, including when it runs locally, then you'll need to provide theProjectId of the Google Cloud Project in which to store the diagnostic information as well as theService andVersionwith which to identify your application.
public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureServices(services => { // Replace ProjectId with your Google Cloud Project ID. // Replace Service with a name or identifier for the service. // Replace Version with a version for the service. services.AddGoogleDiagnostics(ProjectId, Service, Version); // Register other services here if you need them. });Don't forget to start the host.
host = CreateHostBuilder().Build();await host.StartAsync();You can still initialize the separate components using the extension methods described below.This can be useful if you only need to use some of the observability components.
Optional parameters onAddGoogleDiagnostics are also available to specify options for each of the components(logging, tracing and error reporting).
Buffers and buffer configuration
The Diagnostics instrumentation library supports different buffering strategies that may be configured individually for each of theLogging, Tracing and Error Reporting components, i.e. you don't need to use the same buffering strategy for each of the componentsand even if you do, each buffer may be configured differently for each of the components. For instance, a timed buffer may be configuredfor Logging with a 5 second period at the same time as a timed buffer with a 7 second period is configured for Tracing.
These strategies are:
- Timed buffers: Written entries are stored in a buffer that is flushed periodically to the backend service.This is the buffering strategy used by default by the Tracing and Logging components. Since the service callsare performed in the background, this buffering strategy won't affect your application's performance, in particularit won't affect external requests or user interactions. Depending on the amount of entries your application is generating, you maywant to fine tune the timed buffer period, which defaults to 5 seconds, to flush more or less frequently by taking into accountapplication memory comsumption and how soon you need entries to appear on the backend.As stated earlier in this documentation, it is important to note that some environments do limit CPU usage for backgroundoperations, and in such cases, using timed buffers may result in delayed backend entry recording, lost entries or even thread starvationscenarios.
- Sized buffers: Written entries are stored in a buffer that is flushed to the backend service when it reaches a given size.Service calls are not performed in the background, so the sized buffer may affect performance of certain external requests oruser interactions, in particular those who make the buffer reach the flushing size. In general you'll need to fine tune thebuffer size so that flushing occurs as little as possible while keeping memory comsumption at appropriate levels. Adjustments willdepend on the amount of entries your application is generating.
- No buffer: Entries are sent to the backend service as soon as they are generated by your application. This is the buffering strategyused by default by the Error Reporting component. A service call will be made whenever an entry is generated by your application whichmay affect performance greatly, depending on the amount of entries your code is generating.
Below you can see sample code that forces all three components to use no buffering.
public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureServices(services => { // Replace ProjectId with your Google Cloud Project ID. // Replace Service with a name or identifier for the service. // Replace Version with a version for the service. services.AddGoogleDiagnostics(ProjectId, Service, Version, // Configure the three components to use no buffer. traceOptions: TraceOptions.Create(bufferOptions: BufferOptions.NoBuffer()), loggingOptions: LoggingOptions.Create(bufferOptions: BufferOptions.NoBuffer()), errorReportingOptions: ErrorReportingOptions.Create(bufferOptions: BufferOptions.NoBuffer())); // Register other services here if you need them. });Exceptions thrown in timed buffers' timer thread
Rethrowing exceptions thrown in timed buffers' timer thread may immediately crash the application. These exceptions are not propagatedby default, even if the library has been configured to propagate all other exceptions. If you need to handle these exceptions, fordiagnostic or other purposes, you can provide your own exception handler when configuring a timed buffer.
Below you can see sample code that configures all three components to use timed buffers that will write timer thread exceptionsto the console.
public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureServices(services => { // Replace ProjectId with your Google Cloud Project ID. // Replace Service with a name or identifier for the service. // Replace Version with a version for the service. services.AddGoogleDiagnostics(ProjectId, Service, Version, // Configure the three components so that exceptions thrown in the timer thread // of timed buffers are handled by the given handler. traceOptions: TraceOptions.Create(bufferOptions: BufferOptions.TimedBuffer().WithTimerExceptionHandler(ex => Console.WriteLine(ex))), loggingOptions: LoggingOptions.Create(bufferOptions: BufferOptions.TimedBuffer().WithTimerExceptionHandler(ex => Console.WriteLine(ex))), errorReportingOptions: ErrorReportingOptions.Create(bufferOptions: BufferOptions.TimedBuffer().WithTimerExceptionHandler(ex => Console.WriteLine(ex)))); // Register other services here if you need them. });Error reporting
The error reporting component allows you to create error reports from exceptions thrown in your application.
Configuration
The first step is to configure the error reporting component for dependency injection.
public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureServices(services => { services.AddGoogleErrorReporting(new ErrorReportingServiceOptions { // Replace ProjectId with your Google Cloud Project ID. ProjectId = ProjectId, // Replace Service with a name or identifier for the service. ServiceName = Service, // Replace Version with a version for the service. Version = Version }); // Register other services here if you need them. });And then start the host. This will probably be done in yourMain method.
host = CreateHostBuilder().Build();await host.StartAsync();Logging exceptions
Now you can log exceptions whenever they are thrown. Meaningful error reports will be created and sent toGoogle Cloud Error Reporting.
IContextExceptionLogger exceptionLogger = host.Services.GetRequiredService<IContextExceptionLogger>();try{ // This method call throws an exception. ThrowsException();}catch (Exception e){ // The logger may receive an IContextWrapper as a second parameter // with information about the HTTP operation, if any, that produced // the error. It may be null in which case it will be ignored. exceptionLogger.Log(e, null);}Logging
The logging component allows you to store the logs generated by your application in Google Cloud Logger.TheGoogleLogger implementsMicrosoft.Extensions.Logging.ILogger and so it integrates seamlessly with .NET'slogging infrastructure.
Configuration
For configuring the logging component you use theAddGoogle extension method on aMicrosoft.Extensions.Logging.ILoggingBuilder.
You can onfigure logging when configuring your host builder.
public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureLogging(builder => builder.AddGoogle(new LoggingServiceOptions { // Replace ProjectId with your Google Cloud Project ID. ProjectId = ProjectId, // Replace Service with a name or identifier for the service. ServiceName = Service, // Replace Version with a version for the service. Version = Version }));As an alternative, you can configure logging when you are configuring services for your application. This approach is usefulif you are configuring services in aStartup class or similar.
public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureServices(services => { // Replace ProjectId with your Google Cloud Project ID. services.AddLogging(builder => builder.AddGoogle(new LoggingServiceOptions { // Replace ProjectId with your Google Cloud Project ID. ProjectId = ProjectId, // Replace Service with a name or identifier for the service. ServiceName = Service, // Replace Version with a version for the service. Version = Version })); // Register other services here if you need them. });And then start the host. This will probably be done in yourMain.
host = CreateHostBuilder().Build();await host.StartAsync();Log
For logging, youuse the configured Google Cloud Logger as you would any otherMicrosoft.Extensions.Logging.ILogger.
ILogger logger = host.Services.GetRequiredService<ILogger<Program>>();logger.LogInformation($"User {userName} logged in.");Troubleshooting Logging
Sometimes it is necessary to diagnose log operations. It might be that logging is failing or that you simply cannot findwhere the logs are being stored in Google Cloud Logging. What follows are a couple of code samples that can be useful tofind out what might be wrong with logging operations.
Propagating Exceptions
By default the Google Logger won't propagate any exceptions thrown during logging. This is to protect the application fromcrashing if logging is not possible. But logging is an important aspect of most applications so at times we need to know ifit's failing and why. The following example shows how to configure Google Logger so that it propagates exceptions thrown duringlogging.
public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureServices(services => { //Explicitly create logger options that will propagate any exceptions thrown // during logging. RetryOptions retryOptions = RetryOptions.NoRetry(ExceptionHandling.Propagate); // Also set the no buffer option so that writing the logs is attempted immediately. BufferOptions bufferOptions = BufferOptions.NoBuffer(); // Replace ProjectId with your Google Cloud Project ID. services.AddLogging(builder => builder.AddGoogle(new LoggingServiceOptions { // Replace ProjectId with your Google Cloud Project ID. ProjectId = ProjectId, // Replace Service with a name or identifier for the service. ServiceName = Service, // Replace Version with a version for the service. Version = Version, Options = LoggingOptions.Create(retryOptions: retryOptions, bufferOptions: bufferOptions) })); ; // Register other services here if you need them. });Finding out the URL where logs are written
Depending on where your code is running and the options you provided for creating a Google Logger, it might be hard to findyour logs in the Google Cloud Logging Console. We have provided a way for you to obtain the URL where your logs can be found.
As the following code sample shows, you only need to pass aSystem.IO.TextWriter (typicallyConsole.Out orConsole.Error)as part of the options when configuring logging. When theGoogleLoggerProvider is initialized, the URL where its logs can befound will be written to the given text writer.
public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureServices(services => { // Replace ProjectId with your Google Cloud Project ID. services.AddLogging(builder => builder.AddGoogle(new LoggingServiceOptions { // Replace ProjectId with your Google Cloud Project ID. ProjectId = ProjectId, // Replace Service with a name or identifier for the service. ServiceName = Service, // Replace Version with a version for the service. Version = Version, // Set a TextWriter to which you want yout logs URL to be written to. LoggerDiagnosticsOutput = Console.Out })); ; // Register other services here if you need them. });Please note that since this is a Google Logger diagnostics feature, we don't respect settings for exception handling, i.e. we propagateany exception thrown while writing the URL to the given text writer so you know what might be happening. This feature should only beactivated as a one off, if you are having trouble finding your logs in the GCP Console, and not as a permanent feature inproduction code. To deactivate this feature simply stop passing aSystem.IO.TextWriter as part of the options when configuring Google Logger.
Tracing
The tracing component allows you to trace your application and send traces to Google Cloud Trace.
Configuration
The first step is to configure the tracing component for dependency injection.
public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureServices(services => { // Replace ProjectId with your Google Cloud Project ID. services.AddGoogleTrace(new TraceServiceOptions { ProjectId = ProjectId }); // Register other services here if you need them. });And then start the host. This will probably be done in yourMain method.
host = CreateHostBuilder().Build();await host.StartAsync();Starting a trace
How to start a trace will depend on how you want to trace, and what type of application you want to trace.
- You want to trace all activity of your application in one trace (within potentially different spans). Thisis best suited for scheduled services or user facing applications (like desktop applications) where you wantto have one trace per usage session.
- Your application is a service reacting to requests/events (for instance it's a subscriber on a publisher/subscriberarchitectured system). You want a trace per request/event; the trace may have even be initialized by the emitter ofsaid request/event.
One trace per usage session
If you want to have one trace per usage session, then right after starting the host, probably on yourMain methodyou would create the trace.
ITraceContext traceContext = new SimpleTraceContext(null, null, true);var tracerFactory = host.Services.GetRequiredService<Func<ITraceContext, IManagedTracer>>();IManagedTracer tracer = tracerFactory(traceContext);ContextTracerManager.SetCurrentTracer(tracer);Note that when you create the tracing context, you don't need to specify trace ID or span ID (although you may),Google.Cloud.Diagnostics.Common will create a trace ID for you. Each span you create will be created with it's ownspan ID.
Note that you should specifytrue for theshouldTraceparameter to make sure tha tracing happens regardlessof tracing rates/qps, etc.
One trace per request/event
If your application reacts to requests/events, then on the method that receives each of those (your listener method)you need to extract the trace context information from the request and ser it on the tracer.
ITraceContext traceContext = GetTraceContextFromIncomingRequest(request);var tracerFactory = host.Services.GetRequiredService<Func<ITraceContext, IManagedTracer>>();IManagedTracer tracer = tracerFactory(traceContext);ContextTracerManager.SetCurrentTracer(tracer);Note that we can't go into detail here as to how extract trace context information from a request/event, as that'sdependent on the emitter of said request/event.
If the emitter of requests/events is not attaching trace context information, then you can start your owntrace for each request/event. On your listener method, you would have code similar to the one in the[One trace per usage sesion](### One trace per usage session). But consider in this case not forcing the trace,instead specifynull for theshouldTrace parameter. The tracer will decide whether to trace each request basedon tracing rates/qps, etc.
Starting a span
For any traces to be sent to Google Cloud Trace, a span needs to be started.
IManagedTracer currentTracer = host.Services.GetRequiredService<IManagedTracer>();using (currentTracer.StartSpan("testing_tracing")){ Console.WriteLine("Using Cloud Trace from a non ASP.NET Core app");}Or alternatively, using theRunInSpan methods.
----- Snippet Configure -----// <Configure>public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureServices(services => { // Replace ProjectId with your Google Cloud Project ID. services.AddGoogleTrace(new TraceServiceOptions { ProjectId = ProjectId }); // Register other services here if you need them. });// </Configure>----- Snippet Troubleshooting -----// <Troubleshooting>public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureServices(services => { // Explicitly create trace options that will propagate any exceptions thrown during tracing. RetryOptions retryOptions = RetryOptions.NoRetry(ExceptionHandling.Propagate); // Also set the no buffer option so that tracing is attempted immediately. BufferOptions bufferOptions = BufferOptions.NoBuffer(); TraceOptions traceOptions = TraceOptions.Create(bufferOptions: bufferOptions, retryOptions: retryOptions); // Replace ProjectId with your Google Cloud Project ID. services.AddGoogleTrace(new TraceServiceOptions { ProjectId = ProjectId, Options = traceOptions }); // Register other services here if you need them. });// </Troubleshooting>----- Snippet ConfigureHttpClient -----// <ConfigureHttpClient>public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureServices(services => { // Replace ProjectId with your Google Cloud Project ID. services.AddGoogleTrace(new TraceServiceOptions { ProjectId = ProjectId }); // Register an HttpClient for outgoing requests. services.AddHttpClient("tracesOutgoing") // The next call guarantees that trace information is propagated for outgoing // requests that are already being traced. .AddOutgoingGoogleTraceHandler(); // Register other services here if you need them. });// </ConfigureHttpClient>----- Snippet CustomConfigureHttpClient -----// <CustomConfigureHttpClient>public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureServices(services => { // Replace ProjectId with your Google Cloud Project ID. services.AddGoogleTrace(new TraceServiceOptions { ProjectId = ProjectId }); // If the trace context information should be propagated in a custom format // then you register a method that sets the trace context information on the // outgoing request. services.AddSingleton<Action<HttpRequestMessage, ITraceContext>>( (request, traceContext) => request.Headers.Add("custom_trace_id", traceContext.TraceId)); // Register an HttpClient for outgoing requests. services.AddHttpClient("tracesOutgoing") // The next call guarantees that trace information is propagated for outgoing // requests that are already being traced. .AddOutgoingGoogleTraceHandler(); // Register other services here if you need them. });// </CustomConfigureHttpClient>----- Snippet Start -----// <Start>host = CreateHostBuilder().Build();await host.StartAsync();// </Start>----- Snippet IncomingContext -----// <IncomingContext>ITraceContext traceContext = GetTraceContextFromIncomingRequest(request);var tracerFactory = host.Services.GetRequiredService<Func<ITraceContext, IManagedTracer>>();IManagedTracer tracer = tracerFactory(traceContext);ContextTracerManager.SetCurrentTracer(tracer);// </IncomingContext>----- Snippet Trace -----// <Trace>IManagedTracer currentTracer = host.Services.GetRequiredService<IManagedTracer>();using (currentTracer.StartSpan("testing_tracing")){ Console.WriteLine("Using Cloud Trace from a non ASP.NET Core app");}// </Trace>----- Snippet SingleContext -----// <SingleContext>ITraceContext traceContext = new SimpleTraceContext(null, null, true);var tracerFactory = host.Services.GetRequiredService<Func<ITraceContext, IManagedTracer>>();IManagedTracer tracer = tracerFactory(traceContext);ContextTracerManager.SetCurrentTracer(tracer);// </SingleContext>----- Snippet RunIn -----// <RunIn>IManagedTracer currentTracer = host.Services.GetRequiredService<IManagedTracer>();currentTracer.RunInSpan( () => Console.WriteLine("Using Cloud Trace from a non ASP.NET Core app"), "testing_tracing");// </RunIn>----- Snippet TraceOutgoingClientFactory -----// <TraceOutgoingClientFactory>IHttpClientFactory clientFactory = host.Services.GetRequiredService<IHttpClientFactory>();var httpClient = clientFactory.CreateClient("tracesOutgoing");// Any code that makes outgoing requests.var response = await httpClient.GetAsync(OutgoingUrl);// </TraceOutgoingClientFactory>Troubleshooting Tracing
Failures in tracing are most easily diagnosed by removing buffering and propagating exceptions immediately.
public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureServices(services => { // Explicitly create trace options that will propagate any exceptions thrown during tracing. RetryOptions retryOptions = RetryOptions.NoRetry(ExceptionHandling.Propagate); // Also set the no buffer option so that tracing is attempted immediately. BufferOptions bufferOptions = BufferOptions.NoBuffer(); TraceOptions traceOptions = TraceOptions.Create(bufferOptions: bufferOptions, retryOptions: retryOptions); // Replace ProjectId with your Google Cloud Project ID. services.AddGoogleTrace(new TraceServiceOptions { ProjectId = ProjectId, Options = traceOptions }); // Register other services here if you need them. });These options may be specified wherever you are configuring tracing.
Trace Outgoing HTTP Requests
If your application itself performs HTTP requests to other services you may want to propagate trace context information.Therecommended way of creatingHttpClientin .NET Standard 2.0+ and upwards is to use theSystem.Net.Http.IHttpClientFactory defined in theMicrosoft.Extensions.Http package.The following example demonstrates how to register and use anHttpClient using Google Trace so that it propagates tracecontext information for outgoing requests.
Configuration
public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureServices(services => { // Replace ProjectId with your Google Cloud Project ID. services.AddGoogleTrace(new TraceServiceOptions { ProjectId = ProjectId }); // Register an HttpClient for outgoing requests. services.AddHttpClient("tracesOutgoing") // The next call guarantees that trace information is propagated for outgoing // requests that are already being traced. .AddOutgoingGoogleTraceHandler(); // Register other services here if you need them. });Usage
IHttpClientFactory clientFactory = host.Services.GetRequiredService<IHttpClientFactory>();var httpClient = clientFactory.CreateClient("tracesOutgoing");// Any code that makes outgoing requests.var response = await httpClient.GetAsync(OutgoingUrl);Custom trace context for outgoing HTTP requests
If you configure the trace component for outgoing requests, it will, by default, set on themGoogle's own trace header.If you want to propagate trace context information in a format other than Google's trace header, you can use dependencyinjection to register an actionSystem.Action<System.Net.Http.HttpRequestMessage, Google.Cloud.Diagnostics.Common.ITraceContext>that will be used to set trace context information on outgoing HTTP requests. A few things to notice:
The format in which you propagate trace context information to external requests doesn't have to be the same asthe format in which trace context information is received by your application.
The trace context information propagated to outgoing requests will be the information available at the time the request is made, which may or may not be the same as the information you received. For instance, your code may havecreated several trace spans before making the outgoing request, in which case the span ID that will be propagatedis the one of the innermost span that remains open at the moment of sending the outgoing request.
Here's an example of how your configuration may look like. You then useSystem.Net.Http.IHttpClientFactory as shownin [Usage](### Usage).
Note that the following is for demonstration purposes only. We assume that trace context information contains a trace ID onlythat is propagated in acustom_trace_id header. This is of no use in the real world.
public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureServices(services => { // Replace ProjectId with your Google Cloud Project ID. services.AddGoogleTrace(new TraceServiceOptions { ProjectId = ProjectId }); // If the trace context information should be propagated in a custom format // then you register a method that sets the trace context information on the // outgoing request. services.AddSingleton<Action<HttpRequestMessage, ITraceContext>>( (request, traceContext) => request.Headers.Add("custom_trace_id", traceContext.TraceId)); // Register an HttpClient for outgoing requests. services.AddHttpClient("tracesOutgoing") // The next call guarantees that trace information is propagated for outgoing // requests that are already being traced. .AddOutgoingGoogleTraceHandler(); // Register other services here if you need them. });Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2025-10-30 UTC.