зеркало из https://github.com/aspnet/Logging.git
Support stderr in console logger (#913)
This commit is contained in:
Родитель
64724ea6e4
Коммит
b454c5a67e
|
@ -8,7 +8,8 @@
|
|||
"Console":
|
||||
{
|
||||
"IncludeScopes": "true",
|
||||
"TimestampFormat": "[HH:mm:ss] "
|
||||
"TimestampFormat": "[HH:mm:ss] ",
|
||||
"LogToStandardErrorThreshold": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Logging.Abstractions.Internal;
|
||||
|
@ -51,15 +52,18 @@ namespace Microsoft.Extensions.Logging.Console
|
|||
Name = name;
|
||||
Filter = filter ?? ((category, logLevel) => true);
|
||||
ScopeProvider = scopeProvider;
|
||||
LogToStandardErrorThreshold = LogLevel.None;
|
||||
_queueProcessor = loggerProcessor;
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
Console = new WindowsLogConsole();
|
||||
ErrorConsole = new WindowsLogConsole(stdErr: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console = new AnsiLogConsole(new AnsiSystemConsole());
|
||||
ErrorConsole = new AnsiLogConsole(new AnsiSystemConsole(stdErr: true));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,6 +81,20 @@ namespace Microsoft.Extensions.Logging.Console
|
|||
}
|
||||
}
|
||||
|
||||
internal IConsole ErrorConsole
|
||||
{
|
||||
get { return _queueProcessor.ErrorConsole; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
_queueProcessor.ErrorConsole = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Func<string, LogLevel, bool> Filter
|
||||
{
|
||||
get { return _filter; }
|
||||
|
@ -100,6 +118,8 @@ namespace Microsoft.Extensions.Logging.Console
|
|||
|
||||
public bool DisableColors { get; set; }
|
||||
|
||||
internal LogLevel LogToStandardErrorThreshold { get; set; }
|
||||
|
||||
internal string TimestampFormat { get; set; }
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||
|
@ -180,7 +200,8 @@ namespace Microsoft.Extensions.Logging.Console
|
|||
MessageColor = DefaultConsoleColor,
|
||||
LevelString = hasLevel ? logLevelString : null,
|
||||
LevelBackground = hasLevel ? logLevelColors.Background : null,
|
||||
LevelForeground = hasLevel ? logLevelColors.Foreground : null
|
||||
LevelForeground = hasLevel ? logLevelColors.Foreground : null,
|
||||
LogAsError = logLevel >= LogToStandardErrorThreshold
|
||||
});
|
||||
|
||||
logBuilder.Clear();
|
||||
|
@ -289,14 +310,23 @@ namespace Microsoft.Extensions.Logging.Console
|
|||
|
||||
private class AnsiSystemConsole : IAnsiSystemConsole
|
||||
{
|
||||
|
||||
private readonly TextWriter _textWriter;
|
||||
|
||||
/// <inheritdoc />
|
||||
public AnsiSystemConsole(bool stdErr = false)
|
||||
{
|
||||
_textWriter = stdErr? System.Console.Error : System.Console.Out;
|
||||
}
|
||||
|
||||
public void Write(string message)
|
||||
{
|
||||
System.Console.Write(message);
|
||||
_textWriter.Write(message);
|
||||
}
|
||||
|
||||
public void WriteLine(string message)
|
||||
{
|
||||
System.Console.WriteLine(message);
|
||||
_textWriter.WriteLine(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,11 @@ namespace Microsoft.Extensions.Logging.Console
|
|||
public bool IncludeScopes { get; set; }
|
||||
public bool DisableColors { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets value indicating the minimum level of messaged that would get written to <c>Console.Error</c>.
|
||||
/// </summary>
|
||||
public LogLevel LogToStandardErrorThreshold { get; set; } = LogLevel.None;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets format string used to format timestamp in logging messages. Defaults to <c>null</c>
|
||||
/// </summary>
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace Microsoft.Extensions.Logging.Console
|
|||
private bool _disableColors;
|
||||
private IExternalScopeProvider _scopeProvider;
|
||||
private string _timestampFormat;
|
||||
private LogLevel _logToStandardErrorThreshold;
|
||||
|
||||
public ConsoleLoggerProvider(Func<string, LogLevel, bool> filter, bool includeScopes)
|
||||
: this(filter, includeScopes, false)
|
||||
|
@ -56,12 +57,14 @@ namespace Microsoft.Extensions.Logging.Console
|
|||
_includeScopes = options.IncludeScopes;
|
||||
_disableColors = options.DisableColors;
|
||||
_timestampFormat = options.TimestampFormat;
|
||||
_logToStandardErrorThreshold = options.LogToStandardErrorThreshold;
|
||||
var scopeProvider = GetScopeProvider();
|
||||
foreach (var logger in _loggers.Values)
|
||||
{
|
||||
logger.ScopeProvider = scopeProvider;
|
||||
logger.DisableColors = options.DisableColors;
|
||||
logger.TimestampFormat = options.TimestampFormat;
|
||||
logger.LogToStandardErrorThreshold = options.LogToStandardErrorThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,7 +127,8 @@ namespace Microsoft.Extensions.Logging.Console
|
|||
return new ConsoleLogger(name, GetFilter(name, _settings), includeScopes? _scopeProvider: null, _messageQueue)
|
||||
{
|
||||
DisableColors = disableColors,
|
||||
TimestampFormat = _timestampFormat
|
||||
TimestampFormat = _timestampFormat,
|
||||
LogToStandardErrorThreshold = _logToStandardErrorThreshold
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Microsoft.Extensions.Logging.Console.Internal
|
|||
private readonly Thread _outputThread;
|
||||
|
||||
public IConsole Console;
|
||||
public IConsole ErrorConsole;
|
||||
|
||||
public ConsoleLoggerProcessor()
|
||||
{
|
||||
|
@ -46,18 +47,20 @@ namespace Microsoft.Extensions.Logging.Console.Internal
|
|||
// for testing
|
||||
internal virtual void WriteMessage(LogMessageEntry message)
|
||||
{
|
||||
var console = message.LogAsError ? ErrorConsole : Console;
|
||||
|
||||
if (message.TimeStamp != null)
|
||||
{
|
||||
Console.Write(message.TimeStamp, message.MessageColor, message.MessageColor);
|
||||
console.Write(message.TimeStamp, message.MessageColor, message.MessageColor);
|
||||
}
|
||||
|
||||
if (message.LevelString != null)
|
||||
{
|
||||
Console.Write(message.LevelString, message.LevelBackground, message.LevelForeground);
|
||||
console.Write(message.LevelString, message.LevelBackground, message.LevelForeground);
|
||||
}
|
||||
|
||||
Console.Write(message.Message, message.MessageColor, message.MessageColor);
|
||||
Console.Flush();
|
||||
console.Write(message.Message, message.MessageColor, message.MessageColor);
|
||||
console.Flush();
|
||||
}
|
||||
|
||||
private void ProcessLogQueue()
|
||||
|
|
|
@ -13,5 +13,6 @@ namespace Microsoft.Extensions.Logging.Console.Internal
|
|||
public ConsoleColor? LevelForeground;
|
||||
public ConsoleColor? MessageColor;
|
||||
public string Message;
|
||||
public bool LogAsError;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,20 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.Extensions.Logging.Console.Internal
|
||||
{
|
||||
public class WindowsLogConsole : IConsole
|
||||
{
|
||||
private readonly TextWriter _textWriter;
|
||||
|
||||
/// <inheritdoc />
|
||||
public WindowsLogConsole(bool stdErr = false)
|
||||
{
|
||||
_textWriter = stdErr? System.Console.Error : System.Console.Out;
|
||||
}
|
||||
|
||||
private bool SetColor(ConsoleColor? background, ConsoleColor? foreground)
|
||||
{
|
||||
if (background.HasValue)
|
||||
|
@ -30,7 +39,7 @@ namespace Microsoft.Extensions.Logging.Console.Internal
|
|||
public void Write(string message, ConsoleColor? background, ConsoleColor? foreground)
|
||||
{
|
||||
var colorChanged = SetColor(background, foreground);
|
||||
System.Console.Out.Write(message);
|
||||
_textWriter.Write(message);
|
||||
if (colorChanged)
|
||||
{
|
||||
ResetColor();
|
||||
|
@ -40,7 +49,7 @@ namespace Microsoft.Extensions.Logging.Console.Internal
|
|||
public void WriteLine(string message, ConsoleColor? background, ConsoleColor? foreground)
|
||||
{
|
||||
var colorChanged = SetColor(background, foreground);
|
||||
System.Console.Out.WriteLine(message);
|
||||
_textWriter.WriteLine(message);
|
||||
if (colorChanged)
|
||||
{
|
||||
ResetColor();
|
||||
|
|
|
@ -27,15 +27,18 @@ namespace Microsoft.Extensions.Logging.Test
|
|||
private const string _state = "This is a test, and {curly braces} are just fine!";
|
||||
private Func<object, Exception, string> _defaultFormatter = (state, exception) => state.ToString();
|
||||
|
||||
private static (ConsoleLogger Logger, ConsoleSink Sink) SetUp(Func<string, LogLevel, bool> filter, bool includeScopes = false, bool disableColors = false)
|
||||
private static (ConsoleLogger Logger, ConsoleSink Sink, ConsoleSink ErrorSink) SetUp(Func<string, LogLevel, bool> filter, bool includeScopes = false, bool disableColors = false)
|
||||
{
|
||||
// Arrange
|
||||
var sink = new ConsoleSink();
|
||||
var errorSink = new ConsoleSink();
|
||||
var console = new TestConsole(sink);
|
||||
var errorConsole = new TestConsole(errorSink);
|
||||
var logger = new ConsoleLogger(_loggerName, filter, includeScopes ? new LoggerExternalScopeProvider() : null, new TestLoggerProcessor());
|
||||
logger.Console = console;
|
||||
logger.ErrorConsole = errorConsole;
|
||||
logger.DisableColors = disableColors;
|
||||
return (logger, sink);
|
||||
return (logger, sink, errorSink);
|
||||
}
|
||||
|
||||
public ConsoleLoggerTest()
|
||||
|
@ -845,6 +848,32 @@ namespace Microsoft.Extensions.Logging.Test
|
|||
Assert.True(logger.DisableColors);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConsoleLoggerLogsToError_WhenOverErrorLevel()
|
||||
{
|
||||
// Arrange
|
||||
var (logger, sink, errorSink) = SetUp(null);
|
||||
|
||||
logger.LogToStandardErrorThreshold = LogLevel.Warning;
|
||||
|
||||
// Act
|
||||
logger.LogInformation("Info");
|
||||
logger.LogWarning("Warn");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, sink.Writes.Count);
|
||||
Assert.Equal(
|
||||
"info: test[0]" + Environment.NewLine +
|
||||
" Info" + Environment.NewLine,
|
||||
GetMessage(sink.Writes));
|
||||
|
||||
Assert.Equal(2, errorSink.Writes.Count);
|
||||
Assert.Equal(
|
||||
"warn: test[0]" + Environment.NewLine +
|
||||
" Warn" + Environment.NewLine,
|
||||
GetMessage(errorSink.Writes));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(LevelsWithPrefixes))]
|
||||
public void WriteCore_NullMessageWithException(LogLevel level, string prefix)
|
||||
|
@ -1049,6 +1078,37 @@ namespace Microsoft.Extensions.Logging.Test
|
|||
Assert.Null(logger.ScopeProvider);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConsoleLoggerOptions_LogAsErrorLevel_IsReadFromLoggingConfiguration()
|
||||
{
|
||||
var configuration = new ConfigurationBuilder().AddInMemoryCollection(new[] { new KeyValuePair<string, string>("Console:LogToStandardErrorThreshold", "Warning") }).Build();
|
||||
|
||||
var loggerProvider = new ServiceCollection()
|
||||
.AddLogging(builder => builder
|
||||
.AddConfiguration(configuration)
|
||||
.AddConsole())
|
||||
.BuildServiceProvider()
|
||||
.GetRequiredService<ILoggerProvider>();
|
||||
|
||||
var consoleLoggerProvider = Assert.IsType<ConsoleLoggerProvider>(loggerProvider);
|
||||
var logger = (ConsoleLogger)consoleLoggerProvider.CreateLogger("Category");
|
||||
Assert.Equal(LogLevel.Warning, logger.LogToStandardErrorThreshold);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConsoleLoggerOptions_LogAsErrorLevel_IsAppliedToLoggers()
|
||||
{
|
||||
// Arrange
|
||||
var monitor = new TestOptionsMonitor(new ConsoleLoggerOptions());
|
||||
var loggerProvider = new ConsoleLoggerProvider(monitor);
|
||||
var logger = (ConsoleLogger)loggerProvider.CreateLogger("Name");
|
||||
|
||||
// Act & Assert
|
||||
Assert.Equal(LogLevel.None, logger.LogToStandardErrorThreshold);
|
||||
monitor.Set(new ConsoleLoggerOptions() { LogToStandardErrorThreshold = LogLevel.Error});
|
||||
Assert.Equal(LogLevel.Error, logger.LogToStandardErrorThreshold);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConsoleLoggerOptions_IncludeScopes_IsReadFromLoggingConfiguration()
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче