| | | 1 | | using ConsoleLogStreaming.Core; |
| | | 2 | | |
| | | 3 | | namespace Elsa.Diagnostics.ConsoleLogs.Services; |
| | | 4 | | |
| | 9 | 5 | | internal sealed class ElsaConsoleLogProvider( |
| | 9 | 6 | | IConsoleLogProvider inner, |
| | 9 | 7 | | IConsoleLogContextAccessor contextAccessor, |
| | 9 | 8 | | ElsaConsoleLogRecentBuffer recentBuffer) : IConsoleLogProvider, IDisposable, IAsyncDisposable |
| | | 9 | | { |
| | 1 | 10 | | private static readonly IReadOnlyDictionary<string, string> EmptyMetadataFilter = new Dictionary<string, string>(); |
| | | 11 | | |
| | | 12 | | public ValueTask PublishAsync(ConsoleLogLine line, CancellationToken cancellationToken = default) |
| | | 13 | | { |
| | 7 | 14 | | var enrichedLine = Enrich(line); |
| | 7 | 15 | | recentBuffer.Add(enrichedLine); |
| | 7 | 16 | | return inner.PublishAsync(enrichedLine, cancellationToken); |
| | | 17 | | } |
| | | 18 | | |
| | | 19 | | public async ValueTask<RecentConsoleLogsResult> GetRecentAsync(ConsoleLogFilter filter, CancellationToken cancellati |
| | | 20 | | { |
| | 7 | 21 | | if (!HasMetadataFilter(filter)) |
| | 2 | 22 | | return await inner.GetRecentAsync(filter, cancellationToken); |
| | | 23 | | |
| | 5 | 24 | | var result = await inner.GetRecentAsync(filter with |
| | 5 | 25 | | { |
| | 5 | 26 | | Metadata = EmptyMetadataFilter |
| | 5 | 27 | | }, cancellationToken); |
| | 5 | 28 | | var items = recentBuffer.Query(filter); |
| | | 29 | | |
| | 5 | 30 | | return result with { Items = items }; |
| | 7 | 31 | | } |
| | | 32 | | |
| | | 33 | | public async IAsyncEnumerable<ConsoleLogStreamingItem> SubscribeAsync( |
| | | 34 | | ConsoleLogFilter filter, |
| | | 35 | | [EnumeratorCancellation] CancellationToken cancellationToken = default) |
| | | 36 | | { |
| | 1 | 37 | | if (!HasMetadataFilter(filter)) |
| | | 38 | | { |
| | 0 | 39 | | await foreach (var item in inner.SubscribeAsync(filter, cancellationToken).ConfigureAwait(false)) |
| | 0 | 40 | | yield return item; |
| | | 41 | | |
| | 0 | 42 | | yield break; |
| | | 43 | | } |
| | | 44 | | |
| | 6 | 45 | | await foreach (var item in inner.SubscribeAsync(filter with { Metadata = EmptyMetadataFilter }, cancellationToke |
| | | 46 | | { |
| | 2 | 47 | | if (item.Line != null && !MatchesMetadata(item.Line, filter.Metadata)) |
| | | 48 | | continue; |
| | | 49 | | |
| | 1 | 50 | | yield return item; |
| | | 51 | | } |
| | 1 | 52 | | } |
| | | 53 | | |
| | | 54 | | public ValueTask<IReadOnlyCollection<ConsoleLogSource>> ListSourcesAsync(CancellationToken cancellationToken = defau |
| | | 55 | | { |
| | 0 | 56 | | return inner.ListSourcesAsync(cancellationToken); |
| | | 57 | | } |
| | | 58 | | |
| | | 59 | | public void Dispose() |
| | | 60 | | { |
| | 0 | 61 | | switch (inner) |
| | | 62 | | { |
| | | 63 | | case IDisposable disposable: |
| | 0 | 64 | | disposable.Dispose(); |
| | 0 | 65 | | break; |
| | | 66 | | case IAsyncDisposable asyncDisposable: |
| | 0 | 67 | | asyncDisposable.DisposeAsync().AsTask().GetAwaiter().GetResult(); |
| | | 68 | | break; |
| | | 69 | | } |
| | 0 | 70 | | } |
| | | 71 | | |
| | | 72 | | public async ValueTask DisposeAsync() |
| | | 73 | | { |
| | 9 | 74 | | switch (inner) |
| | | 75 | | { |
| | | 76 | | case IAsyncDisposable asyncDisposable: |
| | 0 | 77 | | await asyncDisposable.DisposeAsync(); |
| | 0 | 78 | | break; |
| | | 79 | | case IDisposable disposable: |
| | 0 | 80 | | disposable.Dispose(); |
| | | 81 | | break; |
| | | 82 | | } |
| | 9 | 83 | | } |
| | | 84 | | |
| | | 85 | | private ConsoleLogLine Enrich(ConsoleLogLine line) |
| | | 86 | | { |
| | 7 | 87 | | var ambientMetadata = contextAccessor.GetMetadata(); |
| | 7 | 88 | | if (ambientMetadata.Count == 0) |
| | 4 | 89 | | return line; |
| | | 90 | | |
| | 3 | 91 | | var metadata = new Dictionary<string, string>(line.Metadata, StringComparer.OrdinalIgnoreCase); |
| | 12 | 92 | | foreach (var item in ambientMetadata) |
| | 3 | 93 | | metadata[item.Key] = item.Value; |
| | | 94 | | |
| | 3 | 95 | | return line with { Metadata = metadata }; |
| | | 96 | | } |
| | | 97 | | |
| | 8 | 98 | | private static bool HasMetadataFilter(ConsoleLogFilter filter) => filter.Metadata.Count > 0; |
| | | 99 | | |
| | | 100 | | private static bool MatchesMetadata(ConsoleLogLine line, IReadOnlyDictionary<string, string> metadata) |
| | | 101 | | { |
| | 7 | 102 | | foreach (var (key, value) in metadata) |
| | | 103 | | { |
| | 2 | 104 | | if (!line.Metadata.TryGetValue(key, out var candidate) || !string.Equals(candidate, value, StringComparison. |
| | 1 | 105 | | return false; |
| | | 106 | | } |
| | | 107 | | |
| | 1 | 108 | | return true; |
| | 1 | 109 | | } |
| | | 110 | | } |