using Serilog.Core; using Serilog.Events; using System.Collections.Concurrent; using System.Globalization; namespace ErsatzTV.Core; public class InMemorySink : ILogEventSink { private readonly ConcurrentDictionary> _logs = new(); public void Emit(LogEvent logEvent) { if (logEvent.Properties.TryGetValue(InMemoryLogService.CorrelationIdKey, out var correlationIdValue) && correlationIdValue is ScalarValue { Value: Guid correlationId }) { ConcurrentQueue logQueue = _logs.GetOrAdd(correlationId, _ => new ConcurrentQueue()); using (var writer = new StringWriter()) { writer.Write($"[{logEvent.Timestamp:HH:mm:ss} {logEvent.Level}] "); logEvent.RenderMessage(writer, CultureInfo.CurrentCulture); if (logEvent.Exception != null) { writer.WriteLine(); writer.Write(logEvent.Exception); } logQueue.Enqueue(writer.ToString()); } while (logQueue.Count > 100) { logQueue.TryDequeue(out _); } } } public IEnumerable GetLogs(Guid correlationId) { _logs.TryGetValue(correlationId, out ConcurrentQueue logs); return logs ?? Enumerable.Empty(); } public void ClearLogs(Guid correlationId) { _logs.TryRemove(correlationId, out _); } } public class InMemoryLogService { public InMemorySink Sink { get; } = new(); public static readonly string CorrelationIdKey = "CorrelationId"; }