将boost.log与printf样式的宏一起使用 [英] Using boost.log with printf-style macros

查看:129
本文介绍了将boost.log与printf样式的宏一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个使用定制的,依赖于平台的记录器的应用程序.该应用程序定义了一些printf样式的宏:

I'm working on an application that uses an custom, platform-dependent logger. The application defines some printf-style macros:

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

...

过去几天,我一直在努力将应用程序移动为使用boost.log.我遇到的最大问题是尝试保留此宏格式,以便仅更改记录器内部,因为boost的记录API以iostream样式(即

The past few days I've been working on moving the application to use boost.log. The biggest problem I'm having is trying to retain this macro format so that only the logger internals need to be changed, since boost's logging API is implemented in iostream-style, i.e.

BOOST_LOG(logger) << "something";

  1. 是否有一种简单的方法来提供一个采用printf样式的args并将其打印到boost logger的宏,而不必使用字符串缓冲区? (我认为必须格式化为字符串会影响性能)
  2. 如果没有,是否有一种方法可以使用va_args格式化字符串,而不必使用#ifdef进行格式化功能的不同平台实现? (这首先就是转向boost.log的全部内容)
  1. Is there an easy way to provide a macro that takes printf-style args and prints them to the boost logger without having to use string buffers? (I would think that having to format to a string would be a performance impact)
  2. If not, is there a way to format a string using va_args without having to #ifdef for different platform implementations of formatting functions? (this was the whole point of moving to boost.log in the first place)

推荐答案

不幸的是,没有#ifdef语句就没有干净的实现.我知道您想移植现有的日志以按原样增强日志.那将是不正确的做事方式. printf被设计用于C,而boost log被设计用于C ++.因此,我的建议是正确使用它.您可以使记录宏比代码示例中显示的更加轻松.

Unfortunately, there are no clean implementations without the #ifdef statement. I know you want to port your existing logging to boost log as-is. That would be an incorrect way of doing things. printf was designed to be used for C, while boost log was designed for C++. So, my suggestion would be to use it the right way. You can make your logging macros painless than what you've shown in your code sample.

这是我对boost log的实现,在这里我没有BOOST_LOG(logger) << "something";,而是拥有roLOG_INFO << "something";.我相信这个示例来自boost log的示例之一.

Here's my implementation of boost log where instead of having BOOST_LOG(logger) << "something";, I have it as roLOG_INFO << "something";. I believe this example comes from one of boost log's samples.

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

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;
    }
}

免责声明:我并不是说这是完美的代码.它对我有用,我对此感到满意.

DISCLAIMER: I'm not claiming this to be a perfect piece of code. It works for me and I'm happy with it.

假设您仍然希望记录printf样式,然后考虑以下代码:

Let's say you would still like the option of logging the printf style, then consider the following code:

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)

免责声明:我尚未测试以上代码.您可能需要对其进行调整,以使其适合您.

DISCLAIMER: I haven't tested the above code. You might need to tweak it to make it work for you.

这篇关于将boost.log与printf样式的宏一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