没有Singleton的情况下如何实现便捷的日志记录? [英] How do I implement convenient logging without a Singleton?

查看:85
本文介绍了没有Singleton的情况下如何实现便捷的日志记录?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我当前的实现已简化:

#include <string>
#include <memory>

class Log
{
  public:
    ~Log() {
      // closing file-descriptors, etc...
    }
    static void LogMsg( const std::string& msg )
    {
      static std::unique_ptr<Log> g_singleton;
      if ( !g_singleton.get() )
        g_singleton.reset( new Log );
      g_singleton->logMsg( msg );
    }
  private:
    Log() { }
    void logMsg( const std::string& msg ) {
      // do work
    }
};

总的来说,我对这种实现感到满意,因为:

In general, I am satisfied with this implementation because:


  • 惰性实例化意味着我不付款,除非我使用它

  • 使用unique_ptr意味着自动清除,因此valgrind很高兴

  • 相对简单,易于理解的实现

但是,负面影响是:


  • 单例不利于单元测试

  • 在引入伪全局(有点代码的味道)

所以这是我的问题针对那些成功地将所有单例从中驱除的开发人员他们的C ++代码


  • 您在应用程序范围内的日志记录中使用哪种非单一实现? / strong>

  • 接口是否像上面的Log :: LogMsg()调用一样简单且可访问?

  • What kind of non-Singleton implementation do you use for application-wide logging?
  • Is the interface as simple and accessible as a Log::LogMsg() call above?

我要oid尽可能在我的代码中传递一个Log实例-注意:我问是因为,如果有一个很好的,合理的选择,我也想从我的代码中驱除所有Singleton。

I want to avoid passing a Log instance all over my code, if at all possible - note: I am asking because, I, too, want to exorcise all Singletons from my code if there is a good, reasonable alternative.

推荐答案

首先:不需要使用 std :: unique_ptr

void Log::LogMsg(std::string const& s) {
  static Log L;
  L.log(s);
}

产生完全相同的惰性初始化和清除语义,而不会引入所有语法噪声(和冗余测试)。

Produces exactly the same lazy initialization and cleanup semantics without introducing all the syntax noise (and redundant test).

现在,这已不复存在...

Now that is out of the way...

您的课程非常简单。您可能需要构建稍微复杂一些的版本,日志消息的典型要求是:

Your class is extremely simple. You might want to build a slightly more complicated version, typical requirements for log messages are:


  • 时间戳

  • level

  • 文件

  • line

  • 功能

  • 进程名称/线程ID(如果有)

  • timestamp
  • level
  • file
  • line
  • function
  • process name / thread id (if relevant)

在消息本身之上。

因此,完全可以想到具有多个具有不同参数的对象:

As such, it is perfectly conceivable to have several objects with different parameters:

// LogSink is a backend consuming preformatted messages
// there can be several different instances depending on where
// to send the data
class Logger {
public:
  Logger(Level l, LogSink& ls);

  void operator()(std::string const& message,
                  char const* function,
                  char const* file,
                  int line);

private:
  Level _level;
  LogSink& _sink;
};

为了方便起见,通常将访问包装在宏中:

And you usually wrap the access inside a macro for convenience:

#define LOG(Logger_, Message_)                  \
  Logger_(                                      \
    static_cast<std::ostringstream&>(           \
      std::ostringstream().flush() << Message_  \
    ).str(),                                    \
    __FUNCTION__,                               \
    __FILE__,                                   \
    __LINE__                                    \
  );

现在,我们可以创建一个简单的详细记录器:

Now, we can create a simple verbose logger:

Logger& Debug() {
  static Logger logger(Level::Debug, Console);
  return logger;
}

#ifdef NDEBUG
#  define LOG_DEBUG(_) do {} while(0)
#else
#  define LOG_DEBUG(Message_) LOG(Debug(), Message_)
#endif

并方便使用:

int foo(int a, int b) {
  int result = a + b;

  LOG_DEBUG("a = " << a << ", b = " << b << " --> result = " << result)
  return result;
}

这只蚂蚁的目的是什么?并非所有全局需求都是唯一。通常,单例的唯一性是无用的。

The purpose of this rant ? Not all that is a global need be unique. The uniqueness of Singletons is generally useless.

注意:如果涉及到 std :: ostringstream 吓到你,这很正常,看到这个问题

Note: if the bit of magic involving std::ostringstream scares you, this is normal, see this question

这篇关于没有Singleton的情况下如何实现便捷的日志记录?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