Meziantou.Extensions.Logging.FileLogger 3.0.3

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package Meziantou.Extensions.Logging.FileLogger --version 3.0.3
                    
NuGet\Install-Package Meziantou.Extensions.Logging.FileLogger -Version 3.0.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Meziantou.Extensions.Logging.FileLogger" Version="3.0.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Meziantou.Extensions.Logging.FileLogger" Version="3.0.3" />
                    
Directory.Packages.props
<PackageReference Include="Meziantou.Extensions.Logging.FileLogger" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Meziantou.Extensions.Logging.FileLogger --version 3.0.3
                    
#r "nuget: Meziantou.Extensions.Logging.FileLogger, 3.0.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Meziantou.Extensions.Logging.FileLogger@3.0.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Meziantou.Extensions.Logging.FileLogger&version=3.0.3
                    
Install as a Cake Addin
#tool nuget:?package=Meziantou.Extensions.Logging.FileLogger&version=3.0.3
                    
Install as a Cake Tool

Meziantou.Extensions.Logging.FileLogger

An ILogger implementation that writes to a file. The messages are queued and written by a background thread, so logging doesn't block the application.

Usage

using Microsoft.Extensions.Logging;

var logsDirectory = Path.Combine(Path.GetTempPath(), "logs");
using var provider = new FileLoggerProvider(logsDirectory);

using var loggerFactory = LoggerFactory.Create(builder => builder.AddProvider(provider));
var logger = loggerFactory.CreateLogger("Sample");

logger.LogInformation("Hello from file logger");
Console.WriteLine($"Log file: {provider.LogFilePath}");

Dependency Injection

var builder = Host.CreateApplicationBuilder(args);
builder.Logging.AddFile(options =>
{
    options.Directory = "logs";
    options.RollInterval = RollInterval.Daily;
    options.MaxRetainedFiles = 7;
    options.CompressRolledFiles = true;
    options.IncludeScopes = true;
});

The options can also be set from the configuration, using the File provider alias:

{
  "Logging": {
    "File": {
      "Directory": "logs",
      "RollInterval": "Daily",
      "MaxFileSizeInBytes": 10485760,
      "MaxRetainedFiles": 7,
      "FormatterName": "json",
      "LogLevel": {
        "Default": "Information"
      }
    }
  }
}
builder.Logging.AddFile();

Note that the options related to the log file itself (Directory, file name, Append, rolling, MaxQueueLength, QueueFullMode) are read when the provider is created. The other options are re-read when the configuration changes.

Rolling and retention

Option Description
RollInterval Creates a new file every hour / day / month
MaxFileSizeInBytes Creates a new file when the current one reaches the size limit
MaxRetainedFiles Deletes the oldest files when a new file is created
Compression Compresses the log files using gzip, Brotli, or Zstandard (.NET 11+)
Append Reuses an existing file instead of creating a new one at startup. See the note below

The log files are named {FileNamePrefix}{timestamp}-{processId}{FileNameExtension}, so they are ordered chronologically by name. When the name is already used, a suffix is added (_001, _002, …).

Append reuses a file only when its name matches the name computed at startup, so it needs a stable file name:

  • RollInterval must be set. RollInterval.None includes the seconds in the name, so the name changes on every start.
  • IncludeProcessIdInFileName must be false to reuse a file across restarts, as the identifier of the process changes.

With the default values of these two options, a new file is created on every start even when Append is true.

options.Append = true;
options.RollInterval = RollInterval.Daily;
options.IncludeProcessIdInFileName = false; // Required to reuse the file after a restart

Compression

options.Compression = LogFileCompression.GZip;      // GZip, Brotli, or Zstandard (.NET 11+)
options.CompressionLevel = CompressionLevel.SmallestSize;
options.CompressionMode = LogFileCompressionMode.Continuous;
CompressionMode Description
Continuous (default) The messages are compressed as they are written, so the file is never written uncompressed. The extension of the compression algorithm is part of the file name (2024-01-02-1234.log.gz).
OnRoll The current log file is a plain text file, and it is compressed once it is rolled.

