public static async Task <HealthCheckResult> HealthCheck(this HealthCheckRegistration registration, IServiceProvider provider) { var context = new HealthCheckContext { Registration = registration }; var healthCheckResult = new HealthCheckResult(); try { var res = await registration.Factory(provider).CheckHealthAsync(context).ConfigureAwait(false); healthCheckResult = new HealthCheckResult() { Status = res.Status.ToHealthStatus(), Description = res.Description, Details = res.Data?.ToDictionary(i => i.Key, i => i.Value) }; if (res.Exception != null && !string.IsNullOrEmpty(res.Exception.Message)) { healthCheckResult.Details.Add("error", res.Exception.Message); } } #pragma warning disable CA1031 // Do not catch general exception types catch (Exception e) { // Catch all exceptions so that a status can always be returned healthCheckResult.Details.Add("exception", e.Message); } #pragma warning restore CA1031 // Do not catch general exception types return(healthCheckResult); }
public void AddServiceFabricHealthChecks_RegisterPublisherAndChecks() { string checkName = "MockCheck"; IHealthCheck check = new MockCheck(); IServiceProvider provider = new ServiceCollection() .AddSingleton(new Mock <IAccessor <IServicePartition> >().Object) .AddServiceFabricHealthChecks() .AddCheck(checkName, check) .Services .BuildServiceProvider(); IHealthCheckPublisher[] publishers = provider .GetRequiredService <IEnumerable <IHealthCheckPublisher> >() .ToArray(); Assert.IsTrue( publishers.Any(p => p is ServiceFabricHealthCheckPublisher), FormattableString.Invariant($"{nameof(ServiceFabricHealthCheckPublisher)} publisher should be registered")); IOptions <HealthCheckServiceOptions> options = provider.GetRequiredService <IOptions <HealthCheckServiceOptions> >(); HealthCheckRegistration registration = options.Value.Registrations.SingleOrDefault(r => string.Equals(checkName, r.Name, StringComparison.Ordinal)); Assert.IsNotNull(registration, "HealthCheck should be registered"); Assert.AreEqual(check, registration.Factory(provider)); }
public static async Task <HealthCheckResult> HealthCheck(this HealthCheckRegistration registration, IServiceProvider provider) { var context = new HealthCheckContext { Registration = registration }; var healthCheckResult = new HealthCheckResult(); try { var res = await registration.Factory(provider).CheckHealthAsync(context); healthCheckResult = new HealthCheckResult() { Status = res.Status.ToHealthStatus(), Description = res.Description, Details = res.Data?.ToDictionary(i => i.Key, i => i.Value) }; if (res.Exception != null && !string.IsNullOrEmpty(res.Exception.Message)) { healthCheckResult.Details.Add("error", res.Exception.Message); } } catch (Exception) { } return(healthCheckResult); }
private HttpHealthCheckParameters GetParameters(IServiceProvider provider, string checkName) { IOptions <HealthCheckServiceOptions> options = provider.GetRequiredService <IOptions <HealthCheckServiceOptions> >(); HealthCheckRegistration registration = options.Value.Registrations.SingleOrDefault(r => string.Equals(checkName, r.Name, StringComparison.Ordinal)); Assert.IsNotNull(registration, "HealthCheck should be registered"); IHealthCheck check = registration.Factory(provider); Assert.IsInstanceOfType(check, typeof(HttpEndpointHealthCheck)); return(((HttpEndpointHealthCheck)check).Parameters); }
private async Task <HealthReportEntry> RunCheckAsync(HealthCheckRegistration registration, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var scope = _scopeFactory.CreateAsyncScope(); await using (scope.ConfigureAwait(false)) { 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.Name); 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, tags: registration.Tags); 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: registration.FailureStatus, description: "A timeout occurred while running check.", duration: duration, exception: ex, data: null, tags: registration.Tags); 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: registration.FailureStatus, description: ex.Message, duration: duration, exception: ex, data: null, tags: registration.Tags); Log.HealthCheckError(_logger, registration, ex, duration); } finally { timeoutCancellationTokenSource?.Dispose(); } return(entry); } } }
private async Task <HealthReportEntry> RunCheckAsync(IServiceScope scope, HealthCheckRegistration registration, CacheableHealthChecksServiceOptions cacheOptionsValue, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); // 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 cacheKey = $"{cacheOptionsValue.CachePrefix}{registration.Name}"; if (memoryCache.TryGetValue(cacheKey, out HealthReportEntry entry)) { Log.HealthCheckFromCache(logger, registration, entry); Log.HealthCheckData(logger, registration, entry); } else { var cacheable = registration.Tags.Any(a => a == cacheOptionsValue.Tag); var optionsSnapshot = scope.ServiceProvider.GetService <IOptionsSnapshot <RegistrationOptions> >(); var healthCheck = registration.Factory(scope.ServiceProvider); var stopwatch = ValueStopwatch.StartNew(); var context = new HealthCheckContext { Registration = registration }; Log.HealthCheckBegin(logger, registration); 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(); if (cacheable) { entry = BuildAndCacheReportEntry(cacheKey, registration, cacheOptionsValue, optionsSnapshot, result, duration); } else { entry = new HealthReportEntry( status: result.Status, description: result.Description, duration: duration, exception: result.Exception, data: result.Data, tags: registration.Tags); } Log.HealthCheckEnd(logger, registration, entry, duration); Log.HealthCheckData(logger, registration, entry); } catch (OperationCanceledException ex) when(!cancellationToken.IsCancellationRequested) { var duration = stopwatch.GetElapsedTime(); if (cacheable && cacheOptionsValue.CacheExceptions) { entry = BuildAndCacheExceptionReport(cacheKey, registration, cacheOptionsValue, optionsSnapshot, ex, duration); } else { 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(); if (cacheable && cacheOptionsValue.CacheExceptions) { entry = BuildAndCacheExceptionReport(cacheKey, registration, cacheOptionsValue, optionsSnapshot, ex, duration); } else { 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); } }