【问题标题】:Implementing logging with messages not constructed when severity is low使用严重性较低时未构造的消息实现日志记录
【发布时间】:2021-07-27 17:47:26
【问题描述】:

我想知道是否有任何方法可以确保不构造日志行中定义的消息。在某些情况下,我会添加带有“跟踪”严重性的日志记录,但我担心无论如何都会构建消息(无论严重性是高还是低)。让我们考虑以下简化的日志记录系统:

template<class... Msg>
void logMessage(LogLevel logLevel, Msg... msg) {
    if (logLevel == LogLevel::Info) {
        auto test = fmt::format(std::forward<Msg>(msg)...);
    }
}

通过客户端调用:

logMessage(LogLevel::Info, "this is sample message: {}", 123);

据我所知,即使日志级别不等于“信息”,也无法保证编译器会对此进行优化。因此,不能保证“这是示例消息:{}”字符串不会被构造为临时的右值变量。 实现目标的唯一方法是:

template<class... Msg>
void logMessage(Msg... msg) {
    auto test = fmt::format(std::forward<Msg>(msg)...);
}

但是每个客户端调用看起来像这样:

LogLevel level = LogLevel::Info;
if (level == LogLevel::Debug) {
    logMessage("this is sample message: {}", 123);
}

我想知道是否有任何巧妙的宏使用方法或 constexpr 来获得干净的单行日志记录 API,同时确保当严重性较低时甚至不构造参数? (仍然需要在运行时配置严重性)

【问题讨论】:

  • "this is sample message: {}" 只是一个字符串文字,没有字符串是“构造的”

标签: c++ c++17


【解决方案1】:

序言:我认为这是一个坏主意。表达式的执行顺序是语言的核心基本属性,为了节省几行代码而以透明的方式搞乱它只是在寻求惊喜、意外的程序行为和多余的认知负担。

话虽如此,如果您无论如何都想走这条路,那么获得您想要的行为所需的宏并不是特别复杂:

#define logMessage(level, ...) \
  if(level >= gCurrentLogLevel) logMessageImpl(__VA_ARGS__)

用法:

int bar();

void foo() {
  logMessage(LogLevel::Info, "Some message: {}", bar());
}

在这种情况下,无论好坏,bar() 只有在 gCurrentLogLevel 至少为 LogLevel::Info 时才会被调用。

【讨论】:

  • 谢谢。考虑到在项目中直接在日志消息行中调用函数可能会被禁止,那么我首先看不到高风险。无论如何,断言调用具有相同的考虑,因此我相信对于开发人员来说不会有太大的惊喜。
  • @AdamStepniak 这就是为什么许多组织使用替代的assert() 将表达式的结果转换为发布版本的原因。
猜你喜欢
  • 1970-01-01
  • 2011-10-07
  • 1970-01-01
  • 2021-12-13
  • 2013-08-06
  • 2022-01-22
  • 1970-01-01
  • 2012-05-24
  • 2015-05-21
相关资源
最近更新 更多