Skip to content

Commit c90a679

Browse files
committed
支持使用 stderror 输出控制台日志
1 parent 221b048 commit c90a679

File tree

3 files changed

+64
-30
lines changed

3 files changed

+64
-30
lines changed

src/DotNetCampus.Logger/Writers/ConsoleLogger.cs

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.IO;
34
using System.Text;
5+
using System.Threading;
46
using DotNetCampus.Logging.Writers.ConsoleLoggerHelpers;
57
using DotNetCampus.Logging.Writers.Helpers;
68
using C = DotNetCampus.Logging.Writers.ConsoleLoggerHelpers.ConsoleColors;
@@ -15,7 +17,12 @@ namespace DotNetCampus.Logging.Writers;
1517
/// </summary>
1618
public class ConsoleLogger : ILogger
1719
{
18-
private static readonly TextWriter Out = GetStandardOutputWriter();
20+
private readonly Lazy<TextWriter> _outLazy;
21+
22+
/// <summary>
23+
/// 获取用于输出日志的文本写入流。
24+
/// </summary>
25+
private TextWriter Out => _outLazy.Value;
1926

2027
/// <summary>
2128
/// 用于处理重复的日志,避免重复日志污染控制台输出内容。
@@ -35,24 +42,25 @@ public class ConsoleLogger : ILogger
3542
/// </summary>
3643
/// <param name="threadMode">指定控制台日志的线程安全模式。</param>
3744
/// <param name="mainArgs">Main 方法的参数。</param>
38-
public ConsoleLogger(LogWritingThreadMode threadMode = LogWritingThreadMode.NotThreadSafe, string[]? mainArgs = null)
39-
: this(threadMode.CreateCoreLogWriter(SafeWriteLine), TagFilterManager.FromCommandLineArgs(mainArgs ?? []))
40-
{
41-
}
42-
43-
internal ConsoleLogger(ICoreLogWriter coreWriter, TagFilterManager? tagManager)
45+
public ConsoleLogger(LogWritingThreadMode threadMode = LogWritingThreadMode.NotThreadSafe, IReadOnlyList<string>? mainArgs = null)
4446
{
4547
_repeat = new RepeatLoggerDetector(ClearAndMoveToLastLine);
46-
CoreWriter = coreWriter;
47-
TagManager = tagManager;
48+
CoreWriter = threadMode.CreateCoreLogWriter(SafeWriteLine);
49+
TagManager = TagFilterManager.FromCommandLineArgs(mainArgs ?? []);
4850
_isConsoleOutput = ConsoleInitializer.Initialize();
51+
_outLazy = new Lazy<TextWriter>(GetStandardOutputWriter, LazyThreadSafetyMode.ExecutionAndPublication);
4952
}
5053

5154
/// <summary>
5255
/// 高于或等于此级别的日志才会被记录。
5356
/// </summary>
5457
public LogLevel Level { get; init; }
5558

59+
/// <summary>
60+
/// 指定控制台日志输出的目标。
61+
/// </summary>
62+
public LoggerConsoleOutputTo OutputTo { get; init; }
63+
5664
/// <summary>
5765
/// 最终日志写入器。
5866
/// </summary>
@@ -239,7 +247,7 @@ private void ConsoleMultilineMessage(string message,
239247
/// 安全地写入一行日志,避免出现 IO 异常。
240248
/// </summary>
241249
/// <param name="message"></param>
242-
internal static void SafeWriteLine(string? message)
250+
internal void SafeWriteLine(string? message)
243251
{
244252
try
245253
{
@@ -309,14 +317,22 @@ private int SafeGetSpaceCount(params
309317
/// 如果当前在控制台中输出,则使用控制台的输出流;否则创建一个 UTF-8 编码的标准输出流。
310318
/// </summary>
311319
/// <returns>文本写入流。</returns>
312-
private static TextWriter GetStandardOutputWriter()
320+
private TextWriter GetStandardOutputWriter()
313321
{
314322
if (Console.OutputEncoding.CodePage is not 0)
315323
{
316-
return Console.Out;
324+
return OutputTo switch
325+
{
326+
LoggerConsoleOutputTo.StandardError => Console.Error,
327+
_ => Console.Out,
328+
};
317329
}
318330

319-
var standardOutput = Console.OpenStandardOutput();
331+
var standardOutput = OutputTo switch
332+
{
333+
LoggerConsoleOutputTo.StandardError => Console.OpenStandardError(),
334+
_ => Console.OpenStandardOutput(),
335+
};
320336
var writer = new StreamWriter(standardOutput, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false))
321337
{
322338
AutoFlush = true,
@@ -351,3 +367,19 @@ private static TextWriter GetStandardOutputWriter()
351367
private static string CriticalExceptionTag => $"{B.Black}{D.Bold}{F.Red} X {Reset}{CriticalText} ";
352368
private static string EmptyExceptionTag => " ";
353369
}
370+
371+
/// <summary>
372+
/// 指定控制台日志输出的目标。
373+
/// </summary>
374+
public enum LoggerConsoleOutputTo
375+
{
376+
/// <summary>
377+
/// 输出到标准输出流。
378+
/// </summary>
379+
StandardOutput,
380+
381+
/// <summary>
382+
/// 输出到标准错误流。
383+
/// </summary>
384+
StandardError,
385+
}

src/DotNetCampus.Logger/Writers/ConsoleLoggerBuilder.cs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using System;
2-
using DotNetCampus.Logging.Writers.Helpers;
2+
using System.Collections.Generic;
33

44
namespace DotNetCampus.Logging.Writers;
55

@@ -8,8 +8,9 @@ namespace DotNetCampus.Logging.Writers;
88
/// </summary>
99
public sealed class ConsoleLoggerBuilder
1010
{
11-
private TagFilterManager? _tagFilterManager;
12-
private ICoreLogWriter _coreWriter = new NotThreadSafeLogWriter(ConsoleLogger.SafeWriteLine);
11+
private LogWritingThreadMode _threadMode = LogWritingThreadMode.NotThreadSafe;
12+
private LoggerConsoleOutputTo _outputTo = LoggerConsoleOutputTo.StandardOutput;
13+
private IReadOnlyList<string>? _mainArgs;
1314

1415
/// <summary>
1516
/// 高于或等于此级别的日志才会被记录。
@@ -25,6 +26,12 @@ public ConsoleLoggerBuilder WithLevel(LogLevel level)
2526
return this;
2627
}
2728

29+
public ConsoleLoggerBuilder WithOutput(LoggerConsoleOutputTo outputTo)
30+
{
31+
_outputTo = outputTo;
32+
return this;
33+
}
34+
2835
/// <summary>
2936
/// 指定控制台日志的线程安全模式。
3037
/// </summary>
@@ -33,13 +40,7 @@ public ConsoleLoggerBuilder WithLevel(LogLevel level)
3340
/// <exception cref="ArgumentOutOfRangeException">线程安全模式不支持。</exception>
3441
public ConsoleLoggerBuilder WithThreadSafe(LogWritingThreadMode threadMode)
3542
{
36-
_coreWriter = threadMode switch
37-
{
38-
LogWritingThreadMode.NotThreadSafe => new NotThreadSafeLogWriter(ConsoleLogger.SafeWriteLine),
39-
LogWritingThreadMode.Lock => new LockLogWriter(ConsoleLogger.SafeWriteLine),
40-
LogWritingThreadMode.ProducerConsumer => new ProducerConsumerLogWriter(ConsoleLogger.SafeWriteLine),
41-
_ => throw new ArgumentOutOfRangeException(nameof(threadMode)),
42-
};
43+
_threadMode = threadMode;
4344
return this;
4445
}
4546

@@ -48,19 +49,20 @@ public ConsoleLoggerBuilder WithThreadSafe(LogWritingThreadMode threadMode)
4849
/// </summary>
4950
/// <param name="args">命令行参数。</param>
5051
/// <returns>构造器模式。</returns>
51-
public ConsoleLoggerBuilder FilterConsoleTagsFromCommandLineArgs(string[] args)
52+
public ConsoleLoggerBuilder FilterConsoleTagsFromCommandLineArgs(IReadOnlyList<string> args)
5253
{
53-
_tagFilterManager = TagFilterManager.FromCommandLineArgs(args);
54+
_mainArgs = args;
5455
return this;
5556
}
5657

5758
/// <summary>
5859
/// 创建控制台日志记录器。
5960
/// </summary>
6061
/// <returns>控制台日志记录器。</returns>
61-
internal ConsoleLogger Build() => new(_coreWriter, _tagFilterManager)
62+
internal ConsoleLogger Build() => new(_threadMode, _mainArgs)
6263
{
6364
Level = Level,
65+
OutputTo = _outputTo,
6466
};
6567
}
6668

src/DotNetCampus.Logger/Writers/Helpers/TagFilterManager.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ internal bool IsTagEnabled(string text)
108108
/// 从命令行参数中提取过滤标签。
109109
/// </summary>
110110
/// <param name="args">命令行参数。</param>
111-
public static TagFilterManager? FromCommandLineArgs(string[] args)
111+
public static TagFilterManager? FromCommandLineArgs(IReadOnlyList<string> args)
112112
{
113113
if (!TryGetCommandLineValue(args, LogTagParameterName, out var value))
114114
{
@@ -151,11 +151,11 @@ internal bool IsTagEnabled(string text)
151151
};
152152
}
153153

154-
private static bool TryGetCommandLineValue(string[] args, string parameterName, [NotNullWhen(true)] out string? value)
154+
private static bool TryGetCommandLineValue(IReadOnlyList<string> args, string parameterName, [NotNullWhen(true)] out string? value)
155155
{
156-
for (var i = 0; i < args.Length; i++)
156+
for (var i = 0; i < args.Count; i++)
157157
{
158-
if (string.Equals(args[i], parameterName, StringComparison.OrdinalIgnoreCase) && i + 1 < args.Length)
158+
if (string.Equals(args[i], parameterName, StringComparison.OrdinalIgnoreCase) && i + 1 < args.Count)
159159
{
160160
value = args[i + 1];
161161
return true;

0 commit comments

Comments
 (0)