Filelogger
A lightweight and customizable file logger implementation for the Microsoft.Extensions.Logging framework.
Install / Use
/learn @adams85/FileloggerREADME
| :mega: Important notices | |--------------------------| | If upgrading from v3 to v4, there are some minor breaking changes you may need to be aware of. See the release notes for the details. Documentation of the previous major version (v3) is available here. |
Karambolo.Extensions.Logging.File
This class library contains a lightweight implementation of the Microsoft.Extensions.Logging.ILoggerProvider interface for file logging. Runs on all .NET platforms which implement .NET Standard 2.0+, including .NET Core 2+ (ASP.NET Core 2.1+) and .NET 5+.
The code is based on ConsoleLogger, whose full feature set is implemented (including log scopes and configuration reloading). The library has no 3rd party dependencies.
To prevent I/O blocking, log messages are processed asynchronously in the background, with a guarantee that pending messages are written to file on graceful shutdown.
File system access is implemented on top of the Microsoft.Extensions.FileProviders.IFileProvider abstraction, so it's even possible to use a custom backing storage.
JSON structured logging (following the format established by the JSON formatter of the built-in console logger) is also available.
The self-contained trimmed and Native AOT deployments models are also supported (in applications running on .NET 8 or newer).
Additional features:
- Flexible configuration:
- Hierarchical (two-level) log file settings.
- Fine-grained control over log message filtering.
- File path templates for including log entry date (or other user-defined tokens) in log file paths/names.
- Size-limited log files with customizable counter format. (Log rotation is achievable through customization.)
- Fully customizable log text formatting.
- Designed with extensibility/customizability in mind.
- Support for registering multiple providers with different settings.
Installation
Add the Karambolo.Extensions.Logging.File NuGet package to your project:
dotnet add package Karambolo.Extensions.Logging.File
or, if you want structured logging, add Karambolo.Extensions.Logging.File.Json NuGet package instead:
dotnet add package Karambolo.Extensions.Logging.File.Json
If you have a .NET Core/.NET 5+ project other than an ASP.NET Core web application (e.g. a console application), you should also consider adding explicit references to the following NuGet packages with the version matching your .NET runtime. For example, if your project targets .NET 9:
dotnet add package Microsoft.Extensions.FileProviders.Physical -v 9.0.11
dotnet add package Microsoft.Extensions.Logging.Configuration -v 9.0.11
dotnet add package Microsoft.Extensions.Options.ConfigurationExtensions -v 9.0.11
<details>
<summary>Explanation why this is recommended</summary>
The Karambolo.Extensions.Logging.File package depends on some framework libraries and references the lowest possible versions of these dependencies (e.g. the build targeting .NET 9 references Microsoft.Extensions.Logging.Configuration v9.0.0). These versions may not (mostly will not) align with the version of your application's target platform since that may be a newer patch, minor or even major version. Thus, referencing Karambolo.Extensions.Logging.File in itself may result in referencing outdated framework libraries on that particular platform (sticking to the previous example, Microsoft.Extensions.Logging.Configuration v9.0.0 instead of v9.0.11).
Luckily, in the case of ASP.NET Core this is resolved automatically as ASP.NET Core projects already reference the correct (newer) versions of the framework libraries in question (by means of the Microsoft.AspNetCore.App metapackage).
However, in other cases (like a plain .NET Core/.NET 5+ console application) you may end up with outdated dependencies, which is usually undesired (even can lead to issues like this), so you want to resolve this situation by adding the explicit package references listed above.
For more details, see NuGet package dependency resolution.
</details>Configuration
It's entirely possible to configure the file logger provider by code. However, you usually want to do that using an appsettings.json file. A minimal configuration looks like this:
{
"Logging": {
"File": {
"LogLevel": {
"Default": "Information"
},
"Files": [
{
"Path": "app.log"
}
]
}
}
}
Please note that you need to specify at least one log file to get anything logged. For a full reference of available settings, see the Settings section.
If you've chosen structured logging, replace calls to AddFile(...) with AddJsonFile(...) in the following code examples.
AddJsonFile is just a convenience method, which sets the TextBuilder setting to the default JSON formatter (JsonFileLogEntryTextBuilder) for the logger provider. You can achieve the same effect by using AddFile and setting TextBuilder (or TextBuilderType) to the aforementioned formatter manually. For details, see the Settings section.
It also follows from the above that you can still override this setting in your configuration (appsettings.json or configurer callback) and use other formatters regardless the defaults set by AddJsonFile.
ASP.NET Core
Minimal hosting model
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddFile(o => o.RootPath = builder.Environment.ContentRootPath);
var app = builder.Build();
// ...
app.Run();
Legacy hosting model
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.ConfigureLogging((ctx, builder) =>
{
// The following line might be necessary when using an older version of ASP.NET Core.
// builder.AddConfiguration(ctx.Configuration.GetSection("Logging"));
builder.AddFile(o => o.RootPath = ctx.HostingEnvironment.ContentRootPath);
})
.UseStartup<Startup>();
});
}
.NET Generic Host
Minimal hosting model
var builder = Host.CreateApplicationBuilder(args);
builder.Logging.AddFile(o => o.RootPath = builder.Environment.ContentRootPath);
var host = builder.Build();
// ...
host.Run();
Legacy hosting model
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging((ctx, builder) =>
{
// The following line might be necessary when using an older version of Microsoft.Extensions.Hosting.
// builder.AddConfiguration(ctx.Configuration.GetSection("Logging"));
builder.AddFile(o => o.RootPath = ctx.HostingEnvironment.ContentRootPath);
});
}
Custom setup using DI
// Build configuration
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
// Configure DI
var services = new ServiceCollection();
services.AddLogging(builder =>
{
builder.AddConfiguration(configuration.GetSection("Logging"));
builder.AddFile(o => o.RootPath = AppContext.BaseDirectory);
});
// Build the DI container and start logging
await using (var sp = services.BuildServiceProvider())
{
var logger = sp.GetRequiredService<ILogger<Program>>();
// ...
}
Advanced use cases
Using multiple providers with different settings
First of all, you need a little bit of boilerplate code:
[ProviderAlias("File2")]
class AltFileLoggerProvider : FileLoggerProvider
{
public AltFileLoggerProvider(FileLoggerContext context, IOptionsMonitor<FileLoggerOptions> options, string optionsName) : base(context, options, optionsName) { }
}
And a setup like this:
services.AddLogging(builder =>
{
builder.AddConfiguration(config.GetSection("Logging"));
builder.AddFile(o => o.RootPath = AppContext.BaseDirectory);
builder.AddFile<AltFileLoggerProvider>(configure: o => o.RootPath = AppContext.BaseDirectory);
});
Now, you have two independent
