1 #include "TraceFile.hpp"
2
3 #include <stdexcept>
4
5 #include <QDebug>
6 #include <QMutex>
7 #include <QMutexLocker>
8 #include <QString>
9 #include <QFile>
10 #include <QTextStream>
11
12 #include "pimpl_impl.hpp"
13
14 class TraceFile::impl
15 {
16 public:
17 impl (QString const& trace_file_path);
18 ~impl ();
19
20 // no copying
21 impl (impl const&) = delete;
22 impl& operator = (impl const&) = delete;
23
24 private:
25 // write Qt messages to the diagnostic log file
26 static void message_handler (QtMsgType type, QMessageLogContext const& context, QString const& msg);
27
28 QFile file_;
29 QTextStream stream_;
30 QTextStream * original_stream_;
31 QtMessageHandler original_handler_;
32 static QTextStream * current_stream_;
33 static QMutex mutex_;
34 };
35
36 QTextStream * TraceFile::impl::current_stream_;
37 QMutex TraceFile::impl::mutex_;
38
39 // delegate to implementation class
TraceFile(QString const & trace_file_path)40 TraceFile::TraceFile (QString const& trace_file_path)
41 : m_ {trace_file_path}
42 {
43 }
44
~TraceFile()45 TraceFile::~TraceFile ()
46 {
47 }
48
49
impl(QString const & trace_file_path)50 TraceFile::impl::impl (QString const& trace_file_path)
51 : file_ {trace_file_path}
52 , original_stream_ {current_stream_}
53 , original_handler_ {nullptr}
54 {
55 // if the log file is writeable; initialise diagnostic logging to it
56 // for append and hook up the Qt global message handler
57 if (file_.open (QFile::WriteOnly | QFile::Append | QFile::Text))
58 {
59 stream_.setDevice (&file_);
60 current_stream_ = &stream_;
61 original_handler_ = qInstallMessageHandler (message_handler);
62 }
63 }
64
~impl()65 TraceFile::impl::~impl ()
66 {
67 // unhook our message handler before the stream and file are destroyed
68 if (original_handler_)
69 {
70 qInstallMessageHandler (original_handler_);
71 }
72 current_stream_ = original_stream_; // revert to prior stream
73 }
74
75 // write Qt messages to the diagnostic log file
message_handler(QtMsgType type,QMessageLogContext const & context,QString const & msg)76 void TraceFile::impl::message_handler (QtMsgType type, QMessageLogContext const& context, QString const& msg)
77 {
78 Q_ASSERT_X (current_stream_, "TraceFile:message_handler", "no stream to write to");
79 {
80 QMutexLocker lock {&mutex_}; // thread safety - serialize writes to the trace file
81 *current_stream_ << qFormatLogMessage (type, context, msg) <<
82 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
83 endl;
84 #else
85 Qt::endl;
86 #endif
87 }
88
89 if (QtFatalMsg == type)
90 {
91 throw std::runtime_error {"Fatal Qt Error"};
92 }
93 }
94