PDA

View Full Version : Global debugging function



Phlucious
7th December 2011, 23:45
Maybe this functionality already exists in the Qt docs and I haven't come across it yet, so I'm open to suggestions.

Basically what I'm trying to do is create a one-line, generic, global error reporting mechanism for my multi-file program. When it's compiled in debug mode, the function outputs to qDebug() and I read it from the application output in Qt Creator. However, if it's compiled in release mode, I want the function to output to a file instead of the command prompt.

Here's my (buggy) implementation:

//myerror.h:
#ifndef MYERROR_H
#define MYERROR_H

#ifdef DEBUGMODE //DEBUGMODE is defined in the .pro file by "Debug:DEFINES += DEBUGMODE"
#include <QDebug>
#else
#include <QFile>
QFile ERRLOG("c:/temp/my_errors.log");
#endif

inline void QDEBUG(QString a)
{
#ifdef DEBUGMODE
qDebug() << a;
#else
ERRLOG.write(QString("%1\n").arg(a).toAscii());
#endif
}

#endif // MYERROR_H

//mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
#ifndef DEBUGMODE
ERRLOG.open(QIODevice::WriteOnly);
#endif

ui->setupUi(this);
//etc
}
MainWindow::~MainWindow()
{
#ifndef DEBUGMODE
ERRLOG.close();
#endif
delete ui;
}


Now, this works while I'm in debug mode, but doesn't work when in release mode. The file "my_errors.log" is being generated, but as far as I can tell it was never opened or written to. I can't just open the QFile in myerror.h because it's a header, so I have to do it in mainwindow.cpp.

Additionally, including this header in more than one cpp file resulted in a linker error complaining about multiple definitions, even though I've guarded myerror.h!

Is there a better way to do this? Can I just re-route qDebug() to a file? I couldn't find anything on that in the documentation.

Thanks!

d_stranz
8th December 2011, 00:22
Why don't you look at qInstallMsgHandler()? Looks like that will do everything you're asking for in both release and debug modes.

Phlucious
8th December 2011, 00:24
Figures. I just found that, too! Thanks!

Phlucious
8th December 2011, 19:39
I followed the examples given in the docs and created my own little custom error handler like so:


#define now QTime::currentTime().toString("HH:mm:ss").toLocal8Bit().data()
#define today QDate::currentDate().toString("d-M-yyyy").toLocal8Bit().data()

void handler(QtMsgType type, const char *msg)
{
#ifdef DEBUGMODE
switch (type)
{
case QtDebugMsg:
fprintf(stdout, "Debug: %s\n", msg);
fprintf(stderr, "%s Debug: %s\n", now, msg);
break;
case QtWarningMsg:
fprintf(stdout, "Warning: %s\n", msg);
fprintf(stderr, "%s Warning: %s\n", now, msg);
break;
case QtCriticalMsg:
fprintf(stdout, "Error: %s\n", msg);
fprintf(stderr, "%s Error: %s\n", now, msg);
break;
case QtFatalMsg:
fprintf(stdout, "FATAL ERROR: %s\n", msg);
fprintf(stderr, "%s FATAL ERROR: %s\n", now, msg);
abort();
}
#else //RELEASEMODE
switch (type)
{
case QtDebugMsg:
break;
case QtWarningMsg:
fprintf(stderr, "%s Warning: %s\n", now, msg);
break;
case QtCriticalMsg:
fprintf(stderr, "%s Error: %s\n", now, msg);
break;
case QtFatalMsg:
fprintf(stderr, "%s FATAL ERROR: %s\n", now, msg);
abort();
}
#endif
}

myErrorHandler::myErrorHandler(const char* outfile)
{
freopen(outfile, "w", stderr);
setbuf(stdout, NULL);
fprintf(stderr, "Running LASE.exe on %s at %s.\n", today, now);
}

myErrorHandler::~myErrorHandler()
{
}

void myErrorHandler::install()
{
qInstallMsgHandler(handler);
}


Now, I'm compiling with MSVC2010 so I'm getting the typical "C4996 ______ This function of variable may be unsafe blah blah blah" warning for freopen and setbuf. Personally, I prefer to address all warnings whenever possible, so I'd prefer to use a QDataStream for portability instead of the standard library.

The only way I can think of is to declare a global QDataStream variable with its device set to a global file, but I'd rather avoid setting more global variables if I can. Is this possible?

I suppose I could content myself with disabling those particular warnings, but I can't figure out the syntax.