2013-04-16 58 views
2

我正在使用一個自定義的,依賴於平臺的記錄器的應用程序。該應用程序定義了一些printf風格的宏:使用boost.log與printf風格的宏

#define LOG_DEBUG(format, ...) \ 
    logger.log(DEBUG, __FUNCTION__, format, ##__VA_ARGS__) 

... 

這幾天我一直工作在移動應用程序中使用boost.log。我遇到的最大的問題是試圖保持這個宏格式,以便只記錄器內部需要改變,因爲升壓轉換器的日誌記錄API在iostream的風格來實現,即

BOOST_LOG(logger) << "something"; 
  1. 有一個簡單的提供一個採用printf樣式參數並將它們打印到boost記錄器而不必使用字符串緩衝區的宏的方法? (我認爲必須格式化爲字符串會對性能產生影響)
  2. 如果沒有,是否有一種方法可以使用va_args來格式化字符串,而不必爲#ifdef用於格式化函數的不同平臺實現? (這是首先轉向boost.log的要點)
+0

您是否嘗試過我發佈的答案? –

+0

是的。你用'vsnprintf'給出的最後一個例子非常好。早期的宏定義有點過分,但給了我一些想法。謝謝! – jwalk

回答

0

不幸的是,沒有#ifdef語句沒有乾淨的實現。我知道你想移植現有的日誌記錄以按原樣提升日誌。這將是一種不正確的做事方式。 printf被設計用於C,而boost日誌是爲C++設計的。所以,我的建議是以正確的方式使用它。您可以使您的日誌記錄宏比您在代碼示例中顯示的內容更加輕鬆。

這裏是我的升壓日誌的實現,而不是有BOOST_LOG(logger) << "something";,我把它作爲roLOG_INFO << "something";。我相信這個例子來自boost日誌的樣本之一。

RoLog.h

#include <boost/logging/format_fwd.hpp> 

#include <boost/logging/writer/on_dedicated_thread.hpp> 

// Optimize : use a cache string, to make formatting the message faster 
BOOST_LOG_FORMAT_MSG(optimize::cache_string_one_str<>) 

#ifndef BOOST_LOG_COMPILE_FAST 
#include <boost/logging/format.hpp> 
#include <boost/logging/writer/ts_write.hpp> 
#endif 

// Specify your logging class(es) 
typedef boost::logging::logger_format_write< > log_type; 

// Declare which filters and loggers you'll use 
BOOST_DECLARE_LOG_FILTER(roLogFilter, boost::logging::level::holder) 
BOOST_DECLARE_LOG(roLog, log_type) 

#define roLOG_WHERE_EACH_LINE 0 
#if defined(roLOG_WHERE_EACH_LINE) && roLOG_WHERE_EACH_LINE 
# define _roLOG_WHERE << roWHERE 
#else 
# define _roLOG_WHERE 
#endif 

// Define the macros through which you'll log 
#define roLOG_DBG BOOST_LOG_USE_LOG_IF_LEVEL(roLog(), roLogFilter(), debug) << "[ DEBUG ]:" _roLOG_WHERE 
#define roLOG_WARN BOOST_LOG_USE_LOG_IF_LEVEL(roLog(), roLogFilter(), warning) << "[ WARNING ]:" _roLOG_WHERE 
#define roLOG_ERR BOOST_LOG_USE_LOG_IF_LEVEL(roLog(), roLogFilter(), error) << "[ ERROR ]:" _roLOG_WHERE 
#define roLOG_CRIT BOOST_LOG_USE_LOG_IF_LEVEL(roLog(), roLogFilter(), fatal) << "[ CRITICAL]:" _roLOG_WHERE 
#define roLOG_INFO BOOST_LOG_USE_LOG_IF_LEVEL(roLog(), roLogFilter(), info) 
struct RoLogOptions; 

void roInitLogs(const RoLogOptions& options); 

RoLog.cpp

#include <Core/RoLog.h> 
#include <Core/RoLogOptions.h> 

#include <boost/logging/format.hpp> 
#include <boost/logging/writer/ts_write.hpp> 

using namespace boost::logging; 

BOOST_DEFINE_LOG(roLog, log_type) 
BOOST_DEFINE_LOG_FILTER(roLogFilter, level::holder) 
#define BLOCK(stmts) do{stmts}while(false) 
#define CHECK_AND_DO(var,stmt) if (var) stmt 
//------------------------------------------------------------------------------ 
void roInitLogs(const RoLogOptions& options) 
{ 
    static bool initialize = true; 
    if (initialize) 
    { 
     // Add formatters and destinations 
     // That is, how the message is to be formatted... 
     CHECK_AND_DO(options.printIndex, roLog()->writer().add_formatter(formatter::idx())); 
     CHECK_AND_DO(options.printTimestamp, roLog()->writer().add_formatter(formatter::time(options.timestampFormat))); 
     CHECK_AND_DO(options.autoAppendLine, roLog()->writer().add_formatter(formatter::append_newline())); 

     //  ... and where should it be written to 
     roLog()->writer().add_destination(destination::dbg_window()); 
     CHECK_AND_DO(options.printToStdOut, roLog()->writer().add_destination(destination::cout())); 
     if (!options.logFile.empty()) 
     { 
      destination::file_settings settings; 
      settings.do_append(options.logFileAppendExisting); 
      roLog()->writer().add_destination(destination::file(options.logFile, settings)); 
     } 
     CHECK_AND_DO(options.turnOffCache, roLog()->turn_cache_off()); 

     //  ... and set the log-level 
     level::type boost_log_level; 
     switch(options.logLevel) 
     { 
     case eLogLevel_None: 
      boost_log_level = level::disable_all; 
      break; 
     case eLogLevel_All: 
      boost_log_level = level::enable_all; 
      break; 
     case eLogLevel_Debug: 
      boost_log_level = level::debug; 
      break; 
     case eLogLevel_Info: 
      boost_log_level = level::info; 
      break; 
     case eLogLevel_Warning: 
      boost_log_level = level::warning; 
     case eLogLevel_Error: 
      boost_log_level = level::error; 
      break; 
     case eLogLevel_Critical: 
      boost_log_level = level::fatal; 
      break; 
     case eLogLevel_Default: 
     default: 
#  ifdef _DEBUG 
      boost_log_level = level::debug; 
#  else 
      boost_log_level = level::info; 
#  endif // _DEBUG 
      break; 
     }; 
     roLogFilter()->set_enabled(boost_log_level); 
     initialize = false; 
    } 
} 

免責聲明:我不是說這是代碼完美的作品。它適用於我,我很高興。

比方說,你仍希望登錄printf類型的選項,然後考慮下面的代碼

class LogUtil 
{ 
    static void VLogError(const char* format, va_list argList) 
    { 
#ifdef _WIN32 
     int32 size = _vscprintf(format, argList) + 1; 
#else 
     int32 size = vsnprintf(0, 0, format, argList) + 1; 
#endif 
     if (size > 0) 
     { 
      boost::scoped_array<char> formattedString(new char[size]); 
      vsnprintf(formattedString.get(), size, format, argList); 
      roLOG_ERR << formattedString.get(); 
     } 
    } 
} 
#define roLOGF_ERR(format, ...) LogUtil::VLogError(format, ##__VA_ARGS) 

免責聲明:我沒有測試上面的代碼。您可能需要對其進行調整以使其適用於您。

0

或者只是使用Boost Format來處理printf格式的字符串。例如,

template<typename Level, typename T1> 
inline void log_format(
    const Level level, 
    const char* const fmt, 
    const T1& t1) 
{ 
    BOOST_LOG_SEV(logger::get(), level) << boost::format(fmt) % t1; 
} 

創建logger,並作爲練習留給讀者擴展該處理多個參數(最有可能與可變參數模板參數)。