3

我正在开发一个使用自定义平台相关记录器的应用程序。应用程序定义了一些 printf 风格的宏:

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

...

在过去的几天里,我一直在努力将应用程序迁移到使用boost.log. 我遇到的最大问题是试图保留这种宏格式,以便只需要更改记录器内部,因为 boost 的日志记录 API 是以 iostream 样式实现的,即

BOOST_LOG(logger) << "something";
  1. 有没有一种简单的方法来提供一个宏,该宏采用 printf 样式的 args 并将它们打印到 boost 记录器而不必使用字符串缓冲区?(我认为必须格式化为字符串会影响性能)
  2. 如果没有,有没有一种方法可以格式化字符串,va_args而不必使用#ifdef格式化函数的不同平台实现?(这是首先转移到 boost.log 的重点)
4

2 回答 2

3

或者只是使用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和扩展它以处理多个参数(很可能使用可变参数模板参数)作为练习留给读者。

于 2014-05-22T20:01:07.690 回答
0

不幸的是,没有#ifdef声明就没有干净的实现。我知道您想移植现有的日志记录以按原样提升日志记录。那将是一种不正确的做事方式。printf 设计用于 C,而 boost log 设计用于 C++。所以,我的建议是正确使用它。您可以使您的日志记录宏比您在代码示例中显示的内容更轻松。

这是我对 boost log 的实现BOOST_LOG(logger) << "something";,我没有将它作为roLOG_INFO << "something";. 我相信这个例子来自 boost log 的样本之一。

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)

免责声明:我没有测试过上面的代码。您可能需要对其进行调整以使其适合您。

于 2013-04-16T20:04:55.937 回答