public static IHostBuilder CreateHostBuilder() => new HostBuilder() .ConfigureLogging(builder => builder.ClearProviders()) .ConfigureServices(services => { // We don't care much about which options we are setting. // These are for testing that all the extension method overloads work as expected. services.AddGoogleDiagnostics( new TraceServiceOptions { ProjectId = ProjectId, Options = TraceOptions.Create(retryOptions: RetryOptions.NoRetry(ExceptionHandling.Propagate)) }, new LoggingServiceOptions { ProjectId = ProjectId, ServiceName = Service, Version = Version, Options = LoggingOptions.Create(retryOptions: RetryOptions.NoRetry(ExceptionHandling.Propagate)) }, new ErrorReportingServiceOptions { ProjectId = ProjectId, ServiceName = Service, Version = Version, Options = ErrorReportingOptions.CreateInstance(retryOptions: RetryOptions.NoRetry(ExceptionHandling.Propagate)) }); });
/// <summary> /// Creates an instance of <see cref="GoogleExceptionLogger"/>. /// <para> /// Can be used when running on Google App Engine or Google Compute Engine. /// The Google Cloud Platform project to report errors to will detected from the /// current platform. /// </para> /// </summary> /// <param name="serviceName">An identifier of the service, such as the name of the executable or job. /// Must not be null.</param> /// <param name="version">Represents the source code version that the developer provided. /// Must not be null.</param> /// <param name="options">Optional, error reporting options.</param> public static GoogleExceptionLogger Create(string serviceName, string version, ErrorReportingOptions options = null) { var contextLogger = ContextExceptionLogger.Create(null, serviceName, version, options); return(new GoogleExceptionLogger(contextLogger)); }
/// <summary> /// Configures Google Diagnostics to be used in ASP.NET Core applications. /// </summary> /// <remarks> /// Options may be null in which case defaults will be used. Note that the /// Google Cloud Project ID to use is required. If not set via options, it will be /// obtained from the environment, but only if running on GCP. /// </remarks> public static IServiceCollection AddGoogleDiagnosticsForAspNetCore( this IServiceCollection services, string projectId = null, string serviceName = null, string serviceVersion = null, TraceOptions traceOptions = null, LoggingOptions loggingOptions = null, ErrorReportingOptions errorReportingOptions = null) => services.AddGoogleDiagnosticsForAspNetCore( new AspNetCoreTraceOptions { ServiceOptions = new Common.TraceServiceOptions { Options = traceOptions, ProjectId = projectId } }, new LoggingServiceOptions { Options = loggingOptions, ProjectId = projectId, ServiceName = serviceName, Version = serviceVersion }, new Common.ErrorReportingServiceOptions { Options = errorReportingOptions, ProjectId = projectId, ServiceName = serviceName, Version = serviceVersion });
/// <summary> /// Uses middleware that will report all uncaught exceptions to the Stackdriver /// Error Reporting API. /// </summary> /// <param name="app">The application builder. Cannot be null.</param> /// <param name="projectId">The Google Cloud Platform project ID. Cannot be null.</param> /// <param name="serviceName">An identifier of the service, such as the name of the /// executable or job. Cannot be null.</param> /// <param name="version">Represents the source code version that the developer /// provided. Cannot be null.</param> /// <param name="options">Error reporting options for exception logging.</param> public static void UseGoogleExceptionLogging( this IApplicationBuilder app, string projectId, string serviceName, string version, ErrorReportingOptions options = null) { GaxPreconditions.CheckNotNullOrEmpty(projectId, nameof(projectId)); UseGoogleExceptionLoggingBase(app, projectId, serviceName, version, options); }
private static void ConfigureGoogleDiagnosticsServices( IServiceCollection services, string projectId, string serviceName, string serviceVersion, LoggerOptions loggerOptions, TraceOptions traceOptions, ErrorReportingOptions errorReportingOptions) { projectId = Project.GetAndCheckProjectId(projectId, null); services.AddLogEntryLabelProvider <TraceIdLogEntryLabelProvider>(); services.AddGoogleTraceForAspNetCore(new AspNetCoreTraceOptions { ServiceOptions = new Common.TraceServiceOptions { ProjectId = projectId, Options = traceOptions } }); services.AddGoogleErrorReportingForAspNetCore(new Common.ErrorReportingServiceOptions { ProjectId = projectId, ServiceName = serviceName, Version = serviceVersion, Options = errorReportingOptions }); loggerOptions = loggerOptions ?? LoggerOptions.Create(); loggerOptions.CommonLoggerOptions.ProjectId = projectId; services.AddLogging(builder => builder.AddGoogle(loggerOptions.CommonLoggerOptions)); }
/// <summary> /// Adds services for middleware that will report all uncaught exceptions to the /// Stackdriver Error Reporting API. /// </summary> /// <param name="services">The service collection. Cannot be null.</param> /// <param name="projectId">The Google Cloud Platform project ID. Cannot be null.</param> /// <param name="serviceName">An identifier of the service, such as the name of the /// executable or job. Cannot be null.</param> /// <param name="version">Represents the source code version that the developer /// provided. Cannot be null.</param> /// <param name="options">Error reporting options for exception logging.</param> public static void AddGoogleExceptionLogging( this IServiceCollection services, string projectId, string serviceName, string version, ErrorReportingOptions options = null) { GaxPreconditions.CheckNotNullOrEmpty(projectId, nameof(projectId)); AddGoogleExceptionLoggingBase(services, projectId, serviceName, version, options); }
private static void ConfigureGoogleDiagnosticsServices( IServiceCollection services, string projectId, string serviceName, string serviceVersion, LoggerOptions loggerOptions, TraceOptions traceOptions, ErrorReportingOptions errorReportingOptions) { projectId = Project.GetAndCheckProjectId(projectId, null); services.AddLogEntryLabelProvider <TraceIdLogEntryLabelProvider>(); services.AddSingleton <IStartupFilter>(new GoogleDiagnosticsStartupFilter(projectId, loggerOptions)); services.AddGoogleTrace(options => { options.ProjectId = projectId; options.Options = traceOptions; }); services.AddGoogleExceptionLogging(options => { options.ProjectId = projectId; options.ServiceName = Project.GetServiceName(serviceName, null); options.Version = Project.GetServiceVersion(serviceVersion, null); options.Options = errorReportingOptions; }); }
public void CreateConsumer_ErrorToLogsConsumer() { var eventTarget = EventTarget.ForLogging(_projectId, "test-log", _loggingClient); var options = ErrorReportingOptions.Create(eventTarget); var consumer = options.CreateConsumer(); Assert.IsType <ErrorEventToLogEntryConsumer>(consumer); }
/// <summary> /// Shared code for creating error reporting services. /// </summary> /// <param name="services">The service collection. Cannot be null.</param> /// <param name="projectId">The Google Cloud Platform project ID. If null the project Id will be auto detected.</param> /// <param name="serviceName">An identifier of the service, such as the name of the executable or job. /// Cannot be null.</param> /// <param name="version">Represents the source code version that the developer provided. /// Cannot be null.</param> /// <param name="options">Optional, error reporting options.</param> private static void AddGoogleExceptionLoggingBase( this IServiceCollection services, string projectId, string serviceName, string version, ErrorReportingOptions options = null) { services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton(ErrorReportingContextExceptionLogger.Create(projectId, serviceName, version, options)); services.AddSingleton(CreateExceptionLogger); }
public void CreateConsumer_ErrorConsumer() { var eventTarget = EventTarget.ForErrorReporting(_projectId, _errorClient); var options = ErrorReportingOptions.Create(eventTarget); var consumer = options.CreateConsumer(); Assert.IsType <GrpcErrorEventConsumer>(consumer); }
/// <summary> /// Creates an instance of <see cref="GoogleExceptionLogger"/>. /// </summary> /// <param name="projectId">The Google Cloud Platform project ID. Must not be null.</param> /// <param name="serviceName">An identifier of the service, such as the name of the executable or job. /// Must not be null.</param> /// <param name="version">Represents the source code version that the developer provided. /// Must not be null.</param> /// <param name="options">Optional, error reporting options.</param> public static GoogleExceptionLogger Create(string projectId, string serviceName, string version, ErrorReportingOptions options = null) { GaxPreconditions.CheckNotNullOrEmpty(projectId, nameof(projectId)); var contextLogger = ContextExceptionLogger.Create(projectId, serviceName, version, options); return(new GoogleExceptionLogger(contextLogger)); }
public void CreateConsumer_BufferdConsumer() { var bufferOptions = BufferOptions.SizedBuffer(); var eventTarget = EventTarget.ForLogging(_projectId, "test-log", _loggingClient); var options = ErrorReportingOptions.Create(eventTarget, bufferOptions); var consumer = options.CreateConsumer(); Assert.IsType <SizedBufferingConsumer <ReportedErrorEvent> >(consumer); }
public void ErrorReportingOptions_EventTarget() { var eventTarget = EventTarget.ForErrorReporting(_projectId, _errorClient); var bufferOptions = BufferOptions.SizedBuffer(); var options = ErrorReportingOptions.Create(eventTarget, bufferOptions); Assert.Equal(eventTarget, options.EventTarget); Assert.Equal(bufferOptions, options.BufferOptions); }
/// <summary> /// Configures Google Diagnostics services for Logging, Tracing and Error Reporting middleware. /// </summary> /// <param name="builder">The <see cref="IWebHostBuilder"/> instance.</param> /// <param name="projectId"> /// The Google Cloud Platform project ID. If unspecified and running on GAE/GCE/GKE /// the project ID will be detected from the platform. /// </param> /// <param name="serviceName"> /// An identifier of the service used for exception logging (through Error Reporting), such as the name of the executable or job. /// If unspecified and running on GAE the service name will be detected from the platform. /// This may be different from <see cref="LoggerOptions.ServiceName"/> which is used for log entries logged with <see cref="GoogleLogger"/>. /// </param> /// <param name="serviceVersion"> /// A string that represents the version of the service or the source code used for exception logging. /// If unspecified and running on GAE the service version will be detected from the platform. /// This may be different from <see cref="LoggerOptions.Version"/> which is used for log entries logged with <see cref="GoogleLogger"/>. /// </param> /// <param name="loggerOptions">The options for logging. May be null, in which case default options will be used.</param> /// <param name="traceOptions">The options for tracing. May be null, in which case default options will be used.</param> /// <param name="errorReportingOptions">The options for error reporting. May be null, in which case default options will be used.</param> /// <returns>The <see cref="IWebHostBuilder"/> instance.</returns> public static IWebHostBuilder UseGoogleDiagnostics( this IWebHostBuilder builder, string projectId = null, string serviceName = null, string serviceVersion = null, LoggerOptions loggerOptions = null, TraceOptions traceOptions = null, ErrorReportingOptions errorReportingOptions = null) => builder.ConfigureServices(services => ConfigureGoogleDiagnosticsServices(services, projectId, serviceName, serviceVersion, loggerOptions, traceOptions, errorReportingOptions));
public void CreateConsumer_ErrorToLogsConsumer() { var eventTarget = EventTarget.ForLogging(_projectId, "test-log", _loggingClient); var options = ErrorReportingOptions.Create(eventTarget); var consumer = options.CreateConsumer(); Assert.IsType <RpcRetryConsumer <LogEntry> >(consumer); var retryConsumer = (RpcRetryConsumer <LogEntry>)consumer; Assert.IsType <GrpcLogConsumer>(retryConsumer._consumer); }
/// <summary> /// Shared code for creating <see cref="ErrorReportingExceptionFilter"/>. /// </summary> /// <param name="projectId">The Google Cloud Platform project ID. If null the project Id will be auto detected.</param> /// <param name="serviceName">An identifier of the service, such as the name of the executable or job. /// Cannot be null.</param> /// <param name="version">Represents the source code version that the developer provided. /// Cannot be null.</param> /// <param name="options">Optional, error reporting options.</param> private static ErrorReportingExceptionFilter CreateBase(string projectId, string serviceName, string version, ErrorReportingOptions options = null) { GaxPreconditions.CheckNotNullOrEmpty(serviceName, nameof(serviceName)); GaxPreconditions.CheckNotNullOrEmpty(version, nameof(version)); options = options ?? ErrorReportingOptions.Create(projectId); var consumer = options.CreateConsumer(); return(new ErrorReportingExceptionFilter(consumer, serviceName, version)); }
public async Task LogAsync() { var options = ErrorReportingOptions.Create( EventTarget.ForLogging("pid", loggingClient: new ThrowingLoggingClient())); var consumer = new FakeConsumer(); IContextExceptionLogger logger = new ErrorReportingContextExceptionLogger( consumer, _service, _version, options, null); await logger.LogAsync(CreateException(), new FakeContextWrapper()); ValidateSingleEntry(consumer, _method, _uri, _userAgent, options); }
public async Task LogAsync() { var eventTarget = EventTarget.ForProject("pid"); var options = ErrorReportingOptions.CreateInstance(); var consumer = new FakeConsumer(); IContextExceptionLogger logger = new ErrorReportingContextExceptionLogger( consumer, eventTarget, _serviceContext, options, null); await logger.LogAsync(CreateException(), new FakeContextWrapper()); ValidateSingleEntry(consumer, _method, _uri, _userAgent, options, eventTarget); }
/// <summary> /// Shared code for creating error reporting middleware /// </summary> /// <param name="projectId">The Google Cloud Platform project ID. If null the project Id will be auto detected.</param> /// <param name="serviceName">An identifier of the service, such as the name of the executable or job. /// Cannot be null.</param> /// <param name="version">Represents the source code version that the developer provided. /// Cannot be null.</param> /// <param name="options">Optional, error reporting options.</param> private static void UseGoogleExceptionLoggingBase( this IApplicationBuilder app, string projectId, string serviceName, string version, ErrorReportingOptions options = null) { GaxPreconditions.CheckNotNullOrEmpty(serviceName, nameof(serviceName)); GaxPreconditions.CheckNotNullOrEmpty(version, nameof(version)); options = options ?? ErrorReportingOptions.Create(projectId); var consumer = options.CreateConsumer(); var logger = new ErrorReportingExceptionLogger(consumer, serviceName, version); app.UseMiddleware <ErrorReportingExceptionLoggerMiddleware>(logger); }
public void Log_Simple() { var eventTarget = EventTarget.ForProject("pid"); var options = ErrorReportingOptions.CreateInstance(); var consumer = new FakeConsumer(); IContextExceptionLogger logger = new ErrorReportingContextExceptionLogger( consumer, eventTarget, _serviceContext, options, null); logger.Log(CreateException(), new EmptyContextWrapper()); ValidateSingleEntry(consumer, "", "", "", options, eventTarget); }
public void Log_Simple() { var options = ErrorReportingOptions.Create( EventTarget.ForLogging("pid", loggingClient: new ThrowingLoggingClient())); var consumer = new FakeConsumer(); IContextExceptionLogger logger = new ErrorReportingContextExceptionLogger( consumer, _service, _version, options, null); logger.Log(CreateException(), new EmptyContextWrapper()); ValidateSingleEntry(consumer, "", "", "", options); }
public void Log_Compat() { var eventTarget = EventTarget.ForLogging("pid", loggingClient: new ThrowingLoggingClient()); var options = ErrorReportingOptions.Create(eventTarget); var consumer = new FakeConsumer(); IContextExceptionLogger logger = new ErrorReportingContextExceptionLogger( consumer, eventTarget, _serviceContext, options, null); logger.Log(CreateException(), new FakeContextWrapper()); ValidateSingleEntry(consumer, _method, _uri, _userAgent, options, eventTarget); }
// Sample: ConfigureBuffers 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.CreateInstance(bufferOptions: BufferOptions.NoBuffer())); // Register other services here if you need them. });
public void Log_Simple() { var options = ErrorReportingOptions.Create( EventTarget.ForLogging("pid", loggingClient: new Mock <LoggingServiceV2Client>().Object)); var mockConsumer = new Mock <IConsumer <LogEntry> >(); mockConsumer.Setup(c => c.Receive(IsContext("", "", "", options))); IContextExceptionLogger logger = new ErrorReportingContextExceptionLogger( mockConsumer.Object, _service, _version, options); logger.Log(CreateException(), new EmptyContextWrapper()); mockConsumer.VerifyAll(); }
public override void ConfigureServices(IServiceCollection services) => base.ConfigureServices(services .AddGoogleExceptionLogging(options => { options.ProjectId = ProjectId; options.ServiceName = EntryData.Service; options.Version = EntryData.Version; // This is just so that our validator finds the log entries associated to errors. options.Options = ErrorReportingOptions.Create(EventTarget.ForLogging(ProjectId, "aspnetcore")); }) .AddGoogleTrace(options => { options.ProjectId = ProjectId; options.Options = TraceOptions.Create( double.PositiveInfinity, BufferOptions.NoBuffer(), RetryOptions.NoRetry(ExceptionHandling.Propagate)); }));
public override void ConfigureServices(IServiceCollection services) => base.ConfigureServices(services .AddGoogleErrorReportingForAspNetCore(new Common.ErrorReportingServiceOptions { ProjectId = ProjectId, ServiceName = EntryData.Service, Version = EntryData.Version, Client = new LoggingServiceV2ClientBuilder { TokenAccessMethod = (uri, cancellation) => Task.FromResult("very_bad_token") }.Build(), // This is just so that our validator finds the log entries associated to errors. Options = ErrorReportingOptions.CreateInstance( logName: "aspnetcore", bufferOptions: BufferOptions.NoBuffer(), retryOptions: RetryOptions.NoRetry(ExceptionHandling.Propagate)) }));
public async Task LogAsync() { var options = ErrorReportingOptions.Create( EventTarget.ForLogging("pid", loggingClient: new Mock <LoggingServiceV2Client>().Object)); var mockConsumer = new Mock <IConsumer <LogEntry> >(); mockConsumer.Setup(c => c.ReceiveAsync( IsContext(_method, _uri, _userAgent, options), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(true)); IContextExceptionLogger logger = new ErrorReportingContextExceptionLogger( mockConsumer.Object, _service, _version, options); await logger.LogAsync(CreateException(), new FakeContextWrapper()); mockConsumer.VerifyAll(); }
public override void ConfigureServices(IServiceCollection services) => base.ConfigureServices(services .AddGoogleTraceForAspNetCore(new AspNetCoreTraceOptions { ServiceOptions = new Common.TraceServiceOptions { ProjectId = ProjectId, Options = TraceOptions.Create( double.PositiveInfinity, BufferOptions.NoBuffer(), RetryOptions.NoRetry(ExceptionHandling.Propagate)) } }) .AddGoogleErrorReportingForAspNetCore(new Common.ErrorReportingServiceOptions { ProjectId = ProjectId, ServiceName = EntryData.Service, Version = EntryData.Version, // This is just so that our validator finds the log entries associated to errors. Options = ErrorReportingOptions.CreateInstance( logName: "aspnetcore", bufferOptions: BufferOptions.NoBuffer(), retryOptions: RetryOptions.NoRetry(ExceptionHandling.Propagate)) }));
internal IEnumerable <LogEntry> IsContext( string method, string uri, string userAgent, int statusCode, ErrorReportingOptions options) { return(Match.Create <IEnumerable <LogEntry> >(enumerable => { var e = enumerable.Single(); var eventTarget = options.EventTarget; var json = e.JsonPayload?.Fields; var message = json["message"].StringValue; var context = json["context"]?.StructValue?.Fields; var httpRequest = context["httpRequest"]?.StructValue?.Fields; var methodVal = httpRequest["method"].StringValue; var urlVal = httpRequest["url"].StringValue; var userAgentVal = httpRequest["userAgent"].StringValue; var responseStatusCodeVal = httpRequest["responseStatusCode"].NumberValue; var reportLocation = context["reportLocation"]?.StructValue?.Fields; var filePathVal = reportLocation["filePath"].StringValue; var lineNumberVal = reportLocation["lineNumber"].NumberValue; var functionNameVal = reportLocation["functionName"].StringValue; var serviceContext = json["serviceContext"]?.StructValue?.Fields; var serviceVal = serviceContext["service"].StringValue; var versionVal = serviceContext["version"].StringValue; return e.LogName == eventTarget.LogTarget.GetFullLogName(eventTarget.LogName) && e.Timestamp.Seconds <= Timestamp.FromDateTime(DateTime.UtcNow).Seconds&& e.Resource == eventTarget.MonitoredResource && e.Severity == Logging.Type.LogSeverity.Error && message.Contains(_exceptionMessage) && method.Equals(methodVal) && uri.Equals(urlVal) && userAgent.Equals(userAgentVal) && statusCode == responseStatusCodeVal && (!_isWindows || lineNumberVal > 0) && (!_isWindows || !string.IsNullOrEmpty(filePathVal)) && nameof(CreateException).Equals(functionNameVal) && _service.Equals(serviceVal) && _version.Equals(versionVal); })); }
private void ValidateSingleEntry(FakeConsumer consumer, string method, string uri, string userAgent, ErrorReportingOptions options) { var entries = consumer.Entries.ToList(); if (entries.Count != 1) { Assert.True(false, $"Expected single matching entry. Received:\n{string.Join("\n", entries)}"); } var entry = entries[0]; var json = entry.JsonPayload?.Fields; var eventTarget = options.EventTarget; Assert.Equal(eventTarget.LogTarget.GetFullLogName(eventTarget.LogName), entry.LogName); var currentSeconds = Timestamp.FromDateTime(DateTime.UtcNow).Seconds; Assert.InRange(entry.Timestamp.Seconds, currentSeconds - 10, currentSeconds); Assert.Equal(eventTarget.MonitoredResource, entry.Resource); Assert.Equal(LogSeverity.Error, entry.Severity); Assert.Contains(_exceptionMessage, json["message"].StringValue); var context = json["context"]?.StructValue?.Fields; var httpRequest = context["httpRequest"]?.StructValue?.Fields; Assert.Equal(method, httpRequest["method"].StringValue); Assert.Equal(uri, httpRequest["url"].StringValue); Assert.Equal(userAgent, httpRequest["userAgent"].StringValue); var reportLocation = context["reportLocation"]?.StructValue?.Fields; if (_isWindows) { Assert.InRange(reportLocation["lineNumber"].NumberValue, 1, 5000); // Longer than this file should ever be... Assert.NotEqual("", reportLocation["filePath"].StringValue); } Assert.Equal(nameof(CreateException), reportLocation["functionName"].StringValue); var serviceContext = json["serviceContext"]?.StructValue?.Fields; Assert.Equal(_service, serviceContext["service"].StringValue); Assert.Equal(_version, serviceContext["version"].StringValue); Assert.Contains(_traceId, entry.Trace); Assert.Equal($"{_spanId:x16}", entry.SpanId); Assert.True(entry.TraceSampled); }