Использование boost.log с макросами в стиле printf

Я работаю над приложением, которое использует пользовательский, зависимый от платформы регистратор. Приложение определяет некоторые макросы в стиле printf:

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

...

Последние несколько дней я работал над переносом приложения на использование boost.log, Самая большая проблема, с которой я сталкиваюсь, — это попытка сохранить этот формат макроса, так что необходимо изменить только внутренности регистратора, поскольку API логирования boost реализован в стиле iostream, т.е.

BOOST_LOG(logger) << "something";
  1. Есть ли простой способ предоставить макрос, который принимает аргументы в стиле printf и печатает их в лог-бустер без необходимости использовать строковые буферы? (Я думаю, что форматирование в строку будет влиять на производительность)
  2. Если нет, есть ли способ отформатировать строку, используя va_args без необходимости #ifdef для разных платформ реализации функций форматирования? (в этом и заключался весь смысл перехода на boost.log)

2

Решение

К сожалению, нет чистых реализаций без #ifdef заявление. Я знаю, что вы хотите портировать существующую запись в журнал, чтобы повысить ее как есть. Это был бы неправильный способ делать вещи. printf был разработан для использования на C, в то время как boost log был разработан для 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 и расширение этого для обработки нескольких аргументов (наиболее вероятно с переменными аргументами шаблона) оставлено в качестве упражнения для читателя.

0

По вопросам рекламы [email protected]