Introduction
Serilog enrichers add contextual properties (like request IDs, user IDs, correlation IDs) to log events. When enrichers are not working, the expected properties are missing from log output. This can be caused by incorrect registration, the LogContext not being enabled, enricher ordering issues, or the output template not including the properties.
Symptoms
RequestIdorCorrelationIdnot appearing in log output- Enricher
Enrichmethod is called but property does not appear in sink - Properties appear in console but not in file sink
LogContext.PushPropertyhas no effect- Custom enricher registered but never invoked
Example code that does not work: ```csharp // Enricher is registered but properties do not appear Log.Logger = new LoggerConfiguration() .Enrich.FromLogContext() .Enrich.With<RequestEnricher>() .WriteTo.Console() .CreateLogger();
// Pushing a property does not work without FromLogContext using (LogContext.PushProperty("UserId", "123")) { Log.Information("Processing request"); // UserId does NOT appear without .Enrich.FromLogContext() } ```
Common Causes
.Enrich.FromLogContext()not called (required forLogContext.PushProperty)- Output template does not include the property:
{Properties:j}or{UserId} - Enricher registered after the sink
- Async sink does not flush before application exits
- Property name conflicts with built-in properties
Step-by-Step Fix
- 1.Enable LogContext for scope-based enrichment:
- 2.```csharp
- 3.Log.Logger = new LoggerConfiguration()
- 4..Enrich.FromLogContext() // CRITICAL: enables LogContext.PushProperty
- 5..Enrich.WithEnvironmentName()
- 6..Enrich.WithMachineName()
- 7..WriteTo.Console(
- 8.outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} " +
- 9."{Properties:j}{NewLine}{Exception}")
- 10..CreateLogger();
// Now PushProperty works using (LogContext.PushProperty("UserId", "123")) { Log.Information("Processing request"); // Output: [10:15:00 INF] Processing request {"UserId":"123"} } ```
- 1.Register a custom enricher correctly:
- 2.```csharp
- 3.public class RequestEnricher : ILogEventEnricher
- 4.{
- 5.private readonly IHttpContextAccessor _httpContextAccessor;
public RequestEnricher(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; }
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { var httpContext = _httpContextAccessor.HttpContext; if (httpContext == null) return;
var requestId = httpContext.TraceIdentifier; logEvent.AddOrUpdateProperty( propertyFactory.CreateProperty("RequestId", requestId));
var userAgent = httpContext.Request.Headers["User-Agent"].ToString(); logEvent.AddOrUpdateProperty( propertyFactory.CreateProperty("UserAgent", userAgent)); } }
// Registration in Program.cs builder.Services.AddSerilog((services, config) => { config .Enrich.FromLogContext() .Enrich.With(services.GetRequiredService<RequestEnricher>()) .WriteTo.Console() .ReadFrom.Configuration(builder.Configuration); }); ```
- 1.Use Serilog.AspNetCore request enrichment:
- 2.```csharp
- 3.Log.Logger = new LoggerConfiguration()
- 4..Enrich.FromLogContext()
- 5..Enrich.WithProperty("Application", "MyApp")
- 6..WriteTo.Console(
- 7.outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] " +
- 8."[{RequestId}] [{UserId}] {Message:lj}{NewLine}{Exception}")
- 9..WriteTo.File("logs/app-.log",
- 10.rollingInterval: RollingInterval.Day,
- 11.outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] " +
- 12."{Message:lj}{NewLine}{Exception}")
- 13..CreateLogger();
// In middleware pipeline: app.UseSerilogRequestLogging(options => { options.EnrichDiagnosticContext = (diagnosticContext, httpContext) => { diagnosticContext.Set("UserId", httpContext.User.FindFirstValue(ClaimTypes.NameIdentifier)); diagnosticContext.Set("RequestHost", httpContext.Request.Host.Value); }; }); ```
- 1.Include all properties in output template:
- 2.```csharp
- 3.// Include all properties as JSON
- 4..WriteTo.Console(outputTemplate:
- 5."{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] {Message:lj} {Properties:j}{NewLine}")
// Or specify individual properties .WriteTo.Console(outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{RequestId}] [{CorrelationId}] {Message:lj}{NewLine}") ```
Prevention
- Always call
.Enrich.FromLogContext()when usingLogContext.PushProperty - Verify output template includes the properties you want to see
- Use
Serilog.AspNetCorefor automatic request-level enrichment - Test enrichment in unit tests by capturing log events with
InMemorySink - Use
AddOrUpdatePropertyinstead ofAddPropertyto avoid duplicates - Ensure the enricher is registered in the DI container before Serilog