Setting the color for Console.Error writes
Asked Answered
S

2

10

I’m writing a console application that has a custom logger in it. The logger needs to color anything sent to Console.Error in red. I now have third party references that also write to Console.Out and Console.Error so I have to do this in a way that accounts for them too since I don’t have their source code. I’ve setup my logger so that any code writing to the Console will be using my logger’s TextWriter’s by calling the Console.SetOut & Console.SetError methods. Its kinda-of working but I’m guessing there is some sort of synchronization issue? In my ErrorWriter class you can see I’m setting the console’s foreground color and then calling base.Write() but the result is not as expected. Text coming from Console.Out that should be gray is coming out red and mid-stream it suddenly turns to gray. It’s been consistently changing color from red back to gray at the same character position but I’m assuming that base.Write() doesn’t actually spit out to the Console immediately; there is some kind of lag time/buffer. I’ve tried calling base.Flush() but that makes ALL of the text from Console.Out red which is even worse. How do I solve this problem?

public class Logger
{
    private static TextWriter _out;
    private static ErrorWriter _error;

    public Logger()
    {
        Initiliaze();
    }

    public static TextWriter Out
    {
        get
        {
            return _out;
        }
    }

    public static TextWriter Error
    {
        get
        {
            return _error;
        }
    }

    private static void Initiliaze()
    {
        if (_out == null)
            _out = new StreamWriter(Console.OpenStandardOutput());
        if (_error == null)
            _error = new ErrorWriter(Console.OpenStandardError());

        Console.SetOut(Out);
        Console.SetOut(Error);
    }
}

public class ErrorWriter : StreamWriter
{
    // constructors omitted to save space

    public override void Write(string value)
    {
            Console.ForegroundColor = ConsoleColor.Red;
            base.Write(value);
            //base.Flush();
            Console.ResetColor();
    }

    public override Encoding Encoding
    {
        get { return Encoding.Default; }
    }
}
Silvester answered 10/5, 2012 at 11:11 Comment(2)
See here: #1523436Tisatisane
This doesn't actually work. the .ForegroundColor only seems to modify the stdout and not stderr. If you redirect stdout, then the color changes do not appear on stderr outputAviles
S
2

Turned out to be a stupid copy/paste error! I had two calls to Console.SetOut(). Now its working after change the second one to Console.SetError()

Silvester answered 10/5, 2012 at 22:25 Comment(0)
G
9

You can decorate the method in order to do that:

public class ConsoleErrorWriterDecorator : TextWriter
{
    private TextWriter m_OriginalConsoleStream;

    public ConsoleErrorWriterDecorator(TextWriter consoleTextWriter)
    {
        m_OriginalConsoleStream = consoleTextWriter;
    }

    public override void WriteLine(string value)
    {
        ConsoleColor originalColor = Console.ForegroundColor;
        Console.ForegroundColor = ConsoleColor.Red;

        m_OriginalConsoleStream.WriteLine(value);

        Console.ForegroundColor = originalColor;
    }

    public override Encoding Encoding
    {
        get { return Encoding.Default; }
    }

    public static void SetToConsole()
    {
        Console.SetError(new ConsoleErrorWriterDecorator(Console.Error));
    }
}

Don't forget to run "ConsoleErrorWriterDecorator.SetToConsole();" before you start writing to console

Girondist answered 10/5, 2012 at 12:16 Comment(2)
This doesn't actually work. the .ForegroundColor only seems to modify the stdout and not stderr. If you redirect stdout, then the color changes do not appear on stderr output.Aviles
One drawback here is that other Console.Write methods not specifically overridden won't do anything.Endor
S
2

Turned out to be a stupid copy/paste error! I had two calls to Console.SetOut(). Now its working after change the second one to Console.SetError()

Silvester answered 10/5, 2012 at 22:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.