From 18267c55f2734cf2e2ae75e432e0ff8b41694c30 Mon Sep 17 00:00:00 2001 From: Sandro Fadiga Date: Wed, 26 Sep 2018 00:50:55 -0300 Subject: [PATCH] major fixes and updates LIST OF CHANGES ON THIS COMMIT: - Changed the internal application configuration system to use the standard QSettings from Qt (instead of a cfg file an ini file) - Move some of the syntax to C++ 11 - Used smart pointers where necessary/recommended - Fixed some mem leaks around the code - Enhanced the abstraction of the architecture, removed some unecessary classes added some necessary ones. - Corrected the function that searches for the configuration file (using proper Qt syntax QDir, iterators, etc) - Corrected the XML output file to properly close the XML structure - Corrected some errors on the file handling of the log, and cleanup routines - Created the JSON output file format - Created the SIGNAL/SLOT (Qt) version of an output - SignalOutput - Changed the constants to an proper global include file to easy application config and update - Added extra documentation to the source code - Added a test project to the qlogger project - Changed the qlogger project to a proper static lib project --- QLogger.pro | 30 --- QLoggerLib/jsonoutput.cpp | 88 +++++++ QLoggerLib/jsonoutput.h | 84 ++++++ QLoggerLib/output.cpp | 34 +++ QLoggerLib/signaloutput.cpp | 53 ++++ QLoggerLib/signaloutput.h | 80 ++++++ README | 29 ++- configfilehandler.h | 244 ----------------- configuration.cpp | 138 ---------- configuration.h | 108 -------- qlogger.cpp | 149 ----------- qlogger.h | 185 ------------- qlogger/qlogger.pro | 5 + qlogger/qlogger.pro.user | 330 +++++++++++++++++++++++ qloggerlib/configuration.cpp | 135 ++++++++++ qloggerlib/configuration.h | 152 +++++++++++ qloggerlib/consoleoutput.cpp | 66 +++++ qloggerlib/consoleoutput.h | 81 ++++++ main.cpp => qloggerlib/main.cpp | 26 +- qloggerlib/output.h | 97 +++++++ qloggerlib/qlogger.cpp | 222 ++++++++++++++++ qloggerlib/qlogger.h | 236 +++++++++++++++++ qlogger.cfg => qloggerlib/qlogger.ini | 25 +- qloggerlib/qloggerlib.cpp | 6 + qloggerlib/qloggerlib.h | 13 + qloggerlib/qloggerlib.pro | 47 ++++ qloggerlib/qloggerlib_global.h | 180 +++++++++++++ qloggerlib/textoutput.cpp | 102 ++++++++ qloggerlib/textoutput.h | 91 +++++++ qloggerlib/xmloutput.cpp | 86 ++++++ output.h => qloggerlib/xmloutput.h | 48 ++-- qloggertester/qloggertester.pro | 16 ++ qloggertester/target_wrapper.bat | 10 + qloggertester/tst_qloggertest.cpp | 361 ++++++++++++++++++++++++++ textoutput.cpp | 188 -------------- textoutput.h | 138 ---------- xmloutput.cpp | 100 ------- xmloutput.h | 77 ------ 38 files changed, 2659 insertions(+), 1401 deletions(-) delete mode 100644 QLogger.pro create mode 100644 QLoggerLib/jsonoutput.cpp create mode 100644 QLoggerLib/jsonoutput.h create mode 100644 QLoggerLib/output.cpp create mode 100644 QLoggerLib/signaloutput.cpp create mode 100644 QLoggerLib/signaloutput.h delete mode 100644 configfilehandler.h delete mode 100644 configuration.cpp delete mode 100644 configuration.h delete mode 100644 qlogger.cpp delete mode 100644 qlogger.h create mode 100644 qlogger/qlogger.pro create mode 100644 qlogger/qlogger.pro.user create mode 100644 qloggerlib/configuration.cpp create mode 100644 qloggerlib/configuration.h create mode 100644 qloggerlib/consoleoutput.cpp create mode 100644 qloggerlib/consoleoutput.h rename main.cpp => qloggerlib/main.cpp (85%) create mode 100644 qloggerlib/output.h create mode 100644 qloggerlib/qlogger.cpp create mode 100644 qloggerlib/qlogger.h rename qlogger.cfg => qloggerlib/qlogger.ini (83%) create mode 100644 qloggerlib/qloggerlib.cpp create mode 100644 qloggerlib/qloggerlib.h create mode 100644 qloggerlib/qloggerlib.pro create mode 100644 qloggerlib/qloggerlib_global.h create mode 100644 qloggerlib/textoutput.cpp create mode 100644 qloggerlib/textoutput.h create mode 100644 qloggerlib/xmloutput.cpp rename output.h => qloggerlib/xmloutput.h (60%) create mode 100644 qloggertester/qloggertester.pro create mode 100644 qloggertester/target_wrapper.bat create mode 100644 qloggertester/tst_qloggertest.cpp delete mode 100644 textoutput.cpp delete mode 100644 textoutput.h delete mode 100644 xmloutput.cpp delete mode 100644 xmloutput.h diff --git a/QLogger.pro b/QLogger.pro deleted file mode 100644 index 8006da1..0000000 --- a/QLogger.pro +++ /dev/null @@ -1,30 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2013-03-07T16:20:12 -# -#------------------------------------------------- - -QT += core - -QT -= gui - -TARGET = QLogger -CONFIG += console -CONFIG -= app_bundle - -TEMPLATE = app - - -SOURCES += main.cpp \ - xmloutput.cpp \ - textoutput.cpp \ - qlogger.cpp \ - configuration.cpp - -HEADERS += \ - xmloutput.h \ - textoutput.h \ - qlogger.h \ - output.h \ - configuration.h \ - configfilehandler.h diff --git a/QLoggerLib/jsonoutput.cpp b/QLoggerLib/jsonoutput.cpp new file mode 100644 index 0000000..8566a92 --- /dev/null +++ b/QLoggerLib/jsonoutput.cpp @@ -0,0 +1,88 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include "jsonoutput.h" + +namespace qlogger +{ + +JSONOutput::JSONOutput(Configuration *cfg) : PlainTextOutput (cfg) +{ + this->configuration->setFileNameMask(JSON_FILE_NAME_MASK); +} + +JSONOutput::~JSONOutput() +{ + if(!outputFile.isNull() && outputFile->isOpen()) + { + // end current json file. + close(); + } + PlainTextOutput::close(); +} + +void JSONOutput::close() +{ + if(!outputFile.isNull()) + { + // end current json file. + jsonCurrentLog[JSON_LOGS] = jsonCurrentList; + + QJsonDocument jsonDoc(jsonCurrentLog); + outputFile->write(jsonDoc.toJson()); + // release the file + outputFile->close(); + // clean the json objects + jsonCurrentLog.empty(); + jsonCurrentList.empty(); + } +} + +void JSONOutput::write(const QString message, const QString owner, + const Level lvl, const QDateTime timestamp, + const QString functionName, const int lineNumber) +{ + + if(!outputFile.isNull() + && outputFile->isOpen() + && (outputFile->size() > (configuration->getFileMaxSizeInKb() * 1024))) + { + close(); + } + + if(outputFile.isNull() //if there is no file + || !outputFile->isOpen() // or the file is not opened for writing + || (outputFile->size() > (configuration->getFileMaxSizeInKb() * 1024))) // or the file is already at max size + { + createNextFile(); // create a new file + } + + QJsonObject json; + json[JSON_LINE] = lineNumber; + json[JSON_FUNCTION] = functionName; + json[JSON_DATE_TIME] = timestamp.toString(configuration->getTimestampFormat()); + json[JSON_LEVEL] = levelToString(lvl); + json[JSON_MESSAGE] = message; + json[JSON_OWNER] = owner; + jsonCurrentList.append(json); +} + +} diff --git a/QLoggerLib/jsonoutput.h b/QLoggerLib/jsonoutput.h new file mode 100644 index 0000000..95ec08e --- /dev/null +++ b/QLoggerLib/jsonoutput.h @@ -0,0 +1,84 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef JSONOUTPUT_H +#define JSONOUTPUT_H + +#include "textoutput.h" +#include + +#include +#include +#include + +namespace qlogger { + +//! +//! \brief The JSONOutput class - saves a text file with a standard json format with the log information +//! +class JSONOutput : public PlainTextOutput +{ + +public: + //! + //! \brief JSONOutput + //! \param cfg + //! + JSONOutput(Configuration* cfg); + JSONOutput() = delete; + //! + ~JSONOutput(); + + // Output interface +public: + //! + //! \brief write + //! \param message + //! \param owner + //! \param lvl + //! \param timestamp + //! \param functionName + //! \param lineNumber + //! + void write(const QString message, const QString owner, + const Level lvl, const QDateTime timestamp, + const QString functionName, const int lineNumber); + // Output interface + //! + //! \brief close + //! + void close(); + +private: + //! + //! \brief jsonCurrentLog + //! + QJsonObject jsonCurrentLog; + //! + //! \brief jsonCurrentList + //! + QJsonArray jsonCurrentList; + +}; + +} + +#endif // JSONOUTPUT_H diff --git a/QLoggerLib/output.cpp b/QLoggerLib/output.cpp new file mode 100644 index 0000000..cd26f52 --- /dev/null +++ b/QLoggerLib/output.cpp @@ -0,0 +1,34 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include "output.h" + +namespace qlogger +{ + +Output::Output(Configuration* conf) : configuration(QSharedPointer(conf)) {} + +QSharedPointer Output::getConfiguration() const +{ + return configuration; +} + +} diff --git a/QLoggerLib/signaloutput.cpp b/QLoggerLib/signaloutput.cpp new file mode 100644 index 0000000..5a86138 --- /dev/null +++ b/QLoggerLib/signaloutput.cpp @@ -0,0 +1,53 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include "signaloutput.h" + +#include + +namespace qlogger +{ + + +SignalOutput::SignalOutput(Configuration *cfg) : Output(cfg) +{ +} + +void SignalOutput::write(const QString message, const QString owner, const Level lvl, + const QDateTime timestamp, const QString functionName, + const int lineNumber) +{ + + QString logtext = formatLogText(configuration->getLogTextMask(), + message, owner, levelToString(lvl), + timestamp.toString(configuration->getTimestampFormat()), + functionName, lineNumber); + emit qlogger(logtext); + +} + +void SignalOutput::close() +{ +} + + + +} diff --git a/QLoggerLib/signaloutput.h b/QLoggerLib/signaloutput.h new file mode 100644 index 0000000..d41cdd0 --- /dev/null +++ b/QLoggerLib/signaloutput.h @@ -0,0 +1,80 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef SIGNALOUTPUT_H +#define SIGNALOUTPUT_H + +#include + +#include "consoleoutput.h" + +namespace qlogger +{ + +//! +//! \brief The SignalOutput class - An output class tha 'writes' to a SLOT, this class is also a QObject so +//! it can emit a SIGNAL when a log is written +//! +class SignalOutput : public QObject, public Output +{ + Q_OBJECT + +public: + //! + //! \brief SignalOutput + //! \param cfg + //! + SignalOutput(Configuration *cfg); + SignalOutput() = delete; + //! + ~SignalOutput() = default; + + // Output interface +public: + //! + //! \brief write + //! \param message + //! \param owner + //! \param lvl + //! \param timestamp + //! \param functionName + //! \param lineNumber + //! + void write(const QString message, const QString owner, const Level lvl, + const QDateTime timestamp, const QString functionName, const int lineNumber); + + //! + //! \brief close + //! + void close(); + +signals: + //! + //! \brief qlogger - the signal emmited when 'write' is called + //! \param logtext - the output text written by this log to the SLOT + //! + void qlogger(QString logtext); + +}; + +} + +#endif // SIGNALOUTPUT_H diff --git a/README b/README index c5b3b32..dc29ebb 100644 --- a/README +++ b/README @@ -96,7 +96,7 @@ int main(int argc, char *argv[]) ... ------------------------------------------------------------------------------- This example shows a logger that was added from a configuration file. In order -to use a configuration file, one can simply add a qlogger.cfg (plain text) file +to use a configuration file, one can simply add a qlogger.ini (ini file format) file onto application path. QLogger will parse the file when the first instance of logger is called. Note that this also allows adding logs programatically so they both can be used together. @@ -106,17 +106,28 @@ Example of a configuration file for QLogger: ------------------------------------------------------------------------------- # line comment -# first configuration will log to warn level to a file on c:\ with 1Mb of size -file.level=warn -file.outputType=text +# first configuration will log to warn level to a file on c:\ with 10Mb of size + +[file] +level=warn +outputType=text + # 10mb file -file.maxFileSize=1000 -file.path=c:\ +maxFileSize=10000 +path=c:/temp/ # second config will log to console with trace level and customized log text mask -cons.level=trace -cons.outputType=console -cons.logMask=time:%t owner:%o level:%l function:%f line:%n message:%m +[cons] +level=trace +outputType=console +logMask=time:%t owner:%o level:%l function:%f line:%n message:%m + +# third a xml output +[xml] +level=trace +outputType=xml +fileName=XML_log_%1_%2_%3.xml +path=c:/temp/ ------------------------------------------------------------------------------- This small readme covered almost everything QLogger is capable to do, there are some diff --git a/configfilehandler.h b/configfilehandler.h deleted file mode 100644 index 6081fd3..0000000 --- a/configfilehandler.h +++ /dev/null @@ -1,244 +0,0 @@ -/* - * QLogger - A tiny Qt logging framework. - * - * MIT License - * Copyright (c) 2013 sandro fadiga - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software - * is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies - * or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE - * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef CONFIGFILEHANDLER_H -#define CONFIGFILEHANDLER_H - -#include -#include -#include -#include "configuration.h" - -namespace qlogger -{ - -//! This class is responsible to search on program path for a configuration file -//! Then read and parse this configuration file to generate valid configurations from it -//! -//! The file must be a plain text file with the name qlogger.cfg -//! The following texts are valid on config file. -//! -//! # comment line example -//! owner.level = { FATAL, ERROR, WARN, INFO, DEBUG, TRACE } -//! owner.outputType = { CONSOLE, TEXT, XML } -//! owner.logMask = -//! { for console and text can use the symbols %t %o %l %m , if does not contain %t %l and %m will use the default } -//! owner.maxFileSize = {in kb just a number 100, 1000... only for TEXT and XML} -//! owner.path = { a valid absolut path on the system, if invalid path is given then will default to app path } -//! owner.timestampFormat = -//! { the Qt format for datetime used to format the %t part of console and text and date_time tag of XML, it defaults to platform short format } -//! owner.fileName = { file name mask, must contain all %1 %2 %3 params, example: log_%1_%2_%3.txt -//! owner.fileNameTimeStamp = { the timestamp that will be written in param %3 of the file name mask, must follow QTimeDate string format. - -static const QString CH_LEVEL = "level"; - -static const QString CH_OUTPUT_TYPE = "outputType"; - -static const QString CH_LOG_MASK = "logMask"; - -static const QString CH_MAX_FILE_SIZE = "maxFileSize"; - -static const QString CH_PATH = "path"; - -static const QString CH_TIMESTAMP_FORMAT = "timestampFormat"; - -static const QString CH_FILE_NAME = "fileName"; - -static const QString CH_FILE_NAME_TIMESTAMP = "fileNameTimeStamp"; - -static const QString CH_CONFIG_FILE_NAME = "qlogger.cfg"; - -class ConfigFileHandler -{ - -private: - - inline static void recursiveFolderSearch(QDir& dir, bool &found) - { - QDir path(dir.absolutePath()); - QStringList list = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); - const int size = list.size(); - for(int i = 0; i < size ; ++i) - { - QString currentPath = list.at(i); - if(found) - { - return; - } - else if(QFile::exists(CH_CONFIG_FILE_NAME)) - { - found = true; - return; - } - else - { - found = false; - dir.cd(currentPath); - recursiveFolderSearch(dir, found); - if(!found) - dir.cdUp(); - } - } - } - -protected: - - inline static bool searchForConfigFile() - { - QDir dir(QDir::currentPath()); - //search on the folder tree - bool found = false; - recursiveFolderSearch(dir, found); - return found; - } - - inline static bool createConfiguration(QMultiHash &ownerConfigLines, - QList &configs)//QMultiHash &loggers) - { - QList configTextList = ownerConfigLines.keys(); - QString currentConfig = QString(); - bool localTest = false; // the loggers reference could already been filled from somewhere else - const int size = configTextList.size(); - for(int i = 0 ; i < size ; i++) - { - QString configText = configTextList.at(i); - if(currentConfig != configText) - { - QStringList values = ownerConfigLines.values(configText); - //loggers.insert(config, parseAllLinesOfConfig(config, values)); - configs.append(parseAllLinesOfConfig(configText, values)); - currentConfig = configText; - localTest = true; - } - } - return localTest; - } - - inline static Configuration* parseAllLinesOfConfig(QString owner, QStringList lines) - { - // parsing a structure like ( key=value ) * N - Configuration::Level level = Configuration::q1ERROR; - Configuration::OutputType outputType = Configuration::CONSOLE; - QString logMask = QString(); - int maxFileSize = 0; - QString path = QString(); - QString timestampFormat = QString(); - QString fileName = QString(); - QString fileNameTimestamp = QString(); - int size = lines.size(); - for (int i = 0 ; i < size ; i++)//(QString line , lines) - { - QString line = lines.at(i); - QStringList configList = line.trimmed().split("="); - QString key = configList.isEmpty() ? QString() : configList.at(0); // left hand - QString paramValue = configList.size() < 1 ? QString() : configList.at(1); //right hand - if(key == CH_LEVEL) - { - level = Configuration::levelFromString(paramValue); - } - else if(key == CH_OUTPUT_TYPE) - { - if(paramValue.toUpper().contains("TEXT")) - { - outputType = Configuration::TEXTFILE; - } - else if(paramValue.toUpper().contains("XML")) - { - outputType = Configuration::XMLFILE; - } - else - { - outputType = Configuration::CONSOLE; - } - } - else if(key == CH_LOG_MASK) - { - logMask = paramValue; - } - else if(key == CH_MAX_FILE_SIZE) - { - bool ok; - maxFileSize = paramValue.toInt(&ok); - if(!ok) - maxFileSize = 1000; - } - else if(key == CH_TIMESTAMP_FORMAT) - { - timestampFormat = paramValue; - } - else if(key == CH_FILE_NAME) - { - fileName = paramValue; - } - else if(key == CH_FILE_NAME_TIMESTAMP) - { - fileNameTimestamp = paramValue; - } - else if(key == CH_PATH) - { - path = paramValue; - } - } - - return new Configuration(owner, level, outputType, timestampFormat, logMask, fileName, fileNameTimestamp, path, maxFileSize); - } - -public: - - //! only public method, this will receive a hash by reference and fill it with found configurations - //! false will be returned if no config is filled in - inline static bool parseConfigurationFile(QList &configs)//(QMultiHash &loggers) - { - QMultiHash ownerConfigLines; - QFile* file = new QFile(CH_CONFIG_FILE_NAME); - if (ConfigFileHandler::searchForConfigFile() && - file->open(QIODevice::ReadOnly | QIODevice::Text)) - { - QTextStream ts(file); - QString configLine; - do - { - configLine = ts.readLine(); - if(!configLine.trimmed().isEmpty() && !configLine.trimmed().startsWith("#")) - { - QStringList temp = configLine.split("."); // separate the owner.key=value - QString owner = temp.isEmpty() ? QString() : temp.at(0); - if(!owner.isEmpty() && temp.size() > 1) - { - ownerConfigLines.insert(owner, temp.at(1)); - } - } - } while (!configLine.isNull()); - file->close(); - return createConfiguration(ownerConfigLines, configs); - } - else - { - return false; - } - } - -}; - -} - -#endif // CONFIGFILEHANDLER_H diff --git a/configuration.cpp b/configuration.cpp deleted file mode 100644 index ff14e36..0000000 --- a/configuration.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * QLogger - A tiny Qt logging framework. - * - * MIT License - * Copyright (c) 2013 sandro fadiga - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software - * is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies - * or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE - * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include "configuration.h" - -namespace qlogger -{ - -Configuration::Configuration() : - logOwner(QString()), logLevel(Level(-1)), outputType(OutputType(-1)), outputLog(NULL), timestampFormat(QString()) -{ -} - -Configuration::Configuration(QString logOwner, - Configuration::Level lvl, - OutputType outputType, - QString timestampFormat, - QString logTextMask, - QString fileNameMask, - QString fileNameTimestampFormat, - QString filePath, - int fileMaxSizeInKb) - : logOwner(logOwner), logLevel(lvl), outputType(outputType), outputLog(NULL), timestampFormat(timestampFormat) -{ - - if(this->timestampFormat.isEmpty()) - this->timestampFormat = TIMESTAMP_QLOGGER_FORMAT; - - switch(outputType) - { - case XMLFILE: - this->outputLog = new XmlOutput(logOwner, fileNameMask, fileNameTimestampFormat, filePath, fileMaxSizeInKb); - break; - case TEXTFILE: - this->outputLog = new TextFileOutput(logOwner, logTextMask, filePath, fileMaxSizeInKb, fileNameMask, fileNameTimestampFormat); - break; - case CONSOLE: - default: - this->outputLog = new ConsoleOutput(logTextMask); - break; - } -} - -Configuration::~Configuration() -{ -} - -bool Configuration::operator==(const Configuration &rh) -{ - return (this->logOwner == rh.logOwner && this->logLevel == rh.logLevel && this->outputType == rh.outputType); -} - -QString Configuration::levelToString(const Level level) -{ - static const char* const buffer[] = { "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" }; - return buffer[level]; -} - -Configuration::Level Configuration::levelFromString(const QString level) -{ - QString lvl = level.trimmed().toUpper(); - if (lvl == "FATAL") - { - return Configuration::q0FATAL; - } - else if (lvl == "WARN") - { - return Configuration::q2WARN; - } - else if (lvl == "INFO") - { - return Configuration::q3INFO; - } - else if (lvl == "DEBUG") - { - return Configuration::q4DEBUG; - } - else if (lvl == "TRACE") - { - return Configuration::q5TRACE; - } - else // return default level - { - return Configuration::q1ERROR; - } - -} - -const QString Configuration::getLogOwner() const -{ - return logOwner; -} - -void Configuration::setLogOwner(const QString owner) -{ - this->logOwner = QString(owner); -} - -Configuration::Level Configuration::getLogLevel() const -{ - return logLevel; -} - -Configuration::OutputType Configuration::getOutputType() const -{ - return outputType; -} - -Output* Configuration::getOutputLog() const -{ - return outputLog; -} - -const QString Configuration::getTimestampFormat() const -{ - return timestampFormat; -} - -} diff --git a/configuration.h b/configuration.h deleted file mode 100644 index f09e36c..0000000 --- a/configuration.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * QLogger - A tiny Qt logging framework. - * - * MIT License - * Copyright (c) 2013 sandro fadiga - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software - * is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies - * or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE - * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef CONFIGURATION_H -#define CONFIGURATION_H - -#include -#include -#include "textoutput.h" -#include "xmloutput.h" - -namespace qlogger -{ - -//! -static const QString TIMESTAMP_QLOGGER_FORMAT = "MM/dd/yyyy hh:mm:ss"; - -//! This class stores the configuration details for each log to be created. -//! Default configuration can be created with the default constructor. -class Configuration -{ -public: - - // http://en.wikipedia.org/wiki/Java_logging_framework - // http://commons.apache.org/logging/guide.html#Message%20Priorities/Levels - //! - enum Level - { - q0FATAL, q1ERROR, q2WARN, q3INFO, q4DEBUG, q5TRACE - }; - - //! - enum OutputType - { - CONSOLE, TEXTFILE, XMLFILE - }; - -public: - Configuration(); - - Configuration(QString logOwner, Level lvl = q1ERROR, - OutputType ouputType = CONSOLE, - QString timestampFormat = TIMESTAMP_QLOGGER_FORMAT, - QString logTextMask = DEFAULT_TEXT_MASK, - QString fileNameMask = QString(), - QString fileNameTimestampFormat = FILE_NAME_TIMESTAMP_FORMAT, - QString filePath = QDir::currentPath(), - int fileMaxSizeInKb = 1000); - - //! destructor, check for outputLog and closes it - virtual ~Configuration(); - - //! equals operator is used to check if a configuration have the same level and output type only - bool operator==(const Configuration &rh); - - //! utility to convert the level enum to string - static QString levelToString(const Configuration::Level level); - - static Configuration::Level levelFromString(const QString level); - -private: - //! store the name of the log owner to pass it to the output classes - QString logOwner; - - //! level of this configuration - Level logLevel; - - //! output medium to be used to log the message - OutputType outputType; - - //! this attribute is responsible for writing the log on the output - Output* outputLog; - - //! the date time format to be displayed on the log text it must use Qt Date Time format convention - QString timestampFormat; - -public: - const QString getLogOwner() const; - void setLogOwner(const QString owner); - Level getLogLevel() const; - Configuration::OutputType getOutputType() const; - Output* getOutputLog() const; - const QString getTimestampFormat() const; - -}; - -} - -#endif // CONFIGURATION_H diff --git a/qlogger.cpp b/qlogger.cpp deleted file mode 100644 index 911d7fc..0000000 --- a/qlogger.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * QLogger - A tiny Qt logging framework. - * - * MIT License - * Copyright (c) 2013 sandro fadiga - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software - * is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies - * or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE - * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include "qlogger.h" - -#include -#include - -#include "configfilehandler.h" - -namespace qlogger -{ - -QAtomicPointer QLogger::instance = 0; -QLoggerDestroyer QLogger::destroyer; -QMutex QLogger::mutex; -QMutex QLogger::writex; - -QLoggerDestroyer::QLoggerDestroyer(QAtomicPointer s) -{ - singleton = s; -} - -QLoggerDestroyer::~QLoggerDestroyer() -{ - QLogger::mutex.lock(); - // call the close file methods for all loggers - QLoggerDestroyer::getPointerInstance()->close(); - delete QLoggerDestroyer::getPointerInstance(); - QLogger::mutex.unlock(); -} - -void QLoggerDestroyer::SetSingleton(QAtomicPointer s) -{ - singleton = s; -} - -QLogger::QLogger() -{} - -QLogger::~QLogger() -{} - -void QLogger::close() -{ - QList cfgList = loggers.values(); - const int size = cfgList.size(); - for (int i = 0 ; i < size ; i++) - { - Configuration* cfg = cfgList.at(i); - cfg->getOutputLog()->close(); - } -} - -QLogger* QLogger::getInstance() -{ - if(!QLogger::getPointerInstance()) - { - mutex.lock(); - if (instance.testAndSetOrdered(0, new QLogger())) - { - destroyer.SetSingleton(instance); - QList lst; - //add the default "root" logger - lst.append(new Configuration("root", Configuration::q1ERROR)); - // configuration file read, then start with the default logger - ConfigFileHandler::parseConfigurationFile(lst);//QLogger::getPointerInstance()->loggers); - int size = lst.size(); - for(int i = 0 ; i < size ; i++) - { - Configuration* config = lst.at(i); - QLogger::getPointerInstance()->loggers.insert(config->getLogOwner(), config); - } - } - mutex.unlock(); - } - return QLogger::getPointerInstance(); -} - -void QLogger::addLogger(QString logOwner, Configuration* configuration) -{ - QLogger::getInstance(); - mutex.lock(); - if(!QLogger::getPointerInstance()->loggers.values(logOwner).contains(configuration)) - { - configuration->setLogOwner(logOwner); - QLogger::getPointerInstance()->loggers.insert(logOwner, configuration); - } - mutex.unlock(); -} - -void QLogger::addLogger(Configuration* configuration) -{ - QString logOwner = configuration != NULL ? configuration->getLogOwner() : QString(); - addLogger(logOwner, configuration); -} - -void QLogger::addLogger(QString logOwner) -{ - QLogger::addLogger(logOwner, new Configuration(logOwner)); -} - -void QLogger::addLogger(QString logOwner, Configuration::Level lvl, - Configuration::OutputType ouputType, - QString timestampFormat) -{ - Configuration* cfg = new Configuration(logOwner, lvl, ouputType, timestampFormat); - QLogger::addLogger(logOwner, cfg); -} - -void QLogger::log(Configuration::Level lvl, QString message, QString functionName, int lineNumber, QString owner) -{ - writex.lock(); - QList configs = QLogger::getInstance()->loggers.values(owner); - const int size = configs.size(); - for(int i = 0 ; i < size ; i++) - { - Configuration* cfg = configs.at(i); - if(lvl <= cfg->getLogLevel()) - { - cfg->getOutputLog()->write(message, Configuration::levelToString(lvl), owner, - QDateTime::currentDateTime().toString(cfg->getTimestampFormat()), functionName, lineNumber); - } - } - writex.unlock(); -} - - - -} diff --git a/qlogger.h b/qlogger.h deleted file mode 100644 index 56e76fd..0000000 --- a/qlogger.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * QLogger - A tiny Qt logging framework. - * - * MIT License - * Copyright (c) 2013 sandro fadiga - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software - * is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies - * or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE - * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef QLOGGER_H -#define QLOGGER_H - -#include -#include -#include - -#include "configuration.h" - -namespace qlogger -{ - -class Configuration; -class QLogger; - -//! This class is responsible for returning the memory of QLogger singleton and avoid mem leaks -class QLoggerDestroyer -{ -public: - QLoggerDestroyer(QAtomicPointer s = 0); - ~QLoggerDestroyer(); - void SetSingleton(QAtomicPointer s); - -private: - QAtomicPointer singleton; - -public: - //! Handles the acess to QAtomicPointer methods based on Qt version - inline QLogger* getPointerInstance() - { - #if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) - return singleton; - #else - return singleton.loadAcquire(); - #endif - } - -}; - -//! Main QLogger class, its a singleton responsible for register the log messages to -//! its respective owners and also load the runtime configurations wich defines how each -//! log message will be displayed. -class QLogger -{ - -public: - //! retrives the global instance of the QLogger class, this is private so no ones need to call this directly - static QLogger* getInstance(); - -protected: - // allow the definition of the destroyer inside the singleton - friend class QLoggerDestroyer; - - //! protected constructor to avoid instatiation outside the class - QLogger(); - virtual ~QLogger(); - - //! - void close(); - -private: - //! Singleton instance - static QAtomicPointer instance; - - //! singleton creation mutex - static QMutex mutex; - - //! log writing mutex - static QMutex writex; - - //! this static instance is responsible for call the singleton destructor when program ends - static QLoggerDestroyer destroyer; - - //! this methods adds a loger based on a configuration - static void addLogger(QString logOwner, Configuration* configuration); - -private: - //! Stop the compiler generating methods of copy the object - QLogger(QLogger const& copy); // Not Implemented - QLogger& operator=(QLogger const& copy); // Not Implemented - - //! Handles the acess to QAtomicPointer methods based on Qt version - static inline QLogger* getPointerInstance() - { - #if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) - return instance; - #else - return instance.loadAcquire(); - #endif - } - - -private: - //! logger added at runtime along with their configurations - QMultiHash loggers; - -public: - - //! adds a logger with a default configuration to the list of loggers in runtime - static void addLogger(QString logOwner); - - static void addLogger(Configuration* configuration); - - //! adds a logger passing a configuration to the list of loggers in runtime - static void addLogger(QString logOwner, Configuration::Level lvl, - Configuration::OutputType ouputType, - QString timestampFormat = TIMESTAMP_QLOGGER_FORMAT); - - //! log a message to a specific level - static void log(Configuration::Level, QString message, QString functionName = QString(), int lineNumber = -1, QString owner = "root"); - - //! logs directly to fatal level - inline static void fatal(QString message, QString owner = "root", QString functionName = QString(), int lineNumber = -1) - { - QLogger::log(Configuration::q0FATAL, message, functionName, lineNumber, owner); - } - - //! logs directly to error level - inline static void error(QString message, QString owner = "root", QString functionName = QString(), int lineNumber = -1) - { - QLogger::log(Configuration::q1ERROR, message, functionName, lineNumber, owner); - } - - //! logs directly to warn level - inline static void warn(QString message, QString owner = "root", QString functionName = QString(), int lineNumber = -1) - { - QLogger::log(Configuration::q2WARN, message, functionName, lineNumber, owner); - } - - //! logs directly to info level - inline static void info(QString message, QString owner = "root", QString functionName = QString(), int lineNumber = -1) - { - QLogger::log(Configuration::q3INFO, message, functionName, lineNumber, owner); - } - - //! logs directly to debug level - inline static void debug(QString message, QString owner = "root", QString functionName = QString(), int lineNumber = -1) - { - QLogger::log(Configuration::q4DEBUG, message, functionName, lineNumber, owner); - } - - //! logs directly to trace level - inline static void trace(QString message, QString owner = "root", QString functionName = QString(), int lineNumber = -1) - { - QLogger::log(Configuration::q5TRACE, message, functionName, lineNumber, owner); - } - -}; - -// MACROS FOR THE PEOPLE! -#define QLOG_FATAL(message, ...) QLogger::log(Configuration::q0FATAL, message, __FUNCTION__ , __LINE__, ##__VA_ARGS__); -#define QLOG_ERROR(message, ...) QLogger::log(Configuration::q1ERROR, message, __FUNCTION__ , __LINE__ , ##__VA_ARGS__); -#define QLOG_WARN(message, ...) QLogger::log(Configuration::q2WARN, message, __FUNCTION__ , __LINE__ , ##__VA_ARGS__); -#define QLOG_INFO(message, ...) QLogger::log(Configuration::q3INFO, message, __FUNCTION__ , __LINE__ , ##__VA_ARGS__); -#define QLOG_DEBUG(message, ...) QLogger::log(Configuration::q4DEBUG, message, __FUNCTION__ , __LINE__ , ##__VA_ARGS__); -#define QLOG_TRACE(message, ...) QLogger::log(Configuration::q5TRACE, message, __FUNCTION__ , __LINE__ , ##__VA_ARGS__); - -} - - - -#endif // QLOGGER_H - diff --git a/qlogger/qlogger.pro b/qlogger/qlogger.pro new file mode 100644 index 0000000..415035a --- /dev/null +++ b/qlogger/qlogger.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + ../qloggerlib \ + ../qloggertester diff --git a/qlogger/qlogger.pro.user b/qlogger/qlogger.pro.user new file mode 100644 index 0000000..d3da2af --- /dev/null +++ b/qlogger/qlogger.pro.user @@ -0,0 +1,330 @@ + + + + + + EnvironmentId + {12a5a9ae-37ff-4cb6-b988-27b4d7c799ec} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + -fno-delayed-template-parsing + + true + false + Builtin.TidyAndClazy + + D:/Dev/Source/QLogger/QLogger/QLogger.pro + + + + true + + + + ProjectExplorer.Project.Target.0 + + Desktop Qt 5.11.2 MSVC2017 64bit + Desktop Qt 5.11.2 MSVC2017 64bit + qt.qt5.5112.win64_msvc2017_64_kit + 0 + 0 + 0 + + D:/Dev/Source/QLogger/build-QLogger-Desktop_Qt_5_11_2_MSVC2017_64bit-Debug + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + D:/Dev/Source/QLogger/build-QLogger-Desktop_Qt_5_11_2_MSVC2017_64bit-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + + false + false + true + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + + D:/Dev/Source/QLogger/build-QLogger-Desktop_Qt_5_11_2_MSVC2017_64bit-Profile + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + true + true + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Profile + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 3 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy Configuration + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + QLoggerTester + + Qt4ProjectManager.Qt4RunConfiguration:D:/Dev/Source/QLogger/QLoggerTester/QLoggerTester.pro + true + + ../QLoggerTester/QLoggerTester.pro + + D:/Dev/Source/QLogger/QLoggerTester + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/qloggerlib/configuration.cpp b/qloggerlib/configuration.cpp new file mode 100644 index 0000000..3816ded --- /dev/null +++ b/qloggerlib/configuration.cpp @@ -0,0 +1,135 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "configuration.h" + +namespace qlogger +{ + +Configuration::Configuration(QString logOwner, + Level lvl, + QString textMask, + QString timestampFormat, + QString fileMask, + QString fileTimestampFormat, + QString path, + int maxSizeInKb) + : logOwner(std::move(logOwner)), logLevel(lvl), + logTextMask(std::move(textMask)), timestampFormat(std::move(timestampFormat)), + fileNameMask(std::move(fileMask)), fileNameTimestampFormat(std::move(fileTimestampFormat)), + filePath(std::move(path)), fileMaxSizeInKb(maxSizeInKb) +{ +} + +bool Configuration::operator==(const Configuration &rh) +{ + return (this->logOwner == rh.logOwner && this->logLevel == rh.logLevel); +} + +bool Configuration::validate() +{ + return !(logOwner.isEmpty() || logTextMask.isEmpty() || timestampFormat.isEmpty()); +} + +int Configuration::getFileMaxSizeInKb() const +{ + return fileMaxSizeInKb; +} + +void Configuration::setFileMaxSizeInKb(int value) +{ + fileMaxSizeInKb = value; +} + +QString Configuration::getFilePath() const +{ + return filePath; +} + +void Configuration::setFilePath(const QString &value) +{ + filePath = value; +} + +QString Configuration::getFileNameTimestampFormat() const +{ + return fileNameTimestampFormat; +} + +void Configuration::setFileNameTimestampFormat(const QString &value) +{ + fileNameTimestampFormat = value; +} + +QString Configuration::getFileNameMask() const +{ + return fileNameMask; +} + +void Configuration::setFileNameMask(const QString &value) +{ + fileNameMask = value; +} + +QString Configuration::getLogTextMask() const +{ + return logTextMask; +} + +void Configuration::setLogTextMask(const QString &value) +{ + logTextMask = value; +} + +QString Configuration::getTimestampFormat() const +{ + return timestampFormat; +} + +void Configuration::setTimestampFormat(const QString &value) +{ + timestampFormat = value; +} + +Level Configuration::getLogLevel() const +{ + return logLevel; +} + +void Configuration::setLogLevel(const Level &value) +{ + logLevel = value; +} + +QString Configuration::getLogOwner() const +{ + return logOwner; +} + +void Configuration::setLogOwner(const QString &value) +{ + logOwner = value; +} + + + +} diff --git a/qloggerlib/configuration.h b/qloggerlib/configuration.h new file mode 100644 index 0000000..5b24c79 --- /dev/null +++ b/qloggerlib/configuration.h @@ -0,0 +1,152 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef CONFIGURATION_H +#define CONFIGURATION_H + +#include "qloggerlib_global.h" + +namespace qlogger +{ + +//! +//! \brief The Configuration class - This class stores the configuration details for each log to be created. +//! Default configuration can be created with the constructor and filling only the owner. +//! +class Configuration final +{ +public: + //! + //! \brief Configuration - no empty configs are allowed + //! + Configuration() = delete; + + //! + //! \brief Configuration - the actual constructor to be used with this class + //! \param logOwner - the only required parameter, name of the log owner + //! \param lvl - the level were this log should be triggered + //! \param logTextMask - the actual log text mask, used only for plain text logs outputs + //! \param timestampFormat - the date time format to be displayed on the log text it must use Qt Date Time format convention + //! \param fileNameMask - the mask for a file name of the log file + //! \param fileNameTimestampFormat - the timestamp to be used on the mask for a file name of the log + //! \param filePath - the path were this log file will be saved + //! \param fileMaxSizeInKb - the max sizes of the log output file + //! + Configuration(QString logOwner, Level lvl = q1ERROR, + QString logTextMask = DEFAULT_TEXT_MASK, + QString timestampFormat = TIMESTAMP_QLOGGER_FORMAT, + QString fileNameMask = TEXT_FILE_NAME_MASK, + QString fileNameTimestampFormat = FILE_NAME_TIMESTAMP_FORMAT, + QString filePath = DEFAULT_LOG_PATH, + int fileMaxSizeInKb = DEFAULT_FILE_SIZE); + + + //!destructor as default since not much to do here. + ~Configuration() = default; + + //! + //! \brief operator == equals operator is used to check if a configuration have the same level and owner + //! \param rh + //! \return + //! + bool operator==(const Configuration &rh); + + //! + //! \brief validate - check the class attributes and inform if the class is valid, true = valid, false = invalid + //! \return + //! + bool validate(); + + //! just getters and setters to access class attributes + + QString getLogOwner() const; + void setLogOwner(const QString &value); + + Level getLogLevel() const; + void setLogLevel(const Level &value); + + QString getTimestampFormat() const; + void setTimestampFormat(const QString &value); + + QString getLogTextMask() const; + void setLogTextMask(const QString &value); + + QString getFileNameMask() const; + void setFileNameMask(const QString &value); + + QString getFileNameTimestampFormat() const; + void setFileNameTimestampFormat(const QString &value); + + QString getFilePath() const; + void setFilePath(const QString &value); + + int getFileMaxSizeInKb() const; + void setFileMaxSizeInKb(int value); + +private: + + //! + //! \brief logOwner - the name of the log owner to pass it to the output classes + //! + QString logOwner; + + //! + //! \brief logLevel - level of this configuration + //! + Level logLevel; + + //! + //! \brief logTextMask - the actual log text mask, used only for plain text logs outputs + //! + QString logTextMask; + + //! + //! \brief timestampFormat - the date time format to be displayed on the log text it must use Qt Date Time format convention + //! + QString timestampFormat; + + //! + //! \brief fileNameMask - the mask for a file name of the log file + //! + QString fileNameMask; + + //! + //! \brief fileNameTimestampFormat - the timestamp to be used on the mask for a file name of the log + //! + QString fileNameTimestampFormat; + + //! + //! \brief filePath - the path were this log file will be saved + //! + QString filePath; + + //! + //! \brief fileMaxSizeInKb - the max sizes of the log output file + //! + int fileMaxSizeInKb; + +}; + + + +} + +#endif // CONFIGURATION_H diff --git a/qloggerlib/consoleoutput.cpp b/qloggerlib/consoleoutput.cpp new file mode 100644 index 0000000..ab5acc7 --- /dev/null +++ b/qloggerlib/consoleoutput.cpp @@ -0,0 +1,66 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include "consoleoutput.h" + +#include +#include +#include +#include +#include + +#include "configuration.h" + +namespace qlogger +{ + +ConsoleOutput::ConsoleOutput(Configuration *conf) : Output(conf), outputStream(new QTextStream(stdout)) +{ + outputStream->device()->setTextModeEnabled(true); +} + +ConsoleOutput::~ConsoleOutput() +{ + close(); +} + +void ConsoleOutput::write(const QString message, + const QString owner, + const Level lvl, + const QDateTime timestamp, + const QString functionName, + const int lineNumber) +{ + if(lvl <= configuration->getLogLevel()) // check level before writing + *outputStream << formatLogText(configuration->getLogTextMask(), + message, owner, + levelToString(lvl), + timestamp.toString(configuration->getTimestampFormat()), + functionName, lineNumber) << endl; +} + +void ConsoleOutput::close() +{ + outputStream->flush(); +} + + +} diff --git a/qloggerlib/consoleoutput.h b/qloggerlib/consoleoutput.h new file mode 100644 index 0000000..c30cbde --- /dev/null +++ b/qloggerlib/consoleoutput.h @@ -0,0 +1,81 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef CONSOLEOUTPUT_H +#define CONSOLEOUTPUT_H + +#include "output.h" + +#include +#include +#include + +using namespace std; + +namespace qlogger +{ + +//! +//! \brief The ConsoleOutput class - is the standard output, writes plain text to the console +//! +class ConsoleOutput : public Output +{ +public: + + //! + //! \brief ConsoleOutput - This default constructor sets the class to be on console mode, all logs will be redirected to stdout + //! \param conf + //! + ConsoleOutput(Configuration *conf); + ConsoleOutput() = delete; + //! + //! \brief ~ConsoleOutput + //! + virtual ~ConsoleOutput(); + + //! + //! \brief write - this method is responsible for write the log text in the selected output + //! \param message + //! \param owner + //! \param lvl + //! \param timestamp + //! \param functionName + //! \param lineNumber + //! + virtual void write(const QString message, + const QString owner, + const Level lvl, + const QDateTime timestamp, + const QString functionName, + const int lineNumber); + + //! implemented from output + virtual void close(); + +protected: + //! + //! \brief outputStream - the qt class to output texts + //! + QSharedPointer outputStream; +}; + +} +#endif // CONSOLEOUTPUT_H diff --git a/main.cpp b/qloggerlib/main.cpp similarity index 85% rename from main.cpp rename to qloggerlib/main.cpp index 81edd7f..de02ef8 100644 --- a/main.cpp +++ b/qloggerlib/main.cpp @@ -84,16 +84,16 @@ void heavyLoadToFileTest() void configFromFileTest() { - QLOG_ERROR("this log will test config files, and save a file to more than one log file with 10mb"); - QLOG_ERROR("the config file must be on application path, can be on any folder together with or below the executable"); - QLOG_ERROR("this will take a while"); + QLOG_ERROR("this log will test config files, and save a file to more than one log file with 10mb", "cons"); + QLOG_ERROR("the config file must be on application path, can be on any folder together with or below the executable", "cons"); + QLOG_ERROR("this will take a while", "cons"); - const int count = 500000; + const int count = 5000; for (int i = 0; i != count; ++i) { - QLOG_WARN("loaded a log from config and save to a file !!!!", "file"); - QLOG_ERROR("fatal log from config", "file"); - QLOG_FATAL("loaded a log config from a file", "file"); + QLOG_WARN(QString("a warn log from config and save to a file n:%1 !").arg(i), "file"); + QLOG_ERROR(QString("an error log from config and save to a file n:%1 !").arg(i), "file"); + QLOG_FATAL(QString("a fatal a log from config and save to a file n:%1 !").arg(i), "file"); } for (int i = 0; i != 10; ++i) { @@ -119,10 +119,10 @@ void sameLoggerMultiLevels() void changeAllConfiguration() { - Configuration* cfg = - new Configuration("config", Configuration::q3INFO, Configuration::TEXTFILE, - "dd-MM-yyyy hh:mm:ss", "%t [%l] <%o> : %m", - "myfile_%3_%2_%1.log", "ddMMyyyy_hhmmss", "c:\\", 10000); + shared_ptr cfg = + shared_ptr(new Configuration("config", Configuration::q3INFO, Configuration::TEXTFILE, + "dd-MM-yyyy hh:mm:ss", "%t [%l] <%o> : %m", + "myfile_%3_%2_%1.log", "ddMMyyyy_hhmmss", "c:\\", 10000)); QLogger::addLogger(cfg); const int count = 100; for (int i = 0; i != count; ++i) @@ -160,11 +160,11 @@ int main(int argc, char *argv[]) //changeAllConfiguration(); - //configFromFileTest(); + configFromFileTest(); //overrideRootLoggerBehaviour(); - quickLogger(); + //quickLogger(); return a.exec(); } diff --git a/qloggerlib/output.h b/qloggerlib/output.h new file mode 100644 index 0000000..627d7e2 --- /dev/null +++ b/qloggerlib/output.h @@ -0,0 +1,97 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef OUTPUT_H +#define OUTPUT_H + +#include + +#include "configuration.h" + +using namespace std; + +namespace qlogger +{ + +//! +//! \brief The Output class - Abstract interface class used to define the behaviour of the classes that will log +//! the messages on all types io. +//! +class Output +{ +public: + + //! + //! \brief write - implement this method in order to be called to write the log on the io + //! \param message + //! \param owner + //! \param lvl + //! \param timestamp + //! \param functionName + //! \param lineNumber + //! + virtual void write(const QString message, + const QString owner, + const Level lvl, + const QDateTime timestamp, + const QString functionName, + const int lineNumber) = 0; + + //! + //! \brief close - implement if any cleanup will be done after all logs were written + //! + virtual void close() = 0; + + //! + //! \brief getConfiguration - retrives the configuration associated with this output + //! \return + //! + QSharedPointer getConfiguration() const; + + //! + //! \brief Output - the standard constructor for an output + //! \param conf - the obligatory configuration that this output will hold + //! + Output(Configuration* conf); + + //! virtual destructor to avoid any bad behavior on child classes + virtual ~Output() = default; + + //! no standard constructor, all outputs should receive a configuration + Output() = delete; + //! forbid copying (a safer way to define interfaces) + Output(const Output &) = delete; + Output& operator=(const Output&) = delete; + Output(Output&&) = delete; + Output& operator=(Output&&) = delete; + +protected: + //! + //! \brief configuration - the actual configuration for the log/owner and this output + //! + QSharedPointer configuration; + +}; + + +} + +#endif // OUTPUT_H diff --git a/qloggerlib/qlogger.cpp b/qloggerlib/qlogger.cpp new file mode 100644 index 0000000..d432ab7 --- /dev/null +++ b/qloggerlib/qlogger.cpp @@ -0,0 +1,222 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "qlogger.h" + +#include +#include +#include +#include + +#include "consoleoutput.h" +#include "textoutput.h" +#include "xmloutput.h" +#include "signaloutput.h" +#include "jsonoutput.h" + +namespace qlogger +{ + +QMutex QLogger::writex; + +bool QLogger::instanceFlag = false; + +QLogger& QLogger::instance() +{ + static QLogger instance; + + if(!instanceFlag) + { + instanceFlag = true; + //add the default "root" logger + QLogger::addLogger("root"); + + // load configurations from cfg file (if any) + QLogger::readConfigurationFile(); + } + + return instance; +} + +void QLogger::addLogger(Configuration* configuration, Output *output) +{ + if(configuration != nullptr && output != nullptr) + { + if(configuration->validate()) + { + instance().loggers.insert(configuration->getLogOwner(), QSharedPointer(output)); + } + else //if no logger is created then cleanup memory + { + delete configuration; + delete output; + } + } +} + +void QLogger::addLogger(Configuration* configuration, OutputType type) +{ + if(configuration != nullptr) + { + QLogger::addLogger(configuration->getLogOwner(), + configuration->getLogLevel(), + type, + configuration->getLogTextMask(), + configuration->getTimestampFormat(), + configuration->getFileNameMask(), + configuration->getFileNameTimestampFormat(), + configuration->getFilePath(), + configuration->getFileMaxSizeInKb()); + delete configuration; + } +} + +void QLogger::addLogger(QString logOwner) +{ + QLogger::addLogger(new Configuration(std::move(logOwner)), CONSOLE); +} + +void QLogger::addLogger(QString logOwner, Level lvl, OutputType ouputType, + QString logTextMask, QString timestampFormat, QString fileNameMask, + QString fileNameTimestampFormat, QString filePath, int fileMaxSizeInKb) +{ + Configuration* configuration = new Configuration(std::move(logOwner), lvl, + std::move(logTextMask), + std::move(timestampFormat), + std::move(fileNameMask), + std::move(fileNameTimestampFormat), + std::move(filePath), fileMaxSizeInKb); + Output* output = nullptr; + switch(ouputType) + { + case CONSOLE: + output = new ConsoleOutput(configuration); + break; + case TEXTFILE: + output = new PlainTextOutput(configuration); + break; + case XMLFILE: + output = new XmlOutput(configuration); + break; + case SIGNAL: + output = new SignalOutput(configuration); + break; + case JSON: + output = new JSONOutput(configuration); + break; + }; + addLogger(configuration, output); +} + +void QLogger::log(Level lvl, const QString &message, const QString &functionName, int lineNumber, const QString &owner) +{ + writex.lock(); + + QList> outList = instance().loggers.values(owner); + foreach(QSharedPointer out, outList) + { + if(!out.isNull() && lvl <= out->getConfiguration()->getLogLevel()) + { + out->write(message, owner, lvl, QDateTime::currentDateTime(), functionName, lineNumber); + } + } + writex.unlock(); +} + +void QLogger::fatal(const QString &message, const QString &owner, const QString &functionName, int lineNumber) +{ + QLogger::log(q0FATAL, message, functionName, lineNumber, owner); +} + +void QLogger::error(const QString &message, const QString &owner, const QString &functionName, int lineNumber) +{ + QLogger::log(q1ERROR, message, functionName, lineNumber, owner); +} + +void QLogger::warn(const QString &message, const QString &owner, const QString &functionName, int lineNumber) +{ + QLogger::log(q2WARN, message, functionName, lineNumber, owner); +} + +void QLogger::info(const QString &message, const QString &owner, const QString &functionName, int lineNumber) +{ + QLogger::log(q3INFO, message, functionName, lineNumber, owner); +} + +void QLogger::debug(const QString &message, const QString &owner, const QString &functionName, int lineNumber) +{ + QLogger::log(q4DEBUG, message, functionName, lineNumber, owner); +} + +void QLogger::trace(const QString &message, const QString &owner, const QString &functionName, int lineNumber) +{ + QLogger::log(q5TRACE, message, functionName, lineNumber, owner); +} + +SignalOutput *QLogger::getSignal(const QString &owner) +{ + QSharedPointer out = instance().loggers.value(owner); + auto sig = dynamic_cast(out.get()); + return sig; +} + +QString QLogger::getConfigFilePath(const QString &startingPath, const QString &fileName) +{ + QString path = QDir::cleanPath(startingPath); + QStringList filter; + if (!fileName.isEmpty()) + filter << fileName; + + QDirIterator it(path, filter, QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + if(it.hasNext()) + return it.next(); + + return ""; // file not found +} + +void QLogger::readConfigurationFile() +{ + QSettings settings(getConfigFilePath(QDir::currentPath(), CH_CONFIG_FILE_NAME), QSettings::IniFormat); + + //traverse the "log owners settings" + QStringList owners = settings.childGroups(); + QStringList::const_iterator it; + for(it = owners.constBegin() ; it != owners.constEnd() ; ++it) + { + settings.beginGroup((*it)); // start reading setting from the current owner + QString level = settings.value(CH_LEVEL, ERROR_LEVEL).toString(); + QString outStr = settings.value(CH_OUTPUT_TYPE, CONSOLE_OUTPUT).toString(); //console + QString mask = settings.value(CH_LOG_MASK, DEFAULT_TEXT_MASK).toString(); + QString timestamp = settings.value(CH_TIMESTAMP_FORMAT, TIMESTAMP_QLOGGER_FORMAT).toString(); + QString fileName = settings.value(CH_FILE_NAME, TEXT_FILE_NAME_MASK).toString(); + QString fileTimestamp = settings.value(CH_FILE_NAME_TIMESTAMP, FILE_NAME_TIMESTAMP_FORMAT).toString(); + QString path = settings.value(CH_PATH, DEFAULT_LOG_PATH).toString(); + int fileSize = settings.value(CH_MAX_FILE_SIZE, DEFAULT_FILE_SIZE).toInt(); + settings.endGroup(); + instance().addLogger((*it), levelFromString(level), ouputFromString(outStr), mask, timestamp, fileName, fileTimestamp, path, fileSize); + } + +} + + + +} diff --git a/qloggerlib/qlogger.h b/qloggerlib/qlogger.h new file mode 100644 index 0000000..7ed4c50 --- /dev/null +++ b/qloggerlib/qlogger.h @@ -0,0 +1,236 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef QLOGGER_H +#define QLOGGER_H + +#include +#include +#include +#include +#include + +#include "qloggerlib_global.h" +#include "configuration.h" + +#include "consoleoutput.h" +#include "textoutput.h" +#include "xmloutput.h" +#include "signaloutput.h" + +namespace qlogger +{ + +//! +//! \brief The QLogger class is the main QLogger class, its a singleton responsible for +//! register the log messages to its respective owners and also load the runtime configurations +//! wich defines how each log message will be displayed. +//! +class QLogger final +{ + +public: + //! + //! \brief instance - retrives the global instance of the QLogger class, this is private so no ones need to call this directly + //! \return a global instance of qlogger + //! + static QLogger& instance(); + + //! + //! \brief addLogger - adds a logger (configuration) and takes ownership of the pointer with output + //! \param configuration - a non null configuration (that will be owned by qlogger) + //! \param output - a non null output (that will be owned by qlogger) + //! + static void addLogger(Configuration *configuration, Output *output); + + //! + //! \brief addLogger - adds a logger (configuration) and takes ownership of the pointer with default console output + //! \param configuration - a non null configuration (that will be owned by qlogger) + //! \param type - only the type of output, the actual object will be created based on this information + //! + static void addLogger(Configuration *configuration, OutputType type = CONSOLE); + + //! + //! \brief addLogger - adds a logger with a default configuration to the list of loggers in runtime + //! \param logOwner - the name of the log owner + //! + static void addLogger(QString logOwner); + + + //! + //! \brief addLogger - adds a logger passing a plain attribute configuration to the list of loggers in runtime + //! \param logOwner - name of the owner + //! \param lvl - the desired level for the log + //! \param ouputType - the type of output for the log + //! \param logTextMask - the log text mask, if applicable + //! \param timestampFormat - the timestamp format of the log time + //! \param fileNameMask - the file name of the log, if applicable + //! \param fileNameTimestampFormat - the timestamp format of the filename + //! \param filePath - the file path if applicable + //! \param fileMaxSizeInKb - the max size per file in kb + //! + static void addLogger(QString logOwner, Level lvl, OutputType ouputType = CONSOLE, QString logTextMask = DEFAULT_TEXT_MASK, + QString timestampFormat = TIMESTAMP_QLOGGER_FORMAT, QString fileNameMask = TEXT_FILE_NAME_MASK, + QString fileNameTimestampFormat = FILE_NAME_TIMESTAMP_FORMAT, QString filePath = DEFAULT_LOG_PATH, + int fileMaxSizeInKb = DEFAULT_FILE_SIZE); + + //! + //! \brief log - the generic method to log a message to a specific level + //! \param message - the actual log message to be, er.. logged + //! \param owner - the owner of this log + //! \param functionName - the function (if any) where this log was called + //! \param lineNumber - the line number were this log was called + //! + static void log(Level, const QString &message, const QString &functionName = QString(), int lineNumber = -1, const QString &owner = "root"); + + //! + //! \brief fatal - logs directly to fatal level + //! \param message - the actual log message to be, er.. logged + //! \param owner - the owner of this log + //! \param functionName - the function (if any) where this log was called + //! \param lineNumber - the line number were this log was called + //! + static void fatal(const QString &message, const QString &owner = "root", const QString &functionName = QString(), int lineNumber = -1); + + //! + //! \brief error - logs directly to error level + //! \param message - the actual log message to be, er.. logged + //! \param owner - the owner of this log + //! \param functionName - the function (if any) where this log was called + //! \param lineNumber - the line number were this log was called + //! + static void error(const QString &message, const QString &owner = "root", const QString &functionName = QString(), int lineNumber = -1); + + //! + //! \brief warn - logs directly to warn level + //! \param message - the actual log message to be, er.. logged + //! \param owner - the owner of this log + //! \param functionName - the function (if any) where this log was called + //! \param lineNumber - the line number were this log was called + //! + static void warn(const QString &message, const QString &owner = "root", const QString &functionName = QString(), int lineNumber = -1); + + //! + //! \brief info - logs directly to info level + //! \param message - the actual log message to be, er.. logged + //! \param owner - the owner of this log + //! \param functionName - the function (if any) where this log was called + //! \param lineNumber - the line number were this log was called + //! + static void info(const QString &message, const QString &owner = "root", const QString &functionName = QString(), int lineNumber = -1); + + //! + //! \brief debug - logs directly to debug level + //! \param message - the actual log message to be, er.. logged + //! \param owner - the owner of this log + //! \param functionName - the function (if any) where this log was called + //! \param lineNumber - the line number were this log was called + //! + static void debug(const QString &message, const QString &owner = "root", const QString &functionName = QString(), int lineNumber = -1); + + //! + //! \brief trace - logs directly to trace level + //! \param message - the actual log message to be, er.. logged + //! \param owner - the owner of this log + //! \param functionName - the function (if any) where this log was called + //! \param lineNumber - the line number were this log was called + //! + static void trace(const QString &message, const QString &owner = "root", const QString &functionName = QString(), int lineNumber = -1); + + //! + //! \brief getSignal - return an Signal output class that uses QT Signal/Slot system, this class "emits" + //! a SIGNAL when an log is written + //! \param owner - the owner of the logger with SignalOutput + //! \return - an reference to the SignalOutput object if it exists , otherwise nullptr. + //! + static SignalOutput* getSignal(const QString &owner); + +protected: + + //! + //! \brief getConfigFilePath - return the path (if exists) to the configuration file (.ini) see @readConfigurationFile + //! \param startingPath - were the qlogger will start to search for the settings + //! \param fileName - the name of the setting file + //! \return + //! + static QString getConfigFilePath(const QString &startingPath, const QString &fileName); + + //! + //! \brief readConfigurationFile uses the QSettings standard as configuration file (force to a .ini file) + //! + //! groups are defined as the log owners, a complete configuration with its descriptions as follows: + //! + //! [owner] + //! level = { FATAL, ERROR, WARN, INFO, DEBUG, TRACE } + //! outputType = { CONSOLE, TEXT, XML } + //! logMask = { for console and text can use the symbols %t %o %l %m , if does not contain %t %l and %m will use the default } + //! maxFileSize = {in kb just a number 100, 1000... only for TEXT and XML} + //! path = { a valid absolut path on the system, if invalid path is given then will default to app path } + //! timestampFormat = { the Qt format for datetime used to format the %t part of console and text and date_time tag of XML, it defaults to platform short format } + //! fileName = { file name mask, must contain all %1 %2 %3 params, example: log_%1_%2_%3.txt + //! fileNameTimeStamp = { the timestamp that will be written in param %3 of the file name mask, must follow QTimeDate string format. + //! + //! [another_owner] + //! ... + static void readConfigurationFile(); + +private: + //! protected constructor to avoid instatiation outside the class + QLogger() = default; + ~QLogger() = default; + QLogger(const QLogger&) = delete; + QLogger(QLogger&&) = delete; + QLogger& operator=(const QLogger&) = delete; + QLogger& operator=(QLogger&&) = delete; + +private: + + //! + //! \brief writex - log writing mutex to be (used with threads) + //! + static QMutex writex; + + //! + //! \brief instanceFlag - controls if the instance was called once + //! + static bool instanceFlag; + + //! + //! \brief loggers - the owner / output relationship, it stores loggers based on owner name, tha may + //! have more than one type of output/configuration + //! + QMultiHash> loggers; + +}; + +//! MACROS FOR THE PEOPLE! +#define QLOG_FATAL(message, ...) QLogger::log(q0FATAL, message, __FUNCTION__ , __LINE__, ##__VA_ARGS__); +#define QLOG_ERROR(message, ...) QLogger::log(q1ERROR, message, __FUNCTION__ , __LINE__ , ##__VA_ARGS__); +#define QLOG_WARN(message, ...) QLogger::log(q2WARN, message, __FUNCTION__ , __LINE__ , ##__VA_ARGS__); +#define QLOG_INFO(message, ...) QLogger::log(q3INFO, message, __FUNCTION__ , __LINE__ , ##__VA_ARGS__); +#define QLOG_DEBUG(message, ...) QLogger::log(q4DEBUG, message, __FUNCTION__ , __LINE__ , ##__VA_ARGS__); +#define QLOG_TRACE(message, ...) QLogger::log(q5TRACE, message, __FUNCTION__ , __LINE__ , ##__VA_ARGS__); + +} + + +#endif // QLOGGER_H + diff --git a/qlogger.cfg b/qloggerlib/qlogger.ini similarity index 83% rename from qlogger.cfg rename to qloggerlib/qlogger.ini index 8663a45..fd59ca2 100644 --- a/qlogger.cfg +++ b/qloggerlib/qlogger.ini @@ -23,13 +23,24 @@ # line comment # first configuration will log to warn level to a file on c:\ with 10Mb of size -file.level=warn -file.outputType=text + +[file] +level=warn +outputType=text + # 10mb file -file.maxFileSize=10000 -file.path=c:\ +maxFileSize=10000 +path=c:/temp/ # second config will log to console with trace level and customized log text mask -cons.level=trace -cons.outputType=console -cons.logMask=time:%t owner:%o level:%l function:%f line:%n message:%m +[cons] +level=trace +outputType=console +logMask=time:%t owner:%o level:%l function:%f line:%n message:%m + +# third a xml output +[xml] +level=trace +outputType=xml +fileName=XML_log_%1_%2_%3.xml +path=c:/temp/ diff --git a/qloggerlib/qloggerlib.cpp b/qloggerlib/qloggerlib.cpp new file mode 100644 index 0000000..1f34dca --- /dev/null +++ b/qloggerlib/qloggerlib.cpp @@ -0,0 +1,6 @@ +#include "qloggerlib.h" + + +QLoggerLib::QLoggerLib() +{ +} diff --git a/qloggerlib/qloggerlib.h b/qloggerlib/qloggerlib.h new file mode 100644 index 0000000..bc5d0c5 --- /dev/null +++ b/qloggerlib/qloggerlib.h @@ -0,0 +1,13 @@ +#ifndef QLOGGERLIB_H +#define QLOGGERLIB_H + +#include "qloggerlib_global.h" + +class QLOGGERLIBSHARED_EXPORT QLoggerLib +{ + +public: + QLoggerLib(); +}; + +#endif // QLOGGERLIB_H diff --git a/qloggerlib/qloggerlib.pro b/qloggerlib/qloggerlib.pro new file mode 100644 index 0000000..d7eed4c --- /dev/null +++ b/qloggerlib/qloggerlib.pro @@ -0,0 +1,47 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2018-09-15T18:06:30 +# +#------------------------------------------------- + +QT -= gui + +TARGET = qloggerlib +TEMPLATE = lib +CONFIG += staticlib + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which has been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += xmloutput.cpp \ + textoutput.cpp \ + qlogger.cpp \ + configuration.cpp \ + consoleoutput.cpp \ + output.cpp \ + signaloutput.cpp \ + jsonoutput.cpp + +HEADERS += \ + xmloutput.h \ + textoutput.h \ + qlogger.h \ + output.h \ + configuration.h \ + qloggerlib_global.h \ + consoleoutput.h \ + signaloutput.h \ + jsonoutput.h + +unix { + target.path = /usr/lib + INSTALLS += target +} diff --git a/qloggerlib/qloggerlib_global.h b/qloggerlib/qloggerlib_global.h new file mode 100644 index 0000000..606f022 --- /dev/null +++ b/qloggerlib/qloggerlib_global.h @@ -0,0 +1,180 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef QLOGGERLIB_GLOBAL_H +#define QLOGGERLIB_GLOBAL_H + +#include +#include +#include + +//evaluate if a dynamic library would be better... it constrains the use of macro for log +/* +#if defined(QLOGGERLIB_LIBRARY) +# define QLOGGER_EXPORT Q_DECL_EXPORT +#else +# define QLOGGER_EXPORT Q_DECL_IMPORT +#endif +*/ + +//! the common global consts and methods used across qlogger anything that must be added or +//! configured along the qlogger project must be placed here. +//! +namespace qlogger +{ + +// http://en.wikipedia.org/wiki/Java_logging_framework +// http://commons.apache.org/logging/guide.html#Message%20Priorities/Levels +//! +enum Level +{ + q0FATAL, q1ERROR, q2WARN, q3INFO, q4DEBUG, q5TRACE +}; + +//! +static const QString FATAL_LEVEL = "FATAL"; +static const QString ERROR_LEVEL = "ERROR"; +static const QString WARN_LEVEL = "WARN"; +static const QString INFO_LEVEL = "INFO"; +static const QString DEBUG_LEVEL = "DEBUG"; +static const QString TRACE_LEVEL = "TRACE"; +static const int NUM_LEVEL = 6; +static const QString levelsbuf[NUM_LEVEL] = { FATAL_LEVEL, ERROR_LEVEL, WARN_LEVEL, INFO_LEVEL, DEBUG_LEVEL, TRACE_LEVEL }; + +//! +enum OutputType +{ + CONSOLE, TEXTFILE, XMLFILE, SIGNAL, JSON +}; + +//! +static const QString CONSOLE_OUTPUT = "CONSOLE"; +static const QString TEXTFILE_OUTPUT = "TEXT"; +static const QString XMLFILE_OUTPUT = "XML"; +static const QString SIGNAL_OUTPUT = "SIGNAL"; +static const QString JSON_OUTPUT = "JSON"; +static const int NUM_OUTPUT = 5; +static const QString outsbuf[NUM_OUTPUT] = { CONSOLE_OUTPUT, TEXTFILE_OUTPUT, XMLFILE_OUTPUT, SIGNAL_OUTPUT, JSON_OUTPUT }; + +//! +static const QString CH_LEVEL = "level"; +static const QString CH_OUTPUT_TYPE = "outputType"; +static const QString CH_LOG_MASK = "logMask"; +static const QString CH_MAX_FILE_SIZE = "maxFileSize"; +static const QString CH_PATH = "path"; +static const QString CH_TIMESTAMP_FORMAT = "timestampFormat"; +static const QString CH_FILE_NAME = "fileName"; +static const QString CH_FILE_NAME_TIMESTAMP = "fileNameTimeStamp"; +static const QString CH_CONFIG_FILE_NAME = "qlogger.ini"; + +//! +static const QString TIMESTAMP_QLOGGER_FORMAT = "MM/dd/yyyy hh:mm:ss"; //! default log timestamp output format + +//! %m - message %l - level %o - owner %t - datetime +static const QString DEFAULT_TEXT_MASK = "%t [%o] <%l> (%f) {line:%n} - %m"; + +//! log_appname_logname_datetime.txt %1 = application name , %2 = owner , %3 = timestamp +static const QString TEXT_FILE_NAME_MASK = "log_%1_%2_%3.txt"; + +//! default as the application path +static const QString DEFAULT_LOG_PATH = "."; + +//! +static const int DEFAULT_FILE_SIZE = 1000; + +//! will be used on the file name mask +static const QString FILE_NAME_TIMESTAMP_FORMAT = "yyyyMMdd_hhmmss"; + +//! log_appname_logname_datetime.txt %1 = application name , %2 = owner , %3 = timestamp +static const QString XML_FILE_NAME_MASK = "log_%1_%2_%3.xml"; + +//! +static const QString XML_TAG = ""; +static const QString ROOT_OPEN_TAG = ""; +static const QString ROOT_CLOSE_TAG = ""; +static const QString LOG_TAG_OPEN = ""; +static const QString LOG_TAG_CLOSE = ""; +static const QString DATE_TIME_TAG = "%1"; +static const QString OWNER_TAG = "%1"; +static const QString MESSAGE_TAG = "%1"; +static const QString LINE_TAG = "%1"; +static const QString FUNCTION_TAG = "%1"; +static const QString LEVEL_TAG = "%1"; + +//! log_appname_logname_datetime.txt %1 = application name , %2 = owner , %3 = timestamp +static const QString JSON_FILE_NAME_MASK = "log_%1_%2_%3.json"; + +static const QString JSON_DATE_TIME = "dateTime"; +static const QString JSON_OWNER = "owner"; +static const QString JSON_MESSAGE = "message"; +static const QString JSON_LINE = "line"; +static const QString JSON_FUNCTION = "function"; +static const QString JSON_LEVEL = "level"; +static const QString JSON_LOGS = "logs"; + +//! utility to convert the level enum to string +inline static QString levelToString(const Level level) +{ + return levelsbuf[level]; +} + +//! convert to enum level from string +inline static Level levelFromString(const QString level) +{ + for(int i = 0 ; i < NUM_LEVEL ; i++) + if(0 == level.trimmed().compare(levelsbuf[i], Qt::CaseInsensitive)) + return static_cast(i); + return q1ERROR; +} + +//! convert to enum output type from string +inline static OutputType ouputFromString(const QString out) +{ + for(int i = 0 ; i < NUM_OUTPUT ; i++) + if(0 == out.trimmed().compare(outsbuf[i], Qt::CaseInsensitive)) + return static_cast(i); + return CONSOLE; +} + +//! do a plain text format based on the provided log format mask +inline static QString formatLogText(const QString logFormatMask, + const QString message, + const QString owner, + const QString lvl, + const QString timestamp, + const QString functionName, + const int lineNumber) +{ + QString text = QString(logFormatMask); + text = text.replace("%t", timestamp); + text = text.replace("%m", message); + text = text.replace("%l", lvl); + text = text.replace("%o", owner); + text = text.replace("%f", functionName); + text = text.replace("%n", QString::number(lineNumber)); + return text; +} + +} + + +#endif // QLOGGERLIB_GLOBAL_H + diff --git a/qloggerlib/textoutput.cpp b/qloggerlib/textoutput.cpp new file mode 100644 index 0000000..2dd3ed7 --- /dev/null +++ b/qloggerlib/textoutput.cpp @@ -0,0 +1,102 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "textoutput.h" + +#include "configuration.h" + +#include +#include +#include +#include +#include + +using namespace std; + +namespace qlogger +{ + +PlainTextOutput::PlainTextOutput(Configuration *conf) : ConsoleOutput(conf) +{ +} + +PlainTextOutput::~PlainTextOutput() +{ + close(); +} + +void PlainTextOutput::createNextFile() +{ + // close any open i/o + close(); + + // COMPOSE NEXT FILE NAME + QString newFileName = configuration->getFileNameMask().arg(QCoreApplication::applicationName(), + configuration->getLogOwner(), + QDateTime::currentDateTime().toString(configuration->getFileNameTimestampFormat())); + + // TEXT FILE MODE + QDir dir(configuration->getFilePath()); + QString myFile = dir.absoluteFilePath(newFileName); + outputFile.clear(); // release the memory from preovious files (if any) + outputFile = QSharedPointer(new QFile(myFile)); + + if(outputFile->open(QIODevice::WriteOnly | QIODevice::Text)) + { + outputStream->setDevice((outputFile.get())); + } + + // enables the output to text mode and have correct line breaks + outputStream->device()->setTextModeEnabled(true); + outputStream->setCodec(QTextCodec::codecForName("UTF-8")); +} + +void PlainTextOutput::write(const QString message, + const QString owner, + const Level lvl, + const QDateTime timestamp, + const QString functionName, + const int lineNumber) +{ + if(outputFile.isNull() //if there is no file + || !outputFile->isOpen() // or the file is not opened for writing + || (outputFile->size() > (configuration->getFileMaxSizeInKb() * 1024))) // or the file is already at max size + { + createNextFile(); // create a new file + } + + ConsoleOutput::write(message, owner, lvl, timestamp, functionName, lineNumber); + +} + +void PlainTextOutput::close() +{ + if(!outputStream.isNull()) + outputStream->flush(); + + if(!outputFile.isNull()) + outputFile->close(); + + ConsoleOutput::close(); +} + +} diff --git a/qloggerlib/textoutput.h b/qloggerlib/textoutput.h new file mode 100644 index 0000000..3ef43b1 --- /dev/null +++ b/qloggerlib/textoutput.h @@ -0,0 +1,91 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef TEXTOUTPUT_H +#define TEXTOUTPUT_H + +#include +#include +#include + +#include "consoleoutput.h" + +using namespace std; + +namespace qlogger +{ + +//! +//! \brief The TextFileOutput class is responsible for write plain text log messages for file or stdout (console) +//! +class PlainTextOutput : public ConsoleOutput +{ + +public: + //! + //! \brief PlainTextOutput - This constructor sets the class to operate in text file mode, all logs will be written in a file + //! \param conf + //! + PlainTextOutput(Configuration *conf); + PlainTextOutput() = delete; + //! this destructor also releases any i/o resources associated with this operation + virtual ~PlainTextOutput(); + + //! + //! \brief write - this method is responsible for write the log text in the selected output + //! \param message + //! \param owner + //! \param lvl + //! \param timestamp + //! \param functionName + //! \param lineNumber + //! + virtual void write(const QString message, + const QString owner, + const Level lvl, + const QDateTime timestamp, + const QString functionName, + const int lineNumber); + + //! + //! \brief close + //! + virtual void close(); + +protected: + + //! + //! \brief createNextFile - this method is called when a new file needs to be created due to size limitation + //! + virtual void createNextFile(); + +protected: + //! + //! \brief outputFile - the file handler to save on the output on the file system + //! + QSharedPointer outputFile; + + +}; + +} + +#endif // TEXTOUTPUT_H diff --git a/qloggerlib/xmloutput.cpp b/qloggerlib/xmloutput.cpp new file mode 100644 index 0000000..c243d75 --- /dev/null +++ b/qloggerlib/xmloutput.cpp @@ -0,0 +1,86 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "xmloutput.h" +#include "qloggerlib_global.h" +#include "configuration.h" + +#include +#include +#include + + +namespace qlogger +{ + +XmlOutput::XmlOutput(Configuration *conf) : PlainTextOutput(conf) +{ + this->configuration->setFileNameMask(XML_FILE_NAME_MASK); +} + +XmlOutput::~XmlOutput() +{ + if(!outputFile.isNull() && outputFile->isOpen()) + { + // end current xml file. + *outputStream << ROOT_CLOSE_TAG << endl; + } + PlainTextOutput::close(); +} + +void XmlOutput::write(const QString message, + const QString owner, + const Level lvl, + const QDateTime timestamp, + const QString functionName, + const int lineNumber) +{ + if(!outputFile.isNull() && outputFile->isOpen() && (outputFile->size() > (configuration->getFileMaxSizeInKb() * 1024))) + { + // end current xml file. + *outputStream << ROOT_CLOSE_TAG << endl; + } + + if(outputFile.isNull() //if there is no file + || !outputFile->isOpen() // or the file is not opened for writing + || (outputFile->size() > (configuration->getFileMaxSizeInKb() * 1024))) // or the file is already at max size + { + createNextFile(); // create a new file + + // start the xml file. + *outputStream << XML_TAG << endl; + *outputStream << ROOT_OPEN_TAG << endl; + + } + + *outputStream << LOG_TAG_OPEN << endl; + *outputStream << DATE_TIME_TAG.arg(timestamp.toString(configuration->getTimestampFormat())) << endl; + *outputStream << LEVEL_TAG.arg(lvl) << endl; + *outputStream << OWNER_TAG.arg(owner) << endl; + *outputStream << MESSAGE_TAG.arg(message) << endl; + *outputStream << LINE_TAG.arg(lineNumber) << endl; + *outputStream << FUNCTION_TAG.arg(functionName) << endl; + *outputStream << LOG_TAG_CLOSE << endl; + +} + +} diff --git a/output.h b/qloggerlib/xmloutput.h similarity index 60% rename from output.h rename to qloggerlib/xmloutput.h index 9acaf18..62b4ecf 100644 --- a/output.h +++ b/qloggerlib/xmloutput.h @@ -19,34 +19,52 @@ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#ifndef XMLOUTPUT_H +#define XMLOUTPUT_H -#ifndef OUTPUT_H -#define OUTPUT_H +#include "textoutput.h" -#include +#include +#include namespace qlogger { -//! Abstract interface class used to define the behaviour of the classes that will log the messages on all types io. -class Output +//! +//! \brief The XmlOutput class - This class output logs in form of XML files using the predefined tags above. +//! +class XmlOutput : public PlainTextOutput { public: - //! implement this method in order to be called to write the log on the io + //! + //! \brief XmlOutput - default constructor + //! \param conf + //! + XmlOutput(Configuration *conf); + XmlOutput() = delete; + //! closes any resource used by the file i/o + virtual ~XmlOutput(); + + + + //! + //! \brief write - reimplemented to write a xml on the file + //! \param message + //! \param owner + //! \param lvl + //! \param timestamp + //! \param functionName + //! \param lineNumber + //! virtual void write(const QString message, const QString owner, - const QString lvl, - const QString timestamp, + const Level lvl, + const QDateTime timestamp, const QString functionName, - const int lineNumber) = 0; - - //! implement if any cleanup will be done after all logs were written - virtual void close() = 0; + const int lineNumber); - //! virtual destructor to avoid any bad behavior on child classes - inline virtual ~Output() {} }; } -#endif // OUTPUT_H +#endif // XMLOUTPUT_H diff --git a/qloggertester/qloggertester.pro b/qloggertester/qloggertester.pro new file mode 100644 index 0000000..4f5840d --- /dev/null +++ b/qloggertester/qloggertester.pro @@ -0,0 +1,16 @@ +QT += testlib +QT -= gui + +CONFIG += qt console warn_on depend_includepath testcase +CONFIG -= app_bundle + +TEMPLATE = app + +SOURCES += tst_qloggertest.cpp + +win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../qloggerlib/release/ -lqloggerlib +else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../qloggerlib/debug/ -lqloggerlib +else:unix: LIBS += -L$$OUT_PWD/../qloggerlib/ -lqloggerlib + +INCLUDEPATH += $$PWD/../qloggerlib +DEPENDPATH += $$PWD/../qloggerlib diff --git a/qloggertester/target_wrapper.bat b/qloggertester/target_wrapper.bat new file mode 100644 index 0000000..a30a81d --- /dev/null +++ b/qloggertester/target_wrapper.bat @@ -0,0 +1,10 @@ +@echo off +SetLocal EnableDelayedExpansion +(set PATH=D:\Dev\Qt\5.11.2\msvc2017_64\bin;!PATH!) +if defined QT_PLUGIN_PATH ( + set QT_PLUGIN_PATH=D:\Dev\Qt\5.11.2\msvc2017_64\plugins;!QT_PLUGIN_PATH! +) else ( + set QT_PLUGIN_PATH=D:\Dev\Qt\5.11.2\msvc2017_64\plugins +) +%* +EndLocal diff --git a/qloggertester/tst_qloggertest.cpp b/qloggertester/tst_qloggertest.cpp new file mode 100644 index 0000000..b657825 --- /dev/null +++ b/qloggertester/tst_qloggertest.cpp @@ -0,0 +1,361 @@ +/* + * QLogger - A tiny Qt logging framework. + * + * MIT License + * Copyright (c) 2013 sandro fadiga + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include +#include + +#include +#include +#include +#include +#include + +// add necessary includes here +#include "qlogger.h" + +using namespace qlogger; + +#include + +//! +//! \brief The QLoggerTest class - this is a broad test class for the qlogger project +//! it do some unit testing and also application testing +//! +class QLoggerTest : public QObject +{ + Q_OBJECT + +public: + QLoggerTest() = default; + ~QLoggerTest() = default; + +public slots: + void signalSlotPrinter(QString msg); + void signalSlotPrinter2(QString msg); + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void test_caseQuickLogger(); + void test_caseOverrideRootLoggerBehaviour(); + void test_caseConfigurationEqual(); + void test_caseConfigurationValidate(); + void test_caseConfigurationLevelFromString(); + void test_caseConfigurationLevelToString(); + void test_caseOutputFromString(); + void test_caseConsoleFormatString(); + void test_caseQLoggerAdd(); + void test_caseHeavyLoadFileTest(); + void test_caseConfigFromFile(); + void test_caseSameLoggerMultiLevels(); + void test_caseChangeAllConfiguration(); + void test_caseXmlOutputFromIni(); + void test_caseLogSignals(); + void test_caseJSONOutput(); +}; + +void QLoggerTest::signalSlotPrinter(QString msg) +{ + qDebug() << "test_caseSignalSlot:" << msg << endl; +} + +void QLoggerTest::signalSlotPrinter2(QString msg) +{ + qDebug() << "test_caseSignalSlot 2:" << msg << endl; +} + +void QLoggerTest::initTestCase() +{ + // add a logger with an output to a signal + QLogger::addLogger("sig", q2WARN, SIGNAL); + QLogger::addLogger("sig2", q4DEBUG, SIGNAL); + // connects the signal of the slot with a slot on this test class + connect(QLogger::getSignal("sig"), &SignalOutput::qlogger, this, &QLoggerTest::signalSlotPrinter); + connect(QLogger::getSignal("sig2"), &SignalOutput::qlogger, this, &QLoggerTest::signalSlotPrinter2); + //try to connect to a non existent signal output + connect(QLogger::getSignal("sig3"), &SignalOutput::qlogger, this, &QLoggerTest::signalSlotPrinter2); +} + +void QLoggerTest::cleanupTestCase() +{ +} + +void QLoggerTest::test_caseConfigurationEqual() +{ + Configuration c1("owner", Level::q1ERROR); + Configuration c2("owner", Level::q1ERROR); + QVERIFY2(c1 == c2, "c1 and c2 must be equal"); + + Configuration c3("noowner"); + QVERIFY2(!(c1 == c3), "c1 and c3 must be different"); + + Configuration c4 = c2; + QVERIFY2(c1 == c4, "c1 and c4 must be equal"); +} + +void QLoggerTest::test_caseConfigurationValidate() +{ + Configuration c1("owner", Level::q1ERROR); + QVERIFY2(c1.validate(), "c1 must return validate true"); + + Configuration c2("", q1ERROR); + QVERIFY2(c2.validate() == false, "c2 must return validate false"); + + Configuration c3(nullptr, q1ERROR); + QVERIFY2(c3.validate() == false, "c3 must return validate false"); +} + +void QLoggerTest::test_caseConfigurationLevelFromString() +{ + Configuration c1("owner", q0FATAL); + QVERIFY2(levelFromString(FATAL_LEVEL) == c1.getLogLevel(), "equal levels"); + + Configuration c2("owner", q1ERROR); + QVERIFY2(levelFromString(ERROR_LEVEL) == c2.getLogLevel(), "equal levels"); + + Configuration c3("owner", q2WARN); + QVERIFY2(levelFromString(WARN_LEVEL) == c3.getLogLevel(), "equal levels"); + + Configuration c4("owner", q3INFO); + QVERIFY2(levelFromString(INFO_LEVEL) == c4.getLogLevel(), "equal levels"); + + Configuration c5("owner", q4DEBUG); + QVERIFY2(levelFromString(DEBUG_LEVEL) == c5.getLogLevel(), "equal levels"); + + Configuration c6("owner", q5TRACE); + QVERIFY2(levelFromString(TRACE_LEVEL) == c6.getLogLevel(), "equal levels"); + + QVERIFY2(levelFromString(FATAL_LEVEL) != c6.getLogLevel(), "not equal levels"); +} + +void QLoggerTest::test_caseConfigurationLevelToString() +{ + QVERIFY2(levelToString(q0FATAL) == FATAL_LEVEL, "equal levels"); + + QVERIFY2(levelToString(q1ERROR) == ERROR_LEVEL, "equal levels"); + + QVERIFY2(levelToString(q2WARN) == WARN_LEVEL, "equal levels"); + + QVERIFY2(levelToString(q3INFO) == INFO_LEVEL, "equal levels"); + + QVERIFY2(levelToString(q4DEBUG) == DEBUG_LEVEL, "equal levels"); + + QVERIFY2(levelToString(q5TRACE) == TRACE_LEVEL, "equal levels"); + + QVERIFY2(levelToString(q5TRACE) != FATAL_LEVEL, "not equal levels"); +} + +void QLoggerTest::test_caseOutputFromString() +{ + QVERIFY2(ouputFromString("console") == CONSOLE, "CONSOLE output is equal"); + QVERIFY2(ouputFromString("xml") == XMLFILE, "XML FILE output is equal"); + QVERIFY2(ouputFromString("text") == TEXTFILE, "PLAIN TEXT FILE output is equal"); + QVERIFY2(ouputFromString("signal") == SIGNAL, "SIGNAL output is equal"); +} + +void QLoggerTest::test_caseConsoleFormatString() +{ + Configuration *cf = new Configuration("owner", Level::q1ERROR); + ConsoleOutput *co = new ConsoleOutput(cf); + + co->write("test case on console", "owner", q2WARN, QDateTime::currentDateTime(), "test_caseConsoleFormatString", 123); + + QSharedPointer cfg = co->getConfiguration(); + + //QString msg = co->formatLogText("", "", "", "", "", "", 1); + + QVERIFY2(cfg.get() == cf, "test same reference"); +} + +void QLoggerTest::test_caseQuickLogger() +{ + QLOG_FATAL("this is quick logged using the default root logger"); + QLOG_ERROR("the default root logger has a ERROR level and CONSOLE output as default"); + QLOG_FATAL("this default behaviour can be easily changed, see: overrideRootLoggerBehaviour()"); +} + +void QLoggerTest::test_caseOverrideRootLoggerBehaviour() +{ + //changes the default logger from error and fatal to all levels (top level, trace). + QLOG_TRACE("this will not be displayed, for now root is error and fatal only"); //will not appear on the console ! + QLOG_ERROR("this will be displayed, its an error"); + QLogger::addLogger("root", q5TRACE, CONSOLE); + QLOG_TRACE("now this trace log will be displayed"); +} + +void QLoggerTest::test_caseQLoggerAdd() +{ + Configuration *cf = new Configuration("owner", q1ERROR); + ConsoleOutput *co = new ConsoleOutput(cf); + QLogger::addLogger(cf, co); + QVERIFY2(cf != nullptr, "configuration added to the logger sucessfully"); + QVERIFY2(co != nullptr, "output added to the logger sucessfully"); + QLogger::error("test message","owner"); + + QLOG_ERROR("end of test_caseQLoggerAdd"); +} + +void QLoggerTest::test_caseHeavyLoadFileTest() +{ + QLogger::addLogger("heavy", q1ERROR, TEXTFILE); + QLogger::addLogger("heavy", q0FATAL, CONSOLE); + QLOG_FATAL(QString("start:%1").arg(QTime::currentTime().toString("mmss"))); + const int count = 100000; + + QLOG_FATAL("this will not be logged on the file", "heavy"); + + QLOG_FATAL(QString("end:%1").arg(QTime::currentTime().toString("mmss"))); + + QLOG_FATAL(QString("start:%1").arg(QTime::currentTime().toString("mmss"))); + + for (int i = 0; i != count; ++i) + { + QLOG_ERROR("this warning is logged on the file", "heavy"); + if(i % 10000 == 0) + QLOG_FATAL(QString("STILL WORKING PLEASE WAIT! %1").arg(QTime::currentTime().toString("mmss"))); + + } + QLOG_FATAL(QString("end:%1").arg(QTime::currentTime().toString("mmss"))); +} + +void QLoggerTest::test_caseConfigFromFile() +{ + QLOG_ERROR("this log will test config files, and save a file to more than one log file with 10mb", "cons"); + QLOG_ERROR("the config file must be on application path, can be on any folder together with or below the executable", "cons"); + QLOG_ERROR("this will take a while", "cons"); + + const int count = 50000; + for (int i = 0; i != count; ++i) + { + QLOG_WARN(QString("a warn log from config and save to a file n:%1 !").arg(i), "file"); + QLOG_ERROR(QString("an error log from config and save to a file n:%1 !").arg(i), "file"); + QLOG_FATAL(QString("a fatal a log from config and save to a file n:%1 !").arg(i), "file"); + } + for (int i = 0; i != 5; ++i) + { + QLOG_INFO("config from file, log to console","cons"); + QLOG_TRACE("config from file, log to console","cons"); + } + QLOG_ERROR("end of test, check for the files on c:"); +} + +void QLoggerTest::test_caseSameLoggerMultiLevels() +{ + //one can have a logger with diferent levels to diferent outputs + QLogger::addLogger("multilevel", q0FATAL, CONSOLE); + QLogger::addLogger("multilevel", q5TRACE, TEXTFILE); + const int count = 100; + for (int i = 0; i != count; ++i) + { + QLOG_ERROR("will not be logged to console, but will to the file", "multilevel"); + QLOG_FATAL("will be logged to console and to the file", "multilevel"); + QLOG_WARN("will be logged only to the file", "multilevel") + } +} + +void QLoggerTest::test_caseChangeAllConfiguration() +{ + Configuration* cfg = new Configuration("config", q3INFO, + "%t [%l] <%o> : %m", "dd-MM-yyyy hh:mm:ss", + "myfile_%3_%2_%1.log", "ddMMyyyy_hhmmss", "c:\\temp", 10000); + + QLogger::addLogger(cfg, TEXTFILE); + + const int count = 100; + for (int i = 0; i != count; ++i) + { + QLOG_WARN("this will be saved on a file at c:/temp", "config"); + } + QLOG_FATAL("end of this test: test_caseChangeAllConfiguration()"); +} + +void QLoggerTest::test_caseXmlOutputFromIni() +{ + QLOG_ERROR("this log will test an xml output format"); + + //QLOG_ERROR("this will take a while", "cons"); + + const int count = 500; + for (int i = 0; i != count; ++i) + { + QLOG_TRACE(QString("a TRACE log from config and save to a XML file n:%1 !").arg(i), "xml"); + QLOG_ERROR(QString("an ERROR log from config and save to a XML file n:%1 !").arg(i), "xml"); + QLOG_FATAL(QString("a FATAL log from config and save to a XML file n:%1 !").arg(i), "xml"); + } + + QLOG_ERROR("end of test, check for the files on c:/temp"); +} + +void QLoggerTest::test_caseLogSignals() +{ + QLOG_WARN("signal slot test", "sig"); + QLOG_WARN("signal slot test", "sig"); + QLOG_WARN("signal slot test", "sig"); + QLOG_WARN("signal slot test", "sig"); + QLOG_WARN("signal slot test", "sig"); + + QLOG_DEBUG("signal slot test 2", "sig2"); + QLOG_DEBUG("signal slot test 2", "sig2"); + QLOG_ERROR("signal slot test 2", "sig2"); + QLOG_ERROR("signal slot test 2", "sig2"); + QLOG_ERROR("signal slot test 2", "sig2"); + + // the expected test output is to nothing happens + // since there is no sig3 to connect with + // but a runtime error will be displayed in application console: + // QWARN : QLoggerTest::initTestCase() QObject::connect: invalid null parameter + QLOG_ERROR("non existent signal slot test 3", "sig3"); + QLOG_ERROR("non existent signal slot test 3", "sig3"); + QLOG_ERROR("non existent signal slot test 3", "sig3"); +} + +void QLoggerTest::test_caseJSONOutput() +{ + QLogger::addLogger("json", q5TRACE, JSON); + const int count = 100000; +/* QLOG_FATAL(QString("start:%1").arg(QTime::currentTime().toString("mmss"))); + const int count = 100000; + for (int i = 0; i != count; ++i) + { + if(i % 10000 == 0) + QLOG_WARN("this will not be logged on the file", "json"); + } + QLOG_FATAL(QString("end:%1").arg(QTime::currentTime().toString("mmss"))); +*/ + QLOG_FATAL(QString("start:%1").arg(QTime::currentTime().toString("mmss"))); + + for (int i = 0; i != count; ++i) + { + QLOG_FATAL("this warning is logged on the JSON file", "json"); + if(i % 10000 == 0) + QLOG_FATAL(QString("STILL WORKING PLEASE WAIT! %1").arg(QTime::currentTime().toString("mmss"))); + + } + QLOG_FATAL(QString("end:%1").arg(QTime::currentTime().toString("mmss"))); + + QLOG_INFO("fim test_caseJSONOutput"); +} + + +QTEST_MAIN(QLoggerTest) + +#include "tst_qloggertest.moc" diff --git a/textoutput.cpp b/textoutput.cpp deleted file mode 100644 index aca80e9..0000000 --- a/textoutput.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/* - * QLogger - A tiny Qt logging framework. - * - * MIT License - * Copyright (c) 2013 sandro fadiga - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software - * is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies - * or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE - * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include "textoutput.h" - -#include -#include -#include -#include -#include - -namespace qlogger -{ - -ConsoleOutput::ConsoleOutput(QString mask) - : qTextStream(new QTextStream(stdout)) -{ - // check if a valid log mask is informed, only the log owner is not obligatory - if(!mask.contains("%t") || !mask.contains("%m") || !mask.contains("%l")) - this->logTextMask = DEFAULT_TEXT_MASK; - else - this->logTextMask = mask; - - qTextStream->device()->setTextModeEnabled(true); -} - -ConsoleOutput::~ConsoleOutput() -{ - if(qTextStream) - delete qTextStream; -} - -QString ConsoleOutput::getLogTextMask() const -{ - return logTextMask; -} - -void ConsoleOutput::write(const QString message, - const QString owner, - const QString lvl, - const QString timestamp, - const QString functionName, - const int lineNumber) -{ - //QByteArray msg = QTextCodec::convertFromUnicode(); TODO correct the conversion to from utf-8 to the console output (local) - *qTextStream << formatLogText(this->logTextMask, message, owner, lvl, timestamp, functionName, lineNumber) << endl; -} - -QString ConsoleOutput::formatLogText(const QString logFormatMask, - const QString message, - const QString owner, - const QString lvl, - const QString timestamp, - const QString functionName, - const int lineNumber) -{ - QString text = QString(logFormatMask); - text = text.replace("%t", timestamp); - text = text.replace("%m", message); - text = text.replace("%l", lvl); - text = text.replace("%o", owner); - text = text.replace("%f", functionName); - text = text.replace("%n", QString::number(lineNumber)); - return text; -} - -void ConsoleOutput::close() -{ - qTextStream->flush(); -} - -TextFileOutput::TextFileOutput(QString logOwner, QString logFormatMask, QString path, - int fileSizeInKb, QString fileMask, - QString timestampFormat) - : ConsoleOutput(logFormatMask), - logOwner(logOwner), filePath(path), fileMaxSizeInBytes(fileSizeInKb * 1024), - fileNameMask(fileMask), fileNameTimestampFormat(timestampFormat), currentFile(NULL) -{ - qTextStream = NULL; - - // check if a valid size was informed, minimum of 10k - if(fileMaxSizeInBytes < 10240) - fileMaxSizeInBytes = 10240; - - // check if a valid path was informed - QDir test(filePath); - if(filePath.isEmpty() || !test.exists()) - filePath = QDir::currentPath(); - else - filePath = path; - - if(fileNameTimestampFormat.isEmpty()) - fileNameTimestampFormat = FILE_NAME_TIMESTAMP_FORMAT; - - if(fileNameMask.isEmpty() || !(fileNameMask.contains("%1") && fileNameMask.contains("%2") && fileNameMask.contains("%3"))) - fileNameMask = TEXT_FILE_NAME_MASK; - else - fileNameMask = fileMask; - - createNextFile(); -} - -TextFileOutput::~TextFileOutput() -{ - if(qTextStream) - delete qTextStream; - if(currentFile) - delete currentFile; -} - -void TextFileOutput::createNextFile() -{ - if(qTextStream && currentFile) - { - qTextStream->flush(); - delete qTextStream; - currentFile->flush(); - currentFile->close(); - } - // TEXT FILE MODE - QDir dir(filePath); - QString myFile = dir.absoluteFilePath(getFileName()); - currentFile = new QFile(myFile); - - if(currentFile->open(QIODevice::WriteOnly | QIODevice::Text)) - { - qTextStream = new QTextStream(currentFile); - } - else // Fall back to console mode - { - qTextStream = new QTextStream(stdout); - } - - // enables the output to text mode and have correct line breaks - qTextStream->device()->setTextModeEnabled(true); - qTextStream->setCodec(QTextCodec::codecForName("UTF-8")); -} - -QString TextFileOutput::getFileName() const -{ - QString name = fileNameMask - .arg(QCoreApplication::applicationName()) - .arg(logOwner) - .arg(QDateTime::currentDateTime().toString(fileNameTimestampFormat)); - return name; -} - -void TextFileOutput::write(const QString message, - const QString owner, - const QString lvl, - const QString timestamp, - const QString functionName, - const int lineNumber) -{ - if(currentFile && currentFile->size() > fileMaxSizeInBytes) - { - createNextFile(); - } - ConsoleOutput::write(message, lvl, owner, timestamp, functionName, lineNumber); -} - -//! -void TextFileOutput::close() -{ - qTextStream->flush(); - currentFile->close(); -} - -} diff --git a/textoutput.h b/textoutput.h deleted file mode 100644 index b880e76..0000000 --- a/textoutput.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * QLogger - A tiny Qt logging framework. - * - * MIT License - * Copyright (c) 2013 sandro fadiga - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software - * is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies - * or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE - * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef TEXTOUTPUT_H -#define TEXTOUTPUT_H - -#include "output.h" - -#include -#include -#include - -#include - -// %t - datetime -// %o - owner -// %l - level -// %m - message -static const QString DEFAULT_TEXT_MASK = "%t [%o] <%l> (%f) {line:%n} - %m"; - -//! log_appname_logname_datetime.txt %1 = application name , %2 = owner , %3 = timestamp -static const QString TEXT_FILE_NAME_MASK = "log_%1_%2_%3.txt"; - -//! will be used on the file name mask -static const QString FILE_NAME_TIMESTAMP_FORMAT = "yyyyMMdd_hhmmss"; - -namespace qlogger -{ - -class ConsoleOutput : public Output -{ -public: - //! This default constructor sets the class to be on console mode, all logs will be redirected to stdout - ConsoleOutput(QString mask = DEFAULT_TEXT_MASK); - //ConsoleOutput(); - virtual ~ConsoleOutput(); - - //! this method is responsible for write the log text in the selected output - virtual void write(const QString message, - const QString owner, - const QString lvl, - const QString timestamp, - const QString functionName, - const int lineNumber); - //! implement from output - virtual void close(); - - //! return the current mask used to format the log text - QString getLogTextMask() const; - -protected: - //! the qt class to output texts - QTextStream* qTextStream; - - //! the text mask used to format the log output - QString logTextMask; - - //! uses the mask param and log message to generate the text string which will be logged out. - QString formatLogText(const QString logFormatMask, - const QString message, - const QString owner, - const QString lvl, - const QString timestamp, - const QString functionName, - const int lineNumber); -}; - -//! this class is responsible for write plain text log messages for file or stdout (console) -class TextFileOutput : public ConsoleOutput -{ - -public: - //! This constructor sets the class to operate in text file mode, all logs will be written in a file - TextFileOutput(QString logOwner, QString logFormatMask, QString filePath , int fileMaxSizeInKb , QString fileNameMask = TEXT_FILE_NAME_MASK, - QString fileNameTimestampFormat = FILE_NAME_TIMESTAMP_FORMAT); - virtual ~TextFileOutput(); - - //! this method is responsible for write the log text in the selected output - virtual void write(const QString message, - const QString owner, - const QString lvl, - const QString timestamp, - const QString functionName, - const int lineNumber); - - virtual void close(); - -protected: - //! this method is used to generate a file name based on the application name, log owner and date time - QString getFileName() const; - - //! this method is called when a new file needs to be created due to size limitation - virtual void createNextFile(); - -protected: - - //! this is the log owner name of this output text, used to form the file name - QString logOwner; - - //! this attribute stores the desired path to save the log files - QString filePath; - - //! this attribute stores the maximum file size in bytes - int fileMaxSizeInBytes; - - //! mask used to generate - QString fileNameMask; - - //! the timestamp format to be used in the file name - QString fileNameTimestampFormat; - - //! this attribute represents the current file being used, when in file mode, otherwise = NULL - QFile* currentFile; - -}; - -} - -#endif // TEXTOUTPUT_H diff --git a/xmloutput.cpp b/xmloutput.cpp deleted file mode 100644 index ff7b0cb..0000000 --- a/xmloutput.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * QLogger - A tiny Qt logging framework. - * - * MIT License - * Copyright (c) 2013 sandro fadiga - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software - * is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies - * or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE - * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include "xmloutput.h" - -#include -#include -#include - -namespace qlogger -{ - -XmlOutput::XmlOutput(QString logOwner, - QString fileNameMask, - QString fileNameTimestampFormat, - QString filePath, - int fileMaxSizeInKb) - : TextFileOutput(logOwner, DEFAULT_TEXT_MASK, filePath, fileMaxSizeInKb, fileNameMask, fileNameTimestampFormat) -{ - if(fileNameMask.isEmpty() || !(fileNameMask.contains("%1") && fileNameMask.contains("%2") && fileNameMask.contains("%3"))) - fileNameMask = XML_FILE_NAME_MASK; - - createNextFile(); -} - -XmlOutput::~XmlOutput() -{ -} - -//! -void XmlOutput::close() -{ -} - -void XmlOutput::createNextFile() -{ - if(currentFile && qTextStream) - { - qTextStream->flush(); - currentFile->flush(); - currentFile->close(); - } - currentFile = new QFile(getFileName()); - - if(currentFile->open(QIODevice::WriteOnly | QIODevice::Text)) - { - qTextStream = new QTextStream(currentFile); - //qTextStream->setDevice(¤tFile); - } - // enables the output to text mode and have correct line breaks - qTextStream->device()->setTextModeEnabled(true); - qTextStream->setCodec(QTextCodec::codecForName("UTF-8")); - - *qTextStream << XML_TAG << endl; - *qTextStream << ROOT_TAG_OPEN << endl; -} - -void XmlOutput::write(const QString message, - const QString owner, - const QString lvl, - const QString timestamp, - const QString functionName, - const int lineNumber) -{ - if(currentFile->size() > fileMaxSizeInBytes) - { - createNextFile(); - } - - *qTextStream << LOG_TAG_OPEN << endl; - *qTextStream << DATE_TIME_TAG.arg(timestamp) << endl; - *qTextStream << LEVEL_TAG.arg(lvl) << endl; - *qTextStream << OWNER_TAG.arg(owner) << endl; - *qTextStream << MESSAGE_TAG.arg(message) << endl; - *qTextStream << LINE_TAG.arg(lineNumber) << endl; - *qTextStream << FUNCTION_TAG.arg(functionName) << endl; - *qTextStream << LOG_TAG_CLOSE << endl; -} - - -} diff --git a/xmloutput.h b/xmloutput.h deleted file mode 100644 index 25fa8a0..0000000 --- a/xmloutput.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * QLogger - A tiny Qt logging framework. - * - * MIT License - * Copyright (c) 2013 sandro fadiga - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software - * is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies - * or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE - * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef XMLOUTPUT_H -#define XMLOUTPUT_H - -#include "textoutput.h" - -#include -#include - - -namespace qlogger -{ - -//! log_appname_logname_datetime.txt %1 = application name , %2 = owner , %3 = timestamp -static const QString XML_FILE_NAME_MASK = "log_%1_%2_%3.xml"; - -static const QString XML_TAG = ""; -static const QString ROOT_TAG_OPEN = ""; -static const QString ROOT_TAG_CLOSE = ""; -static const QString LOG_TAG_OPEN = ""; -static const QString LOG_TAG_CLOSE = ""; -static const QString DATE_TIME_TAG = "%1"; -static const QString OWNER_TAG = "%1"; -static const QString MESSAGE_TAG = "%1"; -static const QString LINE_TAG = "%1"; -static const QString FUNCTION_TAG = "%1"; -static const QString LEVEL_TAG = "%1"; - -//! This class output logs in form of XML files using the predefined tags above. -class XmlOutput : public TextFileOutput -{ -public: - XmlOutput(QString logOwner, QString fileNameMask = XML_FILE_NAME_MASK, - QString fileNameTimestampFormat = FILE_NAME_TIMESTAMP_FORMAT, - QString filePath = QDir::currentPath(), int fileMaxSizeInKb = 100); - virtual ~XmlOutput(); - - //! reimplemented to write a xml on the file - virtual void write(const QString message, - const QString owner, - const QString lvl, - const QString timestamp, - const QString functionName, - const int lineNumber); - - virtual void close(); - -protected: - //! this method is called when a new file needs to be created due to size limitation - virtual void createNextFile(); - -}; - -} - -#endif // XMLOUTPUT_H