C ++ 11:如何在没有Singleton的情况下实现方便的日志记录? [英] C++11: How do I implement convenient logging without a 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 ++代码:
- 什么样的非Singleton实现用于应用程序范围的日志? / 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?
我想避免传递Log实例遍历我的代码,如果一切可能 - 注意:我问,因为,我也想从我的代码exocise所有Singleton if有一个好的,合理的替代方案。
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
是不必要的:
First: the use of std::unique_ptr
is unnecessary:
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:
- timestamp
- 进程名称/线程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
>
And use it conveniently:
int foo(int a, int b) {
int result = a + b;
LOG_DEBUG("a = " << a << ", b = " << b << " --> result = " << result)
return result;
}
这个rant的用途?并非所有这些都是全局需要独特。
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
这篇关于C ++ 11:如何在没有Singleton的情况下实现方便的日志记录?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!