Logger estilo C ++ que suporta macro __LINE__ e outros
Eu quero fazer um Logger que possa ser usado comostd::cout
, mas quero registrar alguns dados extras, como data, hora,__LINE__
, __func__
e__FILE__
que deve ser salvo no arquivo automaticamente.
ToolLogger log;
log << "some data" << std::endl;
Saída esperada[14.11.2015 21:10:12.344 (main.cpp) (main,14): some data
Solução inadequadaPara fazer isso eu tenho que colocar macros como__LINE__
direto na linha em que chamo meu logger, caso contrário, as macros não funcionarão corretamente. Descobri que posso substituirstd::endl
com a minha macro que fará essa magia negra assim:
#define __FILENAME__ (strrchr(__FILE__,'/') ? strrchr(__FILE__,'/') + 1 : __FILE__)
#define logendl \
((ToolLogger::fileName = __FILENAME__).empty() ? "" : "") \
<< ((ToolLogger::line = __LINE__) ? "" : "") \
<< ((ToolLogger::function = __func__).empty() ? "" : "") \
<< std::endl
A macrologendl
usa variáveis estáticas do meuToolLogger
classe para salvar os valores de__LINE__
, __func__
e__FILE__
necessário mais tarde. Então, na verdade, usar o criador de logs ficará assim:
ToolLogger log;
log << "some data" << logendl;
Na classe eu tenho que sobrecarregar ooperator<<
para que isso funcione, e eu preciso de dois deles. Um para tomar os valores normais comostd::string
ouint
e o outro para tirar ostd::endl
manipulador. Aqui estão as coisas mais importantes da minha turma:
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;
ProblemaO problema nesta solução é que posso usar meu logger de duas maneiras:
log << "some data" << logendl; // correct //
log << "some data" << std::endl; // compiles -> wrong /
Então, na verdade, preciso remover ooperator<<
da minha classe que levastd::endl
manipulador e resolvê-lo de outra maneira, mas como fazê-lo? Eu estava pensando em mudarstd::endl
nologendl
macro para outro manipulador personalizado e, em seguida, esse manipulador personalizado fará o trabalho que está realmente fazendo ooperator<<
, mas não tenho ideia de como fazê-lo. Estou procurando outra solução, alguma sugestão?