I have a Serilog enricher for getting the currently logged in UserId if available which is initialized in the Logger. I also have a custom Sink that handles logging the log entry to the DB via an Entity Framework DbContext. In my Log table I have a column reserved for the UserId. I have working code to get the User Id from the logEvent Properties, however while Serilog accepts values as object, it seems to only want to ever reveal those values as string. I would like to get the UserId (if available) as it's original expected type. (int?)
The following code works, but I'm left wondering if there is a better way to integrate enricher properties, and other context properties that I might add and want to store separately, or at least with different formatting than Serilog's default formatting:
void ILogEventSink.Emit(LogEvent logEvent)
{
if (logEvent is null) throw new ArgumentNullException(nameof(logEvent));
using (var contextScope = ContextScopeFactory.Create(DbContextScopeOption.ForceCreateNew))
{
string? value = logEvent.Properties.ContainsKey(UserIdEnricher.PropertyName)
? logEvent.Properties[UserIdEnricher.PropertyName].ToString()
: null;
int? userId = int.TryParse(value, out var intVal) ? (int?)intVal : null;
value = logEvent.Properties.ContainsKey(AppIdEnricher.PropertyName)
? logEvent.Properties[AppIdEnricher.PropertyName].ToString()
: null;
AppIds appId = Enum.TryParse<AppIds>(value, out AppIds val) ? val : AppIds.None;
Log log = logEvent.Exception == null
? LoggingRepository.CreateLog(userId, appId, logEvent.Level)
: LoggingRepository.CreateLog(logEvent.Exception, userId, appId, logEvent.Level);
log.Message = logEvent.RenderMessage();
contextScope.SaveChanges();
}
}
One aspect of this logging is that I would like to support logging a JSON object (Not logging the message as JSON, but rather having a column containing optional JSON data such as a serialized object in the event of an exception.) While I can send a JSON string to the Log.Information etc. call, if I want to extract that Property within my Sink, the resulting value is no longer JSON as it applies its own formatting. I've seen examples where if you want to prevent formatting within a message you can use the @ prior to the property name, but I'm left wondering if anything like that is available within a Sink to access a property, or if possibly there is some better way than properties to get unadulterated data from a Log.* call through to the Sink.