First update, less hardcoded
adca9bafe49ec944722a8abaf9defd7257c5d289
1 files changed
LoggerExtensions/FileLogger.cs
diff --git a/LoggerExtensions/FileLogger.cs b/LoggerExtensions/FileLogger.cs
index a78a2c2..f124cac 100644
--- a/LoggerExtensions/FileLogger.cs
+++ b/LoggerExtensions/FileLogger.cs
@@ -1,11 +1,10 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
-using System.Diagnostics;
using System.Threading.Channels;
namespace LoggerExtensions;
-public sealed class FileLogger : ILogger, IDisposable
+public sealed class FileLogger : IDisposable
{
private readonly Channel<string> channel;
private readonly Task consumerTask;
@@ -17,7 +16,6 @@ public sealed class FileLogger : ILogger, IDisposable
public FileLogger(string logDirectory = "Logs")
{
- Debug.WriteLine($"New FileLogger created. Instance hash: {GetHashCode()}");
this.logDirectory = logDirectory;
Directory.CreateDirectory(logDirectory);
@@ -32,27 +30,11 @@ public sealed class FileLogger : ILogger, IDisposable
consumerTask = Task.Run(() => ConsumeAsync(cts.Token));
}
- public void Log<TState>(
- LogLevel logLevel,
- EventId eventId,
- TState state,
- Exception? exception,
- Func<TState, Exception?, string> formatter)
+ internal void WriteMessage(string message)
{
- if (!IsEnabled(logLevel))
- return;
-
- var message = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} [{logLevel,-11}] {formatter(state, exception)}";
-
- if (exception != null)
- message += $"{Environment.NewLine}{exception}";
-
- message += Environment.NewLine;
-
channel.Writer.TryWrite(message);
}
-
private async Task ConsumeAsync(CancellationToken ct)
{
const int batchSize = 200;
@@ -101,6 +83,7 @@ public sealed class FileLogger : ILogger, IDisposable
}
}
}
+
private async Task WriteBatchAsync(List<string> messages, CancellationToken ct)
{
const int maxRetries = 3;
@@ -114,7 +97,7 @@ public sealed class FileLogger : ILogger, IDisposable
}
catch (IOException) when (attempt < maxRetries - 1)
{
- await Task.Delay(100 << attempt, ct); // 100, 200, 400 ms
+ await Task.Delay(100 << attempt, ct);
}
}
}
@@ -128,7 +111,7 @@ public sealed class FileLogger : ILogger, IDisposable
currentDate = today;
currentFilePath = Path.Combine(logDirectory, $"log-{today:yyyyMMdd}.txt");
- FileStream stream = new (
+ FileStream stream = new(
currentFilePath,
FileMode.Append,
FileAccess.Write,
@@ -165,7 +148,6 @@ public sealed class FileLogger : ILogger, IDisposable
public void Dispose()
{
-
channel.Writer.Complete();
cts.CancelAfter(TimeSpan.FromSeconds(8));
@@ -178,20 +160,50 @@ public sealed class FileLogger : ILogger, IDisposable
CloseWriterAsync(cts.Token).GetAwaiter().GetResult();
cts.Dispose();
}
+}
+
+internal sealed class CategoryLogger(FileLogger innerLogger, string categoryName) : ILogger
+{
+ public void Log<TState>(
+ LogLevel logLevel,
+ EventId eventId,
+ TState state,
+ Exception? exception,
+ Func<TState, Exception?, string> formatter)
+ {
+ if (!IsEnabled(logLevel))
+ return;
+ var message = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} [{logLevel,-11}] {categoryName}: {formatter(state, exception)}";
+
+ if (exception != null)
+ message += $"{Environment.NewLine}{exception}";
+
+ message += Environment.NewLine;
+
+ innerLogger.WriteMessage(message);
+ }
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => null;
public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None;
}
-public sealed class FileLoggerProvider(string logDirectory = "Logs") : ILoggerProvider
+public sealed class FileLoggerProvider : ILoggerProvider
{
- private readonly FileLogger logger = new(logDirectory);
+ private readonly FileLogger sharedLogger;
- public ILogger CreateLogger(string categoryName) => logger;
+ public FileLoggerProvider(string logDirectory = "Logs")
+ {
+ sharedLogger = new FileLogger(logDirectory);
+ }
+
+ public ILogger CreateLogger(string categoryName)
+ {
+ return new CategoryLogger(sharedLogger, categoryName);
+ }
- public void Dispose() => logger.Dispose();
+ public void Dispose() => sharedLogger.Dispose();
}
public static class LoggingBuilderExtensions