Esempio n. 1
0
        public static HealthReportEntry TestaControllersInjection(string nomeAPI, IContainer container)
        {
            var mensagens = new List <string>();

            System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
            stopwatch.Start();
            var controllers = Assembly.Load(nomeAPI)
                              .GetTypes()
                              .Where(x => !string.IsNullOrEmpty(x.Namespace))
                              .Where(x => x.IsClass)
                              .Where(x => x.Name.Contains("Controller") && !x.Name.Contains("HealthCheck"))
                              .ToList();

            foreach (var controllerType in controllers)
            {
                try
                {
                    container.GetInstance(controllerType);
                }
                catch (Exception ex)
                {
                    mensagens.Add($"Erro ao instanciar controller: {controllerType.Name}; {ex.Message}");
                }
            }
            stopwatch.Stop();

            var entry = new HealthReportEntry(
                mensagens.Any() ? HealthStatus.Unhealthy : HealthStatus.Healthy,
                "", TimeSpan.FromMilliseconds(stopwatch.ElapsedMilliseconds), null, null);

            return(entry);
        }
        protected override Task DoSendAsync(string checkName, HealthReportEntry entry,
                                            CancellationToken cancellationToken)
        {
            var    serviceName = $"{HostingEnvironment.ApplicationName} ({Dns.GetHostName()})";
            string title       = entry.Status switch
            {
                HealthStatus.Unhealthy => $"Error in {serviceName}. Check: {checkName}",
                HealthStatus.Degraded => $"Check {checkName} in {serviceName} is degraded",
                HealthStatus.Healthy => $"Check {checkName} in {serviceName} is restored",
                _ => $"Unknown check {checkName} status {entry.Status}"
            };
            string summary = string.IsNullOrEmpty(entry.Description) ? "No description" : entry.Description;


            string text = $"{TelegramExtensions.TelegramRaw(title)}\n{TelegramExtensions.TelegramRaw(summary)}";

            if (entry.Status == HealthStatus.Unhealthy || entry.Status == HealthStatus.Degraded)
            {
                if (entry.Exception != null)
                {
                    text += $"\n`{entry.Exception}`";
                }
            }

            return(_telegramBotClient.SendTextMessageAsync(_chatId,
                                                           text, ParseMode.Markdown,
                                                           cancellationToken: cancellationToken));
        }
    }
Esempio n. 3
0
        public void BuildPrtgResponseObject_Healthy()
        {
            var healthReportEntry =
                new HealthReportEntry(HealthStatus.Healthy, null, TimeSpan.FromMilliseconds(10), null, null);
            var healthReportEntries = new Dictionary <string, HealthReportEntry> {
                { "test", healthReportEntry }
            };
            var healthReport = new HealthReport(healthReportEntries, TimeSpan.FromMilliseconds(15));

            var expected = new List <PrtgResponseChannelValueBase>
            {
                new PrtgResponseChannelValueTimeSpan {
                    Channel = "TotalDuration", Value = 15
                },
                new PrtgResponseChannelValueTimeSpan {
                    Channel = "test.Duration", Value = 10
                },
            };

            var actual = PrtgResponseWriter.BuildPrtgResponseObject(healthReport);

            actual.Error.Should().Be(0);
            actual.Text.Should().Be(PrtgResponse.DefaultText);
            actual.Result.Should().BeEquivalentTo(expected, config => config.RespectingRuntimeTypes());
        }
        public Task PublishAsync(HealthReport report, CancellationToken cancellationToken)
        {
            IServicePartition?partition = m_partitionAccessor.Value;

            if (partition == null)
            {
                m_logger.LogWarning(Tag.Create(), "Publisher run before partition provided");

                return(Task.CompletedTask);
            }

            partition.ReportPartitionHealth(new SfHealthInformation(SourceId, "Summary", ConvertStatus(report.Status)));

            foreach (KeyValuePair <string, HealthReportEntry> entryPair in report.Entries)
            {
                HealthReportEntry   entry = entryPair.Value;
                SfHealthInformation sfHealthInformation = new SfHealthInformation(SourceId, entryPair.Key, ConvertStatus(entry.Status))
                {
                    Description = CreateDescription(entry)
                };

                try
                {
                    partition.ReportPartitionHealth(sfHealthInformation);
                }
                catch (Exception exception)
                {
                    m_logger.LogError(Tag.Create(), exception, "Failed to report partition health");
                }
            }

            return(Task.CompletedTask);
        }
