将 boost::log::expressions::attr< std::string > 投射到 std::string
Cast a boost::log::expressions::attr< std::string > to std::string
在使用 Boost.Log 时,我试图保留我的 TimeStamp
格式化程序,例如:
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")
<< " " << expr::attr< std::string >("File")
<< " " << logging::trivial::severity
<< " - " << expr::smessage
)
);
据说我不能使用其他形式的格式化程序,因为我很难将 "TimeStamp"
转换为我的自定义格式:
static void my_formatter(logging::record_view const& rec, logging::formatting_ostream& strm)
{
strm << logging::extract< boost::posix_time::ptime >("TimeStamp", rec);
将输出类似:2015-Jul-01 16:06:31.514053
,而我只对:"%Y-%m-%d %H:%M:%S"
感兴趣。然而,第一种形式非常难以使用,例如我无法将 expr::attr< std::string >
转换为简单的 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::filesystem::path(expr::attr< std::string >("File"))
.filename().string()
<< " " << logging::trivial::severity
<< " - " << expr::smessage
)
);
以上代码甚至无法编译。
有没有一种简单的方法既可以使用我的自定义格式打印 TimeStamp
,又可以同时使用自定义转换为字符串以便能够使用 boost::filesystem::path::filename()
?
在自定义格式化程序中,您可以轻松构建 "%Y-%m-%d %H:%M:%S"
格式的时间戳:
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];
}
有多种方法可以实现您想要的。要理解的关键点是 Boost.Log 格式化表达式(以及过滤器,顺便说一下)是 Boost.Phoenix lambda 函数。因此,您可以使用 Boost.Phoenix 结构(例如 boost::phoenix::bind
)在其中注入您自己的函数。例如,参见示例 here。您的代码看起来像这样:
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
)
);
另一种方法是使用属性关键字并定义一个特定于文件属性的 operator<<
。你可以找到一个例子 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
)
);
请注意,属性关键字显着简化了表达式。
最后,您可以使用wrap_formatter
将您自己的函数注入到流式表达式中。在格式化时,wrap_formatter
调用您的函数,为它提供正在格式化的日志记录和格式化流。当您的函数 returns 包装器自动 returns 对格式化流的引用,以便格式化表达式的其余部分可以继续。
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
)
);
以上内容与 boost::phoenix::bind
的第一个变体类似,但在 file_basename
实现中允许更大的灵活性。
在使用 Boost.Log 时,我试图保留我的 TimeStamp
格式化程序,例如:
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")
<< " " << expr::attr< std::string >("File")
<< " " << logging::trivial::severity
<< " - " << expr::smessage
)
);
据说我不能使用其他形式的格式化程序,因为我很难将 "TimeStamp"
转换为我的自定义格式:
static void my_formatter(logging::record_view const& rec, logging::formatting_ostream& strm)
{
strm << logging::extract< boost::posix_time::ptime >("TimeStamp", rec);
将输出类似:2015-Jul-01 16:06:31.514053
,而我只对:"%Y-%m-%d %H:%M:%S"
感兴趣。然而,第一种形式非常难以使用,例如我无法将 expr::attr< std::string >
转换为简单的 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::filesystem::path(expr::attr< std::string >("File"))
.filename().string()
<< " " << logging::trivial::severity
<< " - " << expr::smessage
)
);
以上代码甚至无法编译。
有没有一种简单的方法既可以使用我的自定义格式打印 TimeStamp
,又可以同时使用自定义转换为字符串以便能够使用 boost::filesystem::path::filename()
?
在自定义格式化程序中,您可以轻松构建 "%Y-%m-%d %H:%M:%S"
格式的时间戳:
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];
}
有多种方法可以实现您想要的。要理解的关键点是 Boost.Log 格式化表达式(以及过滤器,顺便说一下)是 Boost.Phoenix lambda 函数。因此,您可以使用 Boost.Phoenix 结构(例如 boost::phoenix::bind
)在其中注入您自己的函数。例如,参见示例 here。您的代码看起来像这样:
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
)
);
另一种方法是使用属性关键字并定义一个特定于文件属性的 operator<<
。你可以找到一个例子 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
)
);
请注意,属性关键字显着简化了表达式。
最后,您可以使用wrap_formatter
将您自己的函数注入到流式表达式中。在格式化时,wrap_formatter
调用您的函数,为它提供正在格式化的日志记录和格式化流。当您的函数 returns 包装器自动 returns 对格式化流的引用,以便格式化表达式的其余部分可以继续。
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
)
);
以上内容与 boost::phoenix::bind
的第一个变体类似,但在 file_basename
实现中允许更大的灵活性。