Introduction

Serilog's file sink supports rolling log files based on time intervals (hour, day, month). When the file path template does not include the date token, when the rolling interval is misconfigured, or when file permissions prevent new file creation, logs continue appending to a single file or stop being written entirely. This makes log management difficult and can cause disk space issues in production.

Symptoms

  • Log file grows indefinitely without rolling
  • Date token {Date} appears literally in filename instead of being replaced
  • New log file not created at midnight as expected
  • File sink stops writing after first file reaches certain size
  • Log entries missing after file should have rolled

Check file sink configuration: ``csharp Log.Logger = new LoggerConfiguration() .WriteTo.File( path: "logs/app-.log", // MISSING date token rollingInterval: RollingInterval.Day) .CreateLogger();

Common Causes

  • Path template missing the date token (should be app-{Date}.log)
  • Directory does not exist and cannot be created
  • File permissions prevent creating new files
  • RollingInterval set but path does not support it
  • RetainedFileCountLimit deleting files too aggressively

Step-by-Step Fix

  1. 1.**Configure rolling file with correct path template":
  2. 2.```csharp
  3. 3.using Serilog;
  4. 4.using Serilog.Events;

Log.Logger = new LoggerConfiguration() .MinimumLevel.Information() .WriteTo.File( // IMPORTANT: Include {Date} token for rolling path: "logs/app-.log", // Serilog replaces - with the date rollingInterval: RollingInterval.Day, retainedFileCountLimit: 30, // Keep 30 days of logs fileSizeLimitBytes: 100_000_000, // 100MB max per file rollOnFileSizeLimit: true, // Roll when size limit hit shared: true, // Multiple processes can write flushToDiskInterval: TimeSpan.FromSeconds(1)) .CreateLogger();

// Output filenames will be: // app-20260409.log // app-20260410.log // app-20260411.log ```

  1. 1.**Configure different rolling intervals":
  2. 2.```csharp
  3. 3.// Daily rolling (most common)
  4. 4..WriteTo.File("logs/app-.log", rollingInterval: RollingInterval.Day)
  5. 5.// Output: app-20260409.log

// Hourly rolling (high-volume apps) .WriteTo.File("logs/app-.log", rollingInterval: RollingInterval.Hour) // Output: app-20260409-14.log

// Monthly rolling (low-volume apps) .WriteTo.File("logs/app-.log", rollingInterval: RollingInterval.Month) // Output: app-202604.log

// Infinite (no rolling, NOT recommended for production) .WriteTo.File("logs/app.log") // No rolling ```

  1. 1.**Ensure directory exists and has correct permissions":
  2. 2.```csharp
  3. 3.// Ensure log directory exists before configuring Serilog
  4. 4.var logDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
  5. 5.if (!Directory.Exists(logDirectory))
  6. 6.{
  7. 7.Directory.CreateDirectory(logDirectory);
  8. 8.}

Log.Logger = new LoggerConfiguration() .WriteTo.File( path: Path.Combine(logDirectory, "app-.log"), rollingInterval: RollingInterval.Day, // Run as the same user as the app pool / service // Ensure the user has write permissions to the log directory shared: true) .CreateLogger(); ```

  1. 1.**Use async file sink for better performance":
  2. 2.```csharp
  3. 3.// Serilog.Sinks.Async wraps any sink for async writing
  4. 4.// Install: Serilog.Sinks.Async

Log.Logger = new LoggerConfiguration() .WriteTo.Async(async => async.File( path: "logs/app-.log", rollingInterval: RollingInterval.Day, bufferSize: 1000, // Buffer 1000 log events before flushing shared: true)) .CreateLogger(); ```

Prevention

  • Always include the date placeholder in the file path for rolling
  • Set retainedFileCountLimit to prevent disk space exhaustion
  • Use shared: true when multiple processes write to the same log
  • Enable flushToDiskInterval for critical log delivery
  • Monitor log file sizes and rotation in production
  • Add log directory existence check during application startup