Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 32 additions & 13 deletions src/Serilog.Sinks.InMemory/InMemorySink.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
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;
using Serilog.Events;

namespace Serilog.Sinks.InMemory
{
[DebuggerTypeProxy(typeof(InMemorySinkAdvDebugProxy))]
public class InMemorySink : ILogEventSink, IDisposable
{
private static readonly AsyncLocal<InMemorySink> LocalInstance = new AsyncLocal<InMemorySink>();

private ReadOnlyCollection<LogEvent>? _logEventsSnapshot;
private readonly List<LogEvent> _logEvents;
private readonly object _snapShotLock = new object();

public InMemorySink() : this(new List<LogEvent>())
public InMemorySink()
: this(new List<LogEvent>())
{
}

Expand All @@ -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<LogEvent> LogEvents => _logEvents.AsReadOnly();
public IEnumerable<LogEvent> LogEvents => GetLogEvents();

public void Dispose()
{
Expand All @@ -48,17 +51,33 @@ public virtual void Emit(LogEvent logEvent)
lock (_snapShotLock)
{
_logEvents.Add(logEvent);
_logEventsSnapshot = null;
}
}

public InMemorySink Snapshot()
private IEnumerable<LogEvent> 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<LogEvent, bool> predicate)
{
var currentLogEvents = GetLogEvents().Where(predicate).ToList();
return new InMemorySinkSnapshot(currentLogEvents);
}
}
}
28 changes: 28 additions & 0 deletions src/Serilog.Sinks.InMemory/InMemorySinkAdvDebugProxy.cs
Original file line number Diff line number Diff line change
@@ -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<DebugLogEvent>(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<string, LogEventPropertyValue> Properties => logEvent.Properties;

public Exception? Exception => logEvent.Exception;

public LogEvent OriginalLogEvent => logEvent;

public override string ToString() => Message;
}
}