我想创建一个可以像std::cout
一样使用的记录器,但我想记录一些额外的数据,如日期,时间,__LINE__
,__func__
和{{1}应该自动保存到文件中。
__FILE__
ToolLogger log;
log << "some data" << std::endl;
要做到这一点,我必须将[14.11.2015 21:10:12.344 (main.cpp) (main,14): some data
之类的宏直接放在我调用记录器的行中,否则宏将无法正常工作。我发现我可以用我的宏替换__LINE__
,这样就可以做到这样的黑魔法:
std::endl
宏#define __FILENAME__ (strrchr(__FILE__,'/') ? strrchr(__FILE__,'/') + 1 : __FILE__)
#define logendl \
((ToolLogger::fileName = __FILENAME__).empty() ? "" : "") \
<< ((ToolLogger::line = __LINE__) ? "" : "") \
<< ((ToolLogger::function = __func__).empty() ? "" : "") \
<< std::endl
使用我的logendl
类中的静态变量来保存稍后需要的ToolLogger
,__LINE__
和__func__
的值。所以实际上使用记录器将如下所示:
__FILE__
在课堂上我必须重载ToolLogger log;
log << "some data" << logendl;
以使其工作,我需要其中两个。一个用于获取operator<<
或std::string
等正常值,另一个用于采用int
操纵器。这是我班上最重要的事情:
std::endl
此解决方案的问题在于我可以通过两种方式使用记录器:
class ToolLogger
{
public:
// standard operator<< //
template<typename T>
ToolLogger& operator<< (const T& str)
{
out << str;
return *this;
}
// operator<< for taking the std::endl manipulator //
typedef std::basic_ostream<char, std::char_traits<char> > CoutType;
typedef CoutType& (*StandardEndLine)(CoutType&);
ToolLogger& operator<<(StandardEndLine manip)
{
// save fileName, line and function to the file //
// and all what is already in stringstream //
// clear stringstream //
return *this;
}
static string fileName;
static int line;
static string function;
private:
ofstream file;
std::stringstream out;
};
string ToolLogger::fileName;
int ToolLogger::line;
string ToolLogger::function;
所以实际上我需要从我的类log << "some data" << logendl; // correct //
log << "some data" << std::endl; // compiles -> wrong /
操纵器中移除operator<<
,并以其他方式解决它,但是怎么做呢?我在考虑将std::endl
宏中的std::endl
更改为其他自定义操纵器,然后这个自定义操纵器将执行实际执行logendl
的工作,但我不知道该怎么做它。我正在寻找其他解决方案,有什么建议吗?
答案 0 :(得分:2)
这就是我的工作。它有点像你的问题。也就是说,不必定义endl
。我所做的是从构建消息的Logger
类中分离出一个LogMessage
类(它只需要字符串并输出到你需要的地方)。
好处是:
每个班级都很简单。
非常简单的宏。我没有在下面定义宏,但它很容易做到。
无需定义endl
。当LogMessage类破坏
让我知道你的想法:
#include <iostream>
#include <sstream>
#include <string>
// logger class
// this is not complete, it exists just to illustrate the LogIt function
class Logger
{
public:
void LogIt(const std::string & s)
{
std::cout << s << std::endl;
}
};
// builds a logging message; outputs it in the destructor
class LogMessage
{
public:
// constructor
// takes identifying info of message. You can add log level if needed
LogMessage(const char * file, const char * function, int line)
{
os << file << ": " << function << '(' << line << ") ";
}
// output operator
template<typename T>
LogMessage & operator<<(const T & t)
{
os << t;
return *this;
}
// output message to Logger
~LogMessage()
{
Logger logger; // get logger here (perhaps it's a singleton?)
logger.LogIt(os.str());
}
private:
std::ostringstream os;
};
int main()
{
// example usage
// typically this is invoked via a simple macro to reduce typing of the LogMessage constructor
LogMessage(__FILE__, __func__, __LINE__) << "this is an int " << 5;
}
答案 1 :(得分:1)
您可能拥有LoggerAt
类,其中包含LoggerAt(const char*filename, int lineno)
构造函数(可能是std::ostringstream
的子类,等等...),然后定义
#define LOG(Out) do {LoggerAt(__FILE__,__LINE__) \
<< Out << std::endl; }while(0)
在我编写的一些C ++项目中:
void mom_inform_at(const char*fil, int lin, std::ostringstream& out)
{ out.flush();
std::clog << fil << ":" << lin
<< " INFORM: " << out.str() << std::endl ;
}
#define MOM_INFORM_AT(Fil,Lin,Output) do { \
std::ostringstream out_##Lin; \
out_##Lin << mom_outlog << Output ; \
mom_inform_at(Fil,Lin,out_##Lin); \
} while(0)
#define MOM_INFORM_AT_BIS(Fil,Lin,Output) \
MOM_INFORM_AT(Fil,Lin,Output)
#define MOM_INFORM(Out) \
MOM_INFORM_AT_BIS(__FILE__,__LINE__,Out)
使用类似MOM_INFORM("x=" << " point:" << pt);
的内容,您可以想象通常的Point pt;
示例以及std::ostream& operator << (std::ostream&out, const Point&point)
函数。
请注意,要方便地使用 __FILE__
和__LINE__
,您最好使用宏。