parent
58ea57e63f
commit
d805cf3b2e
|
|
@ -39,76 +39,81 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
|
|||
Func<HealthCheckRegistration, bool> predicate,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var registrations = _options.Value.Registrations;
|
||||
async Task<(string registrationName, HealthReportEntry result)> RunCheckAsync(IServiceScope scope, HealthCheckRegistration registration)
|
||||
{
|
||||
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 (registration.Name, entry);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<HealthCheckRegistration> registrations = _options.Value.Registrations;
|
||||
if (predicate != null)
|
||||
{
|
||||
registrations = registrations.Where(predicate);
|
||||
}
|
||||
|
||||
var totalTime = ValueStopwatch.StartNew();
|
||||
Log.HealthCheckProcessingBegin(_logger);
|
||||
|
||||
(string registrationName, HealthReportEntry result)[] results;
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
entries[registration.Name] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
var totalElapsedTime = totalTime.GetElapsedTime();
|
||||
var report = new HealthReport(entries, totalElapsedTime);
|
||||
Log.HealthCheckProcessingEnd(_logger, report.Status, totalElapsedTime);
|
||||
return report;
|
||||
results = await Task.WhenAll(registrations.Select(r => RunCheckAsync(scope, r)));
|
||||
}
|
||||
|
||||
var entries = new Dictionary<string, HealthReportEntry>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var (registrationName, result) in results)
|
||||
{
|
||||
entries[registrationName] = result;
|
||||
}
|
||||
|
||||
var totalElapsedTime = totalTime.GetElapsedTime();
|
||||
var report = new HealthReport(entries, totalElapsedTime);
|
||||
Log.HealthCheckProcessingEnd(_logger, report.Status, totalElapsedTime);
|
||||
return report;
|
||||
}
|
||||
|
||||
private static void ValidateRegistrations(IEnumerable<HealthCheckRegistration> registrations)
|
||||
|
|
|
|||
Loading…
Reference in New Issue