2016-09-17 87 views
0

我使用boost_logging(第2版),我想避免在我的代码,乱扔垃圾这些:如何合并生成唯一标识符的两个boost日志记录宏?

BOOST_LOG_NAMED_SCOPE("SomeModuleName") 
BOOST_LOG_FUNCTION() 

我想第二个是,我宁愿他们在这样的宏观相结合:

#define LOG_NAMED_SCOPE_FUNCTION(name)\ 
    BOOST_LOG_NAMED_SCOPE(name)\ 
    BOOST_LOG_FUNCTION() 

但是当我尝试这样做时出现错误。见下文。

我会特别满意的解决方案,允许我在模块级别执行类似BOOST_LOG_NAMED_SCOPE("SomeModuleName")(也出错)。更好的办法是做一些RAII/AOP的解决方案,让我也可以在函数的开始和结尾添加“输入”和“退出”跟踪消息,因为这是我的最终目标。

我猜测是因为生成的唯一标识符在宏定义的位置扩展,而不是在宏调用时扩展。我也看了一下DEFERRED和EXPAND助手,但我不确定他们会帮助我。

这里的错误消息:

Project/SomeModuleName.cpp:9:5: error: redefinition of '_boost_log_named_scope_sentry_9' 
    LOG_NAMED_SCOPE_FUNCTION("SomeModuleName") 
    ^
Project/Logging.hpp:24:5: note: expanded from macro 'LOG_NAMED_SCOPE_FUNCTION' 
    BOOST_LOG_FUNCTION() 
    ^
/usr/local/include/boost/log/attributes/named_scope.hpp:458:36: note: expanded from macro 'BOOST_LOG_FUNCTION' 
    BOOST_LOG_NAMED_SCOPE_INTERNAL(BOOST_LOG_UNIQUE_IDENTIFIER_NAME(_boost_log_named_scope_sentry_), BOOST_CURRENT_FUNCTION, __FILE__, __LINE__, ::boost::log::attributes::named_scope_entry::function) 
           ^
/usr/local/include/boost/log/utility/unique_identifier_name.hpp:48:5: note: expanded from macro 'BOOST_LOG_UNIQUE_IDENTIFIER_NAME' 
    BOOST_LOG_UNIQUE_IDENTIFIER_NAME_INTERNAL(prefix, __LINE__) 
    ^
note: (skipping 2 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all) 
/usr/local/include/boost/preprocessor/cat.hpp:22:32: note: expanded from macro 'BOOST_PP_CAT' 
# define BOOST_PP_CAT(a, b) BOOST_PP_CAT_I(a, b) 
          ^
/usr/local/include/boost/preprocessor/cat.hpp:29:34: note: expanded from macro 'BOOST_PP_CAT_I' 
# define BOOST_PP_CAT_I(a, b) a ## b 
           ^
<scratch space>:89:1: note: expanded from here 
_boost_log_named_scope_sentry_9 
^ 
Project/SomeModuleName.cpp:9:5: note: previous definition is here 
Project/Logging.hpp:23:5: note: expanded from macro 'LOG_NAMED_SCOPE_FUNCTION' 
    BOOST_LOG_NAMED_SCOPE(name)\ 
    ^
/usr/local/include/boost/log/attributes/named_scope.hpp:449:36: note: expanded from macro 'BOOST_LOG_NAMED_SCOPE' 
    BOOST_LOG_NAMED_SCOPE_INTERNAL(BOOST_LOG_UNIQUE_IDENTIFIER_NAME(_boost_log_named_scope_sentry_), name, __FILE__, __LINE__, ::boost::log::attributes::named_scope_entry::general) 
           ^
/usr/local/include/boost/log/utility/unique_identifier_name.hpp:48:5: note: expanded from macro 'BOOST_LOG_UNIQUE_IDENTIFIER_NAME' 
    BOOST_LOG_UNIQUE_IDENTIFIER_NAME_INTERNAL(prefix, __LINE__) 
    ^
note: (skipping 2 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all) 
/usr/local/include/boost/preprocessor/cat.hpp:22:32: note: expanded from macro 'BOOST_PP_CAT' 
# define BOOST_PP_CAT(a, b) BOOST_PP_CAT_I(a, b) 
          ^
/usr/local/include/boost/preprocessor/cat.hpp:29:34: note: expanded from macro 'BOOST_PP_CAT_I' 
# define BOOST_PP_CAT_I(a, b) a ## b 
           ^
