summaryrefslogtreecommitdiff
path: root/DebugEngine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'DebugEngine.cpp')
-rw-r--r--DebugEngine.cpp386
1 files changed, 386 insertions, 0 deletions
diff --git a/DebugEngine.cpp b/DebugEngine.cpp
new file mode 100644
index 0000000..4fe6314
--- /dev/null
+++ b/DebugEngine.cpp
@@ -0,0 +1,386 @@
+/** \file DebugEngine.cpp
+\brief Define the class for the debug
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include <QDir>
+#include <QFSFileEngine>
+#include <QMessageBox>
+#include <QFileDialog>
+#include <QLocalSocket>
+
+#include "Variable.h"
+#include "DebugEngine.h"
+#include "ExtraSocket.h"
+
+/// \brief The local macro: ULTRACOPIER_DEBUGCONSOLE
+#if defined (__FILE__) && defined (__LINE__)
+ #define ULTRACOPIER_DEBUGCONSOLE(a,b) addDebugInformation(a,__func__,b,__FILE__,__LINE__)
+#else
+ #define ULTRACOPIER_DEBUGCONSOLE(a,b) addDebugInformation(a,__func__,b)
+#endif
+
+#ifdef ULTRACOPIER_DEBUG
+
+/// \brief initiate the ultracopier event dispatcher and check if no other session is running
+DebugEngine::DebugEngine()
+{
+ addDebugInformationCallNumber=0;
+ //Load the first content
+ debugHtmlContent+="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">";
+ debugHtmlContent+="<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">";
+ debugHtmlContent+="<head>";
+ debugHtmlContent+="<meta name=\"Language\" content=\"en\" />";
+ debugHtmlContent+="<meta http-equiv=\"content-language\" content=\"english\" />";
+ debugHtmlContent+="<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />";
+ debugHtmlContent+="<style type=\"text/css\">";
+ debugHtmlContent+="body{font-family:\"DejaVu Sans Mono\";font-size:9pt;}";
+ debugHtmlContent+=".Information td{color:#7485df;}";
+ debugHtmlContent+=".Critical td{color:#ff0c00;background-color:#FFFE8C;}";
+ debugHtmlContent+=".Warning td{color:#efa200;}";
+ debugHtmlContent+=".Notice td{color:#999;}";
+ debugHtmlContent+=".time{font-weight:bold;}";
+ debugHtmlContent+=".Note{font-weight:bold;font-size:1.5em}";
+ debugHtmlContent+=".function{font-style:italic;text-decoration:underline}";
+ debugHtmlContent+=".location{padding-right:15px;}";
+ debugHtmlContent+="td {white-space:nowrap;}";
+ debugHtmlContent+="</style>";
+ debugHtmlContent+="<title>Ultracopier "+QString(ULTRACOPIER_VERSION)+" "+QString(ULTRACOPIER_PLATFORM_NAME)+", debug report</title>";
+ debugHtmlContent+="</head>";
+ debugHtmlContent+="<body>";
+ debugHtmlContent+="<table>";
+ //Load the start time at now
+ startTime.start();
+ //Load the log file end
+ endOfLogFile="</table></body></html>";
+ //check if other instance is running, then switch to memory backend
+ if(tryConnect())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_custom_Notice,"currentBackend: File because other session is runing");
+ currentBackend=Memory;
+ return;
+ }
+ //The lock and log file path is not defined
+ bool fileNameIsLoaded=false;
+ #ifdef ULTRACOPIER_VERSION_PORTABLE
+ #ifdef ULTRACOPIER_VERSION_PORTABLEAPPS
+ //Load the data folder path
+ QDir dir(QCoreApplication::applicationDirPath());
+ dir.cdUp();
+ dir.cdUp();
+ dir.cd("Data");
+ logFile.setFileName(dir.absolutePath()+QDir::separator()+"log.html");
+ lockFile.setFileName(dir.absolutePath()+QDir::separator()+"ultracopier.lock");
+ fileNameIsLoaded=true;
+ #else
+ //Load the ultracopier path
+ QDir dir(QCoreApplication::applicationDirPath());
+ logFile.setFileName(dir.absolutePath()+QDir::separator()+"log.html");
+ lockFile.setFileName(dir.absolutePath()+QDir::separator()+"ultracopier.lock");
+ fileNameIsLoaded=true;
+ #endif
+ #else
+ #ifdef Q_OS_WIN32
+ #define EXTRA_HOME_PATH "\\ultracopier\\"
+ #else
+ #define EXTRA_HOME_PATH "/.config/Ultracopier/"
+ #endif
+ //Load the user path only if exists and writable
+ QDir dir(QFSFileEngine::homePath()+EXTRA_HOME_PATH);
+ bool errorFound=false;
+ //If user's directory not exists create it
+ if(!dir.exists())
+ {
+ //If failed not load the file
+ if(!dir.mkpath(dir.absolutePath()))
+ {
+ errorFound=true;
+ puts(qPrintable("Unable to make path: "+dir.absolutePath()+", disable file log"));
+ }
+ }
+ //If no error found set the file name
+ if(errorFound==false)
+ {
+ fileNameIsLoaded=true;
+ logFile.setFileName(dir.absolutePath()+QDir::separator()+"log.html");
+ lockFile.setFileName(dir.absolutePath()+QDir::separator()+"ultracopier.lock");
+ }
+ errorFound=false;
+ #endif
+ //If the file name is loaded
+ if(fileNameIsLoaded)
+ {
+ //If the previous file is here, then crash previous, ask if the user want to save
+ if(lockFile.exists() && logFile.exists())
+ {
+ //Try open the file as read only to propose save it as the user
+ //Don't ask it if unable to write, because unable to remove, then alert at all start
+ if(removeTheLockFile())
+ {
+ //Ask to the user
+ QMessageBox::StandardButton reply = QMessageBox::question(NULL,"Save the previous report","Ultracopier seam have crashed, do you want save the previous report for report it to the forum?",QMessageBox::Yes|QMessageBox::No,QMessageBox::No);
+ if(reply==QMessageBox::Yes)
+ saveBugReport();
+ }
+ else
+ puts(qPrintable(logFile.fileName()+" unable to open it as read"));
+ }
+ //Now try to create and open the log file and lock file
+ if(!lockFile.open(QIODevice::WriteOnly|QIODevice::Truncate|QIODevice::Unbuffered))
+ {
+ currentBackend=Memory;
+ puts(qPrintable(lockFile.fileName()+" unable to open it as write, log into file disabled"));
+ }
+ else
+ {
+ if(!logFile.open(QIODevice::ReadWrite|QIODevice::Truncate|QIODevice::Unbuffered))
+ {
+ currentBackend=Memory;
+ puts(qPrintable(logFile.fileName()+" unable to open it as write, log into file disabled"));
+ removeTheLockFile();
+ }
+ else
+ {
+ currentBackend=File;
+ logFile.write(debugHtmlContent.toUtf8());
+ }
+ }
+ }
+ if(currentBackend==File)
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_custom_Notice,"currentBackend: File");
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_custom_Notice,"currentBackend: Memory");
+}
+
+/// \brief Destroy the ultracopier event dispatcher
+DebugEngine::~DebugEngine()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_custom_Notice,"start");
+ if(currentBackend==File)
+ {
+ removeTheLockFile();
+ //Finalize the log file
+ logFile.write(endOfLogFile.toUtf8());
+ logFile.close();
+ }
+}
+
+/// \brief ask to the user where save the bug report
+void DebugEngine::saveBugReport()
+{
+ bool errorFound;
+ do
+ {
+ errorFound=false;
+ //Ask where it which save it
+ QString fileName = QFileDialog::getSaveFileName(NULL,"Save file","ultracopier-bug-report.log.html","Log file (*.log.html)");
+ if(fileName!="")
+ {
+ if(QFile::exists(fileName))
+ {
+ if(!QFile::remove(fileName))
+ {
+ errorFound=true;
+ puts(qPrintable(fileName+" unable remove it"));
+ QMessageBox::critical(NULL,"Error","Unable to save the bug report");
+ }
+ }
+ if(!errorFound)
+ {
+ //Open the destination as write
+ if(!logFile.copy(fileName))
+ {
+ errorFound=true;
+ puts(qPrintable(fileName+" unable to open it as write: "+logFile.errorString()));
+ QMessageBox::critical(NULL,"Error","Unable to save the bug report"+logFile.errorString());
+ }
+ }
+ }
+ } while(errorFound!=false);
+}
+
+/// \brief Internal function to remove the lock file
+bool DebugEngine::removeTheLockFile()
+{
+ //close the file and remove it
+ lockFile.close();
+ if(!lockFile.remove())
+ {
+ puts(qPrintable(lockFile.fileName()+" unable to remove it, crash report at the next start"));
+ return false;
+ }
+ else
+ return true;
+}
+
+void DebugEngine::addDebugInformationStatic(const DebugLevel &level,const QString& function,const QString& text,const QString& file,const int& ligne,const QString& location)
+{
+ DebugEngine *debug_engine_instance=DebugEngine::getInstance();
+ DebugLevel_custom tempLevel=DebugLevel_custom_Information;
+ switch(level)
+ {
+ case DebugLevel_Information:
+ tempLevel=DebugLevel_custom_Information;
+ break;
+ case DebugLevel_Critical:
+ tempLevel=DebugLevel_custom_Critical;
+ break;
+ case DebugLevel_Warning:
+ tempLevel=DebugLevel_custom_Warning;
+ break;
+ case DebugLevel_Notice:
+ tempLevel=DebugLevel_custom_Notice;
+ break;
+ default:
+ tempLevel=DebugLevel_custom_Notice;
+ }
+ debug_engine_instance->addDebugInformation(tempLevel,function,text,file,ligne,location);
+ DebugEngine::destroyInstanceAtTheLastCall();
+}
+
+void DebugEngine::addDebugNote(const QString& text)
+{
+ DebugEngine *debug_engine_instance=DebugEngine::getInstance();
+ debug_engine_instance->addDebugInformation(DebugLevel_custom_UserNote,"",text,"",-1,"Core");
+ DebugEngine::destroyInstanceAtTheLastCall();
+}
+
+/// \brief For add message info, this function is thread safe
+void DebugEngine::addDebugInformation(const DebugLevel_custom &level,const QString& function,const QString& text,QString file,const int& ligne,const QString& location)
+{
+ //Remove the compiler extra patch generated
+ file=file.remove(QRegExp("\\.\\.?[/\\\\]([^/]+[/\\\\])?"));
+ QString addDebugInformation_lignestring=QString::number(ligne);
+ QString addDebugInformation_fileString=file;
+ if(ligne!=-1)
+ addDebugInformation_fileString+=":"+addDebugInformation_lignestring;
+ //Load the time from start
+ QString addDebugInformation_time = QString::number(startTime.elapsed());
+ QString addDebugInformation_htmlFormat;
+ switch(level)
+ {
+ case DebugLevel_custom_Information:
+ addDebugInformation_htmlFormat="<tr class=\"Information\"><td class=\"time\">"+addDebugInformation_time+"</span></td><td>"+addDebugInformation_fileString+"</td><td class=\"function\">"+function+"()</td><td class=\"location\">"+location+"</td><td>"+htmlEntities(text)+"</td></tr>\n";
+ break;
+ case DebugLevel_custom_Critical:
+ addDebugInformation_htmlFormat="<tr class=\"Critical\"><td class=\"time\">"+addDebugInformation_time+"</span></td><td>"+addDebugInformation_fileString+"</td><td class=\"function\">"+function+"()</td><td class=\"location\">"+location+"</td><td>"+htmlEntities(text)+"</td></tr>\n";
+ break;
+ case DebugLevel_custom_Warning:
+ addDebugInformation_htmlFormat="<tr class=\"Warning\"><td class=\"time\">"+addDebugInformation_time+"</span></td><td>"+addDebugInformation_fileString+"</td><td class=\"function\">"+function+"()</td><td class=\"location\">"+location+"</td><td>"+htmlEntities(text)+"</td></tr>\n";
+ break;
+ case DebugLevel_custom_Notice:
+ addDebugInformation_htmlFormat="<tr class=\"Notice\"><td class=\"time\">"+addDebugInformation_time+"</span></td><td>"+addDebugInformation_fileString+"</td><td class=\"function\">"+function+"()</td><td class=\"location\">"+location+"</td><td>"+htmlEntities(text)+"</td></tr>\n";
+ break;
+ case DebugLevel_custom_UserNote:
+ addDebugInformation_htmlFormat="<tr class=\"Note\"><td class=\"time\">"+addDebugInformation_time+"</span></td><td>"+addDebugInformation_fileString+"</td><td class=\"function\">"+function+"()</td><td class=\"location\">"+location+"</td><td>"+htmlEntities(text)+"</td></tr>\n";
+ break;
+ }
+ //To prevent access of string in multi-thread
+ {
+ //Show the text in console
+ QString addDebugInformation_textFormat;
+ addDebugInformation_textFormat = "("+addDebugInformation_time.rightJustified(8,' ')+") ";
+ if(file!="" && ligne!=-1)
+ addDebugInformation_textFormat += file+":"+addDebugInformation_lignestring+":";
+ addDebugInformation_textFormat += function+"(), (location: "+location+"): "+text;
+ puts(qPrintable(addDebugInformation_textFormat));
+ QMutexLocker lock_mutex(&mutex);
+ if(currentBackend==File)
+ {
+ if(logFile.size()>64*1024*1024) // greater than 64MB
+ puts("File log greater than 64MB, stop to record it!");
+ else
+ logFile.write(addDebugInformation_htmlFormat.toUtf8());
+ }
+ else
+ {
+ if(debugHtmlContent.size()<64*1024*1024)
+ debugHtmlContent+=addDebugInformation_htmlFormat;
+ else
+ puts("String greater than 64MB, stop to record it!");
+ }
+ ItemOfDebug newItem;
+ newItem.time=addDebugInformation_time;
+ newItem.level=level;
+ newItem.function=function;
+ if(addDebugInformation_lignestring!="-1")
+ newItem.file=file+":"+addDebugInformation_lignestring;
+ else
+ newItem.file=file;
+ newItem.location=location;
+ newItem.text=text;
+ listItemOfDebug << newItem;
+ }
+ //Send the new line
+ if(addDebugInformationCallNumber<ULTRACOPIER_DEBUG_MAX_GUI_LINE)
+ {
+ addDebugInformationCallNumber++;
+ emit newDebugInformation();
+ }
+}
+
+QList<DebugEngine::ItemOfDebug> DebugEngine::getItemList()
+{
+ QList<DebugEngine::ItemOfDebug> returnedList;
+ {
+ QMutexLocker lock_mutex(&mutexList);
+ returnedList=listItemOfDebug;
+ listItemOfDebug.clear();
+ }
+ return returnedList;
+}
+
+/// \brief Get the html text info for re-show it
+QString DebugEngine::getTheDebugHtml()
+{
+ if(currentBackend==File)
+ {
+ logFile.seek(0);
+ if(!logFile.isOpen())
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_custom_Warning,"The log file is not open");
+ return QString().fromUtf8(logFile.readAll().data())+endOfLogFile;
+ }
+ else
+ return debugHtmlContent+endOfLogFile;
+}
+
+/// \brief Get the html end
+QString DebugEngine::getTheDebugEnd()
+{
+ return endOfLogFile;
+}
+
+/// \brief Drop the html entities
+QString DebugEngine::htmlEntities(QString text)
+{
+ text.replace('&',"&amp;");
+ text.replace('"',"&quot;");
+ text.replace('\'',"&#039;");
+ text.replace('<',"&lt;");
+ text.replace('>',"&gt;");
+ return text;
+}
+
+/// \brief return the current backend
+DebugEngine::Backend DebugEngine::getCurrentBackend()
+{
+ return currentBackend;
+}
+
+bool DebugEngine::tryConnect()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_custom_Notice,"start");
+ QLocalSocket localSocket;
+ localSocket.connectToServer(ExtraSocket::pathSocket(ULTRACOPIER_SOCKETNAME),QIODevice::WriteOnly|QIODevice::Unbuffered);
+ if(localSocket.waitForConnected(1000))
+ {
+ localSocket.disconnectFromServer();
+ return true;
+ }
+ else
+ return false;
+}
+
+#endif