Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt5: How to use qDebug() to log in a file, multi-thread application

I started using Qt5 few days ago. I needed a logger for my app and I decided to use qDebug, but it seems it has to be "redirected" in order to have the logs in a file.

I used qInstallMessageHandler to do that and I wrote my own handler as presented below (inspired from other people here).

It seems it works, but as I am not a guru, I have to ask: Is it ok to use this in a multi-thread application or not?

Also, if it is ok/safe for using in a multi-thread app, can it be improved somehow?

void MessageHandler(QtMsgType type, const QMessageLogContext & context, const QString & msg)
{
    mutex.lock();

    QDateTime dateTime(QDateTime::currentDateTime());

    QString timeStr(dateTime.toString("dd-MM-yyyy HH:mm:ss:zzz"));
    QString contextString(QString("(%1, %2)").arg(context.file).arg(context.line));

    QFile outFile("file.log");
    outFile.open(QIODevice::WriteOnly | QIODevice::Append);

    QTextStream stream(&outFile);
    stream << timeStr << " " << contextString << ": " << msg << endl;

    mutex.unlock();
}
like image 379
סטנלי גרונן Avatar asked Apr 04 '15 17:04

סטנלי גרונן


2 Answers

You can not find anywhere in the Qt documentation that qDebug is thread-safe. So it is not safe to call it simultaneously from multiple threads and indeed you would encounter mixed output if you don't use a locking mechanism.

Your locking approach would be better if you use QMutexLocker as it is strongly recommended by the Qt documentation:

void MessageHandler(QtMsgType type, const QMessageLogContext & context, const QString & msg)
{
    QMutexLocker locker(&mutex);
    ...
}

A second approach is to provide a worker class that has slots for writing the log. You can then have an instance of it in a new thread and call it's slots in message handler using QMetaObject::invokeMethod with a Qt::QueuedConnection connection type. This way each call from each thread would be queued and process in the worker thread and it would probably have a better performance since all the job is done in a separate thread.

like image 115
Nejat Avatar answered Nov 01 '22 09:11

Nejat


Your approach looks simple and clean. I'd keep it like that.

There is one thing you can improve: Open the file only once at application start and close it when you close the application. Opening a file is an expensive operation.

You can write into the same open file from multiple threads, since your mutex ensures that only one thread writes at the same time.

like image 41
Simon Warta Avatar answered Nov 01 '22 09:11

Simon Warta