Why ILogger File Logging Fails in Production (and How to Fix It)
Source: Dev.to
Why many .NET developers encounter a confusing issue where logging to a file works perfectly in Development but no log file is created in Production.
In this article we’ll explain:
- Why this happens
- What
ILoggeractually does (and doesn’t) - The most common production pitfalls
- A correct, production‑ready file logging setup
ILogger Does NOT Support File Logging
Microsoft.Extensions.Loggingprovides no built‑in file logger.ILoggeris just an abstraction; actual logging is performed by providers such as:- Console
- Debug
- EventSource
- Third‑party providers (Serilog, NLog, etc.)
ILogger logger;
logger.LogInformation("Hello World");
The code above will never create a file by itself.
If file logging “worked” in Development, it was because:
- A provider was added indirectly
- The IDE displayed Debug output
- Configuration was loaded only in Development
appsettings.Development.json
ASP.NET Core loads configuration in this order:
appsettings.jsonappsettings.{Environment}.json- Environment variables
If file logging is configured only in appsettings.Development.json, the settings are never loaded in Production, so no file logger exists.
Common Production Pitfalls
-
Missing directory – ASP.NET does not create directories automatically.
"path": "Logs/app.log"If the
Logsfolder does not exist, no file is created, and no exception is thrown. -
Insufficient permissions – Production hosts often run under restricted accounts:
- IIS App Pool identity
- Docker container user
- Linux service account
These accounts may lack write access to the target folder, causing silent failures.
Fix: Use Serilog with a File Sink
Add the required packages:
dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Sinks.File
Program.cs
using Serilog;
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog((context, services, configuration) =>
{
configuration
.ReadFrom.Configuration(context.Configuration)
.Enrich.FromLogContext();
});
var app = builder.Build();
app.MapGet("/", (ILogger logger) =>
{
logger.LogInformation("Application started successfully");
return "Hello World";
});
app.Run();
appsettings.json (Production‑ready)
{
"Serilog": {
"Using": [ "Serilog.Sinks.File" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "Logs/app-.log",
"rollingInterval": "Day",
"shared": true
}
}
]
}
}
Ensure Log Directory Exists and Has Proper Permissions
-
Create the folder manually or programmatically before logging starts:
Directory.CreateDirectory("Logs"); -
Grant write access to the runtime account:
-
IIS:
IIS AppPool\YourAppPoolName -
Linux:
chmod -R 755 Logs chown -R appuser:appuser Logs
-
-
Docker / container scenarios – mount a writable volume:
volumes: - ./Logs:/app/Logs
Checklist Before Blaming .NET
- A file‑logging provider (e.g., Serilog, NLog) is installed and configured.
- Logging configuration is present in
appsettings.json(not only inappsettings.Development.json). - The log directory exists.
- The process identity has write permissions to the directory.
- The application does not rely on Debug output for file logging.
ILogger itself is not broken in Production. File‑logging failures are almost always caused by missing providers, mis‑scoped configuration, or file‑system permission issues. Once these are addressed, logging becomes predictable, stable, and production‑safe.