Esempio n. 5
0
        public HealthCheckResponse(HealthReportEntry report)
        {
            Status = report.Status.ToString();

            UserManagement       = GetStatus("UserManagement", report.Data);
            DatabaseConnectivity = GetStatus("Database", report.Data);
        }
Esempio n. 6
0
        public static string CreateHealthReportPlainText(string key, HealthReportEntry entry)
        {
            var entryOutput = new StringBuilder($"{key}: {entry.Status} | {entry.Duration}\n");

            if (entry.Tags?.Any() == true)
            {
                entryOutput.Append("-  Tags:");
                entryOutput.Append(string.Join(", ", entry.Tags));
                entryOutput.Append('\n');
            }

            if (!string.IsNullOrWhiteSpace(entry.Description))
            {
                entryOutput.Append($"-  Description: {entry.Description}\n\n");
            }

            if (entry.Exception != null)
            {
                entryOutput.Append($"-  Exception: {entry.Exception}\n\n");
            }

            if (entry.Data?.Count > 0)
            {
                entryOutput.Append("-  Data:\n");
                foreach (var keyValuePair in entry.Data)
                {
                    entryOutput.Append($"\t{keyValuePair.Key}: {keyValuePair.Value}");
                }
                entryOutput.Append('\n');
            }

            return(entryOutput.ToString());
        }
Esempio n. 7
0
        private void AssertHealtItem(MockServicePartition partition, string name, HealthReport report)
        {
            HealthReportEntry   entry = report.Entries[name];
            SfHealthInformation?info  = partition.HealthInformation.SingleOrDefault(h => string.Equals(h.Property, name, StringComparison.OrdinalIgnoreCase));

            Assert.IsNotNull(info, name);

            Assert.AreEqual(GetMachingState(entry.Status), info.HealthState, nameof(HealthReportEntry.Status));

            if (entry.Status == HealthStatus.Healthy)
            {
                Assert.AreEqual(info.Description, entry.Description, nameof(HealthReportEntry.Description));
            }
            else
            {
                StringAssert.Contains(info.Description, entry.Description, nameof(HealthReportEntry.Description));
                StringAssert.Contains(info.Description, entry.Exception.ToString(), nameof(HealthReportEntry.Exception));
                StringAssert.Contains(info.Description, entry.Duration.ToString(), nameof(HealthReportEntry.Duration));

                int index = 0;
                foreach (string tag in entry.Tags)
                {
                    StringAssert.Contains(info.Description, tag, nameof(HealthReportEntry.Tags) + index);
                    index++;
                }
            }
        }
Esempio n. 8
0
 public SerializableHealthCheckResultEntry(HealthReportEntry entry, string name)
 {
     Description = entry.Description;
     Duration    = entry.Duration;
     Exception   = entry.Exception?.ToString();
     Name        = name;
     Status      = entry.Status;
     Tags        = entry.Tags?.ToList();
 }
 public HealthReportEntryResult(HealthReportEntry entry)
 {
     Data        = entry.Data;
     Description = entry.Description;
     Duration    = entry.Duration;
     Exception   = entry.Exception;
     Tags        = entry.Tags;
     Status      = HealthReportResult <T> .GetHealthStatusString(entry.Status);
 }
Esempio n. 10
0
        public override Task <HealthReport> CheckHealthAsync(Func <HealthCheckRegistration, bool> predicate,
                                                             CancellationToken cancellationToken = new CancellationToken())
        {
            var entry      = new HealthReportEntry(_isHealthy ? HealthStatus.Healthy : HealthStatus.Unhealthy, "", TimeSpan.Zero, null, null);
            var dictionary = new Dictionary <string, HealthReportEntry>
            {
                { "test", entry }
            };

            return(Task.FromResult(new HealthReport(dictionary, TimeSpan.Zero)));
        }
