119 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			119 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|   | #include "TraceFile.hpp"
 | ||
|  | 
 | ||
|  | #include <stdexcept>
 | ||
|  | 
 | ||
|  | #include <QDebug>
 | ||
|  | #include <QString>
 | ||
|  | #include <QFile>
 | ||
|  | #include <QTextStream>
 | ||
|  | #include <QMessageLogContext>
 | ||
|  | #include <QDateTime>
 | ||
|  | #include <QMutex>
 | ||
|  | #include <QMutexLocker>
 | ||
|  | 
 | ||
|  | #include "pimpl_impl.hpp"
 | ||
|  | 
 | ||
|  | 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 () << endl; | ||
|  |   } | ||
|  | 
 | ||
|  |   if (QtFatalMsg == type) | ||
|  |     { | ||
|  |       throw std::runtime_error {"Fatal Qt Error"}; | ||
|  |     } | ||
|  | } |