using Serilog.Events; using LogViewer.Core; using Microsoft.Extensions.Logging; using Serilog.Core; using System.Globalization; namespace Serilog.Sinks.LogView.Core; public class DataStoreLoggerSink( Func dataStoreProvider, Func? getCurrentConfig = null, IFormatProvider? formatProvider = null) : ILogEventSink { protected Func DataStoreProvider { get; } = dataStoreProvider; private IFormatProvider? FormatProvider { get; } = formatProvider; private Func? GetCurrentConfig { get; } = getCurrentConfig; public void Emit(LogEvent logEvent) { LogLevel logLevel = logEvent.Level switch { LogEventLevel.Verbose => LogLevel.Trace, LogEventLevel.Debug => LogLevel.Debug, LogEventLevel.Warning => LogLevel.Warning, LogEventLevel.Error => LogLevel.Error, LogEventLevel.Fatal => LogLevel.Critical, _ => LogLevel.Information }; DataStoreLoggerConfiguration config = GetCurrentConfig?.Invoke() ?? new DataStoreLoggerConfiguration(); EventId eventId = EventIdFactory(logEvent); if (eventId.Id == 0 && config.EventId != 0) eventId = config.EventId; string message = logEvent.RenderMessage(FormatProvider); string exception = logEvent.Exception?.Message ?? (logEvent.Level >= LogEventLevel.Error ? message : string.Empty); LogEntryColor color = config.Colors[logLevel]; AddLogEntry(logLevel, eventId, message, exception, color); } protected virtual void AddLogEntry(LogLevel logLevel, EventId eventId, string message, string exception, LogEntryColor color) { ILogDataStore? dataStore = DataStoreProvider.Invoke(); // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract if (dataStore == null) return; // app is shutting down dataStore.AddEntry(new() { Timestamp = DateTime.UtcNow, LogLevel = logLevel, EventId = eventId, State = message, Exception = exception, Color = color }); } private static EventId EventIdFactory(LogEvent logEvent) { EventId eventId; if (!logEvent.Properties.TryGetValue("EventId", out LogEventPropertyValue? src)) return new(); int? id = null; string? eventName = null; // ref: https://stackoverflow.com/a/56722516 StructureValue? value = src as StructureValue; LogEventProperty? idProperty = value!.Properties.FirstOrDefault(x => x.Name.Equals("Id", StringComparison.Ordinal)); if (idProperty is not null) id = int.Parse(idProperty.Value.ToString(),CultureInfo.InvariantCulture); LogEventProperty? nameProperty = value.Properties.FirstOrDefault(x => x.Name.Equals("Name", StringComparison.Ordinal)); if (nameProperty is not null) eventName = nameProperty.Value.ToString().Trim('"'); eventId = new EventId(id ?? 0, eventName ?? string.Empty); return eventId; } }