Esempio n. 11
0
        public void BuildPrtgResponseObject_Unhealthy()
        {
            var healthReportEntry =
                new HealthReportEntry(HealthStatus.Unhealthy, "description", TimeSpan.Zero, new Exception("testException"), null);
            var healthReportEntries = new Dictionary <string, HealthReportEntry> {
                { "test", healthReportEntry }
            };
            var healthReport = new HealthReport(healthReportEntries, TimeSpan.Zero);

            var actual = PrtgResponseWriter.BuildPrtgResponseObject(healthReport);

            actual.Error.Should().Be(1);
            actual.Text.Should().BeEquivalentTo("test:\ndescription\nSystem.Exception: testException");
        }
Esempio n. 12
0
        private static string EntryDescription(HealthReportEntry entry)
        {
            if (!string.IsNullOrEmpty(entry.Description))
            {
                return(entry.Description);
            }

            return(entry.Status switch
            {
                HealthStatus.Healthy => $"OK - {entry.Duration.TotalSeconds:0.000}s",
                HealthStatus.Degraded => entry.Exception != null ? $"Warning - {entry.Exception.Message}" : "Warning",
                HealthStatus.Unhealthy => entry.Exception != null ? $"Failure - {entry.Exception.Message}" : "Failure",
                _ => entry.ToString(),
            });
Esempio n. 13
0
        public void BuildPrtgResponseObject_Unhealthy_ErrorText()
        {
            var healthReportEntry =
                new HealthReportEntry(HealthStatus.Unhealthy, null, TimeSpan.Zero, null, null);
            var healthReportEntries = new Dictionary <string, HealthReportEntry> {
                { "test", healthReportEntry }
            };
            var healthReport = new HealthReport(healthReportEntries, TimeSpan.Zero);

            var actual = PrtgResponseWriter.BuildPrtgResponseObject(healthReport);

            actual.Error.Should().Be(1);
            actual.Text.Should().BeEquivalentTo("test:\nUnhealthy");
        }
        private string CreateDescription(HealthReportEntry entry)
        {
            // Healthy reports won't be displayed and most of the checks will be healthy,
            // so we are creating a detailed description only for failed checks and avoiding allocations for healthy
            if (entry.Status == HealthStatus.Healthy)
            {
                return(entry.Description);
            }

            return(new StringBuilder()
                   .Append("Exception:").AppendLine(entry.Exception?.ToString())
                   .Append("Description:").AppendLine(entry.Description)
                   .Append("Duration:").AppendLine(entry.Duration.ToString())
                   .Append("Tags:").AppendLine(string.Join(",", entry.Tags))
                   .ToString());
        }
Esempio n. 15
0
        public ServiceHealthInfo Create(string key, HealthReportEntry healthReportEntry)
        {
            if (string.IsNullOrWhiteSpace(key))
            {
                throw new ArgumentNullException(nameof(key));
            }

            return(new ServiceHealthInfo
            {
                Key = key,
                Description = healthReportEntry.Description ?? string.Empty,
                Duration = healthReportEntry.Duration,
                Status = healthReportEntry.Status.ToString(),
                Error = healthReportEntry.Exception?.Message
            });
        }
Esempio n. 16
0
        private AvailabilityTelemetry GetAvailabilityTelemetry(string name, HealthReportEntry entry)
        {
            var availabilityTelemetry = new AvailabilityTelemetry
            {
                Timestamp = DateTimeOffset.UtcNow,

                Duration = entry.Duration,
                Success  = GetSuccessFromStatus(entry.Status),

                Name        = $"{_options.Value.TestNamePrefix}{name}",
                RunLocation = _options.Value.TestRunLocation,
                Message     = entry.Description
            };

            AddHealthReportEntryData(availabilityTelemetry, entry);

            return(availabilityTelemetry);
        }
        private AvailabilityTelemetry GetAvailabilityTelemetry(string name, HealthReportEntry entry)
        {
            var availabilityTelemetry = new AvailabilityTelemetry
            {
                Name      = name,
                Duration  = entry.Duration,
                Message   = entry.Description,
                Timestamp = DateTimeOffset.UtcNow,
                Success   = entry.Status == HealthStatus.Healthy
            };

            availabilityTelemetry.Properties.Add(nameof(entry.Status), entry.Status.ToString());

            foreach (var(key, value) in entry.Data)
            {
                availabilityTelemetry.Properties.Add(key, value?.ToString());
            }

            return(availabilityTelemetry);
        }
        protected override Task DoSendAsync(string checkName, HealthReportEntry entry,
                                            CancellationToken cancellationToken)
        {
            var    serviceName = $"{HostingEnvironment.ApplicationName} ({Dns.GetHostName()})";
            string title       = entry.Status switch
            {
                HealthStatus.Unhealthy => $"Error in {serviceName}. Check: {checkName}",
                HealthStatus.Degraded => $"Check {checkName} in {serviceName} is degraded",
                HealthStatus.Healthy => $"Check {checkName} in {serviceName} is restored",
                _ => $"Unknown check {checkName} status {entry.Status}"
            };
            string color = entry.Status switch
            {
                HealthStatus.Unhealthy => Options.UnHealthyColor,
                HealthStatus.Degraded => Options.DegradedColor,
                HealthStatus.Healthy => Options.HealthyColor,
                _ => ""
            };
            string summary  = string.IsNullOrEmpty(entry.Description) ? "No description" : entry.Description;
            var    sections = new List <Section>();

            if (entry.Status == HealthStatus.Unhealthy || entry.Status == HealthStatus.Degraded)
            {
                if (entry.Exception != null)
                {
                    sections.Add(new Section {
                        ActivityTitle = "Exception", ActivityText = $"```{entry.Exception}```"
                    });
                }
            }

            var client = new TeamsHookClient(_httpClientFactory.CreateClient());

            return(client.PostAsync(Options.WebHookUrl,
                                    new MessageCard {
                Title = title, Text = summary, Sections = sections, ThemeColor = color
            }));
        }
    }
}
        private SfHealthInformation BuildSfHealthInformation(string healthCheckName, HealthReportEntry reportEntry)
        {
            StringBuilder descriptionBuilder = m_stringBuilderPool.Get();

            if (!string.IsNullOrWhiteSpace(reportEntry.Description))
            {
                descriptionBuilder.Append("Description: ").Append(reportEntry.Description).AppendLine();
            }
            descriptionBuilder.Append("Duration: ").Append(reportEntry.Duration).Append('.').AppendLine();
            if (reportEntry.Exception != null)
            {
                descriptionBuilder.Append("Exception: ").Append(reportEntry.Exception).AppendLine();
            }

            string description = descriptionBuilder.ToString();

            m_stringBuilderPool.Return(descriptionBuilder);

            return(new SfHealthInformation(HealthReportSourceId, healthCheckName, ToSfHealthState(reportEntry.Status))
            {
                Description = description,
            });
        }
