/*! * * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. * \copyright \n * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, \n * IN PART OR IN WHOLE, \n * WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. \n * * \file logger.cpp * \date 2019/09/30 * \author Behrouz NematiPour * */ #include "logger.h" // Qt #include #include #include #include #include #include // Project #include "storageglobals.h" #include "filehandler.h" #include "threads.h" using namespace Storage; /*! * \brief Logger::Logger * \details Constructor * \param parent - QObject parent owner object. * Qt handles the children destruction by their parent objects life-cycle. */ Logger::Logger(QObject *parent) : QObject(parent) { } /*! * \brief Logger::init * \details Initializes the Class. * \return False if it has been called before. */ bool Logger::init() { if ( _init ) return false; _init = true; // runs in thread checkLogPath(); initConnections(); LOG_EVENT(QObject::tr("%1 Initialized").arg(metaObject()->className())); return true; } /*! * \brief Logger::init * \details Initialized the Class by calling the init() method first * And initializes the thread vThread by calling initThread * on success init(). * \param vThread - the thread * \return returns the return value of the init() method */ bool Logger::init(QThread &vThread) { if ( ! init() ) return false; initThread(vThread); return true; } /*! * \brief Logger quit * \details quits the class * Calls quitThread */ void Logger::quit() { // coco begin validated: Application termination is not correctly done in coco!!! // it has been tested and works perfectly fine in normal run. quitThread(); } // coco end void Logger::onLog(const QString &vContent, LogType vLogType) { log(vContent,vLogType); } /*! * \brief Logger::initConnections * \details Initializes the required signal/slot connection between this class and other objects * to be able to communicate. * \note No connection has been defined yet. */ void Logger::initConnections() { connect(&_exportWatcher, SIGNAL(finished()), this , SLOT(onExport())); connect(this, SIGNAL(didLog(QString,LogType)), this, SLOT( onLog(QString,LogType))); } /*! * \brief Logger::initThread * \details Moves this object into the thread vThread. * And checks that this method is called from main thread. * Also connects quitThread to application aboutToQuit. * \param vThread - the thread */ void Logger::initThread(QThread &vThread) { // runs in main thread Q_ASSERT_X(QThread::currentThread() == qApp->thread() , __func__, "The Class initialization must be done in Main Thread" ); _thread = &vThread; _thread->setObjectName(QString("%1_Thread").arg(metaObject()->className())); connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(quit())); _thread->start(); moveToThread(_thread); } /*! * \brief Logger::quitThread * \details Moves this object to main thread to be handled by QApplicaiton * And to be destroyed there. */ void Logger::quitThread() { // coco begin validated: Application termination is not correctly done in coco!!! // it has been tested and works perfectly fine in normal run. if (! _thread) return; // runs in thread moveToThread(qApp->thread()); } // coco end /*! * \brief Logger::checkLogPath * \details Sets the log paths and creates them if didn't exist. */ void Logger::checkLogPath() { setLogBasePath(); // try to use /media/sd_card on device if (! setLogPath()) { // check and create log folders & if unsuccessful then setLogBasePath(true); // try to use application folder setLogPath ( ); // check and create log folders // Note: it may require to check for write access regarding device setup } } /*! * \brief Logger::setLogBasePath * \details Tries to the set the log path to the default log path (Log_Base_Path_Name) * Will set the application folder as the base log path if can't set the log path to the default. * Will log the event in that case. * \param vUseApplicationDirPath */ void Logger::setLogBasePath(bool vUseApplicationDirPath) { if (vUseApplicationDirPath) { _dir.setPath(qApp->applicationDirPath()); LOG_EVENT(tr("Application Dir Path used for events logging (%1)").arg(_dir.path())); } else { _dir.setPath(Log_Base_Path_Name); } } /*! * \brief Logger::setLogPath * \details set the log path for each of the Datum, Event, Error log types * \return False if can not st the log paths. */ bool Logger::setLogPath() { bool ok = true; ok = ok && setLogPath(LogType::eLogEvent); ok = ok && setLogPath(LogType::eLogError); ok = ok && setLogPath(LogType::eLogDatum); return ok; } /*! * \brief Logger::setLogPath * \details Sets the log path for the log type vLogType * Creates the folder if not exists. * \param vLogType - log type * \return returns false if the path doesn't exist and folder can't be created. */ bool Logger::setLogPath(LogType vLogType) { _logPathNames[vLogType] = _dir.path() + "/" + _logBasePathNames[vLogType]; if ( ! _dir.exists(_logBasePathNames[vLogType]) ) { if ( ! _dir.mkpath(_logBasePathNames[vLogType]) ) { LOG_ERROR(tr("Can't create %1 log path (%2)") .arg(_logPrefix[vLogType]) .arg(_logPathNames[vLogType]) ); return false; } } return true; } /*! * \brief Logger::log * \details Logs the content vContent in log type of vLogType. * \param vContent - Log content * \param vLogType - Log type * \note This method is not thread-safe so is private and needs to be called by concurrentLog * Which uses QtConcurrent::run to run in thread and thread-safe. */ void Logger::log(const QString &vContent, Logger::LogType vLogType) { QString date = QDate::currentDate().toString(_dateFormat); QString mContent; switch (vLogType) { case eLogEvent: case eLogError: case eLogDatum: break; default: LOG_ERROR(tr("Incorrect type of logging").arg(vLogType)); } mContent += _logPrefix[vLogType]; mContent += _prefixSeparator; mContent += QTime::currentTime().toString(_timeFormat); mContent += _timeSeparator + vContent; QString fileName = date + _dateSeparator + Log_File_Name; _logFileName = _logPathNames[vLogType] + fileName; FileHandler::write(_logFileName, mContent + "\r\n", true); if (vLogType == eLogError) { #ifdef QT_DEBUG //mContent.prepend("\033[1;31m --- @ --- \033[0m"); mContent.prepend(" @ "); #endif qDebug().noquote() << mContent; } } /*! * \brief Logger::concurrentExport * \details Exports the log files from log folder (Storage::Log_Base_Path_Name_Location) * into USB drive folder (Storage::USB_Mount_Point) * \return always returns true for now. * \note This method uses QtConcurrent run to execute the FileHandler copyFolder method. */ bool Logger::concurrentExport() { // coco begin validated: This needs user interaction to export to USB device // has been tested manually QString mSource = Storage::Log_Base_Path_Name_Location; QString mDestination = Storage::USB_Mount_Point; QFuture future = QtConcurrent::run(&FileHandler::copyFolder, mSource, mDestination); _exportWatcher.setFuture(future); future.waitForFinished(); return true; } // coco end void Logger::onExport() { // coco begin validated: This needs user interaction to export to USB device // has been tested manually emit didExport(); } // coco end