我正在使用Boost-Log 2.0,它与版本1存在一些差异,我很难输出“Severity”属性。
我正在使用“Boost.Format-style”格式化程序
"%TimeStamp% [%Uptime%] (%LineID%) <%Severity%>: %Message%"
TimeStamp
,LineID
和Message
为common_attributes
。 Uptime
是我使用attrs::timer()
添加的属性。我认为Severity
在使用severity_logger
时会自动添加,但显然不是,这是我的问题。我得到空的严重性,例如:
2013-Apr-06 19:21:52.408974 [00:00:00.001337] (3) <>: A warning severity message
注意空<>
。我试图使用register_simple_formatter_factory
添加严重性,但后来我得到了编译器错误:
error: no matching function for call to ‘register_simple_formatter_factory(const char [9])’
我不明白为什么。
这是我的代码:
#include <iostream>
#include <boost/log/common.hpp>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/setup/formatter_parser.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/severity_feature.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/attributes.hpp>
using namespace std;
namespace logging = boost::log;
namespace expr = boost::log::expressions;
namespace attrs = boost::log::attributes;
namespace src = boost::log::sources;
namespace keywords = boost::log::keywords;
enum severity_level
{
DEBUG,
INFO,
WARNING,
ERROR,
CRITICAL
};
BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(my_logger, src::severity_logger_mt< severity_level> )
// The formatting logic for the severity level
template< typename CharT, typename TraitsT >
inline std::basic_ostream< CharT, TraitsT >& operator<< (
std::basic_ostream< CharT, TraitsT >& strm, severity_level lvl)
{
static const char* const str[] =
{
"DEBUG",
"INFO",
"WARNING",
"ERROR",
"CRITICAL"
};
if (static_cast< std::size_t >(lvl) < (sizeof(str) / sizeof(*str)))
strm << str[lvl];
else
strm << static_cast< int >(lvl);
return strm;
}
void init() {
// logging::register_simple_formatter_factory< severity_level >("Severity");
logging::add_file_log(
keywords::file_name = "blop.log",
keywords::auto_flush = true,
keywords::open_mode = (std::ios::out | std::ios::app),
keywords::format = "%TimeStamp% [%Uptime%] (%LineID%) <%Severity%>: %Message%"
);
logging::add_common_attributes();
logging::core::get()->add_global_attribute("Uptime", attrs::timer());
}
int main(int argc, const char *argv[]) {
init();
src::severity_logger_mt< severity_level > lg = my_logger::get();
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, CRITICAL) << "A critical severity message";
return 0;
}
注意注释掉的行:
// logging::register_simple_formatter_factory< severity_level >("Severity");
产生上述错误。
我用以下代码编译它:
g++ main.cpp -Wall -DBOOST_ALL_DYN_LINK -lboost_system -lboost_log_setup -lboost_log -lboost_filesystem -lboost_date_time -lboost_thread -o main
答案 0 :(得分:26)
遇到同样的问题(日志文件中的空白%严重性%和尝试添加注册函数时的编译器错误相同)。 我发现对register_simple_formatter_factory的调用应该是:
boost::log::register_simple_formatter_factory< boost::log::trivial::severity_level, char >("Severity");
答案 1 :(得分:4)
这是register_simple_formatter_factory
功能模板的原型:
template<typename AttributeValueT, typename CharT>
void register_simple_formatter_factory(attribute_name const &);
这意味着您忘了typename CharT
,所以,这里是正确的:
logging::register_simple_formatter_factory<severity_level, char>("Severity");
或其他一些字符类型,例如wchar_t
。
答案 2 :(得分:3)
您可以创建自己的后端并在其上调用set_formatter。这是我的代码,显示如何执行此操作以及一些添加内容,如日志文件清理和自动刷新:
BOOST_LOG_DECLARE_GLOBAL_LOGGER(db_logger, src::severity_logger_mt< dreambridge::log::LogLevel >);
#define LOGGER(level) BOOST_LOG_STREAM_SEV(db_logger::get(), level)
void InitializeFileLog(const std::string & logDir)
{
boost::shared_ptr< logging::core > loggingCore = logging::core::get();
db_logger::get().add_attribute(
"TimeStamp",
boost::make_shared< attrs::local_clock >());
string logPath = logDir + "/DreamBridgeSapi2MrcpTts_%N.log";
boost::shared_ptr< sinks::text_file_backend > backend =
boost::make_shared< sinks::text_file_backend >(
// file name pattern
keywords::file_name = logPath,
// rotate the file upon reaching 5 MiB size...
keywords::rotation_size = 5 * 1024 * 1024,
// ...or at midnight, whichever comes first
keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0)
);
backend->auto_flush(true);
// Wrap it into the frontend and register in the core.
// The backend requires synchronization in the frontend.
typedef sinks::synchronous_sink< sinks::text_file_backend > sink_t;
boost::shared_ptr< sink_t > sink(new sink_t(backend));
loggingCore->add_sink(sink);
backend->set_formatter(fmt::stream
<< fmt::date_time< boost::posix_time::ptime >("TimeStamp")
<< " : [" << fmt::attr< dreambridge::log::LogLevel >("Severity")
<< "] " << fmt::message()
);
backend->set_file_collector(sinks::file::make_collector(
// rotated logs will be moved here
keywords::target = logDir + "/old_logs",
// oldest log files will be removed if the total size reaches 100 MiB...
keywords::max_size = 100 * 1024 * 1024,
// ...or the free space in the target directory comes down to 50 MiB
keywords::min_free_space = 50 * 1024 * 1024
));
try
{
backend->scan_for_files(sinks::file::scan_all);
}
catch(std::exception & e)
{
LOGGER(emergency) << "exception during scanning : " << e.what();
}
}
您也可以将日志记录级别设置为:
void SetLogLevel(dreambridge::log::LogLevel logLevel)
{
boost::shared_ptr< logging::core > loggingCore = logging::core::get();
loggingCore->set_filter
(
flt::attr< dreambridge::log::LogLevel >("Severity") <= logLevel
);
}
注意:此代码来自我自己的存储库。 dreamdridge是产品名称,因此是命名空间。
答案 3 :(得分:1)
原因可能是您不应该将数据写入std :: ostream。 boost.log使用boost.log.formatting_ostream输出日志,而不是std :: ostream。 请参阅从http://www.boost.org/doc/libs/1_54_0/libs/log/doc/html/log/detailed/expressions.html页
中提取的此代码// The operator is used when putting the severity level to log
logging::formatting_ostream& operator<<
(
logging::formatting_ostream& strm,
logging::to_log_manip< severity_level, severity_tag > const& manip
)
{
static const char* strings[] =
{
"NORM",
"NTFY",
"WARN",
"ERRR",
"CRIT"
};
severity_level level = manip.get();
if (static_cast< std::size_t >(level) < sizeof(strings) / sizeof(*strings))
strm << strings[level];
else
strm << static_cast< int >(level);
return strm;
}
答案 4 :(得分:0)
正如您W. Merrt和Matt Yang的答案所指出的,更正注册格式化程序(即operator<<
)的调用是您正确编译和运行当前代码所需的全部内容。
但是,为了充分利用Boost Log的过滤功能,您还需要为自定义严重性级别定义operator>>
,然后使用过滤器工厂注册该方法。
template< typename CharT, typename TraitsT>
inline std::basic_istream< CharT, TraitsT >& operator>> (
std::basic_istream< CharT, TraitsT >& strm, severity_level &lvl)
{
std::string tmp;
strm >> tmp;
// can make it case insensitive to allow 'warning' instead of only 'WARNING'
// std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::toupper);
// if you have a lot of levels you may want use a map instead
if (tmp.compare("DEBUG") == 0) lvl = DEBUG;
else if (tmp.compare("INFO") == 0) lvl = INFO;
else if (tmp.compare("WARNING") == 0) lvl = WARNING;
else if (tmp.compare("ERROR") == 0) lvl = ERROR;
else if (tmp.compare("CRITICAL") == 0) lvl = CRITICAL;
// provide a default value for invalid strings
else lvl = DEBUG;
// or you could throw an exception
// else tmp.append(" is not a valid severity level."), throw std::invalid_argument(tmp);
return strm;
}
void init() {
// register operator<< for severity_level
logging::register_simple_formatter_factory< severity_level, char >("Severity");
// register operator>> for severity_level
logging::register_simple_filter_factory< severity_level >("Severity");
logging::add_file_log(
keywords::file_name = "blop.log",
keywords::auto_flush = true,
keywords::open_mode = (std::ios::out | std::ios::app),
keywords::format = "%TimeStamp% [%Uptime%] (%LineID%) <%Severity%>: %Message%",
// now you can filter using the name of the severity level
keywords::filter = "%Severity% >= INFO" );
logging::add_common_attributes();
logging::core::get()->add_global_attribute("Uptime", attrs::timer());
}