Esempio n. 20
0
        public async Task CheckHealthAsyncWithTimeout_IgnoreCheckIfCachedInputIsHealthy()
        {
            var entry = new HealthReportEntry(
                HealthStatus.Healthy,
                "timeout",
                TimeSpan.FromMilliseconds(1),
                null,
                null);
            var cachedItem = new Dictionary <string, object> {
                { "health", new HealthReport(
                      new Dictionary <string, HealthReportEntry> {
                        { "timeout", entry }
                    },
                      TimeSpan.FromMilliseconds(0)) }
            };

            var result = await new HealthController(
                new FakeHealthCheckService(false),
                null, null, new FakeMemoryCache(cachedItem))
                         .CheckHealthAsyncWithTimeout();

            Assert.AreEqual(HealthStatus.Healthy, result.Status);
        }
Esempio n. 21
0
        /// <summary>
        /// With timeout after 15 seconds
        /// </summary>
        /// <param name="timeoutTime">in milliseconds, defaults to 15 seconds</param>
        /// <returns>report</returns>
        internal async Task <HealthReport> CheckHealthAsyncWithTimeout(int timeoutTime = 15000)
        {
            const string healthControllerCacheKey = "health";

            try
            {
                if (_cache != null && _cache.TryGetValue(healthControllerCacheKey, out var objectHealthStatus) &&
                    objectHealthStatus is HealthReport healthStatus &&
                    healthStatus.Status == HealthStatus.Healthy)
                {
                    return(healthStatus);
                }

                var result = await _service.CheckHealthAsync().TimeoutAfter(timeoutTime);

                if (_cache != null && result.Status == HealthStatus.Healthy)
                {
                    _cache.Set(healthControllerCacheKey, result, new TimeSpan(0, 1, 30));
                }
                return(result);
            }
            catch (TimeoutException exception)
            {
                var entry = new HealthReportEntry(
                    HealthStatus.Unhealthy,
                    "timeout",
                    TimeSpan.FromMilliseconds(timeoutTime),
                    exception,
                    null);

                return(new HealthReport(
                           new Dictionary <string, HealthReportEntry> {
                    { "timeout", entry }
                },
                           TimeSpan.FromMilliseconds(timeoutTime)));
            }
        }
