如何在boost log 2.0中记录编码器的行号?

时间:2014-02-28 12:47:40

标签: boost-log

我可以使用LineID属性吗? 我希望我可以使用sink :: set_formatter来代替使用

__LINE__

__FILE__

在每个日志语句中。

5 个答案:

答案 0 :(得分:11)

我一直在努力,直到找到this snippet

#define LFC1_LOG_TRACE(logger) \
BOOST_LOG_SEV(logger, trivial::trace) << "(" << __FILE__ << ", " << __LINE__ << ") "

像魅力一样工作

答案 1 :(得分:4)

Chris显示的解决方案有效,但如果您想自定义格式或选择每个接收器中显示的信息,则需要使用可变常量属性:

   logging::core::get()->add_global_attribute("File", attrs::mutable_constant<std::string>(""));
   logging::core::get()->add_global_attribute("Line", attrs::mutable_constant<int>(0));

然后,您创建一个包含以下新属性的自定义宏:

// New macro that includes severity, filename and line number
#define CUSTOM_LOG(logger, sev) \
   BOOST_LOG_STREAM_WITH_PARAMS( \
      (logger), \
         (set_get_attrib("File", path_to_filename(__FILE__))) \
         (set_get_attrib("Line", __LINE__)) \
         (::boost::log::keywords::severity = (boost::log::trivial::sev)) \
   )

// Set attribute and return the new value
template<typename ValueType>
ValueType set_get_attrib(const char* name, ValueType value) {
   auto attr = logging::attribute_cast<attrs::mutable_constant<ValueType>>(logging::core::get()->get_global_attributes()[name]);
   attr.set(value);
   return attr.get();
}

// Convert file path to only the filename
std::string path_to_filename(std::string path) {
   return path.substr(path.find_last_of("/\\")+1);
}

下一个完整的源代码会创建两个接收器。第一个使用File和Line属性,第二个不使用。

#include <boost/log/trivial.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/attributes/mutable_constant.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/attributes/mutable_constant.hpp>

namespace logging  = boost::log;
namespace attrs    = boost::log::attributes;
namespace expr     = boost::log::expressions;
namespace src      = boost::log::sources;
namespace keywords = boost::log::keywords;

// New macro that includes severity, filename and line number
#define CUSTOM_LOG(logger, sev) \
   BOOST_LOG_STREAM_WITH_PARAMS( \
      (logger), \
         (set_get_attrib("File", path_to_filename(__FILE__))) \
         (set_get_attrib("Line", __LINE__)) \
         (::boost::log::keywords::severity = (boost::log::trivial::sev)) \
   )

// Set attribute and return the new value
template<typename ValueType>
ValueType set_get_attrib(const char* name, ValueType value) {
   auto attr = logging::attribute_cast<attrs::mutable_constant<ValueType>>(logging::core::get()->get_global_attributes()[name]);
   attr.set(value);
   return attr.get();
}

// Convert file path to only the filename
std::string path_to_filename(std::string path) {
   return path.substr(path.find_last_of("/\\")+1);
}

void init() {
   // New attributes that hold filename and line number
   logging::core::get()->add_global_attribute("File", attrs::mutable_constant<std::string>(""));
   logging::core::get()->add_global_attribute("Line", attrs::mutable_constant<int>(0));

   // A file log with time, severity, filename, line and message
   logging::add_file_log (
    keywords::file_name = "sample.log",
    keywords::format = (
     expr::stream
      << expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d_%H:%M:%S.%f")
      << ": <" << boost::log::trivial::severity << "> "
      << '['   << expr::attr<std::string>("File")
               << ':' << expr::attr<int>("Line") << "] "
      << expr::smessage
    )
   );
   // A console log with only time and message
   logging::add_console_log (
    std::clog,
    keywords::format = (
     expr::stream
      << expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S")
      << " | " << expr::smessage
    )
   );
   logging::add_common_attributes();
}

int main(int argc, char* argv[]) {
   init();
   src::severity_logger<logging::trivial::severity_level> lg;

   CUSTOM_LOG(lg, debug) << "A regular message";
   return 0;
}

语句CUSTOM_LOG(lg, debug) << "A regular message";生成两个输出,用这种格式编写一个日志文件......

2015-10-15_15:25:12.743153: <debug> [main.cpp:61] A regular message

...并输出到控制台:

2015-10-15 16:58:35 | A regular message

答案 2 :(得分:1)

