private async Task <HealthReportEntry> RunCheckAsync(IServiceScope scope, HealthCheckRegistration registration, CancellationToken cancellationToken) { await Task.Yield(); cancellationToken.ThrowIfCancellationRequested(); var healthCheck = registration.Factory(scope.ServiceProvider); // If the health check does things like make Database queries using EF or backend HTTP calls, // it may be valuable to know that logs it generates are part of a health check. So we start a scope. using (_logger.BeginScope(new HealthCheckLogScope(registration.Name))) { var stopwatch = ValueStopwatch.StartNew(); var context = new HealthCheckContext { Registration = registration }; Log.HealthCheckBegin(_logger, registration); HealthReportEntry entry; try { var result = await healthCheck.CheckHealthAsync(context, cancellationToken); var duration = stopwatch.GetElapsedTime(); entry = new HealthReportEntry( status: result.Status, description: result.Description, duration: duration, exception: result.Exception, data: result.Data); Log.HealthCheckEnd(_logger, registration, entry, duration); Log.HealthCheckData(_logger, registration, entry); } // Allow cancellation to propagate. catch (Exception ex) when(ex as OperationCanceledException == null) { var duration = stopwatch.GetElapsedTime(); entry = new HealthReportEntry( status: HealthStatus.Unhealthy, description: ex.Message, duration: duration, exception: ex, data: null); Log.HealthCheckError(_logger, registration, ex, duration); } return(entry); } }
private async Task <HealthReportEntry> RunCheckAsync(IServiceScope scope, HealthCheckRegistration registration, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var healthCheck = registration.Factory(scope.ServiceProvider); // If the health check does things like make Database queries using EF or backend HTTP calls, // it may be valuable to know that logs it generates are part of a health check. So we start a scope. using (_logger.BeginScope(new HealthCheckLogScope(registration.Name))) { var stopwatch = ValueStopwatch.StartNew(); var context = new HealthCheckContext { Registration = registration }; Log.HealthCheckBegin(_logger, registration); HealthReportEntry entry; CancellationTokenSource timeoutCancellationTokenSource = null; try { HealthCheckResult result; var checkCancellationToken = cancellationToken; if (registration.Timeout > TimeSpan.Zero) { timeoutCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); timeoutCancellationTokenSource.CancelAfter(registration.Timeout); checkCancellationToken = timeoutCancellationTokenSource.Token; } result = await healthCheck.CheckHealthAsync(context, checkCancellationToken).ConfigureAwait(false); var duration = stopwatch.GetElapsedTime(); entry = new HealthReportEntry( status: result.Status, description: result.Description, duration: duration, exception: result.Exception, data: result.Data); Log.HealthCheckEnd(_logger, registration, entry, duration); Log.HealthCheckData(_logger, registration, entry); } catch (OperationCanceledException ex) when(!cancellationToken.IsCancellationRequested) { var duration = stopwatch.GetElapsedTime(); entry = new HealthReportEntry( status: HealthStatus.Unhealthy, description: "A timeout occured while running check.", duration: duration, exception: ex, data: null); Log.HealthCheckError(_logger, registration, ex, duration); } // Allow cancellation to propagate if it's not a timeout. catch (Exception ex) when(ex as OperationCanceledException == null) { var duration = stopwatch.GetElapsedTime(); entry = new HealthReportEntry( status: HealthStatus.Unhealthy, description: ex.Message, duration: duration, exception: ex, data: null); Log.HealthCheckError(_logger, registration, ex, duration); } finally { timeoutCancellationTokenSource?.Dispose(); } return(entry); } }
public static void HealthCheckData(ILogger logger, HealthCheckRegistration registration, HealthReportEntry entry) { if (entry.Data.Count > 0 && logger.IsEnabled(LogLevel.Debug)) { logger.Log( LogLevel.Debug, EventIds.HealthCheckData, new HealthCheckDataLogValue(registration.Name, entry.Data), null, (state, ex) => state.ToString()); } }
public static void HealthCheckEnd(ILogger logger, HealthCheckRegistration registration, HealthReportEntry entry, TimeSpan duration) { switch (entry.Status) { case HealthStatus.Healthy: _healthCheckEndHealthy(logger, registration.Name, duration.TotalMilliseconds, entry.Status, entry.Description, null); break; case HealthStatus.Degraded: _healthCheckEndDegraded(logger, registration.Name, duration.TotalMilliseconds, entry.Status, entry.Description, null); break; case HealthStatus.Unhealthy: _healthCheckEndUnhealthy(logger, registration.Name, duration.TotalMilliseconds, entry.Status, entry.Description, null); break; } }
public override async Task <HealthReport> CheckHealthAsync( Func <HealthCheckRegistration, bool> predicate, CancellationToken cancellationToken = default) { var registrations = _options.Value.Registrations; using (var scope = _scopeFactory.CreateScope()) { var context = new HealthCheckContext(); var entries = new Dictionary <string, HealthReportEntry>(StringComparer.OrdinalIgnoreCase); var totalTime = ValueStopwatch.StartNew(); Log.HealthCheckProcessingBegin(_logger); foreach (var registration in registrations) { if (predicate != null && !predicate(registration)) { continue; } cancellationToken.ThrowIfCancellationRequested(); var healthCheck = registration.Factory(scope.ServiceProvider); // If the health check does things like make Database queries using EF or backend HTTP calls, // it may be valuable to know that logs it generates are part of a health check. So we start a scope. using (_logger.BeginScope(new HealthCheckLogScope(registration.Name))) { var stopwatch = ValueStopwatch.StartNew(); context.Registration = registration; Log.HealthCheckBegin(_logger, registration); HealthReportEntry entry; try { var result = await healthCheck.CheckHealthAsync(context, cancellationToken); entry = new HealthReportEntry( result.Result ? HealthStatus.Healthy : registration.FailureStatus, result.Description, result.Exception, result.Data); Log.HealthCheckEnd(_logger, registration, entry, stopwatch.GetElapsedTime()); Log.HealthCheckData(_logger, registration, entry); } // Allow cancellation to propagate. catch (Exception ex) when(ex as OperationCanceledException == null) { entry = new HealthReportEntry(HealthStatus.Failed, ex.Message, ex, data: null); Log.HealthCheckError(_logger, registration, ex, stopwatch.GetElapsedTime()); } entries[registration.Name] = entry; } } var report = new HealthReport(entries); Log.HealthCheckProcessingEnd(_logger, report.Status, totalTime.GetElapsedTime()); return(report); } }
public static void HealthCheckEnd(ILogger logger, HealthCheckRegistration registration, HealthReportEntry entry, TimeSpan duration) { _healthCheckEnd(logger, registration.Name, duration.TotalMilliseconds, entry.Status, entry.Description, null); }