Logging to file in .NET

May 9th 2025 Logging .NET

Nowadays, it's common to send logs to your logging platform of choice either via a dedicated logger for that platform or via an OpenTelemetry exporter. But what if the logs have to be read from a file? At least for me, it was surprising that there is no built-in file logger in .NET. It seemed as a natural extension to its feature-rich console logger.

Although writing log entries to a file sounds like an easy task, I didn't want to own this plumbing code. I'd rather use an established library which I can count on to work reliably and not have a negative performance impact on the application. I could only find one such library: Serilog.Extensions.Logging.File, a standalone side product of the well-known Serilog logging library.

The setup was easy enough and well-documented:

  • A single line in the initial dependency injection configuration:
    builder.Logging.AddFile(builder.Configuration.GetSection("Logging"));
    
  • Additional settings in the appsettings.json file (the section they are being read from is defined in the code above; the Logging section seems like an obvious choice):
    {
      "Logging": {
        "PathFormat": "logs/log-{Date}.txt",
        "OutputTemplate": "{Timestamp:o} {RequestId,13} [{Level:u3}] {Message:lj} {Properties:j} ({EventId:x8}){NewLine}{Exception}"
      }
    }
    

This was enough to enable logging to files in a specific folder, using a custom OutputTemplate which also includes log scopes in the message (i.e., the Properties placeholder). The setting is documented here. Below is a sample output using the settings above:

2025-05-04T11:33:42.6493951+02:00 0HNCATR177HLN:00000003 [INF] Date: 5. 05. 2025, Temperature: 47 {"SourceContext":"DotNetFileLogging.Controllers.WeatherForecastController","ClientIp":"127.0.0.1","ActionId":"51e885fa-1860-4247-915c-d26d79a652c3","ActionName":"DotNetFileLogging.Controllers.WeatherForecastController.Get (DotNetFileLogging)","RequestPath":"/weatherforecast/","ConnectionId":"0HNCATR177HLN"} (3047c244)

There aren't many settings available to further customize the logger's behavior. The most important one of them is Json, which instructs the logger to serialize the log messages as JSON instead of emitting them as plain text:

{
  "Logging": {
    "Json": true,
    "PathFormat": "logs/log-{Date}.txt"
  }
}

In this case, the OutputTemplate setting is ignored. Below is a sample output using JSON serialization (it's emitted minimized in a single line, but I formatted it to make it easier to read):

{
  "@t": "2025-05-04T09:40:30.2871220Z",
  "@m": "Date: \"5. 05. 2025\", Temperature: -5",
  "@i": "3047c244",
  "Date": "5. 05. 2025",
  "Temperature": -5,
  "SourceContext": "DotNetFileLogging.Controllers.WeatherForecastController",
  "ClientIp": "127.0.0.1",
  "ActionId": "7f12d227-6fd4-4c79-a800-eed5d98e3fb6",
  "ActionName": "DotNetFileLogging.Controllers.WeatherForecastController.Get (DotNetFileLogging)",
  "RequestId": "0HNCATUQMNSDD:00000003",
  "RequestPath": "/weatherforecast/",
  "ConnectionId": "0HNCATUQMNSDD"
}

If you want to try out the logger yourself, you can find a sample project with it preconfigured in my GitHub repository. It emits messages in plain text to a logs subfolder of the working directory, but you can easily customize the behavior by modifying the appsettings.json file.

Serilog's standalone file logger is an easy recommendation if you need to log to file from your .NET application. It's easy to set up, and it worked well enough for me. Definitely a better alternative to developing your own logger.

Get notified when a new blog post is published (usually every Friday):

Copyright
Creative Commons License