<scratch space>:85:1: note: expanded from here 
_boost_log_named_scope_sentry_9 
^ 
+0

不确定,但你有没有尝试插入分号? :'#define LOG_NAMED_SCOPE_FUNCTION(name)\ BOOST_LOG_NAMED_SCOPE(name); \ BOOST_LOG_FUNCTION()'(对不起,如果它很愚蠢,但我真的不明白如何有这个错误:它应该工作,期间) –

+0

@ Jean-FrançoisFabre如果我添加分号,则会出现同样的错误。我在发布之前尝试过);但是谢谢!这让我明白,问题的一部分是宏是线路敏感的,如果我跳过我的宏并将两个宏调用粘贴在相关函数的同一行上,我试图记录,我得到相同的错误信息。这个换行插入技巧并没有为我工作,虽然:http://stackoverflow.com/a/2567304/232593 –

+1

好吧,所以我愚蠢的评论让你进步。下面是另外一个例子:你是否比较了g ++ -E的输出和没有宏的情况? –

回答

1

您遇到的问题是,因为BOOST_LOG_FUNCTION本质上是基于BOOST_LOG_NAMED_SCOPE - 它增加了其名称对应于当前函数签名范围。这两个宏都创建一个局部变量,该变量的名称对于源文件的给定行是唯一的(它使用__LINE__来生成该名称)。按照C/C++预处理器规则,所有的宏都扩展成一行,所以你的LOG_NAMED_SCOPE_FUNCTION扩展到同一个作用域中的两个相同的命名局部变量,因此编译器错误。

解决此问题的一种方法是定义您的宏,以便它为两个范围直接定义两个不同的变量。变量应该有named_scope::sentry类型,它是一个在构建和销毁时自动推送和弹出范围到堆栈的范围守护程序。

#define LOG_NAMED_SCOPE_FUNCTION(name)\ 
    boost::log::attributes::named_scope::sentry BOOST_LOG_UNIQUE_IDENTIFIER_NAME(scope_sentry1_)(name, __FILE__, __LINE__);\ 
    boost::log::attributes::named_scope::sentry BOOST_LOG_UNIQUE_IDENTIFIER_NAME(scope_sentry2_)(BOOST_CURRENT_FUNCTION, __FILE__, __LINE__, boost::log::attributes::named_scope_entry::function) 

这样每个LOG_NAMED_SCOPE_FUNCTION将两个作用域添加到列表 - 指定的范围和当前功能。

然而,从你的描述看来,这实际上并不是你想要实现的。 Boost.Log不允许直接的方式来标记日志记录与他们的起源模块的名称 - 主要是因为没有可移植的方式知道这一点,而非便携式的方式是昂贵的。但是有很多方法可以模拟这种行为。这里有一些想法。

最简单的方法是使用自己的日志记录宏,该宏将自动添加当前模块名称属性。

// Define the attribute keyword for the module name 
BOOST_LOG_ATTRIBUTE_KEYWORD(a_module, "Module", std::string) 

#define MY_LOG(lg)\ 
    BOOST_LOG(lg) << boost::log::add_value(a_module, CURRENT_MODULE) 

如果定义CURRENT_MODULE字符串命名的项目设置当前模块,该MY_LOG宏将自动追加它作为记录的属性。请参阅有关attribute keywordsadd_value manipulator的文档。

另一种方法是使用channels。如果您的记录器不是由不同模块共享的,您可以将当前模块名称设置为通道名称。或者,如果您已经使用频道,请将其添加为您创建的每个记录器的新单独属性。你可以写你自己的logger feature来自动化。

如果您确实共享记录器,那么您还可以查看scoped attributes的实现方式,特别是BOOST_LOG_SCOPED_THREAD_TAG。由于您可能会调用不同模块之间的函数,因此BOOST_LOG_SCOPED_THREAD_TAG将不适用于您(因为它不会替换集合中的属性(如果已存在的话) - 在您的情况下,这意味着您只会看到首先设置属性的模块),但是你可以实现类似的东西来适应你的情况。这个想法是添加当前模块名称作为线程特定的属性,如果没有添加或替换现有的一个。这必须在一个范围警卫中完成,这个警卫必须在每个可以从其他模块调用的功能中使用。

+0

这解决了我的问题。我重新思考了“模块”,因为我在添加一堆日志之后意识到我所关心的模块是逻辑的而不是物理的。我还简单地添加了一个W/RAII类来记录进入和退出函数,根据我的其他“功能请求”在我的Q中,并将其固定在宏中。 –

相关问题