How to add color coding to boost::log console output?
Asked Answered
B

2

9

I'm trying to add colored log output for boost::log under linux. I read the following and I tried this:

#define MY_LOG_ERROR() BOOST_LOG_TRIVIAL(error) << "\033[1;31"

MY_LOG_ERROR() << "This is an error log."

but it gives me the result below:

[2016-07-11 17:23:16.328435] [0x00007f15f03d6780] [error] [1;31This is an error log.

How to properly add colored log output to boost::log?

Bremble answered 11/7, 2016 at 14:27 Comment(2)
What terminal do you use? They state several times that the terminal must support these color codes...Housebreak
You missed the trailing 'm' in the code sequence.Leuko
L
14

The proper way to customize output with Boost.Log is to use formatters. To set a formatter you will have to set up a sink for that as described here, but you can keep using the BOOST_LOG_TRIVIAL macro for generating log records.

The good thing about formatters is that you can have access to log record attributes like severity level within the formatter. For example, you could use the severity level to choose the color of the formatted log record on the console.

void coloring_formatter(
    logging::record_view const& rec, logging::formatting_ostream& strm)
{
    auto severity = rec[logging::trivial::severity];
    if (severity)
    {
        // Set the color
        switch (severity.get())
        {
        case logging::trivial::severity_level::info:
            strm << "\033[32m";
            break;
        case logging::trivial::severity_level::warning:
            strm << "\033[33m";
            break;
        case logging::trivial::severity_level::error:
        case logging::trivial::severity_level::fatal:
            strm << "\033[31m";
            break;
        default:
            break;
        }
    }

    // Format the message here...
    strm << rec[logging::expressions::smessage];

    if (severity)
    {
        // Restore the default color
        strm << "\033[0m";
    }
}

sink->set_formatter(&coloring_formatter);
Leuko answered 11/7, 2016 at 22:2 Comment(3)
How to add TimeStamp and ThreadID to the format of the log message in the above code? I want the result to be similar to default trivial logging formatting. When I' using logging to file I just write keywords::format = "[%TimeStamp%] [%ThreadID%] [%Severity%]: %Message%".Bremble
I just posted the above comment as new question.Bremble
Since the edit queue is full: this will compile if you remove severity:: from switch cases.Toxicosis
G
3

I've recently done this with a simple custom sink backend

coloured_console_sink.h

#pragma once
#include <boost/log/sinks/basic_sink_backend.hpp>

class coloured_console_sink : public boost::log::sinks::basic_formatted_sink_backend<char, boost::log::sinks::synchronized_feeding>
{
public:
    static void consume(boost::log::record_view const& rec, string_type const& formatted_string);
};

coloured_console_sink.cpp

#include "coloured_console_sink.h"
#include <iostream>
#include <windows.h>
#include <boost/log/trivial.hpp>
#include <boost/log/attributes/value_extraction.hpp>
#include <boost/log/attributes/attribute_value.hpp>

WORD get_colour(boost::log::trivial::severity_level level)
{
    switch (level)
    {
        case boost::log::trivial::trace: return 0x08;
        case boost::log::trivial::debug: return 0x07;
        case boost::log::trivial::info: return 0x0F;
        case boost::log::trivial::warning: return 0x0D;
        case boost::log::trivial::error: return 0x0E;
        case boost::log::trivial::fatal: return 0x0C;
        default: return 0x0F;
    }
}

void coloured_console_sink::consume(boost::log::record_view const& rec, string_type const& formatted_string)
{
    auto level = rec.attribute_values()["Severity"].extract<boost::log::trivial::severity_level>();
    auto hstdout = GetStdHandle(STD_OUTPUT_HANDLE);

    CONSOLE_SCREEN_BUFFER_INFO csbi;
    GetConsoleScreenBufferInfo(hstdout, &csbi);

    SetConsoleTextAttribute(hstdout, get_colour(level.get()));
    std::cout << formatted_string << std::endl;
    SetConsoleTextAttribute(hstdout, csbi.wAttributes);
}

usage

typedef boost::log::sinks::synchronous_sink<coloured_console_sink> coloured_console_sink_t;
auto coloured_console_sink = boost::make_shared<coloured_console_sink_t>();

boost::log::core::get()->add_sink(coloured_console_sink);
Guilbert answered 8/11, 2016 at 17:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.