Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 50 additions & 11 deletions src/NLog/Targets/ColoredConsoleTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public sealed class ColoredConsoleTarget : TargetWithLayoutHeaderAndFooter
/// </remarks>
private bool _pauseLogging;

private bool _disableColors;

private IColoredConsolePrinter _consolePrinter;

/// <summary>
Expand All @@ -80,8 +82,6 @@ public ColoredConsoleTarget()
WordHighlightingRules = new List<ConsoleWordHighlightingRule>();
RowHighlightingRules = new List<ConsoleRowHighlightingRule>();
UseDefaultRowHighlightingRules = true;
_pauseLogging = false;
DetectConsoleAvailable = false;
OptimizeBufferReuse = true;
_consolePrinter = CreateConsolePrinter(EnableAnsiOutput);
}
Expand Down Expand Up @@ -179,11 +179,19 @@ public Encoding Encoding
[DefaultValue(false)]
public bool DetectConsoleAvailable { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to auto-check if the console has been redirected to file
/// - Disables coloring logic when System.Console.IsOutputRedirected = true
/// </summary>
/// <docgen category='Console Options' order='11' />
[DefaultValue(false)]
public bool DetectOutputRedirected { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to auto-flush after <see cref="Console.WriteLine()"/>
/// </summary>
/// <remarks>
/// Normally the standard Console.Out will have <see cref="StreamWriter.AutoFlush"/> = false, but not when piped
/// Normally not required as standard Console.Out will have <see cref="StreamWriter.AutoFlush"/> = true, but not when pipe to file
/// </remarks>
[DefaultValue(false)]
public bool AutoFlush { get; set; }
Expand Down Expand Up @@ -215,13 +223,15 @@ public Encoding Encoding
protected override void InitializeTarget()
{
_pauseLogging = false;
_disableColors = false;

if (DetectConsoleAvailable)
{
string reason;
_pauseLogging = !ConsoleTargetHelper.IsConsoleAvailable(out reason);
if (_pauseLogging)
{
InternalLogger.Info("Console has been detected as turned off. Disable DetectConsoleAvailable to skip detection. Reason: {0}", reason);
InternalLogger.Info("ColoredConsole(Name={0}): Console detected as turned off. Disable DetectConsoleAvailable to skip detection. Reason: {1}", Name, reason);
}
}

Expand All @@ -230,7 +240,30 @@ protected override void InitializeTarget()
ConsoleTargetHelper.SetConsoleOutputEncoding(_encoding, true, _pauseLogging);
#endif

#if NET4_5
if (DetectOutputRedirected)
{
try
{
_disableColors = ErrorStream ? Console.IsErrorRedirected : Console.IsOutputRedirected;
if (_disableColors)
{
InternalLogger.Info("ColoredConsole(Name={0}): Console output is redirected so no colors. Disable DetectOutputRedirected to skip detection.", Name);
if (!AutoFlush && GetOutput() is StreamWriter streamWriter && !streamWriter.AutoFlush)
{
AutoFlush = true;
}
}
}
catch (Exception ex)
{
InternalLogger.Error(ex, "ColoredConsole(Name={0}): Failed checking if Console Output Redirected.", Name);
}
}
#endif

base.InitializeTarget();

if (Header != null)
{
LogEventInfo lei = LogEventInfo.CreateNullEvent();
Expand Down Expand Up @@ -327,16 +360,21 @@ private void WriteToOutput(LogEventInfo logEvent, string message)

private void WriteToOutputWithColor(LogEventInfo logEvent, string message)
{
var matchingRule = GetMatchingRowHighlightingRule(logEvent);

string colorMessage = message ?? string.Empty;
if (WordHighlightingRules.Count > 0)
ConsoleColor? newForegroundColor = null;
ConsoleColor? newBackgroundColor = null;

if (!_disableColors)
{
colorMessage = GenerateColorEscapeSequences(message);
}
var matchingRule = GetMatchingRowHighlightingRule(logEvent);
if (WordHighlightingRules.Count > 0)
{
colorMessage = GenerateColorEscapeSequences(message);
}

ConsoleColor? newForegroundColor = matchingRule.ForegroundColor != ConsoleOutputColor.NoChange ? (ConsoleColor)matchingRule.ForegroundColor : default(ConsoleColor?);
ConsoleColor? newBackgroundColor = matchingRule.BackgroundColor != ConsoleOutputColor.NoChange ? (ConsoleColor)matchingRule.BackgroundColor : default(ConsoleColor?);
newForegroundColor = matchingRule.ForegroundColor != ConsoleOutputColor.NoChange ? (ConsoleColor)matchingRule.ForegroundColor : default(ConsoleColor?);
newBackgroundColor = matchingRule.BackgroundColor != ConsoleOutputColor.NoChange ? (ConsoleColor)matchingRule.BackgroundColor : default(ConsoleColor?);
}

var consoleStream = GetOutput();
if (ReferenceEquals(colorMessage, message) && !newForegroundColor.HasValue && !newBackgroundColor.HasValue)
Expand All @@ -348,6 +386,7 @@ private void WriteToOutputWithColor(LogEventInfo logEvent, string message)
bool wordHighlighting = !ReferenceEquals(colorMessage, message) || message?.IndexOf('\n') >= 0;
WriteToOutputWithPrinter(consoleStream, colorMessage, newForegroundColor, newBackgroundColor, wordHighlighting);
}

if (AutoFlush)
consoleStream.Flush();
}
Expand Down
2 changes: 1 addition & 1 deletion src/NLog/Targets/ConsoleTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public Encoding Encoding
/// Gets or sets a value indicating whether to auto-flush after <see cref="Console.WriteLine()"/>
/// </summary>
/// <remarks>
/// Normally the standard Console.Out will have <see cref="StreamWriter.AutoFlush"/> = false, but not when piped
/// Normally not required as standard Console.Out will have <see cref="StreamWriter.AutoFlush"/> = true, but not when pipe to file
/// </remarks>
[DefaultValue(false)]
public bool AutoFlush { get; set; }
Expand Down
10 changes: 10 additions & 0 deletions tests/NLog.UnitTests/Targets/ColoredConsoleTargetTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,16 @@ public void ColoredConsoleRaceCondtionIgnoreTest()
}
#endif

#if NET4_5
[Fact]
public void ColoredConsoleDetectOutputRedirectedTest()
{
var target = new ColoredConsoleTarget { Layout = "${logger} ${message}", DetectOutputRedirected = true };
AssertOutput(target, "The Cat Sat At The Bar.",
new string[] { "The Cat Sat At The Bar." });
}
#endif

private static void AssertOutput(Target target, string message, string[] expectedParts, string loggerName = "Logger ")
{
var consoleOutWriter = new PartsWriter();
Expand Down