2

非常に詳細なログを生成する必要がある小さなアプリを使用しています。このような単純なシングルトンロガークラスを実装しました

#ifndef LOGGER_H
#define LOGGER_H

#include <QObject>
#include <QMutex>
#include <QFile>

class Logger : public QObject
{
    Q_OBJECT
public:
    static Logger* sharedInstance()
    {
        static QMutex mutex;

        if (!m_sharedInstance)
        {
            mutex.lock();

            if(!m_sharedInstance)
                m_sharedInstance = new Logger;

            mutex.unlock();
        }

        return m_sharedInstance;
    }

    static void dropInstance()
    {
        static QMutex mutex;
        mutex.lock();
        delete m_sharedInstance;
        m_sharedInstance = 0;
        mutex.unlock();
    }

    void setLogFilePathAndOpen(QString path);
    void logMessage(QString message);
    void logMessageWorker(QString message);
    void closeLog();

private:
    Logger() {}

    Logger(const Logger &);
    Logger& operator=(const Logger &);

    static Logger *m_sharedInstance;

    QFile m_logFile;

signals:

public slots:

};

#endif // LOGGER_H

#include <QDateTime>
#include <QtConcurrentRun>

#include "logger.h"

Logger* Logger::m_sharedInstance = 0;

void Logger::setLogFilePathAndOpen(QString path)
{
    m_logFile.setFileName(path);
    m_logFile.open(QIODevice::Append | QIODevice::Text);
}

void Logger::logMessage(QString message)
{
    //TODO calling QtConcurrent causes about a 22% drop in performance. Look at other ways to do this.
    QtConcurrent::run(this, &Logger::logMessageWorker, message);
}

void Logger::logMessageWorker(QString message)
{
    QTextStream out(&m_logFile);
    out << tr("%1: %2\n").arg(QDateTime::currentDateTime().toString()).arg(message);
}

void Logger::closeLog()
{
    m_logFile.close();
}

今、私はQtとC ++に少し慣れていませんが、おそらくこれはすべて間違っているので、気楽に行ってください:)。この方法を使用すると、ログに記録しない場合と比較して、パフォーマンスが約22%低下します。これは、これまで管理できた中で最高の方法です。パフォーマンスの低下は、QtConcurrentスレッドの作成によるものだと思います。

私の質問は、これが最善のアプローチなのか、それともまったくログに記録しないよりもパフォーマンスがさらに向上する、これを実装するためのより良い方法があるのか​​ということだと思います。アプリケーションのロギングが遅くなることは承知していますが、これを可能な限り最小限に抑えようとしています。

4

3 に答える 3

3

非同期ロギングに我慢することをいとわないので、通常、ロギングを単一のスレッドで実行し、それにデータを供給するスレッドセーフなキューを用意する必要があります。以前の回答で投稿したものなど、スレッドセーフなキューはかなりたくさんあります。あなたは(どうやら)Qtプリミティブを使ってそれを書き直したいと思うでしょうが、それは十分に似ているので、書き直しはあなたが使う名前をほとんど変えるでしょう。

そこから、ロギングはかなり簡単になります。ロギングスレッドは、キューからデータを取得してログに書き込み、繰り返します。ロギングスレッドはログに直接アクセスする唯一のスレッドであるため、ロックを行う必要はまったくありません。これは基本的にシングルスレッドコードであり、すべてのロックはキューで処理されます。

于 2012-04-16T18:29:02.033 に答える
1

これに対処するには2つの方法があります。

  1. 既存のロギングフレームワークを再利用するか、少なくともそのアイデアを盗み出します。
  2. ロギングをあまり停止します(ただし、1を実行する必要があります)。

ベストプラクティス ?

一般に、ワーカースレッドによってデキューされるキューにログをキューイングする必要があります。多くの可能な実装(ロックフリーキュー、プールキューなど)がありますが、それほど重要ではありません。1つを選択するだけで、非常に優れたパフォーマンスが得られます。

もちろん、既存のフレームワークを再利用するだけの方がはるかに優れています。Boost.LogまたはPantheiosを調べましたか?


もう1つ注意すべき点は、あまりログを記録するべきではないということです。通常、アプリケーションでログが発生することはほとんどありません。

  • デバッグの実行ではassert、問題が発生した場合に完全なコアダンプを自由に取得できます。
  • リリース実行の場合、条件付きロギングを使用して、例外が存在する場合にのみログを記録できます。

条件付きロギングのトリックは、少し直感に反する可能性があります。std::uncaught_exception()アイデアは、オブジェクトのデストラクタを使用して実際にログに記録することtrueです。もちろん、これは、このロギングに例外がないことを意味します。したがって、プログラミングスキルに非常に自信がない限り、メッセージを事前にフォーマットすることをお勧めします。

于 2012-04-16T18:18:35.723 に答える
0

I am using qDebug, qWarning, etc for logging. And then, redirect the event messages to a log file in this way:

...
qInstallMsgHandler(messageHandler);
...

#define LOG_FILE "path/to/file.log"

void messageHandler(QtMsgType type, const char *msg)
{
#define NOW QDateTime::currentDateTime().toString("MM:dd: hh:mm:ss")
  QString out;
  switch (type) {
  case QtDebugMsg:    out = QString("%1: %2\n").arg(NOW).arg(msg); break;
  case QtWarningMsg:  out = QString("%1: warning: %2\n").arg(NOW).arg(msg); break;
  case QtCriticalMsg: out = QString("%1: critical: %2\n").arg(NOW).arg(msg); break;
  case QtFatalMsg:    out = QString("%1: fatal: %2\n").arg(NOW).arg(msg); break;
  default: return;
  }

  QFile file(LOG_FILE);
  if (file.open(QIODevice::WriteOnly | QIODevice::Append))
    QTextStream(&file) << out;
#undef NOW
}

This approach is thread-safe, though it is not the most efficient one, as the file IO is not cached.

于 2012-12-05T18:53:47.340 に答える