Is there a sample or library for writing a provider for the ASP.NET Core ILogger system that writes to a local file and/or to Azure BLOB storage?
Please do not suggest Serilog as it does not work (for me at least).
You can check the below sample.
Test Result
My sample project structure
AzureBlobLogger.cs
using Azure.Storage.Blobs;
using System.Text;
namespace ilogger_sink
{
public class AzureBlobLogger : ILogger
{
private readonly BlobContainerClient _blobContainerClient;
public AzureBlobLogger(BlobContainerClient blobContainerClient)
{
_blobContainerClient = blobContainerClient;
}
public IDisposable? BeginScope<TState>(TState state) => null;
public bool IsEnabled(LogLevel logLevel) => true;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
string message = formatter(state, exception);
string currentDate = DateTime.UtcNow.ToString("yyyyMMdd");
string blobName = $"log_{currentDate}.txt";
var blobClient = _blobContainerClient.GetBlobClient(blobName);
// In a production environment make sure to handle concurrency and exceptions and use asynchronous methods
string existingLog = "";
if (blobClient.Exists())
{
using (var ms = new MemoryStream())
{
blobClient.DownloadTo(ms);
ms.Position = 0;
using (var reader = new StreamReader(ms))
{
existingLog = reader.ReadToEnd();
}
}
}
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(existingLog + message + Environment.NewLine)))
{
blobClient.Upload(ms, true);
}
}
}
}
AzureBlobLoggerProvider.cs
using Azure.Storage.Blobs;
namespace ilogger_sink
{
public class AzureBlobLoggerProvider : ILoggerProvider
{
private readonly BlobContainerClient _blobContainerClient;
public AzureBlobLoggerProvider(string connectionString, string containerName)
{
var blobServiceClient = new BlobServiceClient(connectionString);
_blobContainerClient = blobServiceClient.GetBlobContainerClient(containerName);
}
public ILogger CreateLogger(string categoryName)
{
return new AzureBlobLogger(_blobContainerClient);
}
public void Dispose() { }
}
}
FileLogger.cs
namespace ilogger_sink
{
public class FileLogger : ILogger
{
private readonly string _logDirectory;
public FileLogger(string logDirectory)
{
_logDirectory = logDirectory;
}
public IDisposable BeginScope<TState>(TState state) => null;
public bool IsEnabled(LogLevel logLevel) => true;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
string message = formatter(state, exception);
string currentDate = DateTime.UtcNow.ToString("yyyyMMdd");
string logFilePath = Path.Combine(_logDirectory, $"log_{currentDate}.txt");
System.IO.File.AppendAllText(logFilePath, message + Environment.NewLine);
}
}
}
FileLoggerProvider.cs
namespace ilogger_sink
{
public class FileLoggerProvider : ILoggerProvider
{
private readonly string _filePath;
public FileLoggerProvider(string filePath)
{
_filePath = filePath;
}
public ILogger CreateLogger(string categoryName)
{
return new FileLogger(_filePath);
}
public void Dispose() { }
}
}
Program.cs
using ilogger_sink.Data;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
namespace ilogger_sink
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
// for testing
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
builder.Services.AddLogging(builder =>
{
builder.AddProvider(new FileLoggerProvider("F:\\..T Core...\\ilogger-sink\\LocalLogs\\"));
builder.AddProvider(new AzureBlobLoggerProvider(
"DefaultEndpointsProt...797iH8QOQ...uffix=core.windows.net",
"jasonlogs"
));
});
// for testing
var app = builder.Build();
...
app.Run();
}
}
}
Test Code in Index.razor
@page "/"
@inject ILogger<Index> Logger
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
<button @onclick="LogMessage">Log a message</button>
Welcome to your new app.
<SurveyPrompt Title="How is Blazor working for you?" />
@code {
private void LogMessage()
{
Logger.LogInformation("This is a test log message from Index.razor");
}
}