< Summary

Information
Class: Elsa.Diagnostics.ConsoleLogs.Services.ConsoleLogContextAccessor
Assembly: Elsa.Diagnostics.ConsoleLogs
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogContextAccessor.cs
Line coverage
89%
Covered lines: 25
Uncovered lines: 3
Coverable lines: 28
Total lines: 67
Line coverage: 89.2%
Branch coverage
81%
Covered branches: 13
Total branches: 16
Branch coverage: 81.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
get_Instance()100%11100%
.ctor()100%11100%
GetMetadata()100%66100%
PushMetadata(...)75%8881.81%
PushWorkflowInstanceId(...)100%11100%
get_Metadata()100%11100%
.ctor(...)100%11100%
Dispose()50%2280%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Diagnostics.ConsoleLogs/Services/ConsoleLogContextAccessor.cs

#LineLine coverage
 1namespace Elsa.Diagnostics.ConsoleLogs.Services;
 2
 3/// <summary>
 4/// Ambient console log context backed by the current async execution context.
 5/// </summary>
 6public sealed class ConsoleLogContextAccessor : IConsoleLogContextAccessor, ConsoleLogStreaming.Core.IConsoleLogMetadata
 7{
 18    private static readonly AsyncLocal<MetadataFrame?> CurrentFrame = new();
 19    private static readonly IReadOnlyDictionary<string, string> Empty = new Dictionary<string, string>();
 10
 11    /// <summary>
 12    /// Gets the process-wide Elsa console log context accessor.
 13    /// </summary>
 1914    public static ConsoleLogContextAccessor Instance { get; } = new();
 15
 116    private ConsoleLogContextAccessor()
 17    {
 118    }
 19
 20    /// <inheritdoc />
 21    public IReadOnlyDictionary<string, string> GetMetadata()
 22    {
 4623        var metadata = CurrentFrame.Value?.Metadata;
 4624        return metadata == null || metadata.Count == 0
 4625            ? Empty
 4626            : new Dictionary<string, string>(metadata, StringComparer.OrdinalIgnoreCase);
 27    }
 28
 29    /// <inheritdoc />
 30    public IDisposable PushMetadata(string key, string value)
 31    {
 5332        if (string.IsNullOrWhiteSpace(key))
 033            throw new ArgumentException("A metadata key is required.", nameof(key));
 34
 5335        if (string.IsNullOrWhiteSpace(value))
 036            throw new ArgumentException("A metadata value is required.", nameof(value));
 37
 5338        var previous = CurrentFrame.Value;
 5339        var metadata = previous?.Metadata != null
 5340            ? new Dictionary<string, string>(previous.Metadata, StringComparer.OrdinalIgnoreCase)
 5341            : new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
 42
 5343        metadata[key] = value;
 5344        CurrentFrame.Value = new(metadata);
 5345        return new MetadataScope(previous);
 46    }
 47
 48    /// <inheritdoc />
 49    public IDisposable PushWorkflowInstanceId(string workflowInstanceId) =>
 2450        PushMetadata(ConsoleLogMetadataKeys.WorkflowInstanceId, workflowInstanceId);
 51
 13052    private sealed record MetadataFrame(IReadOnlyDictionary<string, string> Metadata);
 53
 5354    private sealed class MetadataScope(MetadataFrame? previous) : IDisposable
 55    {
 56        private bool _disposed;
 57
 58        public void Dispose()
 59        {
 5360            if (_disposed)
 061                return;
 62
 5363            CurrentFrame.Value = previous;
 5364            _disposed = true;
 5365        }
 66    }
 67}