diff --git a/src/Serilog.Sinks.InMemory/InMemorySink.cs b/src/Serilog.Sinks.InMemory/InMemorySink.cs index e6c8ca9..dece963 100644 --- a/src/Serilog.Sinks.InMemory/InMemorySink.cs +++ b/src/Serilog.Sinks.InMemory/InMemorySink.cs @@ -1,5 +1,9 @@ -using System; +#nullable enable + +using System; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; using System.Linq; using System.Threading; using Serilog.Core; @@ -7,14 +11,17 @@ namespace Serilog.Sinks.InMemory { + [DebuggerTypeProxy(typeof(InMemorySinkAdvDebugProxy))] public class InMemorySink : ILogEventSink, IDisposable { private static readonly AsyncLocal LocalInstance = new AsyncLocal(); + private ReadOnlyCollection? _logEventsSnapshot; private readonly List _logEvents; private readonly object _snapShotLock = new object(); - public InMemorySink() : this(new List()) + public InMemorySink() + : this(new List()) { } @@ -27,16 +34,12 @@ public static InMemorySink Instance { get { - if (LocalInstance.Value == null) - { - LocalInstance.Value = new InMemorySink(); - } - + LocalInstance.Value ??= new InMemorySink(); return LocalInstance.Value; } } - public IEnumerable LogEvents => _logEvents.AsReadOnly(); + public IEnumerable LogEvents => GetLogEvents(); public void Dispose() { @@ -48,17 +51,33 @@ public virtual void Emit(LogEvent logEvent) lock (_snapShotLock) { _logEvents.Add(logEvent); + _logEventsSnapshot = null; } } - public InMemorySink Snapshot() + private IEnumerable GetLogEvents() { - lock (_snapShotLock) + if (_logEventsSnapshot == null) { - var currentLogEvents = _logEvents.AsReadOnly().ToList(); - - return new InMemorySinkSnapshot(currentLogEvents); + lock (_snapShotLock) + { + _logEventsSnapshot ??= _logEvents.AsReadOnly(); + } } + + return _logEventsSnapshot; + } + + public InMemorySink Snapshot() + { + var currentLogEvents = GetLogEvents().ToList(); + return new InMemorySinkSnapshot(currentLogEvents); + } + + public InMemorySink Snapshot(Func predicate) + { + var currentLogEvents = GetLogEvents().Where(predicate).ToList(); + return new InMemorySinkSnapshot(currentLogEvents); } } } \ No newline at end of file diff --git a/src/Serilog.Sinks.InMemory/InMemorySinkAdvDebugProxy.cs b/src/Serilog.Sinks.InMemory/InMemorySinkAdvDebugProxy.cs new file mode 100644 index 0000000..d1533d5 --- /dev/null +++ b/src/Serilog.Sinks.InMemory/InMemorySinkAdvDebugProxy.cs @@ -0,0 +1,28 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Linq; +using Serilog.Events; + +namespace Serilog.Sinks.InMemory +{ + internal sealed class InMemorySinkAdvDebugProxy(InMemorySink sink) + : List(sink.LogEvents.Select(logEvent => new DebugLogEvent(logEvent))); + + internal sealed class DebugLogEvent(LogEvent logEvent) + { + public LogEventLevel Level => logEvent.Level; + public string Message => logEvent.RenderMessage(); + + public string MessageTemplate => logEvent.MessageTemplate.ToString(); + + public IReadOnlyDictionary Properties => logEvent.Properties; + + public Exception? Exception => logEvent.Exception; + + public LogEvent OriginalLogEvent => logEvent; + + public override string ToString() => Message; + } +} \ No newline at end of file