Reputation: 21
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):
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:
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
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