Esempio n. 22
0
        private HealthReportEntry BuildAndCacheReportEntry(string cacheKey, TimeSpan expiresIn, HealthStatus healthStatus,
                                                           string description, TimeSpan duration, Exception exception, IReadOnlyDictionary <string, object> healthData)
        {
            var expiresAt = DateTime.UtcNow.Add(expiresIn);

            var data = new Dictionary <string, object>(healthData)
            {
                {
                    "cached",
                    $"This response was resolved in {DateTime.UtcNow:R} and will remain in cache until {expiresAt:R}"
                }
            };

            var entry = new HealthReportEntry(
                status: healthStatus,
                description: description,
                duration: duration,
                exception: exception,
                data: data);

            memoryCache.Set(cacheKey, entry, expiresAt);

            return(entry);
        }
Esempio n. 23
0
        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);
            }
        }
        public async Task <HealthReport> CheckHealthAsync(
            // Func<HealthCheckRegistration, bool> predicate,
            IEnumerable <HealthCheckConfig> healthChecks,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            var entries = new Dictionary <string, HealthReportEntry>(StringComparer.OrdinalIgnoreCase);

            var totalTime = Stopwatch.StartNew();

            Log.HealthCheckProcessingBegin(_logger);

            foreach (var healthCheckConfig in healthChecks)
            {
                var healthCheck     = healthCheckConfig.HealthCheck;
                var healthCheckName = healthCheckConfig.Name ?? healthCheck.GetType().Name;

                /*
                 * if (predicate != null && !predicate(registration))
                 * {
                 *  continue;
                 * }
                 */

                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(healthCheckName)))
                {
                    var stopwatch = Stopwatch.StartNew();

                    Log.HealthCheckBegin(_logger, healthCheckName);

                    HealthReportEntry entry;
                    try
                    {
                        var context = new HealthCheckContext
                        {
                            Registration = new HealthCheckRegistration(
                                healthCheckName,
                                healthCheck,
                                null,
                                Enumerable.Empty <string>())
                        };

                        var result = await healthCheck.CheckHealthAsync(context, cancellationToken);

                        var duration = stopwatch.Elapsed;

                        entry = new HealthReportEntry(
                            status: result.Status,
                            description: result.Description,
                            duration: duration,
                            exception: result.Exception,
                            data: result.Data);

                        Log.HealthCheckEnd(_logger, healthCheckName, entry, duration);
                        Log.HealthCheckData(_logger, healthCheckName, entry);
                    }

                    // Allow cancellation to propagate.
                    catch (Exception ex) when(ex as OperationCanceledException == null)
                    {
                        var duration = stopwatch.Elapsed;

                        entry = new HealthReportEntry(
                            status: HealthStatus.Unhealthy,
                            description: ex.Message,
                            duration: duration,
                            exception: ex,
                            data: null);

                        Log.HealthCheckError(_logger, healthCheckName, ex, duration);
                    }

                    entries[healthCheckName] = entry;
                }
            }

            var totalElapsedTime = totalTime.Elapsed;
            var report           = new HealthReport(entries, totalElapsedTime);

            Log.HealthCheckProcessingEnd(_logger, report.Status, totalElapsedTime);
            return(report);
        }
 public static void HealthCheckData(ILogger logger, string healthCheckName, HealthReportEntry entry)
 {
     if (entry.Data.Count > 0 && logger.IsEnabled(LogLevel.Debug))
     {
         logger.Log(
             LogLevel.Debug,
             EventIds.HealthCheckData,
             new HealthCheckDataLogValue(healthCheckName, entry.Data),
             null,
             (state, ex) => state.ToString());
     }
 }
            public static void HealthCheckEnd(ILogger logger, string healthCheckName, HealthReportEntry entry, TimeSpan duration)
            {
                switch (entry.Status)
                {
                case HealthStatus.Healthy:
                    _healthCheckEndHealthy(logger, healthCheckName, duration.TotalMilliseconds, entry.Status, entry.Description, null);
                    break;

                case HealthStatus.Degraded:
                    _healthCheckEndDegraded(logger, healthCheckName, duration.TotalMilliseconds, entry.Status, entry.Description, null);
                    break;

                case HealthStatus.Unhealthy:
                    _healthCheckEndUnhealthy(logger, healthCheckName, duration.TotalMilliseconds, entry.Status, entry.Description, null);
                    break;
                }
            }
    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);
            }
        }
    }
