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

2019-04-05 11:08发布

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();
}

3条回答
小情绪 Triste *
2楼-- · 2019-04-05 11:27

I saw no reply to your concerns about sluggish, I'm sure by this time you figured something out. You could probably improve performance by reducing the amount of code within the critical region. File operations are slow so try to reduce the amount of time spent doing them. This can include keeping the file open, buffering the log and writing periodically, construct the entry out of the locked region and

void MessageHandler(QtMsgType type, const QMessageLogContext & context, const QString & msg)
{

    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));
    QString entryString("%1 %2: %3");
    entryString = entryString.arg(timeStr).arg(contextString).arg(msg);

    QFile outFile("file.log");

    mutex.lock();
    outFile.open(QIODevice::WriteOnly | QIODevice::Append);  
    QTextStream stream(&outFile);  
    stream << entryString << endl;    
    mutex.unlock();
}
查看更多
虎瘦雄心在
3楼-- · 2019-04-05 11:42

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.

查看更多
别忘想泡老子
4楼-- · 2019-04-05 11:43

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.

查看更多
登录 后发表回答