使用C ++进行延迟日志记录

时间:2013-02-02 18:42:27

标签: c++ logging lazy-evaluation

让我们假设我们有几个级别的日志记录:跟踪,调试,信息,错误。 我想知道是否有办法编写以下代码:

enum log_level = {trace, debug, info, error};

log_level global_log_level = info;

void log(log_level level, string& message){
    if (level >= global_log_level){
        std::cout << message << std::endl;
    }
}

string create_message(){
    ...
}

log_level level = debug;
log (level, create_message());

如果level小于global_severity_level,则不调用create_message。实际上,create_message可能很长,无论它创建一个字符串。如果有很多“调试”日志,那么在非调试模式下运行时,这些日志会成为一个巨大的开销。

我知道如果函数“log”是一个宏,则可以这样做,只有在严重性为&gt;时才调用create_message()。 minimal_severity;但没有其他方法没有宏吗?

修改

在上面,我没有指定create_message,因为它可以是任何东西,特别是:

log(level, "Created object " + my_object.getName());

在这种情况下,是否有办法编写日志,以便以相对透明的方式为程序员调用日志创建完整的字符串?

非常感谢

4 个答案:

答案 0 :(得分:6)

有几种选择。一个有趣的方法是将create_message作为std::function<std::string()>传递,并在log内调用它:

void log(log_level level, std::function<std::string()> message_creator){
    if (level >= global_log_level){
        std::cout << message_creator() << std::endl;
    }
}

然后你会这样称呼它:

log(level, create_message);

如果将它们包装在lambda中,这可以作为参数使用任意表达式:

log(level, [&](){ return "Created object " + my_object.getName(); });

如果你真的不想让评论被评估(正如你在评论中描述的那样),那么你需要检查电话之外的等级:

if (level >= global_log_level) {
  log(level, create_message());
}

答案 1 :(得分:5)

与@sftrabbit类似,但正如@ipc所建议的那样。

使用模板来避免std :: function机制,并且编译器可能能够内联这个,因此希望最终会更快。

template< typename F >
void log(log_level level, F message_creator){
    if (level >= global_log_level){
        std::cout << message_creator() << std::endl;
    }
}

答案 2 :(得分:1)

@sftrabbit答案是首选。但是,如果您不想更改log(),可以调用它:

log (level, (level >= global_log_level)? create_message() : "");

答案 3 :(得分:1)

您可以创建一个宏



    #define log(level, message) { \
    if(level >= global_log_level) {\
    cout << message; }}

现在,如果你打电话

log(debug, create_message());
,只有在调试级别是所需的时才会调用create_message。