/** \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 #include #include #include #include #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+=""; debugHtmlContent+=""; debugHtmlContent+=""; debugHtmlContent+=""; debugHtmlContent+=""; debugHtmlContent+=""; debugHtmlContent+=""; debugHtmlContent+="Ultracopier "+QString(ULTRACOPIER_VERSION)+" "+QString(ULTRACOPIER_PLATFORM_NAME)+", debug report"; debugHtmlContent+=""; debugHtmlContent+=""; debugHtmlContent+=""; //Load the start time at now startTime.start(); //Load the log file end endOfLogFile="
"; //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=""+addDebugInformation_time+""+addDebugInformation_fileString+""+function+"()"+location+""+htmlEntities(text)+"\n"; break; case DebugLevel_custom_Critical: addDebugInformation_htmlFormat=""+addDebugInformation_time+""+addDebugInformation_fileString+""+function+"()"+location+""+htmlEntities(text)+"\n"; break; case DebugLevel_custom_Warning: addDebugInformation_htmlFormat=""+addDebugInformation_time+""+addDebugInformation_fileString+""+function+"()"+location+""+htmlEntities(text)+"\n"; break; case DebugLevel_custom_Notice: addDebugInformation_htmlFormat=""+addDebugInformation_time+""+addDebugInformation_fileString+""+function+"()"+location+""+htmlEntities(text)+"\n"; break; case DebugLevel_custom_UserNote: addDebugInformation_htmlFormat=""+addDebugInformation_time+""+addDebugInformation_fileString+""+function+"()"+location+""+htmlEntities(text)+"\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 DebugEngine::getItemList() { QList 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('&',"&"); text.replace('"',"""); text.replace('\'',"'"); text.replace('<',"<"); text.replace('>',">"); 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