| | | 1 | | using Elsa.Dashboard.Abstractions.Contracts; |
| | | 2 | | using Elsa.Dashboard.Abstractions.Models; |
| | | 3 | | using Elsa.Diagnostics.StructuredLogs.Contracts; |
| | | 4 | | using Elsa.Diagnostics.StructuredLogs.Models; |
| | | 5 | | |
| | | 6 | | namespace Elsa.Diagnostics.StructuredLogs.Dashboard; |
| | | 7 | | |
| | 0 | 8 | | public class StructuredLogsDashboardContributor( |
| | 0 | 9 | | IStructuredLogProvider provider, |
| | 0 | 10 | | IEnumerable<IStructuredLogStorageDiagnostics> storageDiagnostics) : IDashboardContributor |
| | | 11 | | { |
| | 0 | 12 | | public string Id => "diagnostics.structured-logs"; |
| | | 13 | | |
| | 0 | 14 | | public int Order => 300; |
| | | 15 | | |
| | | 16 | | public async ValueTask<DashboardOverviewContribution?> GetOverviewAsync(DashboardContext context) |
| | | 17 | | { |
| | 0 | 18 | | var summary = await GetSummaryAsync(context.Range, context.CancellationToken); |
| | 0 | 19 | | return new() |
| | 0 | 20 | | { |
| | 0 | 21 | | Diagnostics = new() |
| | 0 | 22 | | { |
| | 0 | 23 | | StructuredLogs = summary |
| | 0 | 24 | | } |
| | 0 | 25 | | }; |
| | 0 | 26 | | } |
| | | 27 | | |
| | | 28 | | public async ValueTask<IReadOnlyCollection<DashboardFinding>> GetFindingsAsync(DashboardContext context) |
| | | 29 | | { |
| | 0 | 30 | | var summary = await GetSummaryAsync(context.Range, context.CancellationToken); |
| | 0 | 31 | | var findings = new List<DashboardFinding>(); |
| | | 32 | | |
| | 0 | 33 | | if (summary.Capability.Status == DashboardCapabilityStatus.Unauthorized.Status) |
| | 0 | 34 | | findings.Add(Finding("structured-log-unauthorized", DashboardFindingSeverity.Warning, "Structured log dashbo |
| | 0 | 35 | | else if (summary.Capability.Status == DashboardCapabilityStatus.Unavailable.Status) |
| | 0 | 36 | | findings.Add(Finding("structured-log-unavailable", DashboardFindingSeverity.Warning, "Structured log dashboa |
| | | 37 | | |
| | 0 | 38 | | if (summary.StaleSourceCount > 0) |
| | 0 | 39 | | findings.Add(Finding("structured-log-stale-sources", DashboardFindingSeverity.Warning, $"{summary.StaleSourc |
| | 0 | 40 | | if (summary.DroppedWriteCount > 0) |
| | 0 | 41 | | findings.Add(Finding("structured-log-dropped-writes", DashboardFindingSeverity.Error, "Structured log storag |
| | 0 | 42 | | if (summary.RecentErrorOrCriticalCount > 0) |
| | 0 | 43 | | findings.Add(Finding("structured-log-errors", DashboardFindingSeverity.Error, $"{summary.RecentErrorOrCritic |
| | | 44 | | |
| | 0 | 45 | | return findings; |
| | 0 | 46 | | } |
| | | 47 | | |
| | | 48 | | private async Task<DashboardStructuredLogSummary> GetSummaryAsync(DashboardRange range, CancellationToken cancellati |
| | | 49 | | { |
| | | 50 | | try |
| | | 51 | | { |
| | 0 | 52 | | var sources = await provider.ListSourcesAsync(cancellationToken); |
| | 0 | 53 | | var recentErrors = await provider.GetRecentAsync(new() |
| | 0 | 54 | | { |
| | 0 | 55 | | Levels = [StructuredLogLevel.Error, StructuredLogLevel.Critical], |
| | 0 | 56 | | From = range.From, |
| | 0 | 57 | | To = range.To, |
| | 0 | 58 | | Take = 1000 |
| | 0 | 59 | | }, cancellationToken); |
| | | 60 | | |
| | 0 | 61 | | return new() |
| | 0 | 62 | | { |
| | 0 | 63 | | Capability = DashboardCapabilityStatus.Available, |
| | 0 | 64 | | SourceCount = sources.Count, |
| | 0 | 65 | | StaleSourceCount = sources.Count(x => x.Status == StructuredLogSourceStatus.Stale || x.Status == Structu |
| | 0 | 66 | | RecentErrorOrCriticalCount = recentErrors.Items.Count, |
| | 0 | 67 | | DroppedWriteCount = storageDiagnostics.Aggregate(0L, (total, x) => checked(total + x.DroppedWriteCount)) |
| | 0 | 68 | | DroppedEventCount = recentErrors.DroppedEvents |
| | 0 | 69 | | }; |
| | | 70 | | } |
| | 0 | 71 | | catch (UnauthorizedAccessException) |
| | | 72 | | { |
| | 0 | 73 | | return new() { Capability = new(DashboardCapabilityStatus.Unauthorized.Status, "No access to structured logs |
| | | 74 | | } |
| | 0 | 75 | | catch (Exception e) when (e is not OperationCanceledException) |
| | | 76 | | { |
| | 0 | 77 | | return new() { Capability = new(DashboardCapabilityStatus.Unavailable.Status, "Structured log summary is una |
| | | 78 | | } |
| | 0 | 79 | | } |
| | | 80 | | |
| | 0 | 81 | | private static DashboardFinding Finding(string id, string severity, string message, string? targetKind, string? targ |
| | 0 | 82 | | { |
| | 0 | 83 | | Id = id, |
| | 0 | 84 | | Severity = severity, |
| | 0 | 85 | | Message = message, |
| | 0 | 86 | | TargetKind = targetKind, |
| | 0 | 87 | | Target = target, |
| | 0 | 88 | | Priority = priority |
| | 0 | 89 | | }; |
| | | 90 | | } |