Arun S
Arun S

Reputation: 21

Changing color of log output in Windows console using Boost Logs

I am using Boost 1.54 Logging APIs and trying to change the color of the console log output. Below is the link to the minimum test code I am using (felt the code was a bit long to post directly):

http://ideone.com/o2KGw9

So, line 96 works, which is a std::cout to the console in color:

std::cout << colorSet( h, DARKTEAL )<<" I am coloured!!" << colorSet( h, GRAY ) << std::endl;

But when I try to do the same in boost::log::expressions::stream, in line 77, there is no color in the printed text.

logging::formatter fmtconsole = expr::stream << colorSet( h, BLUE )<< "DEBUG:" << expr::smessage << colorSet( h, GRAY ) << "\n";

Below is a screen capture of the output I get:

Console output

I remember reading a post by in the Boost sourceforge forums by Andrey Semashev that it is possible to write a custom formatter that adds color control codes to the output, but AFIK that works only with Linux terminals, which is why I am trying this approach.

Is there a way to achieve this?

Thanks.

UPDATE:

So the way I achieved it is by giving a custom formatter function as Semasheve suggested:

void my_formatter(logging::record_view const& rec, logging::formatting_ostream& strm)
{
    HANDLE h = GetStdHandle( STD_OUTPUT_HANDLE );
    // Finally, put the record message to the stream
    boost::locale::generator gen;
    std::locale::global(gen(""));

    boost::locale::date_time now;
    std::cout.imbue(std::locale());

    std::cout << colorSet( h, BLUE ) << boost::locale::as::ftime( "%H:%M:%S" ) << "[" << now << "] ";
    std::cout << colorSet( h, RED ) << rec[expr::smessage] << colorSet( h, GRAY );

}

Refer to the main code link to see colorSet definition.

And then set the formatter for the backend like:

consolebackend->set_formatter( &my_formatter );

Unfortunately I am not using the formatting_ostream object, which makes this like a not a great solution. And the reason I couldn't use it was because of the way Boost flushes the stream. So I would get only the last color in the stream. Thus I ended up using std::cout directly.

But I am sure it is possible, somehow.

Though this does the job, I still need a mechanism by which I can get a stream as a temporary object, which could be called from a macro.

Maybe something like:

class TMP_LOG
{
    public:
    TMP_LOG(const Color& c) : col(c), m_str() { }

    ~TMP_LOG()
    {
        HANDLE h = GetStdHandle( STD_OUTPUT_HANDLE );
        SetConsoleTextAttribute(h, col);

        BOOST_LOG_SEV( slg, normal ) << m_str.str();

        SetConsoleTextAttribute(h, GRAY);
    }

    std::ostringstream& stream() { return m_str; } 

private:
    std::ostringstream m_str;

    Color col;
};

#define LOG_DEBUG   TMP_LOG(RED).stream()
#define LOG_WARN    TMP_LOG(YELLOW).stream()

Upvotes: 2

Views: 2252

Answers (1)

sehe
sehe

Reputation: 392911

You probably need to write something of a "lazy manipulator" (as otherwise it will evaluate immediately, instead of when actually writing to the output stream).

This will be quite tricky.

Instead, you can use a terminal emulator with ANSI capabilities.

My weapon of choice is mintty, but others exist for windows too

Upvotes: 1

Related Questions