将boost.log与printf样式的宏一起使用 [英] Using boost.log with printf-style macros
问题描述
我正在开发一个使用定制的,依赖于平台的记录器的应用程序.该应用程序定义了一些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";
- 是否有一种简单的方法来提供一个采用printf样式的args并将其打印到boost logger的宏,而不必使用字符串缓冲区? (我认为必须格式化为字符串会影响性能)
- 如果没有,是否有一种方法可以使用
va_args
格式化字符串,而不必使用#ifdef
进行格式化功能的不同平台实现? (这首先就是转向boost.log的全部内容)
- 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)
- 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屋!