#pragma warning restore SYSLIB1006

        public static void HealthCheckEnd(ILogger logger, HealthCheckRegistration registration, HealthReportEntry entry, TimeSpan duration)
        {
            switch (entry.Status)
            {
            case HealthStatus.Healthy:
                HealthCheckEndHealthy(logger, registration.Name, entry.Status, duration.TotalMilliseconds, entry.Description);
                break;

            case HealthStatus.Degraded:
                HealthCheckEndDegraded(logger, registration.Name, entry.Status, duration.TotalMilliseconds, entry.Description, entry.Exception);
                break;

            case HealthStatus.Unhealthy:
                HealthCheckEndUnhealthy(logger, registration.Name, entry.Status, duration.TotalMilliseconds, entry.Description, entry.Exception);
                break;
            }
        }
Esempio n. 29
0
        public override async Task <HealthReport> CheckHealthAsync(Func <HealthCheckRegistration, bool> predicate, CancellationToken cancellationToken = default)
        {
            var registrations     = baseOptions.Value.Registrations;
            var cacheOptionsValue = cacheOptions.Value;

            using (var scope = scopeFactory.CreateScope())
            {
                var context         = new HealthCheckContext();
                var entries         = new Dictionary <string, HealthReportEntry>(StringComparer.OrdinalIgnoreCase);
                var optionsSnapshot = scope.ServiceProvider.GetService <IOptionsSnapshot <RegistrationOptions> >();

                var totalTime = ValueStopwatch.StartNew();
                Log.HealthCheckProcessingBegin(logger);

                foreach (var registration in registrations)
                {
                    if (predicate != null && !predicate(registration))
                    {
                        continue;
                    }

                    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 cacheable = registration.Tags.Any(a => a == cacheOptionsValue.Tag);
                        var cacheKey  = $"{cacheOptionsValue.CachePrefix}{registration.Name}";

                        if (memoryCache.TryGetValue <HealthReportEntry>(cacheKey, out var cachedEntry))
                        {
                            Log.HealthCheckFromCache(logger, registration, cachedEntry);
                            Log.HealthCheckData(logger, registration, cachedEntry);
                            entries[registration.Name] = cachedEntry;
                            continue;
                        }

                        var healthCheck = registration.Factory(scope.ServiceProvider);

                        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();

                            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);
                            }

                            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();

                            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);
                        }

                        entries[registration.Name] = entry;
                    }
                }

                var totalElapsedTime = totalTime.GetElapsedTime();
                var healthReport     = new HealthReport(entries, totalElapsedTime);
                Log.HealthCheckProcessingEnd(logger, healthReport.Status, totalElapsedTime);
                return(healthReport);
            }
        }
Esempio n. 30
0
 public static void HealthCheckFromCache(ILogger logger, HealthCheckRegistration registration, HealthReportEntry entry)
 {
     healthCheckFromCache(logger, registration.Name, null);
 }