File: TraceFile.cpp

package info (click to toggle)
js8call 2.5.1%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 24,720 kB
  • sloc: cpp: 562,655; sh: 898; python: 132; ansic: 102; makefile: 4
file content (108 lines) | stat: -rw-r--r-- 2,980 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include "TraceFile.h"

#include <stdexcept>

#include <QDateTime>
#include <QDebug>
#include <QFile>
#include <QMessageLogContext>
#include <QMutex>
#include <QMutexLocker>
#include <QString>
#include <QTextStream>

#include "JS8_Include/pimpl_impl.h"

namespace {
QMutex lock;
}

class TraceFile::impl {
  public:
    impl(QString const &trace_file_path);
    ~impl();

    // no copying
    impl(impl const &) = delete;
    impl &operator=(impl const &) = delete;

  private:
    // write Qt messages to the diagnostic log file
    static void message_handler(QtMsgType type,
                                QMessageLogContext const &context,
                                QString const &msg);

    QFile file_;
    QTextStream stream_;
    QTextStream *original_stream_;
    QtMessageHandler original_handler_;
    static QTextStream *current_stream_;
};

QTextStream *TraceFile::impl::current_stream_;

// delegate to implementation class
TraceFile::TraceFile(QString const &trace_file_path) : m_{trace_file_path} {}

TraceFile::~TraceFile() {}

TraceFile::impl::impl(QString const &trace_file_path)
    : file_{trace_file_path}, original_stream_{current_stream_},
      original_handler_{nullptr} {
    // if the log file is writeable; initialise diagnostic logging to it
    // for append and hook up the Qt global message handler
    if (file_.open(QFile::WriteOnly | QFile::Append | QFile::Text)) {
        stream_.setDevice(&file_);
        current_stream_ = &stream_;
        original_handler_ = qInstallMessageHandler(message_handler);
    }
}

TraceFile::impl::~impl() {
    // unhook our message handler before the stream and file are destroyed
    if (original_handler_) {
        qInstallMessageHandler(original_handler_);
    }
    current_stream_ = original_stream_; // revert to prior stream
}

// write Qt messages to the diagnostic log file
void TraceFile::impl::message_handler(QtMsgType type,
                                      QMessageLogContext const &context,
                                      QString const &msg) {
    char const *severity;
    switch (type) {
    case QtDebugMsg:
        severity = "Debug";
        break;

    case QtWarningMsg:
        severity = "Warning";
        break;

    case QtFatalMsg:
        severity = "Fatal";
        break;

    default:
        severity = "Critical";
        break;
    }

    {
        // guard against multiple threads with overlapping messages
        QMutexLocker guard(&lock);
        Q_ASSERT_X(current_stream_, "TraceFile:message_handler",
                   "no stream to write to");
        *current_stream_
            << QDateTime::currentDateTimeUtc().toString(
                   "yyyy-MM-ddTHH:mm:ss.zzzZ")
            << '(' << context.file << ':'
            << context.line /* << ", " << context.function */ << ')' << severity
            << ": " << msg.trimmed() << Qt::endl;
    }

    if (QtFatalMsg == type) {
        throw std::runtime_error{"Fatal Qt Error"};
    }
}