/*************************************************************************** * Copyright (C) 2006-2012 by Thomas Schweitzer * * thomas-schweitzer(at)arcor.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2.0 as * * published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program in the file LICENSE.GPL; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "TSLogger.h" #include "ui_TSLoggerDialog.h" #include "SettingsPaths.h" #include #include #include #include #include #include #include #include using namespace tschweitzer; using namespace tschweitzer::debugging; TSLogger*TSLogger::m_instance = NULL; /*! \class TSLogger \brief This class handles any kind of data logging, for debugging and whatever purpose. Beneath being able of displaying a dialog window containing all log messages of the current session, a log file in the systems temporary directory is used. Its name is "UiGUI_log.html". Setting a verbose level allows to only write messages that have the selected minimum priority to the log. */ /*! \brief Returns the only existing instance of TSLogger. If the instance doesn't exist, it will be created. */ TSLogger* TSLogger::getInstance(int verboseLevel) { if (m_instance == NULL) { m_instance = new TSLogger(verboseLevel); } return m_instance; } /*! \brief Returns the only existing instance of TSLogger. If the instance doesn't exist, it will be created. */ TSLogger* TSLogger::getInstance() { #ifdef _DEBUG return TSLogger::getInstance(TQtDebugMsg); #else return TSLogger::getInstance(TQtWarningMsg); #endif } /*! \brief Initializes the dialog and sets the path to the log file in the systems temporary directory. Sets the default verbose level to warning level. */ TSLogger::TSLogger(int verboseLevel) : TQDialog() { m_TSLoggerDialogForm = new Ui::TSLoggerDialog(); m_TSLoggerDialogForm->setupUi(this); #ifdef _DEBUG m_verboseLevel = TQtDebugMsg; #else m_verboseLevel = TQtMsgType(verboseLevel); #endif m_logFileInitState = NOTINITIALZED; connect(m_TSLoggerDialogForm->openLogFileFolderToolButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(openLogFileFolder())); // Make the main application not to wait for the logging window to close. setAttribute(TQt::WA_QuitOnClose, false); } /*! \brief Logs all incoming messages \a msg to the dialogs text edit and to the log file. Only messages whos \a type have a higher priority than the set verbose level are logged. */ void TSLogger::messageHandler(TQtMsgType type, const char *msg) { if (m_instance == NULL) { m_instance = TSLogger::getInstance(); } /* TQMessageBox messageBox; TQString messageBoxText = TQString::fromUtf8( msg ); messageBox.setText( messageBoxText ); messageBox.setWindowModality( TQt::ApplicationModal ); messageBox.exec(); */ // Only log messages that have a higher or equal priority than set with the verbose level. if (type < m_instance->m_verboseLevel) { return; } // Init log message with prepended date and time. TQString message = TQDateTime::currentDateTime().toString(); // Depending on the TQtMsgType prepend a different colored Debug, Warning, Critical or Fatal. switch (type) { case TQtDebugMsg: { message += " Debug: "; break; } case TQtWarningMsg: { message += " Warning: "; break; } case TQtCriticalMsg: { message += "Critical: "; break; } case TQtFatalMsg: { message += " Fatal: "; } // This one is no TQt message type, but can be used to send info messages to the log // by calling TSLogger::messageHandler() directly. case TSLoggerInfoMsg: { message += " Info: "; break; } } // Append the to UTF-8 back converted message parameter. message += TQString::fromUtf8(msg) + "
\n"; // Write the message to the log windows text edit. m_instance->m_TSLoggerDialogForm->logTextEdit->append(message); // Write/append the log message to the log file. m_instance->writeToLogFile(message); // In case of a fatal error abort the application. if (type == TQtFatalMsg) { abort(); } } /*! \brief Calling this the verbose level can be set in a range from 0 to 3 which is equal to debug, warning, critical and fatal priority. */ void TSLogger::setVerboseLevel(int level) { if (level < 0) { m_verboseLevel = TQtDebugMsg; } if (level > 3) { m_verboseLevel = TQtFatalMsg; } else { m_verboseLevel = TQtMsgType(level); } } /*! \brief Deletes the existing m_instance of TSLogger. */ void TSLogger::deleteInstance() { if (m_instance != NULL) { delete m_instance; m_instance = NULL; } } /*! \brief Opens the folder that contains the created log file with the name "UiGUI_log.html". */ void TSLogger::openLogFileFolder() { TQDesktopServices::openUrl(TQFileInfo(m_logFile).absolutePath()); } /*! \brief Writes the \a message to the used log file. */ void TSLogger::writeToLogFile(const TQString &message) { // If the file where all logging messages should go to isn't initilized yet, do that now. if (m_logFileInitState == NOTINITIALZED) { m_logFileInitState = INITIALIZING; // On different systems it may be that "TQDir::tempPath()" ends with a "/" or not. So check // this. // Remove any trailing slashes. TQString tempPath = TQFileInfo(SettingsPaths::getTempPath()).absolutePath(); while (tempPath.right(1) == "/") { tempPath.chop(1); } // To make the temporary log file invulnerable against file symbolic link hacks // append the current date and time up to milliseconds to its name and a random character. TQString logFileName = "UiGUI_log_" + TQDateTime::currentDateTime().toString("yyyyMMdd"); logFileName += "-" + TQDateTime::currentDateTime().toString("hhmmsszzz"); // By random decide whether to append a number or an upper or lower case character. qsrand(time(NULL)); unsigned char randomChar; switch (qrand() % 3) { // Append a number from 0 to 9. case 0: { randomChar = qrand() % 10 + '0'; break; } // Append a upper case characer between A and Z. case 1: { randomChar = qrand() % 26 + 'A'; break; } // Append a lower case characer between a and z. default: { randomChar = qrand() % 26 + 'a'; break; } } logFileName += "_" + TQString(randomChar) + ".html"; m_logFile.setFileName(tempPath + "/" + logFileName); // Set the tooltip of the open log file folder button to show the unique name of the log file. m_TSLoggerDialogForm->openLogFileFolderToolButton->setToolTip( m_TSLoggerDialogForm->openLogFileFolderToolButton->toolTip() + " (" + logFileName + ")"); m_logFileInitState = INITIALZED; } // Add the message to the message queue. m_messageQueue << message; // If the logging file is initialzed, write all messages contained in the message queue into the // file. if (m_logFileInitState == INITIALZED) { // Write/append the log message to the log file. if (m_logFile.open(TQIODevice::WriteOnly | TQIODevice::Text | TQIODevice::Append)) { TQTextStream out(&m_logFile); while (!m_messageQueue.isEmpty()) { out << m_messageQueue.takeFirst() << "\n"; } m_logFile.close(); } } }