.NET Serilog升级后同一LoggerConfiguration多次调用CreateLogger报错
Ah, I ran into this exact issue when upgrading Serilog a while back! The problem boils down to a breaking change in Serilog 2.x: LoggerConfiguration became immutable, and the library now blocks calling CreateLogger() more than once on the same configuration instance. Your 1.5 code worked because Serilog didn't enforce this guard clause back then, but 2.3.0 is strict about it to prevent weird, hard-to-debug logging behavior.
Your original approach reuses the same loggerConfiguration object, tweaks it, and calls CreateLogger() twice — which is exactly what the new check is stopping. Instead, you need to build your entire logging pipeline (both email and database sinks) in a single configuration chain, then call CreateLogger() once.
Here's the corrected code
// Start with your base enrichment var loggerConfiguration = new LoggerConfiguration() .Enrich.With(new LogEnricher(User: userId, Name: Name)); // Build the full pipeline: add both sinks and all required enrichers in one chain _Logger = loggerConfiguration // Shared or first sink enrichments .Enrich.WithProperty("TimeStamp", DateTime.UtcNow) // Configure the email sink first .WriteTo.Email( connectionInfo: new EmailConnectionInfo() { EmailSubject = "", ToEmail = "", MailServer = "", NetworkCredentials = "", FromEmail = "", IsBodyHtml = true, EnableSsl = false }, outputTemplate: outputTemplate, batchPostingLimit: 1, restrictedToMinimumLevel: LogEventLevel.Verbose) // Add database-specific enrichments .Enrich.With(new LogEnricher(currentUser: userId, moduleName: moduleName)) .Enrich.WithProperty("Level", logLevel) // Configure the SQL Server sink .WriteTo.MSSqlServer( connectionString: "ConnectionString", tableName: "someTable", columnOptions: columnOptions, restrictedToMinimumLevel: LogEventLevel.Error) // Only call CreateLogger() ONCE — this creates a logger that sends logs to both sinks .CreateLogger();
Important things to keep in mind:
- Immutable Configs: Every
.Enrich()or.WriteTo()call returns a newLoggerConfigurationinstance. Modifying the original object directly (like your old code did) won't work in 2.x — you have to chain the calls together. - One CreateLogger() Call: This ensures both sinks are attached to the same logger instance, so when you log an error, it gets sent to both the email and the database (which is what you want!).
- Sink-Specific Setup: If you need certain enrichers to only apply to one sink, you can use
WriteTo.Conditional()or check if the sink supports its own enrichment settings (some sinks let you add enrichers just for themselves).
内容的提问来源于stack exchange,提问作者suman

