Cast a boost::log::expressions::attr< std::string > to std::string

北战南征 提交于 2019-11-29 02:36:38

There are multiple ways to achieve what you want. The key point to understand is that Boost.Log formatting expressions (as well as filters, by the way) are Boost.Phoenix lambda functions. As such you can inject your own functions in them using Boost.Phoenix constructs such as boost::phoenix::bind. See an example here, for instance. Your code would look something like this:

std::string file_basename(logging::value_ref< std::string > const& filename)
{
  // Check to see if the attribute value has been found
  if (filename)
    return boost::filesystem::path(filename.get()).filename().string();
  else
    return std::string();
}

// ...

logging::add_file_log
(
  keywords::file_name = "my.log",
  keywords::format =
  (
    expr::stream
      << expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S")
      << "," << expr::attr< int >("Line")
      << " " << boost::phoenix::bind(&file_basename, expr::attr< std::string >("File"))
      << " " << logging::trivial::severity
      << " - " << expr::smessage
  )
);

Another way to do that is to use attribute keywords and define an operator<< specific for the File attribute. You can find an example here.

BOOST_LOG_ATTRIBUTE_KEYWORD(a_timestamp, "TimeStamp", boost::posix_time::ptime)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_line, "Line", int)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_file, "File", std::string)

namespace std {

logging::formatting_ostream& operator<<
(
  logging::formatting_ostream& strm,
  logging::to_log_manip< std::string, tag::a_file > const& manip
)
{
  strm << boost::filesystem::path(manip.get()).filename().string();
  return strm;
}

} // namespace std

// ...

logging::add_file_log
(
  keywords::file_name = "my.log",
  keywords::format =
  (
    expr::stream
      << expr::format_date_time(a_timestamp, "%Y-%m-%d %H:%M:%S")
      << "," << a_line
      << " " << a_file
      << " " << logging::trivial::severity
      << " - " << expr::smessage
  )
);

Notice that attribute keywords simplify expressions significantly.

Lastly, you can use wrap_formatter to inject your own function into the streaming expression. When it comes to formatting, wrap_formatter invokes your function providing it with the log record being formatted and the formatting stream. When your function returns the wrapper automatically returns the reference to the formatting stream so that the rest of the formatting expression can proceed.

BOOST_LOG_ATTRIBUTE_KEYWORD(a_timestamp, "TimeStamp", boost::posix_time::ptime)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_line, "Line", int)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_file, "File", std::string)

void file_basename(logging::record_view const& record, logging::formatting_ostream& strm)
{
  // Check to see if the attribute value has been found
  logging::value_ref< std::string, tag::a_file > filename = record[a_file];
  if (filename)
    strm << boost::filesystem::path(filename.get()).filename().string();
}

// ...

logging::add_file_log
(
  keywords::file_name = "my.log",
  keywords::format =
  (
    expr::stream
      << expr::format_date_time(a_timestamp, "%Y-%m-%d %H:%M:%S")
      << "," << a_line
      << " " << expr::wrap_formatter(&file_basename)
      << " " << logging::trivial::severity
      << " - " << expr::smessage
  )
);

The above is similar to the first variant with boost::phoenix::bind but allows for more flexibility in the file_basename implementation.

In custom formatter you can easily build the timestamp in "%Y-%m-%d %H:%M:%S" format:

void my_formatter(logging::record_view const& rec, logging::formatting_ostream& strm)
{
    const boost::posix_time::ptime &pt = *logging::extract< boost::posix_time::ptime >("TimeStamp", rec);
    strm << pt.date() << " " << pt.time_of_day().hours() << ":" << pt.time_of_day().minutes() << ":" << pt.time_of_day().seconds()
    ...
    << rec[expr::smessage];
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!