├── .gitignore ├── LICENSE.txt ├── QsLog.cpp ├── QsLog.h ├── QsLog.pri ├── QsLogChanges.txt ├── QsLogDest.cpp ├── QsLogDest.h ├── QsLogDestConsole.cpp ├── QsLogDestConsole.h ├── QsLogDestFile.cpp ├── QsLogDestFile.h ├── QsLogDestFunctor.cpp ├── QsLogDestFunctor.h ├── QsLogDisableForThisFile.h ├── QsLogLevel.h ├── QsLogReadme.txt ├── QsLogSharedLibrary.pro ├── README.md ├── example ├── log_example.pro ├── log_example_main.cpp ├── log_example_main.pro ├── log_example_shared.cpp ├── log_example_shared.h └── log_example_shared.pro └── unittest ├── QtTestUtil ├── QtTestUtil.h ├── SimpleChecker.cpp ├── TestRegistration.h ├── TestRegistry.cpp └── TestRegistry.h ├── TestLog.cpp └── unittest.pro /.gitignore: -------------------------------------------------------------------------------- 1 | *.pro.user 2 | build-* 3 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Razvan Petru 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this 10 | list of conditions and the following disclaimer in the documentation and/or other 11 | materials provided with the distribution. 12 | * The name of the contributors may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 19 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 24 | OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /QsLog.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Razvan Petru 2 | // All rights reserved. 3 | 4 | // Redistribution and use in source and binary forms, with or without modification, 5 | // are permitted provided that the following conditions are met: 6 | 7 | // * Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, this 10 | // list of conditions and the following disclaimer in the documentation and/or other 11 | // materials provided with the distribution. 12 | // * The name of the contributors may not be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 19 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 24 | // OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #include "QsLog.h" 27 | #include "QsLogDest.h" 28 | #ifdef QS_LOG_SEPARATE_THREAD 29 | #include 30 | #include 31 | #endif 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | namespace QsLogging 40 | { 41 | typedef QVector DestinationList; 42 | 43 | static const char TraceString[] = "TRACE"; 44 | static const char DebugString[] = "DEBUG"; 45 | static const char InfoString[] = "INFO "; 46 | static const char WarnString[] = "WARN "; 47 | static const char ErrorString[] = "ERROR"; 48 | static const char FatalString[] = "FATAL"; 49 | 50 | // not using Qt::ISODate because we need the milliseconds too 51 | static const QString fmtDateTime("yyyy-MM-ddThh:mm:ss.zzz"); 52 | 53 | static Logger* sInstance = 0; 54 | 55 | static const char* LevelToText(Level theLevel) 56 | { 57 | switch (theLevel) { 58 | case TraceLevel: 59 | return TraceString; 60 | case DebugLevel: 61 | return DebugString; 62 | case InfoLevel: 63 | return InfoString; 64 | case WarnLevel: 65 | return WarnString; 66 | case ErrorLevel: 67 | return ErrorString; 68 | case FatalLevel: 69 | return FatalString; 70 | case OffLevel: 71 | return ""; 72 | default: { 73 | Q_ASSERT(!"bad log level"); 74 | return InfoString; 75 | } 76 | } 77 | } 78 | 79 | #ifdef QS_LOG_SEPARATE_THREAD 80 | class LogWriterRunnable : public QRunnable 81 | { 82 | public: 83 | LogWriterRunnable(QString message, Level level); 84 | virtual void run(); 85 | 86 | private: 87 | QString mMessage; 88 | Level mLevel; 89 | }; 90 | #endif 91 | 92 | class LoggerImpl 93 | { 94 | public: 95 | LoggerImpl(); 96 | 97 | #ifdef QS_LOG_SEPARATE_THREAD 98 | QThreadPool threadPool; 99 | #endif 100 | QMutex logMutex; 101 | Level level; 102 | DestinationList destList; 103 | bool includeTimeStamp; 104 | bool includeLogLevel; 105 | }; 106 | 107 | #ifdef QS_LOG_SEPARATE_THREAD 108 | LogWriterRunnable::LogWriterRunnable(QString message, Level level) 109 | : QRunnable() 110 | , mMessage(message) 111 | , mLevel(level) 112 | { 113 | } 114 | 115 | void LogWriterRunnable::run() 116 | { 117 | Logger::instance().write(mMessage, mLevel); 118 | } 119 | #endif 120 | 121 | 122 | LoggerImpl::LoggerImpl() 123 | : level(InfoLevel) 124 | , includeTimeStamp(true) 125 | , includeLogLevel(true) 126 | { 127 | // assume at least file + console 128 | destList.reserve(2); 129 | #ifdef QS_LOG_SEPARATE_THREAD 130 | threadPool.setMaxThreadCount(1); 131 | threadPool.setExpiryTimeout(-1); 132 | #endif 133 | } 134 | 135 | 136 | Logger::Logger() 137 | : d(new LoggerImpl) 138 | { 139 | } 140 | 141 | Logger& Logger::instance() 142 | { 143 | if (!sInstance) 144 | sInstance = new Logger; 145 | 146 | return *sInstance; 147 | } 148 | 149 | void Logger::destroyInstance() 150 | { 151 | delete sInstance; 152 | sInstance = 0; 153 | } 154 | 155 | // tries to extract the level from a string log message. If available, conversionSucceeded will 156 | // contain the conversion result. 157 | Level Logger::levelFromLogMessage(const QString& logMessage, bool* conversionSucceeded) 158 | { 159 | if (conversionSucceeded) 160 | *conversionSucceeded = true; 161 | 162 | if (logMessage.startsWith(QLatin1String(TraceString))) 163 | return TraceLevel; 164 | if (logMessage.startsWith(QLatin1String(DebugString))) 165 | return DebugLevel; 166 | if (logMessage.startsWith(QLatin1String(InfoString))) 167 | return InfoLevel; 168 | if (logMessage.startsWith(QLatin1String(WarnString))) 169 | return WarnLevel; 170 | if (logMessage.startsWith(QLatin1String(ErrorString))) 171 | return ErrorLevel; 172 | if (logMessage.startsWith(QLatin1String(FatalString))) 173 | return FatalLevel; 174 | 175 | if (conversionSucceeded) 176 | *conversionSucceeded = false; 177 | return OffLevel; 178 | } 179 | 180 | Logger::~Logger() 181 | { 182 | #ifdef QS_LOG_SEPARATE_THREAD 183 | d->threadPool.waitForDone(); 184 | #endif 185 | delete d; 186 | d = 0; 187 | } 188 | 189 | void Logger::addDestination(DestinationPtr destination) 190 | { 191 | Q_ASSERT(destination.data()); 192 | d->destList.push_back(destination); 193 | } 194 | 195 | void Logger::setLoggingLevel(Level newLevel) 196 | { 197 | d->level = newLevel; 198 | } 199 | 200 | Level Logger::loggingLevel() const 201 | { 202 | return d->level; 203 | } 204 | 205 | void Logger::setIncludeTimestamp(bool e) 206 | { 207 | d->includeTimeStamp = e; 208 | } 209 | 210 | bool Logger::includeTimestamp() const 211 | { 212 | return d->includeTimeStamp; 213 | } 214 | 215 | void Logger::setIncludeLogLevel(bool l) 216 | { 217 | d->includeLogLevel = l; 218 | } 219 | 220 | bool Logger::includeLogLevel() const 221 | { 222 | return d->includeLogLevel; 223 | } 224 | 225 | //! creates the complete log message and passes it to the logger 226 | void Logger::Helper::writeToLog() 227 | { 228 | const char* const levelName = LevelToText(level); 229 | QString completeMessage; 230 | Logger &logger = Logger::instance(); 231 | if (logger.includeLogLevel()) { 232 | completeMessage. 233 | append(levelName). 234 | append(' '); 235 | } 236 | if (logger.includeTimestamp()) { 237 | completeMessage. 238 | append(QDateTime::currentDateTime().toString(fmtDateTime)). 239 | append(' '); 240 | } 241 | completeMessage.append(buffer); 242 | Logger::instance().enqueueWrite(completeMessage, level); 243 | } 244 | 245 | Logger::Helper::~Helper() 246 | { 247 | try { 248 | writeToLog(); 249 | } 250 | catch(std::exception&) { 251 | // you shouldn't throw exceptions from a sink 252 | Q_ASSERT(!"exception in logger helper destructor"); 253 | } 254 | } 255 | 256 | //! directs the message to the task queue or writes it directly 257 | void Logger::enqueueWrite(const QString& message, Level level) 258 | { 259 | #ifdef QS_LOG_SEPARATE_THREAD 260 | LogWriterRunnable *r = new LogWriterRunnable(message, level); 261 | d->threadPool.start(r); 262 | #else 263 | write(message, level); 264 | #endif 265 | } 266 | 267 | //! Sends the message to all the destinations. The level for this message is passed in case 268 | //! it's useful for processing in the destination. 269 | void Logger::write(const QString& message, Level level) 270 | { 271 | QMutexLocker lock(&d->logMutex); 272 | for (DestinationList::iterator it = d->destList.begin(), 273 | endIt = d->destList.end();it != endIt;++it) { 274 | (*it)->write(message, level); 275 | } 276 | } 277 | 278 | } // end namespace 279 | -------------------------------------------------------------------------------- /QsLog.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Razvan Petru 2 | // All rights reserved. 3 | 4 | // Redistribution and use in source and binary forms, with or without modification, 5 | // are permitted provided that the following conditions are met: 6 | 7 | // * Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, this 10 | // list of conditions and the following disclaimer in the documentation and/or other 11 | // materials provided with the distribution. 12 | // * The name of the contributors may not be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 19 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 24 | // OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #ifndef QSLOG_H 27 | #define QSLOG_H 28 | 29 | #include "QsLogLevel.h" 30 | #include "QsLogDest.h" 31 | #include 32 | #include 33 | 34 | #define QS_LOG_VERSION "2.0b3" 35 | 36 | namespace QsLogging 37 | { 38 | class Destination; 39 | class LoggerImpl; // d pointer 40 | 41 | class QSLOG_SHARED_OBJECT Logger 42 | { 43 | public: 44 | static Logger& instance(); 45 | static void destroyInstance(); 46 | static Level levelFromLogMessage(const QString& logMessage, bool* conversionSucceeded = 0); 47 | 48 | ~Logger(); 49 | 50 | //! Adds a log message destination. Don't add null destinations. 51 | void addDestination(DestinationPtr destination); 52 | //! Logging at a level < 'newLevel' will be ignored 53 | void setLoggingLevel(Level newLevel); 54 | //! The default level is INFO 55 | Level loggingLevel() const; 56 | //! Set to false to disable timestamp inclusion in log messages 57 | void setIncludeTimestamp(bool e); 58 | //! Default value is true. 59 | bool includeTimestamp() const; 60 | //! Set to false to disable log level inclusion in log messages 61 | void setIncludeLogLevel(bool l); 62 | //! Default value is true. 63 | bool includeLogLevel() const; 64 | 65 | //! The helper forwards the streaming to QDebug and builds the final 66 | //! log message. 67 | class QSLOG_SHARED_OBJECT Helper 68 | { 69 | public: 70 | explicit Helper(Level logLevel) : 71 | level(logLevel), 72 | qtDebug(&buffer) 73 | {} 74 | ~Helper(); 75 | QDebug& stream(){ return qtDebug; } 76 | 77 | private: 78 | void writeToLog(); 79 | 80 | Level level; 81 | QString buffer; 82 | QDebug qtDebug; 83 | }; 84 | 85 | private: 86 | Logger(); 87 | Logger(const Logger&); // not available 88 | Logger& operator=(const Logger&); // not available 89 | 90 | void enqueueWrite(const QString& message, Level level); 91 | void write(const QString& message, Level level); 92 | 93 | LoggerImpl* d; 94 | 95 | friend class LogWriterRunnable; 96 | }; 97 | 98 | } // end namespace 99 | 100 | //! Logging macros: define QS_LOG_LINE_NUMBERS to get the file and line number 101 | //! in the log output. 102 | #ifndef QS_LOG_LINE_NUMBERS 103 | #define QLOG_TRACE() \ 104 | if (QsLogging::Logger::instance().loggingLevel() > QsLogging::TraceLevel) {} \ 105 | else QsLogging::Logger::Helper(QsLogging::TraceLevel).stream() 106 | #define QLOG_DEBUG() \ 107 | if (QsLogging::Logger::instance().loggingLevel() > QsLogging::DebugLevel) {} \ 108 | else QsLogging::Logger::Helper(QsLogging::DebugLevel).stream() 109 | #define QLOG_INFO() \ 110 | if (QsLogging::Logger::instance().loggingLevel() > QsLogging::InfoLevel) {} \ 111 | else QsLogging::Logger::Helper(QsLogging::InfoLevel).stream() 112 | #define QLOG_WARN() \ 113 | if (QsLogging::Logger::instance().loggingLevel() > QsLogging::WarnLevel) {} \ 114 | else QsLogging::Logger::Helper(QsLogging::WarnLevel).stream() 115 | #define QLOG_ERROR() \ 116 | if (QsLogging::Logger::instance().loggingLevel() > QsLogging::ErrorLevel) {} \ 117 | else QsLogging::Logger::Helper(QsLogging::ErrorLevel).stream() 118 | #define QLOG_FATAL() \ 119 | if (QsLogging::Logger::instance().loggingLevel() > QsLogging::FatalLevel) {} \ 120 | else QsLogging::Logger::Helper(QsLogging::FatalLevel).stream() 121 | #else 122 | #define QLOG_TRACE() \ 123 | if (QsLogging::Logger::instance().loggingLevel() > QsLogging::TraceLevel) {} \ 124 | else QsLogging::Logger::Helper(QsLogging::TraceLevel).stream() << __FILE__ << '@' << __LINE__ 125 | #define QLOG_DEBUG() \ 126 | if (QsLogging::Logger::instance().loggingLevel() > QsLogging::DebugLevel) {} \ 127 | else QsLogging::Logger::Helper(QsLogging::DebugLevel).stream() << __FILE__ << '@' << __LINE__ 128 | #define QLOG_INFO() \ 129 | if (QsLogging::Logger::instance().loggingLevel() > QsLogging::InfoLevel) {} \ 130 | else QsLogging::Logger::Helper(QsLogging::InfoLevel).stream() << __FILE__ << '@' << __LINE__ 131 | #define QLOG_WARN() \ 132 | if (QsLogging::Logger::instance().loggingLevel() > QsLogging::WarnLevel) {} \ 133 | else QsLogging::Logger::Helper(QsLogging::WarnLevel).stream() << __FILE__ << '@' << __LINE__ 134 | #define QLOG_ERROR() \ 135 | if (QsLogging::Logger::instance().loggingLevel() > QsLogging::ErrorLevel) {} \ 136 | else QsLogging::Logger::Helper(QsLogging::ErrorLevel).stream() << __FILE__ << '@' << __LINE__ 137 | #define QLOG_FATAL() \ 138 | if (QsLogging::Logger::instance().loggingLevel() > QsLogging::FatalLevel) {} \ 139 | else QsLogging::Logger::Helper(QsLogging::FatalLevel).stream() << __FILE__ << '@' << __LINE__ 140 | #endif 141 | 142 | #ifdef QS_LOG_DISABLE 143 | #include "QsLogDisableForThisFile.h" 144 | #endif 145 | 146 | #endif // QSLOG_H 147 | -------------------------------------------------------------------------------- /QsLog.pri: -------------------------------------------------------------------------------- 1 | INCLUDEPATH += $$PWD 2 | #DEFINES += QS_LOG_LINE_NUMBERS # automatically writes the file and line for each log message 3 | #DEFINES += QS_LOG_DISABLE # logging code is replaced with a no-op 4 | #DEFINES += QS_LOG_SEPARATE_THREAD # messages are queued and written from a separate thread 5 | SOURCES += $$PWD/QsLogDest.cpp \ 6 | $$PWD/QsLog.cpp \ 7 | $$PWD/QsLogDestConsole.cpp \ 8 | $$PWD/QsLogDestFile.cpp \ 9 | $$PWD/QsLogDestFunctor.cpp 10 | 11 | HEADERS += $$PWD/QsLogDest.h \ 12 | $$PWD/QsLog.h \ 13 | $$PWD/QsLogDestConsole.h \ 14 | $$PWD/QsLogLevel.h \ 15 | $$PWD/QsLogDestFile.h \ 16 | $$PWD/QsLogDisableForThisFile.h \ 17 | $$PWD/QsLogDestFunctor.h 18 | 19 | OTHER_FILES += \ 20 | $$PWD/QsLogChanges.txt \ 21 | $$PWD/QsLogReadme.txt \ 22 | $$PWD/LICENSE.txt 23 | -------------------------------------------------------------------------------- /QsLogChanges.txt: -------------------------------------------------------------------------------- 1 | ------------------- 2 | QsLog version 2.0b4 3 | Fixes: 4 | Fixed file name case error for Linux. 5 | 6 | Misc: 7 | * Moved to separate git repository. 8 | 9 | ------------------- 10 | QsLog version 2.0b3 11 | 12 | Changes: 13 | * added functor logging destination (thanks to Omar Carey for providing a patch) 14 | 15 | ------------------- 16 | QsLog version 2.0b2 17 | 18 | Changes: 19 | * function signature redefinition for file destination creation 20 | * added shared library build configuration. Credit goes to Xavier Lamien 21 | for the Linux-specific config. 22 | * removed Symbian support 23 | * this version does not guarantee support for Nokia N9 devices, although it should in theory still 24 | work with them 25 | * workaround for Issue 8 - when used from an executable and a plugin QsLog only logs from the 26 | executable. 27 | * utility function to parse the level from an existing log message 28 | 29 | Known issues: 30 | * The current version will crash at program exit when using QS_LOG_SEPARATE_THREAD and linking 31 | with QsLog dynamically. 32 | 33 | ------------------- 34 | QsLog version 2.0b1 35 | 36 | Changes: 37 | * destination pointers use shared pointer semantics 38 | * the file destination supports log rotation. As a consequence, log files are encoded as UTF-8 and 39 | the log appends rather than truncating on every startup when rotation is enabled. 40 | * added the posibility of disabling logging either at run time or compile time. 41 | * added the possibility of using a separate thread for writing to the log destinations. 42 | 43 | Fixes: 44 | * renamed the main.cpp example to avoid QtCreator confusion 45 | * offer a way to check if the destination creation has failed (for e.g files) 46 | -------------------------------------------------------------------------------- /QsLogDest.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Razvan Petru 2 | // All rights reserved. 3 | 4 | // Redistribution and use in source and binary forms, with or without modification, 5 | // are permitted provided that the following conditions are met: 6 | 7 | // * Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, this 10 | // list of conditions and the following disclaimer in the documentation and/or other 11 | // materials provided with the distribution. 12 | // * The name of the contributors may not be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 19 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 24 | // OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #include "QsLogDest.h" 27 | #include "QsLogDestConsole.h" 28 | #include "QsLogDestFile.h" 29 | #include "QsLogDestFunctor.h" 30 | #include 31 | 32 | namespace QsLogging 33 | { 34 | 35 | Destination::~Destination() 36 | { 37 | } 38 | 39 | //! destination factory 40 | DestinationPtr DestinationFactory::MakeFileDestination(const QString& filePath, 41 | LogRotationOption rotation, const MaxSizeBytes &sizeInBytesToRotateAfter, 42 | const MaxOldLogCount &oldLogsToKeep) 43 | { 44 | if (EnableLogRotation == rotation) { 45 | QScopedPointer logRotation(new SizeRotationStrategy); 46 | logRotation->setMaximumSizeInBytes(sizeInBytesToRotateAfter.size); 47 | logRotation->setBackupCount(oldLogsToKeep.count); 48 | 49 | return DestinationPtr(new FileDestination(filePath, RotationStrategyPtr(logRotation.take()))); 50 | } 51 | 52 | return DestinationPtr(new FileDestination(filePath, RotationStrategyPtr(new NullRotationStrategy))); 53 | } 54 | 55 | DestinationPtr DestinationFactory::MakeDebugOutputDestination() 56 | { 57 | return DestinationPtr(new DebugOutputDestination); 58 | } 59 | 60 | DestinationPtr DestinationFactory::MakeFunctorDestination(QsLogging::Destination::LogFunction f) 61 | { 62 | return DestinationPtr(new FunctorDestination(f)); 63 | } 64 | 65 | DestinationPtr DestinationFactory::MakeFunctorDestination(QObject *receiver, const char *member) 66 | { 67 | return DestinationPtr(new FunctorDestination(receiver, member)); 68 | } 69 | 70 | } // end namespace 71 | -------------------------------------------------------------------------------- /QsLogDest.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Razvan Petru 2 | // All rights reserved. 3 | 4 | // Redistribution and use in source and binary forms, with or without modification, 5 | // are permitted provided that the following conditions are met: 6 | 7 | // * Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, this 10 | // list of conditions and the following disclaimer in the documentation and/or other 11 | // materials provided with the distribution. 12 | // * The name of the contributors may not be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 19 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 24 | // OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #ifndef QSLOGDEST_H 27 | #define QSLOGDEST_H 28 | 29 | #include "QsLogLevel.h" 30 | #include 31 | #include 32 | class QString; 33 | class QObject; 34 | 35 | #ifdef QSLOG_IS_SHARED_LIBRARY 36 | #define QSLOG_SHARED_OBJECT Q_DECL_EXPORT 37 | #elif QSLOG_IS_SHARED_LIBRARY_IMPORT 38 | #define QSLOG_SHARED_OBJECT Q_DECL_IMPORT 39 | #else 40 | #define QSLOG_SHARED_OBJECT 41 | #endif 42 | 43 | namespace QsLogging 44 | { 45 | 46 | class QSLOG_SHARED_OBJECT Destination 47 | { 48 | public: 49 | typedef void (*LogFunction)(const QString &message, Level level); 50 | 51 | public: 52 | virtual ~Destination(); 53 | virtual void write(const QString& message, Level level) = 0; 54 | virtual bool isValid() = 0; // returns whether the destination was created correctly 55 | }; 56 | typedef QSharedPointer DestinationPtr; 57 | 58 | 59 | // a series of "named" paramaters, to make the file destination creation more readable 60 | enum LogRotationOption 61 | { 62 | DisableLogRotation = 0, 63 | EnableLogRotation = 1 64 | }; 65 | 66 | struct QSLOG_SHARED_OBJECT MaxSizeBytes 67 | { 68 | MaxSizeBytes() : size(0) {} 69 | explicit MaxSizeBytes(qint64 size_) : size(size_) {} 70 | qint64 size; 71 | }; 72 | 73 | struct QSLOG_SHARED_OBJECT MaxOldLogCount 74 | { 75 | MaxOldLogCount() : count(0) {} 76 | explicit MaxOldLogCount(int count_) : count(count_) {} 77 | int count; 78 | }; 79 | 80 | 81 | //! Creates logging destinations/sinks. The caller shares ownership of the destinations with the logger. 82 | //! After being added to a logger, the caller can discard the pointers. 83 | class QSLOG_SHARED_OBJECT DestinationFactory 84 | { 85 | public: 86 | static DestinationPtr MakeFileDestination(const QString& filePath, 87 | LogRotationOption rotation = DisableLogRotation, 88 | const MaxSizeBytes &sizeInBytesToRotateAfter = MaxSizeBytes(), 89 | const MaxOldLogCount &oldLogsToKeep = MaxOldLogCount()); 90 | static DestinationPtr MakeDebugOutputDestination(); 91 | // takes a pointer to a function 92 | static DestinationPtr MakeFunctorDestination(Destination::LogFunction f); 93 | // takes a QObject + signal/slot 94 | static DestinationPtr MakeFunctorDestination(QObject *receiver, const char *member); 95 | }; 96 | 97 | } // end namespace 98 | 99 | #endif // QSLOGDEST_H 100 | -------------------------------------------------------------------------------- /QsLogDestConsole.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Razvan Petru 2 | // All rights reserved. 3 | 4 | // Redistribution and use in source and binary forms, with or without modification, 5 | // are permitted provided that the following conditions are met: 6 | 7 | // * Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, this 10 | // list of conditions and the following disclaimer in the documentation and/or other 11 | // materials provided with the distribution. 12 | // * The name of the contributors may not be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 19 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 24 | // OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #include "QsLogDestConsole.h" 27 | #include 28 | #include 29 | 30 | #if defined(Q_OS_WIN) 31 | #define WIN32_LEAN_AND_MEAN 32 | #include 33 | void QsDebugOutput::output( const QString& message ) 34 | { 35 | OutputDebugStringW(reinterpret_cast(message.utf16())); 36 | OutputDebugStringW(L"\n"); 37 | } 38 | #elif defined(Q_OS_UNIX) 39 | #include 40 | void QsDebugOutput::output( const QString& message ) 41 | { 42 | fprintf(stderr, "%s\n", qPrintable(message)); 43 | fflush(stderr); 44 | } 45 | #endif 46 | 47 | void QsLogging::DebugOutputDestination::write(const QString& message, Level) 48 | { 49 | QsDebugOutput::output(message); 50 | } 51 | 52 | bool QsLogging::DebugOutputDestination::isValid() 53 | { 54 | return true; 55 | } 56 | -------------------------------------------------------------------------------- /QsLogDestConsole.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Razvan Petru 2 | // All rights reserved. 3 | 4 | // Redistribution and use in source and binary forms, with or without modification, 5 | // are permitted provided that the following conditions are met: 6 | 7 | // * Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, this 10 | // list of conditions and the following disclaimer in the documentation and/or other 11 | // materials provided with the distribution. 12 | // * The name of the contributors may not be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 19 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 24 | // OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #ifndef QSLOGDESTCONSOLE_H 27 | #define QSLOGDESTCONSOLE_H 28 | 29 | #include "QsLogDest.h" 30 | 31 | class QString; 32 | 33 | class QsDebugOutput 34 | { 35 | public: 36 | static void output(const QString& a_message); 37 | }; 38 | 39 | namespace QsLogging 40 | { 41 | 42 | // debugger sink 43 | class DebugOutputDestination : public Destination 44 | { 45 | public: 46 | void write(const QString& message, Level level) override; 47 | bool isValid() override; 48 | }; 49 | 50 | } 51 | 52 | #endif // QSLOGDESTCONSOLE_H 53 | -------------------------------------------------------------------------------- /QsLogDestFile.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Razvan Petru 2 | // All rights reserved. 3 | 4 | // Redistribution and use in source and binary forms, with or without modification, 5 | // are permitted provided that the following conditions are met: 6 | 7 | // * Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, this 10 | // list of conditions and the following disclaimer in the documentation and/or other 11 | // materials provided with the distribution. 12 | // * The name of the contributors may not be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 19 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 24 | // OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #include "QsLogDestFile.h" 27 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 28 | #include 29 | #endif 30 | #include 31 | #include 32 | #include 33 | 34 | #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) 35 | namespace Qt { 36 | static const QTextStreamFunction endl = ::endl; 37 | } 38 | #endif 39 | 40 | const int QsLogging::SizeRotationStrategy::MaxBackupCount = 10; 41 | 42 | QsLogging::RotationStrategy::~RotationStrategy() 43 | { 44 | } 45 | 46 | QsLogging::SizeRotationStrategy::SizeRotationStrategy() 47 | : mCurrentSizeInBytes(0) 48 | , mMaxSizeInBytes(0) 49 | , mBackupsCount(0) 50 | { 51 | } 52 | 53 | void QsLogging::SizeRotationStrategy::setInitialInfo(const QFile &file) 54 | { 55 | mFileName = file.fileName(); 56 | mCurrentSizeInBytes = file.size(); 57 | } 58 | 59 | void QsLogging::SizeRotationStrategy::includeMessageInCalculation(const QString &message) 60 | { 61 | mCurrentSizeInBytes += message.toUtf8().size(); 62 | } 63 | 64 | bool QsLogging::SizeRotationStrategy::shouldRotate() 65 | { 66 | return mCurrentSizeInBytes > mMaxSizeInBytes; 67 | } 68 | 69 | // Algorithm assumes backups will be named filename.X, where 1 <= X <= mBackupsCount. 70 | // All X's will be shifted up. 71 | void QsLogging::SizeRotationStrategy::rotate() 72 | { 73 | if (!mBackupsCount) { 74 | if (!QFile::remove(mFileName)) 75 | std::cerr << "QsLog: backup delete failed " << qPrintable(mFileName); 76 | return; 77 | } 78 | 79 | // 1. find the last existing backup than can be shifted up 80 | const QString logNamePattern = mFileName + QString::fromUtf8(".%1"); 81 | int lastExistingBackupIndex = 0; 82 | for (int i = 1;i <= mBackupsCount;++i) { 83 | const QString backupFileName = logNamePattern.arg(i); 84 | if (QFile::exists(backupFileName)) 85 | lastExistingBackupIndex = qMin(i, mBackupsCount - 1); 86 | else 87 | break; 88 | } 89 | 90 | // 2. shift up 91 | for (int i = lastExistingBackupIndex;i >= 1;--i) { 92 | const QString oldName = logNamePattern.arg(i); 93 | const QString newName = logNamePattern.arg(i + 1); 94 | QFile::remove(newName); 95 | const bool renamed = QFile::rename(oldName, newName); 96 | if (!renamed) { 97 | std::cerr << "QsLog: could not rename backup " << qPrintable(oldName) 98 | << " to " << qPrintable(newName); 99 | } 100 | } 101 | 102 | // 3. rename current log file 103 | const QString newName = logNamePattern.arg(1); 104 | if (QFile::exists(newName)) 105 | QFile::remove(newName); 106 | if (!QFile::rename(mFileName, newName)) { 107 | std::cerr << "QsLog: could not rename log " << qPrintable(mFileName) 108 | << " to " << qPrintable(newName); 109 | } 110 | } 111 | 112 | QIODevice::OpenMode QsLogging::SizeRotationStrategy::recommendedOpenModeFlag() 113 | { 114 | return QIODevice::Append; 115 | } 116 | 117 | void QsLogging::SizeRotationStrategy::setMaximumSizeInBytes(qint64 size) 118 | { 119 | Q_ASSERT(size >= 0); 120 | mMaxSizeInBytes = size; 121 | } 122 | 123 | void QsLogging::SizeRotationStrategy::setBackupCount(int backups) 124 | { 125 | Q_ASSERT(backups >= 0); 126 | mBackupsCount = qMin(backups, SizeRotationStrategy::MaxBackupCount); 127 | } 128 | 129 | 130 | QsLogging::FileDestination::FileDestination(const QString& filePath, RotationStrategyPtr rotationStrategy) 131 | : mRotationStrategy(rotationStrategy) 132 | { 133 | mFile.setFileName(filePath); 134 | if (!mFile.open(QFile::WriteOnly | QFile::Text | mRotationStrategy->recommendedOpenModeFlag())) 135 | std::cerr << "QsLog: could not open log file " << qPrintable(filePath); 136 | mOutputStream.setDevice(&mFile); 137 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 138 | mOutputStream.setCodec(QTextCodec::codecForName("UTF-8")); 139 | #endif 140 | 141 | mRotationStrategy->setInitialInfo(mFile); 142 | } 143 | 144 | void QsLogging::FileDestination::write(const QString& message, Level) 145 | { 146 | mRotationStrategy->includeMessageInCalculation(message); 147 | if (mRotationStrategy->shouldRotate()) { 148 | mOutputStream.setDevice(NULL); 149 | mFile.close(); 150 | mRotationStrategy->rotate(); 151 | if (!mFile.open(QFile::WriteOnly | QFile::Text | mRotationStrategy->recommendedOpenModeFlag())) 152 | std::cerr << "QsLog: could not reopen log file " << qPrintable(mFile.fileName()); 153 | mRotationStrategy->setInitialInfo(mFile); 154 | mOutputStream.setDevice(&mFile); 155 | } 156 | 157 | mOutputStream << message << Qt::endl; 158 | mOutputStream.flush(); 159 | } 160 | 161 | bool QsLogging::FileDestination::isValid() 162 | { 163 | return mFile.isOpen(); 164 | } 165 | 166 | -------------------------------------------------------------------------------- /QsLogDestFile.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Razvan Petru 2 | // All rights reserved. 3 | 4 | // Redistribution and use in source and binary forms, with or without modification, 5 | // are permitted provided that the following conditions are met: 6 | 7 | // * Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, this 10 | // list of conditions and the following disclaimer in the documentation and/or other 11 | // materials provided with the distribution. 12 | // * The name of the contributors may not be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 19 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 24 | // OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #ifndef QSLOGDESTFILE_H 27 | #define QSLOGDESTFILE_H 28 | 29 | #include "QsLogDest.h" 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | namespace QsLogging 36 | { 37 | class RotationStrategy 38 | { 39 | public: 40 | virtual ~RotationStrategy(); 41 | 42 | virtual void setInitialInfo(const QFile &file) = 0; 43 | virtual void includeMessageInCalculation(const QString &message) = 0; 44 | virtual bool shouldRotate() = 0; 45 | virtual void rotate() = 0; 46 | virtual QIODevice::OpenMode recommendedOpenModeFlag() = 0; 47 | }; 48 | 49 | // Never rotates file, overwrites existing file. 50 | class NullRotationStrategy : public RotationStrategy 51 | { 52 | public: 53 | void setInitialInfo(const QFile &) override {} 54 | void includeMessageInCalculation(const QString &) override {} 55 | bool shouldRotate() override { return false; } 56 | void rotate() override {} 57 | QIODevice::OpenMode recommendedOpenModeFlag() override { return QIODevice::Truncate; } 58 | }; 59 | 60 | // Rotates after a size is reached, keeps a number of <= 10 backups, appends to existing file. 61 | class SizeRotationStrategy : public RotationStrategy 62 | { 63 | public: 64 | SizeRotationStrategy(); 65 | static const int MaxBackupCount; 66 | 67 | void setInitialInfo(const QFile &file) override; 68 | void includeMessageInCalculation(const QString &message) override; 69 | bool shouldRotate() override; 70 | void rotate() override; 71 | QIODevice::OpenMode recommendedOpenModeFlag() override; 72 | 73 | void setMaximumSizeInBytes(qint64 size); 74 | void setBackupCount(int backups); 75 | 76 | private: 77 | QString mFileName; 78 | qint64 mCurrentSizeInBytes; 79 | qint64 mMaxSizeInBytes; 80 | int mBackupsCount; 81 | }; 82 | 83 | typedef QSharedPointer RotationStrategyPtr; 84 | 85 | // file message sink 86 | class FileDestination : public Destination 87 | { 88 | public: 89 | FileDestination(const QString& filePath, RotationStrategyPtr rotationStrategy); 90 | void write(const QString& message, Level level) override; 91 | bool isValid() override; 92 | 93 | private: 94 | QFile mFile; 95 | QTextStream mOutputStream; 96 | QSharedPointer mRotationStrategy; 97 | }; 98 | 99 | } 100 | 101 | #endif // QSLOGDESTFILE_H 102 | -------------------------------------------------------------------------------- /QsLogDestFunctor.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014, Razvan Petru 2 | // Copyright (c) 2014, Omar Carey 3 | // All rights reserved. 4 | 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, this 11 | // list of conditions and the following disclaimer in the documentation and/or other 12 | // materials provided with the distribution. 13 | // * The name of the contributors may not be used to endorse or promote products 14 | // derived from this software without specific prior written permission. 15 | 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 | // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 20 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 24 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 25 | // OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | #include "QsLogDestFunctor.h" 28 | #include 29 | #include 30 | 31 | QsLogging::FunctorDestination::FunctorDestination(LogFunction f) 32 | : QObject(NULL) 33 | , mLogFunction(f) 34 | { 35 | } 36 | 37 | QsLogging::FunctorDestination::FunctorDestination(QObject *receiver, const char *member) 38 | : QObject(NULL) 39 | , mLogFunction(NULL) 40 | { 41 | connect(this, SIGNAL(logMessageReady(QString,int)), receiver, member, Qt::QueuedConnection); 42 | } 43 | 44 | 45 | void QsLogging::FunctorDestination::write(const QString &message, QsLogging::Level level) 46 | { 47 | if (mLogFunction) 48 | mLogFunction(message, level); 49 | 50 | if (level > QsLogging::TraceLevel) 51 | emit logMessageReady(message, static_cast(level)); 52 | } 53 | 54 | bool QsLogging::FunctorDestination::isValid() 55 | { 56 | return true; 57 | } 58 | -------------------------------------------------------------------------------- /QsLogDestFunctor.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014, Razvan Petru 2 | // Copyright (c) 2014, Omar Carey 3 | // All rights reserved. 4 | 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, this 11 | // list of conditions and the following disclaimer in the documentation and/or other 12 | // materials provided with the distribution. 13 | // * The name of the contributors may not be used to endorse or promote products 14 | // derived from this software without specific prior written permission. 15 | 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 | // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 20 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 24 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 25 | // OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | #ifndef QSLOGDESTFUNCTOR_H 28 | #define QSLOGDESTFUNCTOR_H 29 | 30 | #include "QsLogDest.h" 31 | #include 32 | 33 | namespace QsLogging 34 | { 35 | // Offers various types of function-like sinks. 36 | // This is an advanced destination type. Depending on your configuration, LogFunction might be 37 | // called from a different thread or even a different binary. You should not access QsLog from 38 | // inside LogFunction and should not perform any time-consuming operations. 39 | // logMessageReady is connected through a queued connection and trace messages are not included 40 | class FunctorDestination : public QObject, public Destination 41 | { 42 | Q_OBJECT 43 | public: 44 | explicit FunctorDestination(LogFunction f); 45 | FunctorDestination(QObject *receiver, const char *member); 46 | 47 | void write(const QString &message, Level level) override; 48 | bool isValid() override; 49 | 50 | protected: 51 | // int used to avoid registering a new enum type 52 | Q_SIGNAL void logMessageReady(const QString &message, int level); 53 | 54 | private: 55 | LogFunction mLogFunction; 56 | }; 57 | } 58 | 59 | #endif // QSLOGDESTFUNCTOR_H 60 | -------------------------------------------------------------------------------- /QsLogDisableForThisFile.h: -------------------------------------------------------------------------------- 1 | #ifndef QSLOGDISABLEFORTHISFILE_H 2 | #define QSLOGDISABLEFORTHISFILE_H 3 | 4 | #include 5 | // When included AFTER QsLog.h, this file will disable logging in that C++ file. When included 6 | // before, it will lead to compiler warnings or errors about macro redefinitions. 7 | 8 | #undef QLOG_TRACE 9 | #undef QLOG_DEBUG 10 | #undef QLOG_INFO 11 | #undef QLOG_WARN 12 | #undef QLOG_ERROR 13 | #undef QLOG_FATAL 14 | 15 | #define QLOG_TRACE() if (1) {} else qDebug() 16 | #define QLOG_DEBUG() if (1) {} else qDebug() 17 | #define QLOG_INFO() if (1) {} else qDebug() 18 | #define QLOG_WARN() if (1) {} else qDebug() 19 | #define QLOG_ERROR() if (1) {} else qDebug() 20 | #define QLOG_FATAL() if (1) {} else qDebug() 21 | 22 | #endif // QSLOGDISABLEFORTHISFILE_H 23 | -------------------------------------------------------------------------------- /QsLogLevel.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Razvan Petru 2 | // All rights reserved. 3 | 4 | // Redistribution and use in source and binary forms, with or without modification, 5 | // are permitted provided that the following conditions are met: 6 | 7 | // * Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, this 10 | // list of conditions and the following disclaimer in the documentation and/or other 11 | // materials provided with the distribution. 12 | // * The name of the contributors may not be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 19 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 24 | // OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #ifndef QSLOGLEVEL_H 27 | #define QSLOGLEVEL_H 28 | 29 | namespace QsLogging 30 | { 31 | 32 | enum Level 33 | { 34 | TraceLevel = 0, 35 | DebugLevel, 36 | InfoLevel, 37 | WarnLevel, 38 | ErrorLevel, 39 | FatalLevel, 40 | OffLevel 41 | }; 42 | 43 | } 44 | 45 | #endif // QSLOGLEVEL_H 46 | -------------------------------------------------------------------------------- /QsLogReadme.txt: -------------------------------------------------------------------------------- 1 | QsLog - the simple Qt logger 2 | ------------------------------------------------------------------------------- 3 | QsLog is an easy to use logger that is based on Qt's QDebug class. 4 | 5 | Features 6 | ------------------------------------------------------------------------------- 7 | * Six logging levels (from trace to fatal) 8 | * Logging level threshold configurable at runtime. 9 | * Minimum overhead when logging is turned off. 10 | * Multiple destinations, comes with file and debug destinations. 11 | * Thread-safe 12 | * Logging of common Qt types out of the box. 13 | * Immediate logging or queueing messages in a separate thread. 14 | * Small dependency: just drop it in your project directly. 15 | 16 | Usage 17 | ------------------------------------------------------------------------------- 18 | By directly including QsLog in your project: 19 | 1. Include QsLog.pri in your pro file 20 | 2. Include QsLog.h in your C++ files. Include QsLogDest.h only where you create/add destinations. 21 | 3. Get the instance of the logger by calling QsLogging::Logger::instance(); 22 | 4. Optionally set the logging level. Info is default. 23 | 5. Create as many destinations as you want by using the QsLogging::DestinationFactory. 24 | 6. Add the destinations to the logger instance by calling addDestination. 25 | 7. Start logging! 26 | Note: when you want to use QsLog both from an executable and a shared library you have to 27 | link dynamically with QsLog due to a limitation with static variables. 28 | 29 | By linking to QsLog dynamically: 30 | 1. Build QsLog using the QsLogSharedLibrary.pro. 31 | 2. Add the QsLog shared library to your LIBS project dependencies. 32 | 3. Follow the steps in "directly including QsLog in your project" starting with step 2. 33 | 34 | Configuration 35 | ------------------------------------------------------------------------------- 36 | QsLog has several configurable parameters: 37 | * defining QS_LOG_LINE_NUMBERS in the .pri file enables writing the file and line number 38 | automatically for each logging call 39 | * defining QS_LOG_SEPARATE_THREAD will route all log messages to a separate thread. 40 | 41 | Sometimes it's necessary to turn off logging. This can be done in several ways: 42 | * globally, at compile time, by enabling the QS_LOG_DISABLE macro in the .pri file. 43 | * globally, at run time, by setting the log level to "OffLevel". 44 | * per file, at compile time, by including QsLogDisableForThisFile.h in the target file. 45 | 46 | Thread safety 47 | ------------------------------------------------------------------------------- 48 | The Qt docs say: A thread-safe function can be called simultaneously from multiple threads, 49 | even when the invocations use shared data, because all references to the shared data are serialized. 50 | A reentrant function can also be called simultaneously from multiple threads, but only if each 51 | invocation uses its own data. 52 | 53 | Since sending the log message to the destinations is protected by a mutex, the logging macros are 54 | thread-safe provided that the log has been initialized - i.e: instance() has been called. 55 | The instance function and the setup functions (e.g: setLoggingLevel, addDestination) are NOT 56 | thread-safe and are NOT reentrant. 57 | 58 | IMPORTANT: when using a separate thread for logging, your program might crash at exit time on some 59 | operating systems if you won't call Logger::destroyInstance() before your program exits. 60 | This function can be called either before returning from main in a console app or 61 | inside QCoreApplication::aboutToQuit in a Qt GUI app. 62 | The reason is that the logging thread is still running as some objects are destroyed by 63 | the OS. Calling destroyInstance will wait for the thread to finish. 64 | Nothing will happen if you forget to call the function when not using a separate thread 65 | for logging. 66 | -------------------------------------------------------------------------------- /QsLogSharedLibrary.pro: -------------------------------------------------------------------------------- 1 | # This pro file will build QsLog as a shared library 2 | include(QsLog.pri) 3 | 4 | TARGET = QsLog 5 | VERSION = "2.0.0" 6 | QT -= gui 7 | CONFIG -= console 8 | CONFIG -= app_bundle 9 | CONFIG += shared 10 | TEMPLATE = lib 11 | 12 | DESTDIR = $$PWD/build-QsLogShared 13 | OBJECTS_DIR = $$DESTDIR/obj 14 | MOC_DIR = $$DESTDIR/moc 15 | 16 | win32 { 17 | DEFINES += QSLOG_IS_SHARED_LIBRARY 18 | } 19 | 20 | unix:!macx { 21 | # make install will install the shared object in the appropriate folders 22 | headers.files = QsLog.h QsLogDest.h QsLogLevel.h 23 | headers.path = /usr/include/$(QMAKE_TARGET) 24 | 25 | other_files.files = *.txt 26 | other_files.path = /usr/local/share/$(QMAKE_TARGET) 27 | 28 | contains(QT_ARCH, x86_64) { 29 | target.path = /usr/lib64 30 | } else { 31 | target.path = /usr/lib 32 | } 33 | 34 | INSTALLS += headers target other_files 35 | } 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## QsLog - the simple Qt logger ## 2 | QsLog is an easy to use logger that is based on Qt's QDebug class. QsLog is released as open source, under the MIT license. 3 | 4 | ###Contribution policy### 5 | Bug fixes are welcome, larger changes however are not encouraged at this point due to the lack of time on my side for reviewing and integrating them. Your best bet in this case would be to open a ticket for your change or forking the project and implementing your change there, with the possibility of having it integrated in the future. 6 | All contributions will be credited, license of the contributions should be MIT. 7 | 8 | ### Features ### 9 | * Six logging levels (from trace to fatal) 10 | * Logging level threshold configurable at runtime. 11 | * Minimum overhead when logging is turned off. 12 | * Supports multiple destinations, comes with file and debug destinations. 13 | * Thread-safe 14 | * Supports logging of common Qt types out of the box. 15 | * Small dependency: just drop it in your project directly. 16 | 17 | ### Usage ### 18 | * Include QsLog.h. Include QsLogDest.h only where you create/add destinations. 19 | * Get the instance of the logger by calling QsLogging::Logger::instance(); 20 | * Optionally set the logging level. Info is default. 21 | * Create as many destinations as you want by using the QsLogging::DestinationFactory. 22 | * Add the destinations to the logger instance by calling addDestination. 23 | 24 | **Note**: The logger does not take ownership of the destinations. Make sure that the destinations still exist when you call one of the logging macros. A good place to create the destinations is the program's main function. 25 | 26 | ### Disabling logging ### 27 | Sometimes it's necessary to turn off logging. This can be done in several ways: 28 | 29 | * globally, at compile time, by enabling the QS_LOG_DISABLE macro in the supplied .pri file. 30 | * globally, at run time, by setting the log level to "OffLevel". 31 | * per file, at compile time, by including QsLogDisableForThisFile.h in the target file. 32 | 33 | ### Thread safety ### 34 | The Qt docs say: 35 | A **thread-safe** function can be called simultaneously from multiple threads, even when the invocations use shared data, because all references to the shared data are serialized. 36 | A **reentrant** function can also be called simultaneously from multiple threads, but only if each invocation uses its own data. 37 | 38 | Since sending the log message to the destinations is protected by a mutex, the logging macros are thread-safe provided that the log has been initialized - i.e: instance() has been called. 39 | The instance function and the setup functions (e.g: setLoggingLevel, addDestination) are NOT thread-safe and are NOT reentrant. -------------------------------------------------------------------------------- /example/log_example.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | CONFIG += ordered 3 | 4 | SUBDIRS = ../QsLogSharedLibrary.pro \ 5 | log_example_shared.pro \ 6 | log_example_main.pro 7 | -------------------------------------------------------------------------------- /example/log_example_main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Razvan Petru 2 | // All rights reserved. 3 | 4 | // Redistribution and use in source and binary forms, with or without modification, 5 | // are permitted provided that the following conditions are met: 6 | 7 | // * Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, this 10 | // list of conditions and the following disclaimer in the documentation and/or other 11 | // materials provided with the distribution. 12 | // * The name of the contributors may not be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 19 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 24 | // OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #include "QsLog.h" 27 | #include "QsLogDest.h" 28 | #include "log_example_shared.h" 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | void logFunction(const QString &message, QsLogging::Level level) 35 | { 36 | std::cout << "From log function: " << qPrintable(message) << " " << static_cast(level) 37 | << std::endl; 38 | } 39 | 40 | // This small example shows how QsLog can be used inside a project. 41 | int main(int argc, char *argv[]) 42 | { 43 | QCoreApplication a(argc, argv); 44 | 45 | using namespace QsLogging; 46 | 47 | // 1. init the logging mechanism 48 | Logger& logger = Logger::instance(); 49 | logger.setLoggingLevel(QsLogging::TraceLevel); 50 | const QString sLogPath(QDir(a.applicationDirPath()).filePath("log.txt")); 51 | 52 | // 2. add two destinations 53 | DestinationPtr fileDestination(DestinationFactory::MakeFileDestination( 54 | sLogPath, EnableLogRotation, MaxSizeBytes(512), MaxOldLogCount(2))); 55 | DestinationPtr debugDestination(DestinationFactory::MakeDebugOutputDestination()); 56 | DestinationPtr functorDestination(DestinationFactory::MakeFunctorDestination(&logFunction)); 57 | logger.addDestination(debugDestination); 58 | logger.addDestination(fileDestination); 59 | logger.addDestination(functorDestination); 60 | 61 | // 3. start logging 62 | QLOG_INFO() << "Program started"; 63 | QLOG_INFO() << "Built with Qt" << QT_VERSION_STR << "running on" << qVersion(); 64 | 65 | QLOG_TRACE() << "Here's a" << QString::fromUtf8("trace") << "message"; 66 | QLOG_DEBUG() << "Here's a" << static_cast(QsLogging::DebugLevel) << "message"; 67 | QLOG_WARN() << "Uh-oh!"; 68 | qDebug() << "This message won't be picked up by the logger"; 69 | QLOG_ERROR() << "An error has occurred"; 70 | qWarning() << "Neither will this one"; 71 | QLOG_FATAL() << "Fatal error!"; 72 | 73 | logger.setLoggingLevel(QsLogging::OffLevel); 74 | for (int i = 0;i < 10000000;++i) { 75 | QLOG_ERROR() << QString::fromUtf8("this message should not be visible"); 76 | } 77 | logger.setLoggingLevel(QsLogging::TraceLevel); 78 | 79 | // 4. log from a shared library - should automatically share the same log instance as above 80 | QLibrary myLib("log_example_shared"); 81 | typedef LogExampleShared* (*LogExampleGetter)(); 82 | typedef void(*LogExampleDeleter)(LogExampleShared*); 83 | LogExampleGetter fLogCreator = (LogExampleGetter) myLib.resolve("createExample"); 84 | LogExampleDeleter fLogDeleter = (LogExampleDeleter)myLib.resolve("destroyExample"); 85 | LogExampleShared *logFromShared = 0; 86 | if (fLogCreator && fLogDeleter) { 87 | logFromShared = fLogCreator(); 88 | logFromShared->logSomething(); 89 | fLogDeleter(logFromShared); 90 | } else if (!fLogCreator || !fLogDeleter) { 91 | QLOG_ERROR() << "could not resolve shared library function(s)"; 92 | } 93 | 94 | QLOG_DEBUG() << "Program ending"; 95 | 96 | QsLogging::Logger::destroyInstance(); 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /example/log_example_main.pro: -------------------------------------------------------------------------------- 1 | #This project links with QsLog dynamically and outputs an executable file. 2 | 3 | QT -= gui 4 | TARGET = log_example 5 | CONFIG += console 6 | CONFIG -= app_bundle 7 | TEMPLATE = app 8 | SOURCES += log_example_main.cpp 9 | INCLUDEPATH += $$PWD/../ 10 | DEFINES += QSLOG_IS_SHARED_LIBRARY_IMPORT 11 | 12 | LIBS += -L$$PWD/../build-QsLogShared 13 | win32 { 14 | LIBS += -lQsLog2 15 | } else { 16 | LIBS += -lQsLog 17 | } 18 | LIBS += -L$$PWD/../build-QsLogExample -llog_example_shared 19 | 20 | DESTDIR = $$PWD/../build-QsLogExample 21 | OBJECTS_DIR = $$DESTDIR/obj 22 | -------------------------------------------------------------------------------- /example/log_example_shared.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Razvan Petru 2 | // All rights reserved. 3 | 4 | // Redistribution and use in source and binary forms, with or without modification, 5 | // are permitted provided that the following conditions are met: 6 | 7 | // * Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, this 10 | // list of conditions and the following disclaimer in the documentation and/or other 11 | // materials provided with the distribution. 12 | // * The name of the contributors may not be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 19 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 24 | // OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #include "log_example_shared.h" 27 | #include "QsLog.h" 28 | 29 | void LogExampleShared::logSomething() 30 | { 31 | QLOG_INFO() << "this message is comming from a shared library"; 32 | } 33 | 34 | LogExampleShared* createExample() 35 | { 36 | return new LogExampleShared(); 37 | } 38 | 39 | 40 | void destroyExample(LogExampleShared *example) 41 | { 42 | delete example; 43 | } 44 | -------------------------------------------------------------------------------- /example/log_example_shared.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Razvan Petru 2 | // All rights reserved. 3 | 4 | // Redistribution and use in source and binary forms, with or without modification, 5 | // are permitted provided that the following conditions are met: 6 | 7 | // * Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, this 10 | // list of conditions and the following disclaimer in the documentation and/or other 11 | // materials provided with the distribution. 12 | // * The name of the contributors may not be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 19 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 24 | // OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #ifndef LOGEXAMPLESHARED_H 27 | #define LOGEXAMPLESHARED_H 28 | 29 | #include 30 | 31 | #ifdef EXAMPLE_IS_SHARED_LIBRARY 32 | #define EXAMPLE_SHARED_OBJECT Q_DECL_IMPORT 33 | #else 34 | #define EXAMPLE_SHARED_OBJECT Q_DECL_EXPORT 35 | #endif 36 | 37 | class EXAMPLE_SHARED_OBJECT LogExampleShared 38 | { 39 | public: 40 | void logSomething(); 41 | }; 42 | 43 | extern "C" { 44 | LogExampleShared *createExample(); 45 | void destroyExample(LogExampleShared *example); 46 | } 47 | 48 | #endif // LOGEXAMPLESHARED_H 49 | -------------------------------------------------------------------------------- /example/log_example_shared.pro: -------------------------------------------------------------------------------- 1 | #This project file links with QsLog dynamically and outputs a shared object. 2 | 3 | QT -= gui 4 | 5 | TARGET = log_example_shared 6 | TEMPLATE = lib 7 | 8 | DEFINES += EXAMPLE_IS_SHARED_LIBRARY QSLOG_IS_SHARED_LIBRARY_IMPORT 9 | SOURCES += log_example_shared.cpp 10 | HEADERS += log_example_shared.h 11 | INCLUDEPATH += $$PWD/../ 12 | DESTDIR = $$PWD/../build-QsLogExample 13 | OBJECTS_DIR = $$DESTDIR/obj 14 | 15 | LIBS += -L$$PWD/../build-QsLogShared 16 | win32 { 17 | LIBS += -lQsLog2 18 | } else { 19 | LIBS += -lQsLog 20 | } 21 | 22 | 23 | -------------------------------------------------------------------------------- /unittest/QtTestUtil/QtTestUtil.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 Remko Troncon 3 | * Licensed under the MIT license. 4 | * See COPYING for license details. 5 | */ 6 | 7 | #ifndef QtTestUtil_H 8 | #define QtTestUtil_H 9 | 10 | #include 11 | #include 12 | #include "QtTestUtil/TestRegistration.h" 13 | 14 | /** 15 | * A macro to register a test class. 16 | * 17 | * This macro will create a static variable which registers the 18 | * testclass with the TestRegistry, and creates an instance of the 19 | * test class. 20 | * 21 | * Execute this macro in the body of your unit test's .cpp file, e.g. 22 | * class MyTest { 23 | * ... 24 | * }; 25 | * 26 | * QTTESTUTIL_REGISTER_TEST(MyTest) 27 | */ 28 | #define QTTESTUTIL_REGISTER_TEST(TestClass) \ 29 | static QtTestUtil::TestRegistration TestClass##Registration 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /unittest/QtTestUtil/SimpleChecker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 Remko Troncon 3 | * Licensed under the MIT license. 4 | * See COPYING for license details. 5 | */ 6 | 7 | #include 8 | 9 | #include "QtTestUtil/TestRegistry.h" 10 | 11 | /** 12 | * Runs all tests registered with the QtTestUtil registry. 13 | */ 14 | int main(int argc, char* argv[]) { 15 | QCoreApplication application(argc, argv); 16 | return QtTestUtil::TestRegistry::getInstance()->runTests(argc, argv); 17 | } 18 | -------------------------------------------------------------------------------- /unittest/QtTestUtil/TestRegistration.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 Remko Troncon 3 | * Licensed under the MIT license. 4 | * See COPYING for license details. 5 | */ 6 | 7 | #ifndef QtTestUtil_TestRegistration_H 8 | #define QtTestUtil_TestRegistration_H 9 | 10 | #include "QtTestUtil/TestRegistry.h" 11 | 12 | namespace QtTestUtil { 13 | 14 | /** 15 | * A wrapper class around a test to manage registration and static 16 | * creation of an instance of the test class. 17 | * This class is used by QTTESTUTIL_REGISTER_TEST(), and you should not 18 | * use this class directly. 19 | */ 20 | template 21 | class TestRegistration { 22 | public: 23 | TestRegistration() { 24 | test_ = new TestClass(); 25 | TestRegistry::getInstance()->registerTest(test_); 26 | } 27 | 28 | ~TestRegistration() { 29 | delete test_; 30 | } 31 | 32 | private: 33 | TestClass* test_; 34 | }; 35 | 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /unittest/QtTestUtil/TestRegistry.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 Remko Troncon 3 | * Licensed under the MIT license. 4 | * See COPYING for license details. 5 | */ 6 | 7 | #include "QtTestUtil/TestRegistry.h" 8 | 9 | #include 10 | 11 | namespace QtTestUtil { 12 | 13 | TestRegistry* TestRegistry::getInstance() { 14 | static TestRegistry registry; 15 | return ®istry; 16 | } 17 | 18 | void TestRegistry::registerTest(QObject* test) { 19 | tests_ += test; 20 | } 21 | 22 | int TestRegistry::runTests(int argc, char* argv[]) { 23 | int result = 0; 24 | foreach(QObject* test, tests_) { 25 | result |= QTest::qExec(test, argc, argv); 26 | } 27 | return result; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /unittest/QtTestUtil/TestRegistry.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 Remko Troncon 3 | * Licensed under the MIT license. 4 | * See COPYING for license details. 5 | */ 6 | 7 | #ifndef QtTestUtil_TestRegistry_H 8 | #define QtTestUtil_TestRegistry_H 9 | 10 | #include 11 | 12 | class QObject; 13 | 14 | namespace QtTestUtil { 15 | 16 | /** 17 | * A registry of QtTest test classes. 18 | * All test classes registered with QTTESTUTIL_REGISTER_TEST add 19 | * themselves to this registry. All registered tests can then be run at 20 | * once using runTests(). 21 | */ 22 | class TestRegistry { 23 | public: 24 | /** 25 | * Retrieve the single instance of the registry. 26 | */ 27 | static TestRegistry* getInstance(); 28 | 29 | /** 30 | * Register a QtTest test. 31 | * This method is called by QTTESTUTIL_REGISTER_TEST, and you should 32 | * not use this method directly. 33 | */ 34 | void registerTest(QObject*); 35 | 36 | /** 37 | * Run all registered tests using QTest::qExec() 38 | */ 39 | int runTests(int argc, char* argv[]); 40 | 41 | private: 42 | TestRegistry() {} 43 | 44 | private: 45 | QList tests_; 46 | }; 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /unittest/TestLog.cpp: -------------------------------------------------------------------------------- 1 | #include "QtTestUtil/QtTestUtil.h" 2 | #include "QsLog.h" 3 | #include "QsLogDest.h" 4 | #include 5 | #include 6 | #include 7 | 8 | // A destination that tracks log messages 9 | class MockDestination : public QsLogging::Destination 10 | { 11 | public: 12 | virtual void write(const QString &message, QsLogging::Level level) 13 | { 14 | Message m; 15 | m.text = message; 16 | m.level = level; 17 | mMessages.push_back(m); 18 | ++mCountByLevel[level]; 19 | } 20 | 21 | virtual bool isValid() 22 | { 23 | return true; 24 | } 25 | 26 | struct Message 27 | { 28 | Message() : level(QsLogging::TraceLevel) {} 29 | QString text; 30 | QsLogging::Level level; 31 | }; 32 | 33 | void clear() 34 | { 35 | mMessages.clear(); 36 | mCountByLevel.clear(); 37 | } 38 | 39 | int messageCount() const 40 | { 41 | return mMessages.count(); 42 | } 43 | 44 | int messageCountForLevel(QsLogging::Level level) const 45 | { 46 | return mCountByLevel.value(level); 47 | } 48 | 49 | bool hasMessage(const QString &messageContent, QsLogging::Level level) const 50 | { 51 | Q_FOREACH (const Message &m, mMessages) { 52 | if (m.level == level && m.text.contains(messageContent)) 53 | return true; 54 | } 55 | 56 | return false; 57 | } 58 | 59 | const Message& messageAt(int index) 60 | { 61 | Q_ASSERT(index >= 0 && index < messageCount()); 62 | return mMessages.at(index); 63 | } 64 | 65 | private: 66 | QHash mCountByLevel; 67 | QList mMessages; 68 | }; 69 | 70 | // Autotests for QsLog 71 | class TestLog : public QObject 72 | { 73 | Q_OBJECT 74 | public: 75 | TestLog() 76 | : mockDest1(new MockDestination) 77 | , mockDest2(new MockDestination) 78 | { 79 | } 80 | 81 | private slots: 82 | void initTestCase(); 83 | void testAllLevels(); 84 | void testMessageText(); 85 | void testLevelChanges(); 86 | void testLevelParsing(); 87 | void cleanupTestCase(); 88 | 89 | private: 90 | QSharedPointer mockDest1; 91 | QSharedPointer mockDest2; 92 | }; 93 | 94 | void TestLog::initTestCase() 95 | { 96 | using namespace QsLogging; 97 | QCOMPARE(Logger::instance().loggingLevel(), InfoLevel); 98 | Logger::instance().setLoggingLevel(TraceLevel); 99 | QCOMPARE(Logger::instance().loggingLevel(), TraceLevel); 100 | Logger::instance().addDestination(mockDest1); 101 | Logger::instance().addDestination(mockDest2); 102 | } 103 | 104 | void TestLog::testAllLevels() 105 | { 106 | mockDest1->clear(); 107 | mockDest2->clear(); 108 | 109 | QLOG_TRACE() << "trace level"; 110 | QLOG_DEBUG() << "debug level"; 111 | QLOG_INFO() << "info level"; 112 | QLOG_WARN() << "warn level"; 113 | QLOG_ERROR() << "error level"; 114 | QLOG_FATAL() << "fatal level"; 115 | 116 | using namespace QsLogging; 117 | QCOMPARE(mockDest1->messageCount(), 6); 118 | QCOMPARE(mockDest1->messageCountForLevel(TraceLevel), 1); 119 | QCOMPARE(mockDest1->messageCountForLevel(DebugLevel), 1); 120 | QCOMPARE(mockDest1->messageCountForLevel(InfoLevel), 1); 121 | QCOMPARE(mockDest1->messageCountForLevel(WarnLevel), 1); 122 | QCOMPARE(mockDest1->messageCountForLevel(ErrorLevel), 1); 123 | QCOMPARE(mockDest1->messageCountForLevel(FatalLevel), 1); 124 | QCOMPARE(mockDest2->messageCount(), 6); 125 | QCOMPARE(mockDest2->messageCountForLevel(TraceLevel), 1); 126 | QCOMPARE(mockDest2->messageCountForLevel(DebugLevel), 1); 127 | QCOMPARE(mockDest2->messageCountForLevel(InfoLevel), 1); 128 | QCOMPARE(mockDest2->messageCountForLevel(WarnLevel), 1); 129 | QCOMPARE(mockDest2->messageCountForLevel(ErrorLevel), 1); 130 | QCOMPARE(mockDest2->messageCountForLevel(FatalLevel), 1); 131 | } 132 | 133 | void TestLog::testMessageText() 134 | { 135 | mockDest1->clear(); 136 | 137 | QLOG_DEBUG() << "foobar"; 138 | QLOG_WARN() << "eiszeit"; 139 | QLOG_FATAL() << "ruh-roh!"; 140 | using namespace QsLogging; 141 | QVERIFY(mockDest1->hasMessage("foobar", DebugLevel)); 142 | QVERIFY(mockDest1->hasMessage("eiszeit", WarnLevel)); 143 | QVERIFY(mockDest1->hasMessage("ruh-roh!", FatalLevel)); 144 | QCOMPARE(mockDest1->messageCount(), 3); 145 | } 146 | 147 | void TestLog::testLevelChanges() 148 | { 149 | mockDest1->clear(); 150 | mockDest2->clear(); 151 | 152 | using namespace QsLogging; 153 | Logger::instance().setLoggingLevel(WarnLevel); 154 | QCOMPARE(Logger::instance().loggingLevel(), WarnLevel); 155 | 156 | QLOG_TRACE() << "one"; 157 | QLOG_DEBUG() << "two"; 158 | QLOG_INFO() << "three"; 159 | QCOMPARE(mockDest1->messageCount(), 0); 160 | QCOMPARE(mockDest2->messageCount(), 0); 161 | 162 | QLOG_WARN() << "warning"; 163 | QLOG_ERROR() << "error"; 164 | QLOG_FATAL() << "fatal"; 165 | QCOMPARE(mockDest1->messageCountForLevel(WarnLevel), 1); 166 | QCOMPARE(mockDest1->messageCountForLevel(ErrorLevel), 1); 167 | QCOMPARE(mockDest1->messageCountForLevel(FatalLevel), 1); 168 | QCOMPARE(mockDest1->messageCount(), 3); 169 | QCOMPARE(mockDest2->messageCountForLevel(WarnLevel), 1); 170 | QCOMPARE(mockDest2->messageCountForLevel(ErrorLevel), 1); 171 | QCOMPARE(mockDest2->messageCountForLevel(FatalLevel), 1); 172 | QCOMPARE(mockDest2->messageCount(), 3); 173 | } 174 | 175 | void TestLog::testLevelParsing() 176 | { 177 | mockDest1->clear(); 178 | 179 | QLOG_TRACE() << "one"; 180 | QLOG_DEBUG() << "two"; 181 | QLOG_INFO() << "three"; 182 | QLOG_WARN() << "warning"; 183 | QLOG_ERROR() << "error"; 184 | QLOG_FATAL() << "fatal"; 185 | 186 | using namespace QsLogging; 187 | for(int i = 0;i < mockDest1->messageCount();++i) { 188 | bool conversionOk = false; 189 | const MockDestination::Message& m = mockDest1->messageAt(i); 190 | QCOMPARE(Logger::levelFromLogMessage(m.text, &conversionOk), m.level); 191 | QCOMPARE(Logger::levelFromLogMessage(m.text), m.level); 192 | QCOMPARE(conversionOk, true); 193 | } 194 | } 195 | 196 | void TestLog::cleanupTestCase() 197 | { 198 | QsLogging::Logger::destroyInstance(); 199 | } 200 | 201 | QTTESTUTIL_REGISTER_TEST(TestLog); 202 | #include "TestLog.moc" 203 | -------------------------------------------------------------------------------- /unittest/unittest.pro: -------------------------------------------------------------------------------- 1 | QT += core 2 | 3 | TARGET = QsLogUnitTest 4 | CONFIG += console qtestlib 5 | CONFIG -= app_bundle 6 | TEMPLATE = app 7 | 8 | # test-case sources 9 | SOURCES += TestLog.cpp 10 | 11 | # component sources 12 | include(../QsLog.pri) 13 | 14 | SOURCES += \ 15 | ./QtTestUtil/TestRegistry.cpp \ 16 | ./QtTestUtil/SimpleChecker.cpp 17 | 18 | HEADERS += \ 19 | ./QtTestUtil/TestRegistry.h \ 20 | ./QtTestUtil/TestRegistration.h \ 21 | ./QtTestUtil/QtTestUtil.h 22 | --------------------------------------------------------------------------------