static void Main(string[] args) { // Log configuration should be setup on client app side, so I left this here. // I don't like an idea to add Serilog packages to this project, but I see no other way at the moment. // Every so called sink (ColoredConsole, File, etc) is a standalone package, so configuration must be done here. // There is another aproach - a congig file. If we go with config file, then probably we can avoid issue above. /* we cannot configure Serilog inside client app cuz we are going to hide log provider from end users behind our wrapper * var cfg = new LoggerConfiguration() * .Enrich.FromLogContext() * .MinimumLevel.Debug() * .WriteTo.ColoredConsole( * LogEventLevel.Verbose, * "{NewLine}{Timestamp:HH:mm:ss} [{Level}] ({CorrelationToken}) {Message}{NewLine}{Exception}"); */ var configuration = new ConfigurationBuilder() .AddJsonFile("appsettings.json") .Build(); using (ILogger logger = new SerilogLogger(configuration)) { //Simple log entry logger.Debug("Hello World!"); //Parameterized log entry var quota = 100; var user = new { FirstName = "John", LastName = "Walter" }; logger.Write(LogLevel.Warning, "Disk quota {Quota} MB exceeded by {User}", quota, user); //Exception handling var myDataObject = new { Property1 = "Value1", Property2 = "Value2", Property3 = "Value3" }; try { int x = 0; int y = 10 / x; } catch (Exception ex) { logger.Fatal("Got an exception for {MyDataObject}", ex, myDataObject); } } Console.ReadKey(); }
private void PerformLog(LogEntry logEntry) { if (DiagnosticContext == null || SerilogLogger == null) { throw new InvalidOperationException($"Configure asp.net core & serilog using https://github.com/serilog/serilog-aspnetcore"); } bool isRequestLogEntry = false; if (logEntry.LogData.Any(ld => ld.Key == nameof(IRequestInformationProvider.DisplayUrl)) && HttpContextAccessor.HttpContext != null) { isRequestLogEntry = true; HttpContext httpContext = HttpContextAccessor.HttpContext; IUserInformationProvider userInformationProvider = httpContext.RequestServices.GetRequiredService <IUserInformationProvider>(); } var keyValues = logEntry.LogData.Select(ld => { string k = ld.Key; if (k == nameof(IRequestInformationProvider.HttpMethod) || k == nameof(IRequestInformationProvider.DisplayUrl) || k == "ResponseStatusCode" || ld.Value == null) { return(Key: null, Value: null); // Already being logged by serilog! } string v = null; if (ld.Value is string valueAsStr) { v = valueAsStr; } if (k == "ClientLogs" || k == "OperationArgs") { v = Formatter.Serialize(ld.Value); } else { v = ld.Value.ToString(); } return(Key: k, Value: v); }) .Where(d => d.Key != null) .ToList(); keyValues.Add((Key: nameof(LogEntry.MemoryUsage), Value: logEntry.MemoryUsage.ToString())); if (logEntry.AppServerDateTime.HasValue) { keyValues.Add((Key: nameof(LogEntry.AppServerDateTime), Value: logEntry.AppServerDateTime.ToString())); } keyValues.Add((Key: nameof(LogEntry.Severity), Value: logEntry.Severity)); keyValues.Add((Key: nameof(LogEntry.Message), Value: logEntry.Message)); if (logEntry.Id.HasValue) { keyValues.Add((Key: nameof(LogEntry.Id), Value: logEntry.Id.ToString())); } if (logEntry.AppServerThreadId.HasValue) { keyValues.Add((Key: nameof(LogEntry.AppServerThreadId), Value: logEntry.AppServerThreadId.ToString())); } foreach (var(Key, Value) in keyValues.OrderBy(kv => kv.Key)) { DiagnosticContext.Set(Key, Value); } if (isRequestLogEntry == true) { LogData userAgent = logEntry.LogData.FirstOrDefault(ld => ld.Key == nameof(IRequestInformationProvider.UserAgent)); if (userAgent != null) { DiagnosticContext.Set("UserAgent", userAgent.Value); } } else { Exception ex = null; try { var(Key, Value) = keyValues.ExtendedSingleOrDefault("Finding ExceptionTypeAssemblyQualifiedName...", kv => kv.Key == "ExceptionTypeAssemblyQualifiedName"); if (!string.IsNullOrEmpty(Value)) { ex = (Exception)Activator.CreateInstance(Type.GetType(Value) ?? throw new InvalidOperationException($"{Value} could not be found"), args: new object[] { logEntry.Message }); } } catch { } LogEventLevel level = logEntry.Severity switch { "Information" => LogEventLevel.Information, "Warning" => LogEventLevel.Warning, "Error" => LogEventLevel.Error, "Fatal" => LogEventLevel.Fatal, _ => LogEventLevel.Debug, }; SerilogLogger.Write(level, ex?.Message ?? logEntry.Message); } }