另一种可能性是在创建每个日志记录后为其添加行和文件属性。这是可能的,因为在较新的版本中。稍后添加的属性不参与过滤。

假设用变量logger标识了severity_logger:

boost::log::record rec = logger.open_record(boost::log::keywords::severity = <some severity value>);
if (rec)
{
    rec.attribute_values().insert(boost::log::attribute_name("Line"),
        boost::log::attributes::constant<unsigned int>(__LINE__).get_value());
    ... other stuff appended to record ...
}

当然,上述内容将包含在方便的宏中。

稍后您可以使用自定义格式化程序为接收器显示此属性:

sink->set_formatter( ...other stuff... << expr::attr<unsigned int>("Line") << ...other stuff... );

与之前的答案不同,此方法需要更多自定义代码,无法使用现成的boost记录宏。

答案 3 :(得分:0)

为了后人的缘故 - 为了简单的日志记录需求,我为非常简单的日志记录需求制作了这组宏,这对我很有帮助。但它们总体上说明了如何做到这一点,这个概念很容易与Boost一起使用。它们应该是一个文件的本地文件(在多个进程中运行,有时在多个进程中的多个线程中运行)。它们是为了相对简单而不是速度而制造的。如果声明等,他们是安全的,以便不偷窃别人。在想要记录的功能开始时,一个调用

GLogFunc("function name");

然后可以这样做来记录完整的一行:

GLogL("this is a log entry with a string: " << some_string);

他们就是这样 -

#define GLogFunc(x)     std::stringstream logstr; \
                        std::string logfunc; \
                        logfunc = x

#define GLog(x)         do { logstr << x; } while(0)

#define GLogComplete    do { \
                            _log << "[PID:" << _my_process << " L:" << __LINE__ << "] ((" << logfunc << ")) " << logstr.str() << endl; \
                             logstr.str(""); \
                             _log.flush(); \ 
                        } while(0)

#define GLogLine(x)     do { GLog(x); GLogComplete; } while(0)
#define GLogL(x)        GLogLine(x)
#define GLC             GLogComplete

还可以通过几行构建日志......

GLog("I did this.");
// later
GLog("One result was " << some_number << " and then " << something_else);
// finally
GLog("And now I'm done!");
GLogComplete;

无论是什么流_log(我将它作为类构造函数中的文件打开,在这个实例中保证是安全的)得到这样的输出:

[PID:4848 L:348] ((SetTextBC)) ERROR: bad argument row:0 col:-64

它们可以有条件地关闭,所有性能损失都会在编译时被符号否定:

#ifdef LOGGING_ENABLED
... do the stuff above ...
#else

#define GLogFunc(x)
#define GLog(x)
#define GLogComplete
#define GLogLine(x) 
#define GLogL(x)

#endif

答案 4 :(得分:0)

这是我的解决方案。

设置代码

auto formatter =
    expr::format("[ %3% %1%:%2% :: %4%]")
    % expr::attr< std::string >("File")
    % expr::attr< uint32_t >("Line")
    % expr::attr< boost::posix_time::ptime >("TimeStamp")
    % expr::smessage
    ;

/* stdout sink*/
boost::shared_ptr< sinks::text_ostream_backend > backend =
    boost::make_shared< sinks::text_ostream_backend >();
backend->add_stream(
    boost::shared_ptr< std::ostream >(&std::clog, NullDeleter()));

// Enable auto-flushing after each log record written
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_ostream_backend > sink2_t;
boost::shared_ptr< sink2_t > sink_text(new sink2_t(backend));

logging::add_common_attributes();

sink_text->set_formatter(formatter);

日志使用代码(简短版):

rec.attribute_values().insert("File", attrs::make_attribute_value(std::string(__FILE__))); \

完整版:

#define LOG(s, message) { \
  src::severity_logger< severity_level > slg; \
  logging::record rec = slg.open_record(keywords::severity = s); \
  if (rec) \
  { \
    rec.attribute_values().insert("File", attrs::make_attribute_value(boost::filesystem::path(__FILE__).filename().string())); \
    rec.attribute_values().insert("Line", attrs::make_attribute_value(uint32_t(__LINE__))); \
    logging::record_ostream strm(rec); \
    strm << message; \
    strm.flush(); \
    slg.push_record(boost::move(rec)); \
  } \

} \

如果我定义全局属性(就像之前建议过的人那样),即

logging::core::get()->add_global_attribute("File", attrs::mutable_constant<std::string>(""));

然后我得到文件/ stiring。