diff --git a/src/dotnetCampus.Logger/Writers/ConsoleLogger.cs b/src/dotnetCampus.Logger/Writers/ConsoleLogger.cs index db38b54..25c46f2 100644 --- a/src/dotnetCampus.Logger/Writers/ConsoleLogger.cs +++ b/src/dotnetCampus.Logger/Writers/ConsoleLogger.cs @@ -26,7 +26,7 @@ public class ConsoleLogger : ILogger /// 指定控制台日志的线程安全模式。 /// Main 方法的参数。 public ConsoleLogger(LogWritingThreadMode threadMode = LogWritingThreadMode.NotThreadSafe, string[]? mainArgs = null) - : this(threadMode.CreateCoreLogWriter(), TagFilterManager.FromCommandLineArgs(mainArgs ?? [])) + : this(threadMode.CreateCoreLogWriter(SafeWriteLine), TagFilterManager.FromCommandLineArgs(mainArgs ?? [])) { } @@ -127,18 +127,35 @@ private void ConsoleMultilineMessage(string message, Func forma { if (forceSingleLine || !message.Contains('\n')) { - Console.WriteLine(formatter(message)); + SafeWriteLine(formatter(message)); } else { using var reader = new StringReader(message); while (reader.ReadLine() is { } line) { - Console.WriteLine(formatter(line)); + SafeWriteLine(formatter(line)); } } } + /// + /// 安全地写入一行日志,避免出现 IO 异常。 + /// + /// + internal static void SafeWriteLine(string? message) + { + try + { + Console.WriteLine(message); + } + catch (IOException) + { + // 如果写入日志时发生 IO 异常,已经没有办法救活了。 + // 这是日志系统的内部实现,所以日志也记不了了,汗…… + } + } + /// /// 清空当前行并移动光标到上一行。 /// diff --git a/src/dotnetCampus.Logger/Writers/ConsoleLoggerBuilder.cs b/src/dotnetCampus.Logger/Writers/ConsoleLoggerBuilder.cs index 5907290..fe42708 100644 --- a/src/dotnetCampus.Logger/Writers/ConsoleLoggerBuilder.cs +++ b/src/dotnetCampus.Logger/Writers/ConsoleLoggerBuilder.cs @@ -9,7 +9,7 @@ namespace dotnetCampus.Logging.Writers; public sealed class ConsoleLoggerBuilder { private TagFilterManager? _tagFilterManager; - private ICoreLogWriter _coreWriter = new NotThreadSafeLogWriter(); + private ICoreLogWriter _coreWriter = new NotThreadSafeLogWriter(ConsoleLogger.SafeWriteLine); /// /// 高于或等于此级别的日志才会被记录。 @@ -35,9 +35,9 @@ public ConsoleLoggerBuilder WithThreadSafe(LogWritingThreadMode threadMode) { _coreWriter = threadMode switch { - LogWritingThreadMode.NotThreadSafe => new NotThreadSafeLogWriter(), - LogWritingThreadMode.Lock => new LockLogWriter(), - LogWritingThreadMode.ProducerConsumer => new ProducerConsumerLogWriter(), + LogWritingThreadMode.NotThreadSafe => new NotThreadSafeLogWriter(ConsoleLogger.SafeWriteLine), + LogWritingThreadMode.Lock => new LockLogWriter(ConsoleLogger.SafeWriteLine), + LogWritingThreadMode.ProducerConsumer => new ProducerConsumerLogWriter(ConsoleLogger.SafeWriteLine), _ => throw new ArgumentOutOfRangeException(nameof(threadMode)), }; return this; diff --git a/src/dotnetCampus.Logger/Writers/Helpers/ICoreLogWriter.cs b/src/dotnetCampus.Logger/Writers/Helpers/ICoreLogWriter.cs index 4d28ac1..fed7b0a 100644 --- a/src/dotnetCampus.Logger/Writers/Helpers/ICoreLogWriter.cs +++ b/src/dotnetCampus.Logger/Writers/Helpers/ICoreLogWriter.cs @@ -25,14 +25,14 @@ internal interface ICoreLogWriter /// /// 不处理线程安全问题的日志写入器。 /// -internal sealed class NotThreadSafeLogWriter : ICoreLogWriter +internal sealed class NotThreadSafeLogWriter(Action logger) : ICoreLogWriter { /// public void Write(string? message) { if (message is not null) { - Console.WriteLine(message); + logger(message); } } @@ -46,7 +46,7 @@ public void Do(Action action) /// /// 使用锁来保证线程安全的日志写入器。 /// -internal sealed class LockLogWriter : ICoreLogWriter +internal sealed class LockLogWriter(Action logger) : ICoreLogWriter { private readonly object _lock = new(); @@ -57,7 +57,7 @@ public void Write(string? message) { lock (_lock) { - Console.WriteLine(message); + logger(message); } } } @@ -77,13 +77,15 @@ public void Do(Action action) /// internal sealed class ProducerConsumerLogWriter : ICoreLogWriter { + private readonly Action _logger; private readonly BlockingCollection _queue = new(); /// /// 创建 的新实例,并启动消费线程。 /// - public ProducerConsumerLogWriter() + public ProducerConsumerLogWriter(Action logger) { + _logger = logger; new Task(Consume, TaskCreationOptions.LongRunning).Start(); } @@ -112,7 +114,7 @@ private void Consume() switch (item) { case string message: - Console.WriteLine(message); + _logger(message); break; case Action action: action(); diff --git a/src/dotnetCampus.Logger/Writers/LogWritingThreadMode.cs b/src/dotnetCampus.Logger/Writers/LogWritingThreadMode.cs index 072db49..762e507 100644 --- a/src/dotnetCampus.Logger/Writers/LogWritingThreadMode.cs +++ b/src/dotnetCampus.Logger/Writers/LogWritingThreadMode.cs @@ -36,13 +36,14 @@ internal static class LogWritingThreadModeExtensions /// 根据 创建对应的 实例。 /// /// 线程安全模式。 + /// 实际的日志写入方法。 /// 最终日志写入器。 /// 当线程安全模式不支持时抛出。 - public static ICoreLogWriter CreateCoreLogWriter(this LogWritingThreadMode threadMode) => threadMode switch + public static ICoreLogWriter CreateCoreLogWriter(this LogWritingThreadMode threadMode, Action logger) => threadMode switch { - LogWritingThreadMode.NotThreadSafe => new NotThreadSafeLogWriter(), - LogWritingThreadMode.Lock => new LockLogWriter(), - LogWritingThreadMode.ProducerConsumer => new ProducerConsumerLogWriter(), + LogWritingThreadMode.NotThreadSafe => new NotThreadSafeLogWriter(logger), + LogWritingThreadMode.Lock => new LockLogWriter(logger), + LogWritingThreadMode.ProducerConsumer => new ProducerConsumerLogWriter(logger), _ => throw new ArgumentOutOfRangeException(nameof(threadMode)), }; }