Continuous doesn't need any extra disk space and doesn't pause the logging to compress a big file, but the compressed stream is only finalized when the file is rolled or when the provider is disposed, so the current log file may not be readable by all the tools while the application is running. Use OnRoll when you need to read the current log file with the usual text tools.

Append is ignored when the messages are compressed continuously, as appending to a compressed file would produce a file that most tools cannot read entirely.

MaxFileSizeInBytes is compared to the size of the file on disk, so it accounts for the compression. As the compressed size is only known once the data is flushed, the file may be rolled slightly before the limit.

Permissions

On Unix, the log files are created with the default mode of the platform, which usually makes them readable by every local user. Set UnixCreateMode when the messages can contain sensitive data:

options.UnixCreateMode = UnixFileMode.UserRead | UnixFileMode.UserWrite;

The value is ignored on Windows, and it is still filtered by the umask of the process. The mode of the directory is not changed, so create the directory yourself when it must be private too.

Formatters

SimpleFileFormatter (default) writes one human-readable line per entry:

[2024-01-02 03:04:05.006] [INFO] [Sample.Program] => Scope1 Hello world

JsonFileFormatter writes one JSON object per entry, including the message template and its named parameters:

builder.Logging.AddFile("logs", options => options.FormatterName = FileFormatterNames.Json);
{"Timestamp":"2024-01-02 03:04:05.006","LogLevel":"INFO","Category":"Sample.Program","Message":"Hello world","State":{"Name":"world","{OriginalFormat}":"Hello {Name}"},"Scopes":["Scope1"]}

You can also write a custom formatter by inheriting from FileFormatter and setting FileLoggerOptions.Formatter.

Content of the messages

Option Default Description
MinLevel Trace Minimum level of the messages written to the file
TimestampFormat yyyy-MM-dd HH:mm:ss.fff Format of the timestamp, null to omit it
UseUtcTimestamp true Use UTC instead of the local time
IncludeLogLevel true Write the log level
IncludeCategory true Write the category
UseShortCategoryName false Write only the last segment of the category
IncludeScopes false Write the scopes
IncludeEventId false Write the event id
IncludeThreadId false Write the id of the thread that logged the message
IncludeActivityTracking false Write the trace id and the span id of Activity.Current
EscapeControlCharacters false Escape the control characters, so an entry always spans a single line

Untrusted data in the messages

SimpleFileFormatter writes the messages as-is, so a value containing a line break produces several lines. When the value comes from an untrusted source, it can forge entries that look exactly like real ones:

logger.LogInformation("User said: {Text}", "hello\n[2020-01-01 00:00:00.000] [CRIT] [Security] admin login succeeded");

Set EscapeControlCharacters to true to write \n, \r, \t and the other control characters as escape sequences, so an entry always spans a single line. The stack traces are then written on a single line, which is harder to read. JsonFileFormatter is not affected, as the JSON writer already escapes the control characters.

Reliability

  • The messages are queued in a bounded queue. When it is full, QueueFullMode determines if the caller waits for room (default), or if the message is dropped.
  • The pending messages are flushed as soon as the queue is empty, and at most every FlushInterval when the logger cannot keep up.
  • FlushAsync waits for the pending messages to be written.
  • When the log file cannot be created or written, a warning is written on the standard error stream and the application keeps running.
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed.  net11.0 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.0.7 43 10/21/2026
3.0.6 87 10/11/2026
3.0.5 121 9/11/2026
3.0.4 116 9/6/2026
3.0.3 115 9/3/2026
3.0.2 114 9/3/2026
3.0.1 110 8/29/2026
3.0.0 136 8/19/2026
2.0.1 118 8/9/2026
2.0.0 135 7/5/2026
1.0.8 133 6/28/2026
1.0.7 137 6/13/2026
1.0.6 124 5/31/2026
1.0.5 131 5/14/2026
1.0.4 129 4/25/2026
1.0.3 134 3/29/2026
1.0.2 133 3/15/2026
1.0.1 138 2/22/2026
1.0.0 142 2/5/2026