Boost :: log:基于级别的不同格式(HTML格式)
问题描述:
我正在研究基本的boost example from here。我正在配置我的应用程序所需的内容,但我被卡住了。这里是我现在的位置:Boost :: log:基于级别的不同格式(HTML格式)
#include <fstream>
#include <iomanip>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/smart_ptr/make_shared_object.hpp>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
namespace logging = boost::log;
namespace src = boost::log::sources;
namespace expr = boost::log::expressions;
namespace sinks = boost::log::sinks;
namespace keywords = boost::log::keywords;
void init()
{
typedef sinks::synchronous_sink<sinks::text_ostream_backend> text_sink;
boost::log::core::get()->add_global_attribute("TimeStamp", boost::log::attributes::utc_clock());
boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>();
sink->locked_backend()->add_stream(
boost::make_shared<std::ofstream>("log.html"));
sink->set_formatter
(
expr::stream
<< expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y.%m.%d-%H:%M:%S-UTC")
<< ": <" << logging::trivial::severity << "> " << expr::smessage
);
logging::core::get()->add_sink(sink);
}
int main(int, char*[])
{
std::cout<<"Start"<<std::endl;
init();
logging::add_common_attributes();
using namespace logging::trivial;
src::severity_logger<severity_level> lg;
BOOST_LOG_SEV(lg, trace) << "A trace severity message";
BOOST_LOG_SEV(lg, debug) << "A debug severity message";
BOOST_LOG_SEV(lg, info) << "An informational severity message";
BOOST_LOG_SEV(lg, warning) << "A warning severity message";
BOOST_LOG_SEV(lg, error) << "An error severity message";
BOOST_LOG_SEV(lg, fatal) << "A fatal severity message";
std::cout<<"End"<<std::endl;
return 0;
}
我想要的格式取决于严重程度。这是因为我的日志输出是HTML。例如,这些消息我在主那里应该输出打印这样的文件:
<font color='black'>A trace severity message</font>
<font color='gray'>A debug severity message</font>
<font color='blue'>An informational severity message</font>
<font color='orange'>A warning severity message</font>
<font color='red'>An error severity message</font>
<strong><font color='red'>A fatal severity message</font></strong>
这可能与简单的模型我在那里?需要做些什么?
插入if
条件到sink->set_formatter()
。我不能在那里使用C++ 11 lambda。
答
有很多方法可以做你想做的事情。最直接的方法是使用conditional formatter:
sink->set_formatter
(
expr::stream
<< expr::if_(logging::trivial::severity <= logging::trivial::severity_level::trace)
[
expr::stream << "<font color='black'>"
]
.else_
[
expr::stream << expr::if_(logging::trivial::severity <= logging::trivial::severity_level::debug)
[
// ...
]
]
<< expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y.%m.%d-%H:%M:%S-UTC")
<< ": <" << logging::trivial::severity << "> " << expr::smessage
);
但是,这种方法可以是相当繁琐的,并且具有最佳性能。
更好的解决方案是将你的函数注入格式化程序。这里有一个例子:
boost::string_view prefix_formatter(
logging::value_ref< logging::trivial::severity_level, logging::trivial::tag::severity > const& level)
{
if (level)
{
switch (level.get())
{
case logging::trivial::severity_level::trace:
return "<font color='black'>";
case logging::trivial::severity_level::debug:
return "<font color='gray'>";
// ...
}
}
return boost::string_view();
}
boost::string_view suffix_formatter(
logging::value_ref< logging::trivial::severity_level, logging::trivial::tag::severity > const& level)
{
if (level)
{
switch (level.get())
{
case logging::trivial::severity_level::trace:
return "</font>";
// ...
}
}
return boost::string_view();
}
sink->set_formatter
(
expr::stream
<< boost::phoenix::bind(&prefix_formatter, logging::trivial::severity.or_none())
<< expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y.%m.%d-%H:%M:%S-UTC")
<< ": <" << logging::trivial::severity << "> " << expr::smessage
<< boost::phoenix::bind(&suffix_formatter, logging::trivial::severity.or_none())
);
这里,or_none
使得value_ref
是空的,如果属性不存在的日志记录,因此需要检查它在prefix_formatter
和suffix_formatter
。
最后,由于您正在编写HTML,因此您可能希望将输出中的保留字符自动转换为转义序列。 XML character decorator可以帮助你。
答
我能够像这样做,使用自定义格式:
#include <fstream>
#include <iomanip>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/smart_ptr/make_shared_object.hpp>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include "boost/log/utility/setup.hpp"
#include "boost/log/support/date_time.hpp"
#include <boost/log/expressions/formatters/xml_decorator.hpp>
namespace b_logging = boost::log;
namespace b_srcs = b_logging::sources;
namespace b_expr = b_logging::expressions;
namespace b_sinks = b_logging::sinks;
b_logging::formatting_ostream& severity_wrap_prefix(b_logging::formatting_ostream& strm, const b_logging::trivial::severity_level& sev)
{
if (sev == b_logging::trivial::severity_level::trace)
strm << "<font color='gray'>";
else if(sev == b_logging::trivial::severity_level::debug)
strm << "<font color='#808080'>";
else if(sev == b_logging::trivial::severity_level::info)
strm << "<font color='green'>";
else if(sev == b_logging::trivial::severity_level::warning)
strm << "<font color='orange'>";
else if(sev == b_logging::trivial::severity_level::error)
strm << "<font color='red'>";
else if(sev == b_logging::trivial::severity_level::fatal)
strm << "<strong><font color='red'>";
else
strm << "<UNKNOWN SEVERITY LEVEL>";
return strm;
}
b_logging::formatting_ostream& severity_wrap_suffix(b_logging::formatting_ostream& strm, const b_logging::trivial::severity_level& sev)
{
if (sev == b_logging::trivial::severity_level::trace)
strm << "</font><br>";
else if(sev == b_logging::trivial::severity_level::debug)
strm << "</font><br>";
else if(sev == b_logging::trivial::severity_level::info)
strm << "</font><br>";
else if(sev == b_logging::trivial::severity_level::warning)
strm << "</font><br>";
else if(sev == b_logging::trivial::severity_level::error)
strm << "</font><br>";
else if(sev == b_logging::trivial::severity_level::fatal)
strm << "</strong></font><br>";
else
strm << "<UNKNOWN SEVERITY LEVEL>";
return strm;
}
std::string ptime_to_string(const boost::posix_time::ptime& time)
{
std::stringstream str;
boost::posix_time::time_facet *facet = new boost::posix_time::time_facet("%d.%m.%Y-%H:%M:%S-UTC");
str.imbue(std::locale(str.getloc(), facet));
str << time;
return str.str();
}
void init()
{
b_logging::core::get()->add_global_attribute("TimeStamp", b_logging::attributes::utc_clock());
typedef b_sinks::synchronous_sink<b_sinks::text_ostream_backend> text_sink;
boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>();
sink->locked_backend()->add_stream(
boost::make_shared<std::ofstream>("sample.htm"));
sink->set_formatter([&](b_logging::record_view const& rec, b_logging::formatting_ostream& strm)
{
const b_logging::trivial::severity_level& sev = *b_logging::extract<b_logging::trivial::severity_level>("Severity", rec);
const boost::posix_time::ptime &pt = *b_logging::extract<boost::posix_time::ptime>("TimeStamp", rec);
severity_wrap_prefix(strm,sev);
strm << ptime_to_string(pt) << ": "
<< rec[b_expr::smessage];
strm << b_expr::xml_decor[b_expr::stream << b_expr::smessage];
severity_wrap_suffix(strm,sev);
});
b_logging::core::get()->add_sink(sink);
}
int main(int, char*[])
{
std::cout<<"Start"<<std::endl;
init();
b_logging::add_common_attributes();
using namespace b_logging::trivial;
b_srcs::severity_logger<severity_level> lg;
BOOST_LOG_SEV(lg, trace) << "A trace severity message";
BOOST_LOG_SEV(lg, debug) << "A debug severity message";
BOOST_LOG_SEV(lg, info) << "An informational severity message";
BOOST_LOG_SEV(lg, warning) << "A warning severity message";
BOOST_LOG_SEV(lg, error) << "An error severity message";
BOOST_LOG_SEV(lg, fatal) << "A fatal severity message";
std::cout<<"End"<<std::endl;
return 0;
}
安德烈的解决方案并没有为我工作,因为显然string_view
是新的东西,在我提升我找不到它是附带Debian Jessie,Boost 1.55。
谢谢你的回答。我试图实现它。那'string_view'不是升压1.55,对不对?我在Debian Jessie上,在整个'/ usr /'目录下找不到grep。 –
不,它稍后添加。您可以使用'boost :: string_ref'或'std :: string'来代替。 –
非常感谢。我不知道。实际上今天早上我读了'string_view'并了解它是什么。另一方面,我找到了解决问题的办法,并在另一个答案中写下了它。我从你身上学到了很多东西,所以我对此加以赞赏:)再次感谢! –