Wednesday, October 12, 2016

c++ Diagnostic Logging Hack

Here is a quick and dirty c++ logging hack.
I got tired of recreating something like it.


LoggingHack.h


#ifdef LOGGING_HACK

class JLogStream
{
public:
virtual ~JLogStream() {
}
};

extern JLogStream* jlogs;

extern JLogStream& operator<< (JLogStream& rlog, const std::string& val);
extern JLogStream& operator<< (JLogStream& rlog, const std::wstring& val);
extern JLogStream& operator<< (JLogStream& rlog, const char* zStr);
extern JLogStream& operator<< (JLogStream& rlog, const wchar_t* zStr);
extern JLogStream& operator<< (JLogStream& rlog, int val);
extern JLogStream& operator<< (JLogStream& rlog, std::stringstream &val);
extern JLogStream& operator<< (JLogStream& rlog, std::wstringstream &val);

#define JLOG( x ) { (*jlogs) << x << "\n"; }

#else
#define JLOG( x ) ;
#endif



LoggingHack.cpp




#ifdef LOGGING_HACK

#include <sstream>

#include "LoggingHack.h"

class JLogStreamImpl : public JLogStream
{
private:
FILE* jlog_fout1;
FILE* jlog_fout2;
FILE* jlog_fout3;

public:
JLogStreamImpl()
{
std::stringstream ss1;
ss1 << "c:\\delme\\" << LOGGING_HACK_FILE_BASE_NAME << ".log";
std::stringstream ss2;
ss2 << "c:\\delme\\" << LOGGING_HACK_FILE_BASE_NAME << " - " << ::GetTickCount() << ".log";
std::stringstream ss3;
ss3 << "c:\\delme\\" << LOGGING_HACK_FILE_BASE_NAME << "-rolling.log";

fopen_s(&jlog_fout1, ss1.str().c_str(), "wt");
fopen_s(&jlog_fout2, ss2.str().c_str(), "wt");
fopen_s(&jlog_fout3, ss3.str().c_str(), "at");

log(ss1.str().c_str());
}

void log(const char* zStr)
{
fwrite(zStr, strlen(zStr), 1, jlog_fout1);
fwrite(zStr, strlen(zStr), 1, jlog_fout2);
fwrite(zStr, strlen(zStr), 1, jlog_fout3);

fflush(jlog_fout1);
fflush(jlog_fout2);
fflush(jlog_fout3);
}

void log(const wchar_t* zStr)
{
int ncharLen;
ncharLen = WideCharToMultiByte(CP_UTF8, 0, zStr, -1, NULL, 0, NULL, NULL);
char* zstr = new char[ncharLen];
WideCharToMultiByte(CP_UTF8, 0, zStr, -1, zstr, ncharLen, NULL, NULL);
log("UNICODE:");
log(zstr);
}

void log(int val)
{
std::stringstream ss;
ss << val;
log(ss);
}

void log(std::stringstream &val)
{
log(val.str().c_str());
}

void log(std::wstringstream &val)
{
log(val.str().c_str());
}

};

extern JLogStream& operator<< (JLogStream& rlog, const std::string& val)
{
dynamic_cast<JLogStreamImpl*>(&rlog)->log(val.c_str());
return rlog;
}

extern JLogStream& operator<< (JLogStream& rlog, const std::wstring& val)
{
dynamic_cast<JLogStreamImpl*>(&rlog)->log(val.c_str());
return rlog;
}

extern JLogStream& operator<< (JLogStream& rlog, const char* zStr)
{
dynamic_cast<JLogStreamImpl*>(&rlog)->log(zStr);
return rlog;
}

extern JLogStream& operator<< (JLogStream& rlog, const wchar_t* zStr)
{
dynamic_cast<JLogStreamImpl*>(&rlog)->log(zStr);
return rlog;
}

extern JLogStream& operator<< (JLogStream& rlog, int val)
{
dynamic_cast<JLogStreamImpl*>(&rlog)->log(val);
return rlog;
}

extern JLogStream& operator<< (JLogStream& rlog, std::stringstream &val)
{
dynamic_cast<JLogStreamImpl*>(&rlog)->log(val);
return rlog;
}

extern JLogStream& operator<< (JLogStream& rlog, std::wstringstream &val)
{
dynamic_cast<JLogStreamImpl*>(&rlog)->log(val);
return rlog;
}


JLogStreamImpl theLogStream;

JLogStream* jlogs = &theLogStream;


#else
#define jlog(s) ;
#define jlog(s1, s2) ;
#endif



Include this in one cpp file of the dll or exe: Replacing LogBaseName with the desired name

#define LOGGING_HACK
#define LOGGING_HACK_FILE_BASE_NAME "LogBaseName"
#include "..\..\..\..\LoggingHack.cpp"


Include this in the other cpp files of the module:

#define LOGGING_HACK
#include "..\..\..\..\LoggingHack.h"


Use it like this:

JLOG(__FILE__ << "@" << __LINE__);