Alex
Alex

Reputation: 799

How to change TimeStamp output when using boost log?

I'm trying to find a simplest way to change the output of TimeStamp. This is how I initialize the log library

  boost::log::add_common_attributes();
  boost::log::register_simple_formatter_factory<SeverityLevel, char>("Severity");
  boost::log::register_simple_formatter_factory<boost::posix_time::ptime, char>("TimeStamp");
  boost::log::add_file_log(
     boost::log::keywords::file_name = strFileName,
     boost::log::keywords::open_mode = std::ios_base::out | std::ios_base::app,
     boost::log::keywords::format = "[%TimeStamp%] {%Severity% @ %Channel%} %Message%",
     boost::log::keywords::auto_flush = true
  );

I, also, add following declarations

enum class SeverityLevel {
   Debug = 0,
   Info,
   Warning,
   Error,
   Critical
};

BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", SeverityLevel)
BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "TimeStamp", boost::posix_time::ptime)

std::ostream& operator <<(std::ostream& objStream, SeverityLevel eLevel);
boost::log::formatting_ostream& operator <<(boost::log::formatting_ostream& objStream, boost::log::to_log_manip<SeverityLevel, tag::severity> const& objManipulator);

std::ostream& operator <<(std::ostream& objStream, boost::posix_time::ptime objTime);
boost::log::formatting_ostream& operator <<(boost::log::formatting_ostream& objStream, boost::log::to_log_manip<boost::posix_time::ptime, tag::timestamp> const& objManipulator);

Of course, I implement those operators, but their implementation is not important for the question.

In the result the operator related to Severity "std::ostream& operator <<(std::ostream& objStream, SeverityLevel eLevel)" is called as it's supposed to, when I write a log entry, but the operator related to TimeStamp is not. What am I doing wrong here?

Why I need this is to customize the way how timestamp is written. I know there are other ways to do it completely differently by setting sink formatters, for example. I would like to use the string format template instead as it is shown in this example.

Upvotes: 1

Views: 40

Answers (1)

sehe
sehe

Reputation: 393134

First, you ask for "the simplest way" - I think it's the one from the docs:

void init()
{
    logging::add_file_log
    (
        keywords::file_name = "sample_%N.log",
        // This makes the sink to write log records that look like this:
        // YYYY-MM-DD HH:MI:SS: <normal> A normal severity message
        // YYYY-MM-DD HH:MI:SS: <error> An error severity message
        keywords::format =
        (
            expr::stream
                << expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S")
                << ": <" << logging::trivial::severity
                << "> " << expr::smessage
        )
    );
}

Other than that you say:

I implement those operators, but their implementation is not important for the question.

The implementation isn't, but the place where they are defined is. Operators are found using Argument Dependent Lookup. It's important for them to be in the namespace that declares your argument type.

This might explain that your own enum SeverityLevel is working for you, but not boost::posix_time::ptime. I donot suggest you override operator<<(ostream& for ptime. Instead consider using the output facets from the DateTime library

Here's a proof of concept that demonstrates that the ADL trick will work:

Live On Coliru

#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/log/common.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/utility/setup.hpp>

namespace MyLib {
    enum class SeverityLevel { Debug, Info, Warning, Error, Critical };

    BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", SeverityLevel)
    BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "TimeStamp", boost::posix_time::ptime)

    std::ostream& operator<<(std::ostream& os, SeverityLevel l) { //
        return os << "[Severity:" << static_cast<int>(l) << "]";
    }
} // namespace MyLib

namespace boost::posix_time { // DO NOT DO THIS IN PRODUCTION CODE
    std::ostream& operator<<(std::ostream& os, boost::posix_time::ptime) {
        return os << "[TODO:" << __LINE__ << "]";
    }
} // namespace boost::posix_time

using MyLib::SeverityLevel;

void init_logging(std::string const& strFileName) {

    namespace l  = boost::log;
    namespace kw = l::keywords;
    l::add_common_attributes();

    l::register_simple_formatter_factory<SeverityLevel, char>("Severity");
    l::register_simple_formatter_factory<boost::posix_time::ptime, char>("TimeStamp");
    l::add_file_log(                                                         //
        kw::file_name  = strFileName,                                        //
        kw::open_mode  = std::ios_base::out | std::ios_base::app,            //
        kw::format     = "[%TimeStamp%] {%Severity% @ %Channel%} %Message%", //
        kw::auto_flush = true                                                //
    );
}

int main() {
    init_logging("test.log");

    boost::log::sources::severity_logger<SeverityLevel> lg;
    BOOST_LOG(lg) << "A trace severity message";
}

Logging e.g.

[[TODO:21]] {[Severity:0] @ } A message
[[TODO:21]] {[Severity:0] @ } A message
[[TODO:21]] {[Severity:0] @ } A message
[[TODO:21]] {[Severity:0] @ } A message
[[TODO:21]] {[Severity:0] @ } A message

Upvotes: 0

Related Questions