【问题标题】:What is good practice for generating verbose output?生成详细输出的好习惯是什么?
【发布时间】:2010-11-18 08:10:45
【问题描述】:

生成详细输出的好习惯是什么?目前,我有一个功能

bool verbose;
int setVerbose(bool v)
{
    errormsg = "";
    verbose = v;
    if (verbose == v)
        return 0;
    else
        return -1;
}

每当我想生成输出时,我都会做类似的事情

if (debug)
     std::cout << "deleting interp" << std::endl;

但是,我认为这不是很优雅。所以我想知道实现这个冗长开关的好方法是什么?

【问题讨论】:

  • 你的setVerbose不是总是返回0吗?
  • 是的,除非发生非常深奥的事情。只是我有一堆 setSomething() 函数,如果操作成功,它们都返回 0,否则返回 -1。所以这只是一个具有一致界面的问题......
  • 我看不懂这段代码。这是编辑出错的案例吗?

标签: c++ verbosity


【解决方案1】:

最简单的方法是创建小类如下(这里是Unicode版本,但您可以轻松地将其更改为单字节版本):

#include <sstream>
#include <boost/format.hpp>
#include <iostream>
using namespace std;

enum log_level_t {
    LOG_NOTHING,
    LOG_CRITICAL,
    LOG_ERROR,
    LOG_WARNING,
    LOG_INFO,
    LOG_DEBUG
};

namespace log_impl {
class formatted_log_t {
public:
    formatted_log_t( log_level_t level, const wchar_t* msg ) : fmt(msg), level(level) {}
    ~formatted_log_t() {
        // GLOBAL_LEVEL is a global variable and could be changed at runtime
        // Any customization could be here
        if ( level <= GLOBAL_LEVEL ) wcout << level << L" " << fmt << endl;
    }        
    template <typename T> 
    formatted_log_t& operator %(T value) {
        fmt % value;
        return *this;
    }    
protected:
    log_level_t     level;
    boost::wformat      fmt;
};
}//namespace log_impl
// Helper function. Class formatted_log_t will not be used directly.
template <log_level_t level>
log_impl::formatted_log_t log(const wchar_t* msg) {
    return log_impl::formatted_log_t( level, msg );
}

帮助函数log 被制作为模板以获得良好的调用语法。那么它可以通过以下方式使用:

int main ()
{
    // Log level is clearly separated from the log message
    log<LOG_DEBUG>(L"TEST %3% %2% %1%") % 5 % 10 % L"privet";
    return 0;
}

您可以在运行时通过更改全局 GLOBAL_LEVEL 变量来更改详细级别。

【讨论】:

  • 我喜欢这个答案。我真的只需要这个非常简单的标准输出日志,不需要文件/网络的东西(我希望)。所以我会尽量减少外部依赖的数量,然后自己实现。
  • 我觉得这个解决方案很聪明而且很有帮助,我希望我能给它 10 个赞! :-)
  • 我相信 GLOBAL_LEVEL 变量会在翻译单元中出现问题,对吗?你将如何实现这个变量?
  • 把它放在namespace@quimnuss
【解决方案2】:
int threshold = 3;
class mystreambuf: public std::streambuf
{
};
mystreambuf nostreambuf;
std::ostream nocout(&nostreambuf);
#define log(x) ((x >= threshold)? std::cout : nocout)

int main()
{
    log(1) << "No hello?" << std::endl;     // Not printed on console, too low log level.
    log(5) << "Hello world!" << std::endl;  // Will print.
    return 0;
}

【讨论】:

  • 是否有可能将 std::endl “包含”到 log() 定义中?
  • Define log(x) 可以很容易地替换为内联函数。这里有使用定义的理由吗?
  • 关于 std::endl: 我不知道。如果你想要更少的代码,你总是可以使用 typedef,比如 _e。 Regardig #define/inline:没有理由。
【解决方案3】:

你可以使用log4cpp

【讨论】:

  • 那有异步日志功能吗?
  • 不知道有没有。对不起。
  • 我同意使用适当的日志库是答案,而不是手动编码,尽管 Log4cpp 似乎已经垂死了。另一方面,logging.apache.org/log4cxx/index.html 是活生生的。根据网站,它确实支持异步日志记录,但我认为这与这个问题无关。
  • 更现代的替代方案:github.com/gabime/spdlog 速度非常快,使用起来非常直观,并且维护良好。
【解决方案4】:

您可以将您的功能包装在一个支持

class Trace {
   public:
      enum { Enable, Disable } state;
   // ...
   operator<<(...)
};

然后你可以做类似的事情

trace << Trace::Enable;
trace << "deleting interp"

【讨论】:

  • 我喜欢将错误记录系统包装在一个类中的想法。您也可以在类中存储输出文件的位置等内容。
  • 只是为了让我正确理解你:我之前会创建一个名为 trace 的 Trace 类的实例?然后是另一个问题:为什么 Trace::Enable 足以将状态设置为 Enable?我对c ++还是很陌生,有点困惑。也许你的想法中多三行会帮助我更好地理解发生了什么。但我绝对喜欢你的想法!
  • 是的,您需要创建一个 Trace 类的实例;对于希望使用它的每个组件,这可以是静态的或本地的。 Trace::Enable 将切换 Trace 类中的一个内部标志(状态枚举的一个实例)。这将非常像 std::hex 允许 std::cout 以十六进制格式而不是十进制格式输出。由于您将编写 operator
  • Andreash, Trace::Enable 足以将状态设置为Enable,因为您将为&lt;&lt; 运算符编写代码,使您的班级知道如何处理该标志。这里没有魔法。就个人而言,我只是制作一个普通的成员函数并说trace.enable()
【解决方案5】:

1.如果您使用 g++,您可以使用 -D 标志,这允许编译器定义您选择的宏。

定义

例如:

#ifdef DEBUG_FLAG
 printf("My error message");
#endif

2.我同意这也不优雅,所以让它更好一点:

void verbose(const char * fmt, ... )
{
va_list args;  /* Used as a pointer to the next variable argument. */
va_start( args, fmt );  /* Initialize the pointer to arguments. */

#ifdef DEBUG_FLAG
printf(fmt, &args);  
#endif
/*This isn't tested, the point is to be able to pass args to 
printf*/
}

你可以像 printf 一样使用:

verbose("Error number %d\n",errorno);

3. 第三种更简单、更类似于 C++ 和 Unix 的解决方案是将参数传递给您的程序,该参数将被用作前面的宏 - 以初始化特定变量(即可以是一个全局常量)。

示例: $ ./myprogram -v

if(optarg('v')) static const verbose = 1;

【讨论】:

    猜你喜欢
    • 2020-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-01
    • 1970-01-01
    • 2018-04-07
    • 2020-01-22
    • 1970-01-01
    相关资源
    最近更新 更多