< Summary

Information
Class: Elsa.Diagnostics.StructuredLogs.Dashboard.StructuredLogsDashboardContributor
Assembly: Elsa.Diagnostics.StructuredLogs.Dashboard
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Diagnostics.StructuredLogs.Dashboard/Dashboard/StructuredLogsDashboardContributor.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 59
Coverable lines: 59
Total lines: 94
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 12
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
get_Id()100%210%
get_Order()100%210%
GetOverviewAsync()100%210%
GetFindingsAsync()0%110100%
GetSummaryAsync()100%210%
Finding(...)100%210%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Diagnostics.StructuredLogs.Dashboard/Dashboard/StructuredLogsDashboardContributor.cs

#LineLine coverage
 1using Elsa.Dashboard.Abstractions.Contracts;
 2using Elsa.Dashboard.Abstractions.Models;
 3using Elsa.Diagnostics.StructuredLogs.Contracts;
 4using Elsa.Diagnostics.StructuredLogs.Models;
 5using JetBrains.Annotations;
 6
 7// ReSharper disable once CheckNamespace
 8namespace Elsa.Diagnostics.StructuredLogs.Dashboard;
 9
 10/// <inheritdoc />
 11[UsedImplicitly]
 012public class StructuredLogsDashboardContributor(
 013    IStructuredLogProvider provider,
 014    IEnumerable<IStructuredLogStorageDiagnostics> storageDiagnostics) : IDashboardContributor
 15{
 016    public string Id => "diagnostics.structured-logs";
 17
 018    public int Order => 300;
 19
 20    public async ValueTask<DashboardOverviewContribution?> GetOverviewAsync(DashboardContext context)
 21    {
 022        var summary = await GetSummaryAsync(context.Range, context.CancellationToken);
 023        return new()
 024        {
 025            Diagnostics = new()
 026            {
 027                StructuredLogs = summary
 028            }
 029        };
 030    }
 31
 32    public async ValueTask<IReadOnlyCollection<DashboardFinding>> GetFindingsAsync(DashboardContext context)
 33    {
 034        var summary = await GetSummaryAsync(context.Range, context.CancellationToken);
 035        var findings = new List<DashboardFinding>();
 36
 037        if (summary.Capability.Status == DashboardCapabilityStatus.Unauthorized.Status)
 038            findings.Add(Finding("structured-log-unauthorized", DashboardFindingSeverity.Warning, "Structured log dashbo
 039        else if (summary.Capability.Status == DashboardCapabilityStatus.Unavailable.Status)
 040            findings.Add(Finding("structured-log-unavailable", DashboardFindingSeverity.Warning, "Structured log dashboa
 41
 042        if (summary.StaleSourceCount > 0)
 043            findings.Add(Finding("structured-log-stale-sources", DashboardFindingSeverity.Warning, $"{summary.StaleSourc
 044        if (summary.DroppedWriteCount > 0)
 045            findings.Add(Finding("structured-log-dropped-writes", DashboardFindingSeverity.Error, "Structured log storag
 046        if (summary.RecentErrorOrCriticalCount > 0)
 047            findings.Add(Finding("structured-log-errors", DashboardFindingSeverity.Error, $"{summary.RecentErrorOrCritic
 48
 049        return findings;
 050    }
 51
 52    private async Task<DashboardStructuredLogSummary> GetSummaryAsync(DashboardRange range, CancellationToken cancellati
 53    {
 54        try
 55        {
 056            var sources = await provider.ListSourcesAsync(cancellationToken);
 057            var recentErrors = await provider.GetRecentAsync(new()
 058            {
 059                Levels = [StructuredLogLevel.Error, StructuredLogLevel.Critical],
 060                From = range.From,
 061                To = range.To,
 062                Take = 1000
 063            }, cancellationToken);
 64
 065            return new()
 066            {
 067                Capability = DashboardCapabilityStatus.Available,
 068                SourceCount = sources.Count,
 069                StaleSourceCount = sources.Count(x => x.Status == StructuredLogSourceStatus.Stale || x.Status == Structu
 070                RecentErrorOrCriticalCount = recentErrors.Items.Count,
 071                DroppedWriteCount = storageDiagnostics.Aggregate(0L, (total, x) => checked(total + x.DroppedWriteCount))
 072                DroppedEventCount = recentErrors.DroppedEvents
 073            };
 74        }
 075        catch (UnauthorizedAccessException)
 76        {
 077            return new() { Capability = new(DashboardCapabilityStatus.Unauthorized.Status, "No access to structured logs
 78        }
 079        catch (Exception e) when (e is not OperationCanceledException)
 80        {
 081            return new() { Capability = new(DashboardCapabilityStatus.Unavailable.Status, "Structured log summary is una
 82        }
 083    }
 84
 085    private static DashboardFinding Finding(string id, string severity, string message, string? targetKind, string? targ
 086    {
 087        Id = id,
 088        Severity = severity,
 089        Message = message,
 090        TargetKind = targetKind,
 091        Target = target,
 092        Priority = priority
 093    };
 94}