Why ILogger File Logging Fails in Production (and How to Fix It)

Published: (December 26, 2025 at 12:38 AM EST)
2 min read
Source: Dev.to

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 ILogger actually does (and doesn’t)
  • The most common production pitfalls
  • A correct, production‑ready file logging setup

ILogger Does NOT Support File Logging

  • Microsoft.Extensions.Logging provides no built‑in file logger.
  • ILogger is 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:

  1. appsettings.json
  2. appsettings.{Environment}.json
  3. 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 Logs folder 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 in appsettings.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.

Back to Blog

Related posts

Read more »

WebForms Core in NuGet

Overview WebForms Core, the server‑driven UI technology developed by Elanat, is now officially available on NuGet under the package name WFC. The package lets...

Stop Using IOptions Wrong in .NET!

IOptions vs IOptionsSnapshot vs IOptionsMonitor – Which One Should You Use? Ever got confused about which one to use in your .NET app? You're not alone! Let me...