Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decorating System.Console.Out to add color

I have the simple function

let OutputDebugToConsole () =
    new System.Diagnostics.TextWriterTraceListener(System.Console.Out)
        |> System.Diagnostics.Debug.Listeners.Add |> ignore

to redirect the debug output from Debug.WriteLine to the console.

I wish to have the debug output in a different colour, by setting Console.ForegroundColor to gray, for example. Obviously the colour needs to be reset after each writing for normal text to be written in standard colours. My idea is to pass a different TextWriter that decorates the Write method.

First, is this a sensible way of thinking about the problem? Second, to do this would I need to rewrite all methods of my TextWriter or is there a different way?

like image 619
Muhammad Alkarouri Avatar asked Jan 15 '23 15:01

Muhammad Alkarouri


2 Answers

Console.ForegroundColor has both a property getter and setter so it is technically possible to simply store the old color, assign it, write and restore the old color.

It is however not thread-safe to do so. Another thread may also use Console.Write and assign the ForegroundColor property to get its own preferred color. That's a race, your logger may end up writing with the color selected by the other thread. And the other way around. There's a lock that prevents both threads writing text to the console and get their output intermingled, but it is taken too late. There is no simple way to solve that, other than having your logger using pinvoke so that it doesn't need to use ForegroundColor at all.

That's a fugly little detail if there ever was one. That's why it is usually better to use a logging library that takes care of these nasty little details. NLog for example.

like image 132
Hans Passant Avatar answered Jan 22 '23 08:01

Hans Passant


You can implement this in a fairly straightforward way using the Printf.kprintf function, as demonstrated in this blog post: Colored printf

Basically, Printf.kprintf accepts a continuation which the formatted string is applied to; the blog post I linked shows how you can pass a continuation which sets the console color, prints the string, then restores the original color before returning.

As Hans Passant wrote in his answer, there are thread-safety issues with setting/restoring the console color so you should be sure to design your application accordingly (if you're using multiple threads or the F# async workflow).

like image 25
Jack P. Avatar answered Jan 22 '23 08:01

Jack P.