Google.Cloud.Diagnostics.AspNetCore
Google.Cloud.Diagnostics.AspNetCore
is an ASP.NET Core instrumentation library for Google Logging,
Error Reporting and Tracing. It allows for simple integration of Google observability components into ASP.NET Core 2.1+ applications
with minimal custom code.
Note: ASP.NET Core 2.1 is the long-term support release of ASP.NET Core 2.x.
Google.Cloud.Diagnostics.Common
and
Google.Cloud.Diagnostics.AspNetCore3
are the recommended instrumentations libraries if you are writing non ASP.NET Core .NET Standard 2.0+ or ASP.NET Core 3.1+
applications respectively.
Google.Cloud.Diagnostics.Common
documentation is still relevant when using Google.Cloud.Diagnostics.AspNetCore
,
as tracing, logging and error reporting is done in the same manner when using either of the packages.
Configuration of Google.Cloud.Diagnostics.AspNetCore
and some aspects related to ASP.NET Core applications
being web applications are covered in this document.
Note:
This documentation is for version 4.4.0
of the library.
Some samples may not work with other versions.
Installation
Install the Google.Cloud.Diagnostics.AspNetCore
package from NuGet. Add it to
your project in the normal way (for example by right-clicking on the
project in Visual Studio and choosing "Manage NuGet Packages...").
Authentication
When running on Google Cloud Platform, no action needs to be taken to authenticate.
Otherwise, the simplest way of authenticating your API calls is to
download a service account JSON file then set the GOOGLE_APPLICATION_CREDENTIALS
environment variable to refer to it.
The credentials will automatically be used to authenticate. See the Getting Started With
Authentication guide for more details.
See API Permissions for entries.write
for the permissions needed for Logging and Error Reporting.
See API Permissions for PatchTraces for the permissions needed for Tracing.
Note
TheGoogle.Cloud.Diagnostics.AspNetCore
package attempts to collect the filename and line number when error entries are collected. However, to be able to collect this information PDBs must be included with the deployed code.Note
Some environments limit or disable CPU usage for background activities, while some others allow you to configure CPU allocation for request processing only. When running on environments with limited CPU for background activities, take care not to use the timed buffer options for any of Logging, Tracing or Error Reporting. Take into account that the timed buffer is used for the Logging and Tracing components by default so you will need to explicitly configure the buffers by using theGoogle.Cloud.Diagnostics.Common.LoggerOptions
andGoogle.Cloud.Diagnostics.Common.TraceOptions
classes. The Error Reporting component does not buffer entries by default. See theGoogle.Cloud.Diagnostics.Common
documentation documentation for more information on buffers. Here you can read more about CPU allocation in Google Cloud Run.
Getting started
The easiest way to configure Google Cloud Diagnostics is using the AddGoogleDiagnosticsForAspNetCore
overloaded extension method on IServiceCollection
.
This configures the Logging, Tracing and Error Reporting components, including neccesarry middlewares.
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 for ProjectId
, Service
and Version
since they can be automatically obtained by the AddGoogleDiagnosticsForAspNetCore
methods as far
as they make sense for the environment. (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 the
ProjectId
of the Google Cloud Project in which to store the diagnostic information as well as the Service
and Version
with which to identify your application.
public void ConfigureServices(IServiceCollection 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.AddGoogleDiagnosticsForAspNetCore(ProjectId, Service, Version);
// Add any other services your application requires, for instance,
// depending on the version of ASP.NET Core you are using, you may
// need one of the following:
// services.AddMvc();
// services.AddControllersWithViews();
}
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 on AddGoogleDiagnosticsForAspNetCore
are also available to specify options for each
of the components (logging, tracing and error reporting).
Error Reporting
The error reporting component allows you to create error reports from exceptions thrown in your application. You can explicitly log exceptions you have caught, but the component will also log exceptions that haven't been caught/handled by your code.
Configuration
You only need to use the AddGoogleErrorReportingForAspNetCore
extension method on an IServiceCollection
.
You usually do this on the ConfigureServices
method of your Startup
class.
public void ConfigureServices(IServiceCollection services)
{
services.AddGoogleErrorReportingForAspNetCore(new Common.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
});
// Add any other services your application requires, for instance,
// depending on the version of ASP.NET Core you are using, you may
// need one of the following:
// services.AddMvc();
// services.AddControllersWithViews();
}
Error reports will be automatically created from uncaught exceptions and sent to Google Cloud Error Reporting.
Log Exceptions
You can also log exceptions explicitly.
/// <summary>
/// This method catches an exception thrown by another method and explicitly
/// logs that exception.
/// The <see cref="IExceptionLogger"/> is populated by dependency injection
/// thanks to the use of the <see cref="FromServicesAttribute"/> attribute.
/// </summary>
public void CatchesAndLogsException(string id, [FromServices]IExceptionLogger exceptionLogger)
{
try
{
// This method call throws an exception.
ThrowsException(id);
}
catch (Exception e)
{
exceptionLogger.Log(e);
}
}
Logging
Configuring and using Google Cloud Logging in ASP.NET Core applications is very similar to doing so in a
non ASP.NET Core application. See the
Google.Cloud.Diagnostics.Common
documentation for more information.
Configuration
Configuration of Google Cloud Logging in ASP.NET Core applications is almost the same as for non ASP.NET Core applications. You just build the Host as recommended for ASP.NET Core applications instead of using the general purpose host builder.
return new WebHostBuilder()
.ConfigureLogging(
// Replace projectId with your Google Cloud Project ID.
builder => builder.AddGoogle(new LoggingServiceOptions { ProjectId = projectId }))
.UseStartup<Startup>();
As an alternative, you can configure logging when you are configuring services for your application. This approach is useful
if you are configuring services in a Startup
class or similar. This alternative is used in the same way for ASP.NET Core and
non ASP.NET Core applications alike.
Log
When logging, the main difference between ASP.NET Core and non ASP.NET Core applications is how you obtain a logger in container activated classes, like controllers, pages, etc. Your code does not have to explicitly resolve the dependency, instead the logger will get injected on construction.
public class LoggingSamplesController : Controller
{
private ILogger _logger;
public LoggingSamplesController(ILogger<LoggingSamplesController> logger) =>
_logger = logger;
/// <summary>
/// This method logs an Information level message.
/// </summary>
public void LogInformation(string id)
{
// Log whatever message you want to log.
_logger.LogInformation($"Id received: {id}");
}
}
Tracing
The tracing component allows you to trace your application and send traces to Google Cloud Trace.
Configuration
You only need to use the AddGoogleTraceForAspNetCore
extension method on an IServiceCollection
.
You usually do this on the ConfigureServices
method of your Startup
class.
public void ConfigureServices(IServiceCollection services)
{
// Replace ProjectId with your Google Cloud Project ID.
services.AddGoogleTraceForAspNetCore(new AspNetCoreTraceOptions
{
ServiceOptions = new Common.TraceServiceOptions
{
ProjectId = ProjectId
}
});
// Add any other services your application requires, for instance,
// depending on the version of ASP.NET Core you are using, you may
// need one of the following:
// services.AddMvc();
// services.AddControllersWithViews();
}
Tracing in Controllers
To use the IManagedTracer
in controllers you can either inject the singleton instance of
IManagedTracer
into the controller's constructor (see TraceSamplesConstructorController
) or you
can inject the IManagedTracer
into the action method using the [FromServices]
attribute
(see TraceSamplesMethodController
).
public class TraceSamplesConstructorController : Controller
{
private readonly IManagedTracer _tracer;
/// <summary>
/// The <see cref="IManagedTracer"/> is populated by dependency injection.
/// </summary>
public TraceSamplesConstructorController(IManagedTracer tracer)
{
_tracer = tracer;
}
public void TraceHelloWorld(string id)
{
// Change the name of the span to what makese sense in your context.
using (_tracer.StartSpan(id))
{
// The code whose execution is to be included in the span goes here.
ViewData["Message"] = "Hello World.";
}
}
}
public class TraceSamplesMethodController : Controller
{
/// <summary>
/// Manually trace a set of operations.
/// The <see cref="IManagedTracer"/> is populated by dependency injection
/// thanks to the use of the <see cref="FromServicesAttribute"/> attribute.
/// </summary>
public void TraceHelloWorld(string id, [FromServices] IManagedTracer tracer)
{
// Change the name of the span to what makese sense in your context.
using (tracer.StartSpan(id))
{
// The code whose execution is to be included in the span goes here.
ViewData["Message"] = "Hello World.";
}
}
}
Using Tracing with other than Google's own trace header
The Google.Cloud.Diagnostics
packages have been coupled to
Google's own trace header from their
initial release up to, and including, version 4.2.0. Starting on version 4.3.0-beta01 and upwards
it is possible to consume and emit trace context information in a format other than Google's own
trace header.
The default behaviour of the libraries is still to consume and emit trace context information using Google's trace header.
Custom trace context for incoming HTTP requests
If the HTTP requests that your application handles contain trace context information in a custom format you need to use dependency injection to register:
- A
Google.Cloud.Diagnostics.Common.ITraceContext
, which will probably be scoped, and that you can create from information obtained from any other services available via dependency injection, includingMicrosoft.AspNetCore.Http.IHttpContextAccessor
. The trace context will be obtained per request and used as the parent context for all trace spans, either implicit or explicit, initiated from within the code handling the request. - A
System.Action<Micorosft.AspNetCore.Http.HttpResponse, Google.Cloud.Diagnostics.Common.ITraceContext>
that will be used to set trace context information on the HTTP response to each request. This will be called before returning a response with the updated (as modified by the request handling code) trace context information.
Custom trace context for outgoing HTTP requests
See also Google.Cloud.Diagnostics.Common
documentation for Outgoing HTTP Requests.
If your application itself performs HTTP requests to other services and you want to propagate trace context
information in a format other than Google's trace header, you can use dependency injection to register a
System.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 as the format in which trace context information is received by your application. You might even be accepting Google's trace header, but the service you are calling is not.
- 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 have created several trace spans before making the outgoing request, in which case the span ID that will be propagated is the one of the innermost span that remains open at the moment of sending the outgoing request.
Custom trace context: example
The following is for demonstration purposes only. We assume that trace context information contains a trace ID only
that is propagated in a custom_trace_id
header. This is of no use in the real world.
public void ConfigureServices(IServiceCollection services)
{
// Register a trace context provider method that inspects the request and
// extracts the trace context information.
services.AddScoped(CustomTraceContextProvider);
static ITraceContext CustomTraceContextProvider(IServiceProvider sp)
{
var accessor = sp.GetRequiredService<IHttpContextAccessor>();
string traceId = accessor.HttpContext?.Request?.Headers["custom_trace_id"];
return new SimpleTraceContext(traceId, null, null);
}
// Register a method that sets the updated trace context information on the response.
services.AddSingleton<Action<HttpResponse, ITraceContext>>(
(response, traceContext) => response.Headers.Add("custom_trace_id", traceContext.TraceId));
// Now you can register Google Trace normally.
// Replace ProjectId with your Google Cloud Project ID.
services.AddGoogleTraceForAspNetCore(new AspNetCoreTraceOptions
{
ServiceOptions = new Common.TraceServiceOptions
{
ProjectId = ProjectId
}
});
// If your application is making outgoing HTTP requests then you configure
// your HTTP client for trace propagation as you normally would.
// 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();
// Add any other services your application requires, for instance,
// depending on the version of ASP.NET Core you are using, you may
// need one of the following:
// services.AddMvc();
// services.AddControllersWithViews();
}