mirror of
https://github.com/YACReader/yacreader
synced 2025-06-04 01:28:55 -04:00
Update QsLog to 2.1 snapshot 46b643d5bcbc
This commit is contained in:
parent
c13ec618d0
commit
1568a5f253
110
third_party/QsLog/CMakeLists.txt
vendored
Normal file
110
third_party/QsLog/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
# CMake build support courtesy of Axel Gembe <axel@gembe.net>
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
project(QsLog)
|
||||
|
||||
# Add CMake modules
|
||||
set(CMAKE_MODULE_PATH
|
||||
"${QsLog_SOURCE_DIR}/cmake"
|
||||
"${CMAKE_MODULE_PATH}"
|
||||
)
|
||||
|
||||
include(QsLogConfigTargets)
|
||||
|
||||
# Add a _d to debug binaries
|
||||
set(CMAKE_DEBUG_POSTFIX "_d")
|
||||
|
||||
# Qt5
|
||||
find_package(Qt5Core REQUIRED)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
# As moc files are generated in the binary dir, tell to always look for includes there
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
# Specify build paths
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${QsLog_BINARY_DIR}/lib)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${QsLog_BINARY_DIR}/lib)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${QsLog_BINARY_DIR}/bin)
|
||||
|
||||
set(HEADER_FILES
|
||||
QsLog.h
|
||||
QsLogDest.h
|
||||
QsLogDestConsole.h
|
||||
QsLogDestFile.h
|
||||
QsLogDestFunctor.h
|
||||
QsLogDisableForThisFile.h
|
||||
QsLogLevel.h
|
||||
QsLogMessage.h
|
||||
QsLogSharedLibrary.h
|
||||
)
|
||||
|
||||
set(SOURCE_FILES
|
||||
QsLog.cpp
|
||||
QsLogDest.cpp
|
||||
QsLogDestConsole.cpp
|
||||
QsLogDestFile.cpp
|
||||
QsLogDestFunctor.cpp
|
||||
QsLogMessage.cpp
|
||||
QsLogLevel.cpp
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
# Apple's compiler will not find standard includes like <thread> or <mutex> with 10.7 target otherwise
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
endif()
|
||||
|
||||
# Use 10.7 OSX SDK
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.7")
|
||||
|
||||
option(QS_LOG_LINE_NUMBERS "Automatically writes the file and line for each log message" OFF)
|
||||
if(QS_LOG_LINE_NUMBERS)
|
||||
add_definitions(-DQS_LOG_LINE_NUMBERS)
|
||||
endif()
|
||||
|
||||
option(QS_LOG_DISABLE "Logging code is replaced with a no-op" OFF)
|
||||
if(QS_LOG_DISABLE)
|
||||
add_definitions(-DQS_LOG_DISABLE)
|
||||
endif()
|
||||
|
||||
option(QS_LOG_SEPARATE_THREAD "Messages are queued and written from a separate thread" OFF)
|
||||
if(QS_LOG_SEPARATE_THREAD)
|
||||
add_definitions(-DQS_LOG_SEPARATE_THREAD)
|
||||
endif()
|
||||
|
||||
option(QS_LOG_WIN_PRINTF_CONSOLE "Use fprintf instead of OutputDebugString on Windows" OFF)
|
||||
if(QS_LOG_WIN_PRINTF_CONSOLE)
|
||||
add_definitions(-DQS_LOG_WIN_PRINTF_CONSOLE)
|
||||
endif()
|
||||
|
||||
option(QS_LOG_IS_SHARED_LIBRARY "Build shared library" ON)
|
||||
if(QS_LOG_IS_SHARED_LIBRARY)
|
||||
set(QS_LOG_LIBRARY_TYPE SHARED)
|
||||
add_definitions(-DQSLOG_IS_SHARED_LIBRARY)
|
||||
else(QS_LOG_IS_SHARED_LIBRARY)
|
||||
set(QS_LOG_LIBRARY_TYPE STATIC)
|
||||
endif(QS_LOG_IS_SHARED_LIBRARY)
|
||||
|
||||
option(QS_LOG_BUILD_WINDOW "Build log window, depends on Qt5::Widgets" OFF)
|
||||
if(QS_LOG_BUILD_WINDOW)
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
list(APPEND ADDITIONAL_LIBRARIES Qt5::Widgets)
|
||||
list(APPEND HEADER_FILES QsLogWindowModel.h QsLogWindow.h)
|
||||
list(APPEND SOURCE_FILES QsLogWindowModel.cpp QsLogWindow.cpp)
|
||||
list(APPEND UI_FILES QsLogWindow.ui)
|
||||
list(APPEND RES_FILES QsLogWindow.qrc)
|
||||
qt5_wrap_ui(UI_SOURCE_FILES ${UI_FILES})
|
||||
qt5_add_resources(RES_SOURCE_FILES ${RES_FILES})
|
||||
add_definitions(-DQS_LOG_WINDOW)
|
||||
endif()
|
||||
|
||||
add_library(QsLog ${QS_LOG_LIBRARY_TYPE} ${HEADER_FILES} ${SOURCE_FILES} ${UI_SOURCE_FILES} ${RES_SOURCE_FILES})
|
||||
|
||||
target_link_libraries(QsLog Qt5::Core ${ADDITIONAL_LIBRARIES})
|
||||
|
||||
install(FILES ${HEADER_FILES} DESTINATION include/QsLog)
|
||||
QsLog_install_target(QsLog "")
|
||||
|
||||
option(QS_LOG_BUILD_TESTS "Build unit tests" OFF)
|
||||
if(QS_LOG_BUILD_TESTS)
|
||||
add_subdirectory(unittest)
|
||||
endif()
|
24
third_party/QsLog/LICENSE.txt
vendored
Normal file
24
third_party/QsLog/LICENSE.txt
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
Copyright (c) 2010 - 2016 Razvan Petru
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
* The name of the contributors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
264
third_party/QsLog/QsLog.cpp
vendored
264
third_party/QsLog/QsLog.cpp
vendored
@ -26,147 +26,152 @@
|
||||
#include "QsLog.h"
|
||||
#include "QsLogDest.h"
|
||||
#ifdef QS_LOG_SEPARATE_THREAD
|
||||
#include <QThreadPool>
|
||||
#include <QRunnable>
|
||||
#include <QThread>
|
||||
#include <QWaitCondition>
|
||||
#include <queue>
|
||||
#endif
|
||||
#include <QMutex>
|
||||
#include <QVector>
|
||||
#include <QDateTime>
|
||||
#include <QLatin1String>
|
||||
#include <QtGlobal>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace QsLogging
|
||||
{
|
||||
typedef QVector<DestinationPtr> DestinationList;
|
||||
|
||||
static const char TraceString[] = "TRACE";
|
||||
static const char DebugString[] = "DEBUG";
|
||||
static const char InfoString[] = "INFO ";
|
||||
static const char WarnString[] = "WARN ";
|
||||
static const char ErrorString[] = "ERROR";
|
||||
static const char FatalString[] = "FATAL";
|
||||
|
||||
// not using Qt::ISODate because we need the milliseconds too
|
||||
static const QString fmtDateTime("yyyy-MM-ddThh:mm:ss.zzz");
|
||||
|
||||
static Logger* sInstance = 0;
|
||||
|
||||
static const char* LevelToText(Level theLevel)
|
||||
{
|
||||
switch (theLevel) {
|
||||
case TraceLevel:
|
||||
return TraceString;
|
||||
case DebugLevel:
|
||||
return DebugString;
|
||||
case InfoLevel:
|
||||
return InfoString;
|
||||
case WarnLevel:
|
||||
return WarnString;
|
||||
case ErrorLevel:
|
||||
return ErrorString;
|
||||
case FatalLevel:
|
||||
return FatalString;
|
||||
case OffLevel:
|
||||
return "";
|
||||
default: {
|
||||
assert(!"bad log level");
|
||||
return InfoString;
|
||||
}
|
||||
}
|
||||
}
|
||||
using DestinationList = std::vector<DestinationPtrU>;
|
||||
|
||||
#ifdef QS_LOG_SEPARATE_THREAD
|
||||
class LogWriterRunnable : public QRunnable
|
||||
//! Messages can be enqueued from other threads and will be logged one by one.
|
||||
//! Note: std::queue was used instead of QQueue because it accepts types missing operator=.
|
||||
class LoggerThread : public QThread
|
||||
{
|
||||
public:
|
||||
LogWriterRunnable(QString message, Level level);
|
||||
virtual void run();
|
||||
void enqueue(const LogMessage& message)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
messageQueue.push(message);
|
||||
waitCondition.wakeOne();
|
||||
}
|
||||
|
||||
void requestStop()
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
requestInterruption();
|
||||
waitCondition.wakeOne();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void run()
|
||||
{
|
||||
while (true) {
|
||||
QMutexLocker locker(&mutex);
|
||||
if (messageQueue.empty() && !isInterruptionRequested()) {
|
||||
waitCondition.wait(&mutex);
|
||||
}
|
||||
if (isInterruptionRequested()) {
|
||||
break;
|
||||
}
|
||||
|
||||
const LogMessage msg = messageQueue.front();
|
||||
messageQueue.pop();
|
||||
locker.unlock();
|
||||
Logger::instance().write(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QString mMessage;
|
||||
Level mLevel;
|
||||
QMutex mutex;
|
||||
QWaitCondition waitCondition;
|
||||
std::queue<LogMessage> messageQueue;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
class LoggerImpl
|
||||
{
|
||||
public:
|
||||
LoggerImpl();
|
||||
~LoggerImpl();
|
||||
|
||||
#ifdef QS_LOG_SEPARATE_THREAD
|
||||
QThreadPool threadPool;
|
||||
bool shutDownLoggerThread();
|
||||
|
||||
LoggerThread loggerThread;
|
||||
#endif
|
||||
QMutex logMutex;
|
||||
Level level;
|
||||
DestinationList destList;
|
||||
};
|
||||
|
||||
#ifdef QS_LOG_SEPARATE_THREAD
|
||||
LogWriterRunnable::LogWriterRunnable(QString message, Level level)
|
||||
: QRunnable()
|
||||
, mMessage(message)
|
||||
, mLevel(level)
|
||||
{
|
||||
}
|
||||
|
||||
void LogWriterRunnable::run()
|
||||
{
|
||||
Logger::instance().write(mMessage, mLevel);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
LoggerImpl::LoggerImpl()
|
||||
: level(InfoLevel)
|
||||
{
|
||||
// assume at least file + console
|
||||
destList.reserve(2);
|
||||
destList.reserve(2); // assume at least file + console
|
||||
#ifdef QS_LOG_SEPARATE_THREAD
|
||||
threadPool.setMaxThreadCount(1);
|
||||
threadPool.setExpiryTimeout(-1);
|
||||
loggerThread.start(QThread::LowPriority);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Logger::Logger()
|
||||
: d(new LoggerImpl)
|
||||
LoggerImpl::~LoggerImpl()
|
||||
{
|
||||
#ifdef QS_LOG_SEPARATE_THREAD
|
||||
#if defined(Q_OS_WIN) && defined(QSLOG_IS_SHARED_LIBRARY)
|
||||
// Waiting on the thread here is too late and can lead to deadlocks. More details:
|
||||
// * Another reason not to do anything scary in your DllMain:
|
||||
// https://blogs.msdn.microsoft.com/oldnewthing/20040128-00/?p=40853
|
||||
// * Dynamic Link libraries best practices:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971%28v=vs.85%29.aspx#general_best_practices
|
||||
Q_ASSERT(loggerThread.isFinished());
|
||||
if (!loggerThread.isFinished()) {
|
||||
qCritical("You must shut down the QsLog thread, otherwise deadlocks can occur!");
|
||||
}
|
||||
#endif
|
||||
shutDownLoggerThread();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef QS_LOG_SEPARATE_THREAD
|
||||
bool LoggerImpl::shutDownLoggerThread()
|
||||
{
|
||||
if (loggerThread.isFinished()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
loggerThread.requestStop();
|
||||
return loggerThread.wait();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Logger& Logger::instance()
|
||||
{
|
||||
if (!sInstance)
|
||||
sInstance = new Logger;
|
||||
|
||||
return *sInstance;
|
||||
}
|
||||
|
||||
void Logger::destroyInstance()
|
||||
{
|
||||
delete sInstance;
|
||||
sInstance = 0;
|
||||
static Logger instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
// tries to extract the level from a string log message. If available, conversionSucceeded will
|
||||
// contain the conversion result.
|
||||
Level Logger::levelFromLogMessage(const QString& logMessage, bool* conversionSucceeded)
|
||||
{
|
||||
using namespace QsLogging;
|
||||
|
||||
if (conversionSucceeded)
|
||||
*conversionSucceeded = true;
|
||||
|
||||
if (logMessage.startsWith(QLatin1String(TraceString)))
|
||||
if (logMessage.startsWith(QLatin1String(LevelName(TraceLevel))))
|
||||
return TraceLevel;
|
||||
if (logMessage.startsWith(QLatin1String(DebugString)))
|
||||
if (logMessage.startsWith(QLatin1String(LevelName(DebugLevel))))
|
||||
return DebugLevel;
|
||||
if (logMessage.startsWith(QLatin1String(InfoString)))
|
||||
if (logMessage.startsWith(QLatin1String(LevelName(InfoLevel))))
|
||||
return InfoLevel;
|
||||
if (logMessage.startsWith(QLatin1String(WarnString)))
|
||||
if (logMessage.startsWith(QLatin1String(LevelName(WarnLevel))))
|
||||
return WarnLevel;
|
||||
if (logMessage.startsWith(QLatin1String(ErrorString)))
|
||||
if (logMessage.startsWith(QLatin1String(LevelName(ErrorLevel))))
|
||||
return ErrorLevel;
|
||||
if (logMessage.startsWith(QLatin1String(FatalString)))
|
||||
if (logMessage.startsWith(QLatin1String(LevelName(FatalLevel))))
|
||||
return FatalLevel;
|
||||
|
||||
if (conversionSucceeded)
|
||||
@ -174,19 +179,54 @@ Level Logger::levelFromLogMessage(const QString& logMessage, bool* conversionSuc
|
||||
return OffLevel;
|
||||
}
|
||||
|
||||
Logger::~Logger()
|
||||
Logger::~Logger() noexcept = default;
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
bool Logger::shutDownLoggerThread()
|
||||
{
|
||||
#ifdef QS_LOG_SEPARATE_THREAD
|
||||
d->threadPool.waitForDone();
|
||||
return d->shutDownLoggerThread();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
delete d;
|
||||
d = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Logger::addDestination(DestinationPtrU&& destination)
|
||||
{
|
||||
Q_ASSERT(destination.get());
|
||||
QMutexLocker lock(&d->logMutex);
|
||||
d->destList.emplace_back(std::move(destination));
|
||||
}
|
||||
|
||||
void Logger::addDestination(DestinationPtr destination)
|
||||
DestinationPtrU Logger::removeDestination(const QString &type)
|
||||
{
|
||||
assert(destination.data());
|
||||
d->destList.push_back(destination);
|
||||
QMutexLocker lock(&d->logMutex);
|
||||
|
||||
const auto it = std::find_if(d->destList.begin(), d->destList.end(), [&type](const DestinationPtrU& dest){
|
||||
return dest->type() == type;
|
||||
});
|
||||
|
||||
if (it != d->destList.end()) {
|
||||
auto removed = std::move(*it);
|
||||
d->destList.erase(it);
|
||||
return removed;
|
||||
}
|
||||
|
||||
return DestinationPtrU();
|
||||
}
|
||||
|
||||
bool Logger::hasDestinationOfType(const char* type) const
|
||||
{
|
||||
QMutexLocker lock(&d->logMutex);
|
||||
const QLatin1String latin1Type(type);
|
||||
for (const auto& dest : d->destList) {
|
||||
if (dest->type() == latin1Type) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Logger::setLoggingLevel(Level newLevel)
|
||||
@ -199,50 +239,36 @@ Level Logger::loggingLevel() const
|
||||
return d->level;
|
||||
}
|
||||
|
||||
//! creates the complete log message and passes it to the logger
|
||||
void Logger::Helper::writeToLog()
|
||||
Logger::Helper::~Helper() noexcept
|
||||
{
|
||||
const char* const levelName = LevelToText(level);
|
||||
const QString completeMessage(QString("%1 %2 %3")
|
||||
.arg(levelName)
|
||||
.arg(QDateTime::currentDateTime().toString(fmtDateTime))
|
||||
.arg(buffer)
|
||||
);
|
||||
|
||||
Logger::instance().enqueueWrite(completeMessage, level);
|
||||
const LogMessage msg(buffer, QDateTime::currentDateTimeUtc(), level);
|
||||
Logger::instance().enqueueWrite(msg);
|
||||
}
|
||||
|
||||
Logger::Helper::~Helper()
|
||||
|
||||
Logger::Logger()
|
||||
: d(new LoggerImpl)
|
||||
{
|
||||
try {
|
||||
writeToLog();
|
||||
}
|
||||
catch(std::exception&) {
|
||||
// you shouldn't throw exceptions from a sink
|
||||
assert(!"exception in logger helper destructor");
|
||||
//CHANGED throw;
|
||||
}
|
||||
qRegisterMetaType<LogMessage>("QsLogging::LogMessage");
|
||||
}
|
||||
|
||||
//! directs the message to the task queue or writes it directly
|
||||
void Logger::enqueueWrite(const QString& message, Level level)
|
||||
void Logger::enqueueWrite(const LogMessage& message)
|
||||
{
|
||||
#ifdef QS_LOG_SEPARATE_THREAD
|
||||
LogWriterRunnable *r = new LogWriterRunnable(message, level);
|
||||
d->threadPool.start(r);
|
||||
d->loggerThread.enqueue(message);
|
||||
#else
|
||||
write(message, level);
|
||||
write(message);
|
||||
#endif
|
||||
}
|
||||
|
||||
//! Sends the message to all the destinations. The level for this message is passed in case
|
||||
//! it's useful for processing in the destination.
|
||||
void Logger::write(const QString& message, Level level)
|
||||
void Logger::write(const LogMessage& message)
|
||||
{
|
||||
QMutexLocker lock(&d->logMutex);
|
||||
for (DestinationList::iterator it = d->destList.begin(),
|
||||
endIt = d->destList.end();it != endIt;++it) {
|
||||
(*it)->write(message, level);
|
||||
for (auto& dest : d->destList) {
|
||||
dest->write(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
51
third_party/QsLog/QsLog.h
vendored
51
third_party/QsLog/QsLog.h
vendored
@ -27,30 +27,55 @@
|
||||
#define QSLOG_H
|
||||
|
||||
#include "QsLogLevel.h"
|
||||
#include "QsLogDest.h"
|
||||
#include "QsLogMessage.h"
|
||||
#include "QsLogSharedLibrary.h"
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <memory>
|
||||
|
||||
#define QS_LOG_VERSION "2.0b3"
|
||||
#define QS_LOG_VERSION "2.1"
|
||||
|
||||
namespace QsLogging
|
||||
{
|
||||
|
||||
class Destination;
|
||||
class LoggerImpl; // d pointer
|
||||
using DestinationPtrU = std::unique_ptr<Destination>;
|
||||
|
||||
class QSLOG_SHARED_OBJECT Logger
|
||||
{
|
||||
public:
|
||||
static Logger& instance();
|
||||
static void destroyInstance();
|
||||
static Level levelFromLogMessage(const QString& logMessage, bool* conversionSucceeded = 0);
|
||||
|
||||
~Logger();
|
||||
public:
|
||||
Logger(const Logger&) = delete;
|
||||
Logger& operator=(const Logger&) = delete;
|
||||
|
||||
~Logger() noexcept;
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
//! When QS_LOG_SEPARATE_THREAD is defined on Windows, and you are using this library as a DLL,
|
||||
//! this function must be called before your program ends, to ensure a clean shutdown of the logger thread.
|
||||
//! Failing to call it will result in an assert being triggered, an error message being printed
|
||||
//! out and most probably a deadlock.
|
||||
//! Returns the wait result for the thread. When called on a non-threaded logger returns true
|
||||
//! immediately.
|
||||
bool shutDownLoggerThread();
|
||||
#endif
|
||||
|
||||
//! Adds a log message destination. Don't add null destinations.
|
||||
void addDestination(DestinationPtr destination);
|
||||
//! Logging at a level < 'newLevel' will be ignored
|
||||
void addDestination(DestinationPtrU &&destination);
|
||||
|
||||
//! Removes and returns a previously added destination. Returns null if not found.
|
||||
DestinationPtrU removeDestination(const QString& type);
|
||||
|
||||
//! Checks if a destination of a specific type has been added. Pass T::Type as parameter.
|
||||
bool hasDestinationOfType(const char* type) const;
|
||||
|
||||
//! Messages at a level < 'newLevel' will be ignored
|
||||
void setLoggingLevel(Level newLevel);
|
||||
|
||||
//! The default level is INFO
|
||||
Level loggingLevel() const;
|
||||
|
||||
@ -62,12 +87,10 @@ public:
|
||||
explicit Helper(Level logLevel) :
|
||||
level(logLevel),
|
||||
qtDebug(&buffer) {}
|
||||
~Helper();
|
||||
~Helper() noexcept;
|
||||
QDebug& stream(){ return qtDebug; }
|
||||
|
||||
private:
|
||||
void writeToLog();
|
||||
|
||||
Level level;
|
||||
QString buffer;
|
||||
QDebug qtDebug;
|
||||
@ -75,15 +98,13 @@ public:
|
||||
|
||||
private:
|
||||
Logger();
|
||||
Logger(const Logger&); // not available
|
||||
Logger& operator=(const Logger&); // not available
|
||||
|
||||
void enqueueWrite(const QString& message, Level level);
|
||||
void write(const QString& message, Level level);
|
||||
void enqueueWrite(const LogMessage& message);
|
||||
void write(const LogMessage& message);
|
||||
|
||||
LoggerImpl* d;
|
||||
std::unique_ptr<LoggerImpl> d;
|
||||
|
||||
friend class LogWriterRunnable;
|
||||
friend class LoggerThread;
|
||||
};
|
||||
|
||||
} // end namespace
|
||||
|
27
third_party/QsLog/QsLog.pri
vendored
27
third_party/QsLog/QsLog.pri
vendored
@ -2,21 +2,40 @@ INCLUDEPATH += $$PWD
|
||||
#DEFINES += QS_LOG_LINE_NUMBERS # automatically writes the file and line for each log message
|
||||
#DEFINES += QS_LOG_DISABLE # logging code is replaced with a no-op
|
||||
#DEFINES += QS_LOG_SEPARATE_THREAD # messages are queued and written from a separate thread
|
||||
#DEFINES += QS_LOG_WIN_PRINTF_CONSOLE # Use fprintf instead of OutputDebugString on Windows
|
||||
#DEFINES += QS_LOG_WINDOW # allows easily showing log messages in a UI
|
||||
|
||||
contains(DEFINES, QS_LOG_WINDOW) {
|
||||
message("Will include log window destination")
|
||||
QT += gui
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
SOURCES += $$PWD/QsLogWindow.cpp \
|
||||
$$PWD/QsLogWindowModel.cpp
|
||||
HEADERS += $$PWD/QsLogWindow.h \
|
||||
$$PWD/QsLogWindowModel.h
|
||||
FORMS += $$PWD/QsLogWindow.ui
|
||||
RESOURCES += $$PWD/QsLogWindow.qrc
|
||||
}
|
||||
|
||||
SOURCES += $$PWD/QsLogDest.cpp \
|
||||
$$PWD/QsLog.cpp \
|
||||
$$PWD/QsLogDestConsole.cpp \
|
||||
$$PWD/QsLogDestFile.cpp \
|
||||
$$PWD/QsLogDestFunctor.cpp
|
||||
$$PWD/QsLogDestFunctor.cpp \
|
||||
$$PWD/QsLogMessage.cpp \
|
||||
$$PWD/QsLogLevel.cpp
|
||||
|
||||
HEADERS += $$PWD/QSLogDest.h \
|
||||
HEADERS += $$PWD/QsLogDest.h \
|
||||
$$PWD/QsLog.h \
|
||||
$$PWD/QsLogDestConsole.h \
|
||||
$$PWD/QsLogLevel.h \
|
||||
$$PWD/QsLogDestFile.h \
|
||||
$$PWD/QsLogDisableForThisFile.h \
|
||||
$$PWD/QsLogDestFunctor.h
|
||||
$$PWD/QsLogDestFunctor.h \
|
||||
$$PWD/QsLogMessage.h \
|
||||
$$PWD/QsLogSharedLibrary.h
|
||||
|
||||
OTHER_FILES += \
|
||||
$$PWD/QsLogChanges.txt \
|
||||
$$PWD/QsLogReadme.txt \
|
||||
$$PWD/README.md \
|
||||
$$PWD/LICENSE.txt
|
||||
|
69
third_party/QsLog/QsLogChanges.txt
vendored
Normal file
69
third_party/QsLog/QsLogChanges.txt
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
-------------------
|
||||
QsLog version 2.1
|
||||
|
||||
Changes:
|
||||
* Allowed checking if a destination of a certain type has already been added.
|
||||
* Allowed using fprintf instead of OutputDebugString on Windows.
|
||||
* Made building/running the example from QtCreator easier. Unfortunately I couldn't find a
|
||||
satisfactory way of doing this using pure qmake, so an env var is needed.
|
||||
* Added support for CMake builds (Qt5 only, courtesy of A.Gembe).
|
||||
|
||||
Fixes:
|
||||
* Fixed build for Qt < 5.4 (courtesy of P.Hille).
|
||||
|
||||
-------------------
|
||||
QsLog version 2.0
|
||||
|
||||
Changes:
|
||||
* Added possibility to remove destinations.
|
||||
* Added unit tests for rotation and destination removal.
|
||||
|
||||
Fixes:
|
||||
* Fixed rare codec error in combination with custom ICU.
|
||||
|
||||
-------------------
|
||||
QsLog version 2.0b4
|
||||
|
||||
Fixes:
|
||||
Fixed file name case error for Linux.
|
||||
|
||||
Misc:
|
||||
* Moved to separate git repository.
|
||||
|
||||
-------------------
|
||||
QsLog version 2.0b3
|
||||
|
||||
Changes:
|
||||
* added functor logging destination (thanks to Omar Carey for providing a patch)
|
||||
|
||||
-------------------
|
||||
QsLog version 2.0b2
|
||||
|
||||
Changes:
|
||||
* function signature redefinition for file destination creation
|
||||
* added shared library build configuration. Credit goes to Xavier Lamien <laxathom@fedoraproject.org>
|
||||
for the Linux-specific config.
|
||||
* removed Symbian support
|
||||
* this version does not guarantee support for Nokia N9 devices, although it should in theory still
|
||||
work with them
|
||||
* workaround for Issue 8 - when used from an executable and a plugin QsLog only logs from the
|
||||
executable.
|
||||
* utility function to parse the level from an existing log message
|
||||
|
||||
Known issues:
|
||||
* The current version will crash at program exit when using QS_LOG_SEPARATE_THREAD and linking
|
||||
with QsLog dynamically.
|
||||
|
||||
-------------------
|
||||
QsLog version 2.0b1
|
||||
|
||||
Changes:
|
||||
* destination pointers use shared pointer semantics
|
||||
* the file destination supports log rotation. As a consequence, log files are encoded as UTF-8 and
|
||||
the log appends rather than truncating on every startup when rotation is enabled.
|
||||
* added the posibility of disabling logging either at run time or compile time.
|
||||
* added the possibility of using a separate thread for writing to the log destinations.
|
||||
|
||||
Fixes:
|
||||
* renamed the main.cpp example to avoid QtCreator confusion
|
||||
* offer a way to check if the destination creation has failed (for e.g files)
|
26
third_party/QsLog/QsLogDest.cpp
vendored
26
third_party/QsLog/QsLogDest.cpp
vendored
@ -32,39 +32,37 @@
|
||||
namespace QsLogging
|
||||
{
|
||||
|
||||
Destination::~Destination()
|
||||
{
|
||||
}
|
||||
Destination::~Destination() noexcept = default;
|
||||
|
||||
//! destination factory
|
||||
DestinationPtr DestinationFactory::MakeFileDestination(const QString& filePath,
|
||||
DestinationPtrU DestinationFactory::MakeFileDestination(const QString& filePath,
|
||||
LogRotationOption rotation, const MaxSizeBytes &sizeInBytesToRotateAfter,
|
||||
const MaxOldLogCount &oldLogsToKeep)
|
||||
{
|
||||
if (EnableLogRotation == rotation) {
|
||||
QScopedPointer<SizeRotationStrategy> logRotation(new SizeRotationStrategy);
|
||||
if (LogRotationOption::EnableLogRotation == rotation) {
|
||||
std::unique_ptr<SizeRotationStrategy> logRotation(new SizeRotationStrategy);
|
||||
logRotation->setMaximumSizeInBytes(sizeInBytesToRotateAfter.size);
|
||||
logRotation->setBackupCount(oldLogsToKeep.count);
|
||||
|
||||
return DestinationPtr(new FileDestination(filePath, RotationStrategyPtr(logRotation.take())));
|
||||
return DestinationPtrU(new FileDestination(filePath, std::move(logRotation)));
|
||||
}
|
||||
|
||||
return DestinationPtr(new FileDestination(filePath, RotationStrategyPtr(new NullRotationStrategy)));
|
||||
return DestinationPtrU(new FileDestination(filePath, RotationStrategyPtrU(new NullRotationStrategy)));
|
||||
}
|
||||
|
||||
DestinationPtr DestinationFactory::MakeDebugOutputDestination()
|
||||
DestinationPtrU DestinationFactory::MakeDebugOutputDestination()
|
||||
{
|
||||
return DestinationPtr(new DebugOutputDestination);
|
||||
return DestinationPtrU(new DebugOutputDestination);
|
||||
}
|
||||
|
||||
DestinationPtr DestinationFactory::MakeFunctorDestination(QsLogging::Destination::LogFunction f)
|
||||
DestinationPtrU DestinationFactory::MakeFunctorDestination(QsLogging::Destination::LogFunction f)
|
||||
{
|
||||
return DestinationPtr(new FunctorDestination(f));
|
||||
return DestinationPtrU(new FunctorDestination(f));
|
||||
}
|
||||
|
||||
DestinationPtr DestinationFactory::MakeFunctorDestination(QObject *receiver, const char *member)
|
||||
DestinationPtrU DestinationFactory::MakeFunctorDestination(QObject *receiver, const char *member)
|
||||
{
|
||||
return DestinationPtr(new FunctorDestination(receiver, member));
|
||||
return DestinationPtrU(new FunctorDestination(receiver, member));
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
51
third_party/QsLog/QsLogDest.h
vendored
51
third_party/QsLog/QsLogDest.h
vendored
@ -27,37 +27,44 @@
|
||||
#define QSLOGDEST_H
|
||||
|
||||
#include "QsLogLevel.h"
|
||||
#include <QSharedPointer>
|
||||
#include "QsLogMessage.h"
|
||||
#include "QsLogSharedLibrary.h"
|
||||
#include <QtGlobal>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
class QString;
|
||||
class QObject;
|
||||
|
||||
#ifdef QSLOG_IS_SHARED_LIBRARY
|
||||
#define QSLOG_SHARED_OBJECT Q_DECL_EXPORT
|
||||
#elif QSLOG_IS_SHARED_LIBRARY_IMPORT
|
||||
#define QSLOG_SHARED_OBJECT Q_DECL_IMPORT
|
||||
#else
|
||||
#define QSLOG_SHARED_OBJECT
|
||||
#endif
|
||||
|
||||
namespace QsLogging
|
||||
{
|
||||
|
||||
class QSLOG_SHARED_OBJECT Destination
|
||||
{
|
||||
public:
|
||||
typedef void (*LogFunction)(const QString &message, Level level);
|
||||
using LogFunction = std::function<void(const LogMessage& message)>;
|
||||
|
||||
public:
|
||||
virtual ~Destination();
|
||||
virtual void write(const QString& message, Level level) = 0;
|
||||
virtual bool isValid() = 0; // returns whether the destination was created correctly
|
||||
virtual ~Destination() noexcept;
|
||||
virtual void write(const LogMessage& message) = 0;
|
||||
//!
|
||||
//! \brief isValid
|
||||
//! \return whether the destination was created correctly
|
||||
//!
|
||||
virtual bool isValid() = 0;
|
||||
//!
|
||||
//! \brief type
|
||||
//! \return the type as a string e.g: console, file.
|
||||
//! The returned value may change in different versions of QsLog, but two destinations
|
||||
//! of the same type will return the same value.
|
||||
//!
|
||||
virtual QString type() const = 0;
|
||||
};
|
||||
typedef QSharedPointer<Destination> DestinationPtr;
|
||||
|
||||
using DestinationPtrU = std::unique_ptr<Destination>;
|
||||
|
||||
// a series of "named" paramaters, to make the file destination creation more readable
|
||||
enum LogRotationOption
|
||||
enum class LogRotationOption
|
||||
{
|
||||
DisableLogRotation = 0,
|
||||
EnableLogRotation = 1
|
||||
@ -78,20 +85,20 @@ struct QSLOG_SHARED_OBJECT MaxOldLogCount
|
||||
};
|
||||
|
||||
|
||||
//! Creates logging destinations/sinks. The caller shares ownership of the destinations with the logger.
|
||||
//! After being added to a logger, the caller can discard the pointers.
|
||||
//! Creates logging destinations/sinks. The caller takes ownership of the destinations from the
|
||||
//! factory and will pass ownership to the logger when adding the destination.
|
||||
class QSLOG_SHARED_OBJECT DestinationFactory
|
||||
{
|
||||
public:
|
||||
static DestinationPtr MakeFileDestination(const QString& filePath,
|
||||
LogRotationOption rotation = DisableLogRotation,
|
||||
static DestinationPtrU MakeFileDestination(const QString& filePath,
|
||||
LogRotationOption rotation = LogRotationOption::DisableLogRotation,
|
||||
const MaxSizeBytes &sizeInBytesToRotateAfter = MaxSizeBytes(),
|
||||
const MaxOldLogCount &oldLogsToKeep = MaxOldLogCount());
|
||||
static DestinationPtr MakeDebugOutputDestination();
|
||||
static DestinationPtrU MakeDebugOutputDestination();
|
||||
// takes a pointer to a function
|
||||
static DestinationPtr MakeFunctorDestination(Destination::LogFunction f);
|
||||
static DestinationPtrU MakeFunctorDestination(Destination::LogFunction f);
|
||||
// takes a QObject + signal/slot
|
||||
static DestinationPtr MakeFunctorDestination(QObject *receiver, const char *member);
|
||||
static DestinationPtrU MakeFunctorDestination(QObject* receiver, const char* member);
|
||||
};
|
||||
|
||||
} // end namespace
|
||||
|
29
third_party/QsLog/QsLogDestConsole.cpp
vendored
29
third_party/QsLog/QsLogDestConsole.cpp
vendored
@ -27,29 +27,36 @@
|
||||
#include <QString>
|
||||
#include <QtGlobal>
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
void QsDebugOutput::output( const QString& message )
|
||||
{
|
||||
OutputDebugStringW(reinterpret_cast<const WCHAR*>(message.utf16()));
|
||||
OutputDebugStringW(L"\n");
|
||||
}
|
||||
#elif defined(Q_OS_UNIX)
|
||||
#if defined(Q_OS_UNIX) || defined(Q_OS_WIN) && defined(QS_LOG_WIN_PRINTF_CONSOLE)
|
||||
#include <cstdio>
|
||||
void QsDebugOutput::output( const QString& message )
|
||||
{
|
||||
fprintf(stderr, "%s\n", qPrintable(message));
|
||||
fflush(stderr);
|
||||
}
|
||||
#elif defined(Q_OS_WIN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
void QsDebugOutput::output( const QString& message )
|
||||
{
|
||||
OutputDebugStringW(reinterpret_cast<const WCHAR*>(message.utf16()));
|
||||
OutputDebugStringW(L"\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
void QsLogging::DebugOutputDestination::write(const QString& message, Level)
|
||||
const char* const QsLogging::DebugOutputDestination::Type = "console";
|
||||
|
||||
void QsLogging::DebugOutputDestination::write(const LogMessage& message)
|
||||
{
|
||||
QsDebugOutput::output(message);
|
||||
QsDebugOutput::output(message.formatted);
|
||||
}
|
||||
|
||||
bool QsLogging::DebugOutputDestination::isValid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QString QsLogging::DebugOutputDestination::type() const
|
||||
{
|
||||
return QString::fromLatin1(Type);
|
||||
}
|
||||
|
10
third_party/QsLog/QsLogDestConsole.h
vendored
10
third_party/QsLog/QsLogDestConsole.h
vendored
@ -27,7 +27,6 @@
|
||||
#define QSLOGDESTCONSOLE_H
|
||||
|
||||
#include "QsLogDest.h"
|
||||
|
||||
class QString;
|
||||
|
||||
class QsDebugOutput
|
||||
@ -40,11 +39,14 @@ namespace QsLogging
|
||||
{
|
||||
|
||||
// debugger sink
|
||||
class DebugOutputDestination : public Destination
|
||||
class QSLOG_SHARED_OBJECT DebugOutputDestination : public Destination
|
||||
{
|
||||
public:
|
||||
virtual void write(const QString& message, Level level);
|
||||
virtual bool isValid();
|
||||
static const char* const Type;
|
||||
|
||||
void write(const LogMessage& message) override;
|
||||
bool isValid() override;
|
||||
QString type() const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
85
third_party/QsLog/QsLogDestFile.cpp
vendored
85
third_party/QsLog/QsLogDestFile.cpp
vendored
@ -26,21 +26,13 @@
|
||||
#include "QsLogDestFile.h"
|
||||
#include <QTextCodec>
|
||||
#include <QDateTime>
|
||||
#include <QString>
|
||||
#include <QtGlobal>
|
||||
#include <iostream>
|
||||
|
||||
const int QsLogging::SizeRotationStrategy::MaxBackupCount = 10;
|
||||
|
||||
QsLogging::RotationStrategy::~RotationStrategy()
|
||||
{
|
||||
}
|
||||
|
||||
QsLogging::SizeRotationStrategy::SizeRotationStrategy()
|
||||
: mCurrentSizeInBytes(0)
|
||||
, mMaxSizeInBytes(0)
|
||||
, mBackupsCount(0)
|
||||
{
|
||||
}
|
||||
QsLogging::RotationStrategy::~RotationStrategy() noexcept = default;
|
||||
|
||||
void QsLogging::SizeRotationStrategy::setInitialInfo(const QFile &file)
|
||||
{
|
||||
@ -48,9 +40,20 @@ void QsLogging::SizeRotationStrategy::setInitialInfo(const QFile &file)
|
||||
mCurrentSizeInBytes = file.size();
|
||||
}
|
||||
|
||||
void QsLogging::SizeRotationStrategy::setInitialInfo(const QString &filePath, int fileSize)
|
||||
{
|
||||
mFileName = filePath;
|
||||
mCurrentSizeInBytes = fileSize;
|
||||
}
|
||||
|
||||
void QsLogging::SizeRotationStrategy::includeMessageInCalculation(const QString &message)
|
||||
{
|
||||
mCurrentSizeInBytes += message.toUtf8().size();
|
||||
includeMessageInCalculation(message.toUtf8());
|
||||
}
|
||||
|
||||
void QsLogging::SizeRotationStrategy::includeMessageInCalculation(const QByteArray &message)
|
||||
{
|
||||
mCurrentSizeInBytes += message.size();
|
||||
}
|
||||
|
||||
bool QsLogging::SizeRotationStrategy::shouldRotate()
|
||||
@ -63,8 +66,9 @@ bool QsLogging::SizeRotationStrategy::shouldRotate()
|
||||
void QsLogging::SizeRotationStrategy::rotate()
|
||||
{
|
||||
if (!mBackupsCount) {
|
||||
if (!QFile::remove(mFileName))
|
||||
if (!removeFileAtPath(mFileName)) {
|
||||
std::cerr << "QsLog: backup delete failed " << qPrintable(mFileName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -73,18 +77,19 @@ void QsLogging::SizeRotationStrategy::rotate()
|
||||
int lastExistingBackupIndex = 0;
|
||||
for (int i = 1;i <= mBackupsCount;++i) {
|
||||
const QString backupFileName = logNamePattern.arg(i);
|
||||
if (QFile::exists(backupFileName))
|
||||
if (fileExistsAtPath(backupFileName)) {
|
||||
lastExistingBackupIndex = qMin(i, mBackupsCount - 1);
|
||||
else
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. shift up
|
||||
for (int i = lastExistingBackupIndex;i >= 1;--i) {
|
||||
const QString oldName = logNamePattern.arg(i);
|
||||
const QString newName = logNamePattern.arg(i + 1);
|
||||
QFile::remove(newName);
|
||||
const bool renamed = QFile::rename(oldName, newName);
|
||||
removeFileAtPath(newName);
|
||||
const bool renamed = renameFileFromTo(oldName, newName);
|
||||
if (!renamed) {
|
||||
std::cerr << "QsLog: could not rename backup " << qPrintable(oldName)
|
||||
<< " to " << qPrintable(newName);
|
||||
@ -93,9 +98,10 @@ void QsLogging::SizeRotationStrategy::rotate()
|
||||
|
||||
// 3. rename current log file
|
||||
const QString newName = logNamePattern.arg(1);
|
||||
if (QFile::exists(newName))
|
||||
QFile::remove(newName);
|
||||
if (!QFile::rename(mFileName, newName)) {
|
||||
if (fileExistsAtPath(newName)) {
|
||||
removeFileAtPath(newName);
|
||||
}
|
||||
if (!renameFileFromTo(mFileName, newName)) {
|
||||
std::cerr << "QsLog: could not rename log " << qPrintable(mFileName)
|
||||
<< " to " << qPrintable(newName);
|
||||
}
|
||||
@ -118,33 +124,53 @@ void QsLogging::SizeRotationStrategy::setBackupCount(int backups)
|
||||
mBackupsCount = qMin(backups, SizeRotationStrategy::MaxBackupCount);
|
||||
}
|
||||
|
||||
bool QsLogging::SizeRotationStrategy::removeFileAtPath(const QString &path)
|
||||
{
|
||||
return QFile::remove(path);
|
||||
}
|
||||
|
||||
QsLogging::FileDestination::FileDestination(const QString& filePath, RotationStrategyPtr rotationStrategy)
|
||||
: mRotationStrategy(rotationStrategy)
|
||||
bool QsLogging::SizeRotationStrategy::fileExistsAtPath(const QString &path)
|
||||
{
|
||||
return QFile::exists(path);
|
||||
}
|
||||
|
||||
bool QsLogging::SizeRotationStrategy::renameFileFromTo(const QString &from, const QString &to)
|
||||
{
|
||||
return QFile::rename(from, to);
|
||||
}
|
||||
|
||||
const char* const QsLogging::FileDestination::Type = "file";
|
||||
|
||||
QsLogging::FileDestination::FileDestination(const QString& filePath, RotationStrategyPtrU&& rotationStrategy)
|
||||
: mRotationStrategy(std::move(rotationStrategy))
|
||||
{
|
||||
mFile.setFileName(filePath);
|
||||
if (!mFile.open(QFile::WriteOnly | QFile::Text | mRotationStrategy->recommendedOpenModeFlag()))
|
||||
if (!mFile.open(QFile::WriteOnly | QFile::Text | mRotationStrategy->recommendedOpenModeFlag())) {
|
||||
std::cerr << "QsLog: could not open log file " << qPrintable(filePath);
|
||||
}
|
||||
mOutputStream.setDevice(&mFile);
|
||||
mOutputStream.setCodec(QTextCodec::codecForName("UTF-8"));
|
||||
|
||||
mRotationStrategy->setInitialInfo(mFile);
|
||||
}
|
||||
|
||||
void QsLogging::FileDestination::write(const QString& message, Level)
|
||||
void QsLogging::FileDestination::write(const LogMessage& message)
|
||||
{
|
||||
mRotationStrategy->includeMessageInCalculation(message);
|
||||
const QByteArray utf8Message = message.formatted.toUtf8();
|
||||
mRotationStrategy->includeMessageInCalculation(utf8Message);
|
||||
if (mRotationStrategy->shouldRotate()) {
|
||||
mOutputStream.setDevice(NULL);
|
||||
mOutputStream.setDevice(nullptr);
|
||||
mFile.close();
|
||||
mRotationStrategy->rotate();
|
||||
if (!mFile.open(QFile::WriteOnly | QFile::Text | mRotationStrategy->recommendedOpenModeFlag()))
|
||||
if (!mFile.open(QFile::WriteOnly | QFile::Text | mRotationStrategy->recommendedOpenModeFlag())) {
|
||||
std::cerr << "QsLog: could not reopen log file " << qPrintable(mFile.fileName());
|
||||
}
|
||||
mRotationStrategy->setInitialInfo(mFile);
|
||||
mOutputStream.setDevice(&mFile);
|
||||
mOutputStream.setCodec(QTextCodec::codecForName("UTF-8"));
|
||||
}
|
||||
|
||||
mOutputStream << message << endl;
|
||||
mOutputStream << utf8Message << endl;
|
||||
mOutputStream.flush();
|
||||
}
|
||||
|
||||
@ -153,3 +179,8 @@ bool QsLogging::FileDestination::isValid()
|
||||
return mFile.isOpen();
|
||||
}
|
||||
|
||||
QString QsLogging::FileDestination::type() const
|
||||
{
|
||||
return QString::fromLatin1(Type);
|
||||
}
|
||||
|
||||
|
71
third_party/QsLog/QsLogDestFile.h
vendored
71
third_party/QsLog/QsLogDestFile.h
vendored
@ -29,71 +29,92 @@
|
||||
#include "QsLogDest.h"
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
#include <QtGlobal>
|
||||
#include <QSharedPointer>
|
||||
#include <memory>
|
||||
|
||||
namespace QsLogging
|
||||
{
|
||||
class RotationStrategy
|
||||
class QSLOG_SHARED_OBJECT RotationStrategy
|
||||
{
|
||||
public:
|
||||
virtual ~RotationStrategy();
|
||||
virtual ~RotationStrategy() noexcept;
|
||||
|
||||
virtual void setInitialInfo(const QFile &file) = 0;
|
||||
virtual void includeMessageInCalculation(const QString &message) = 0;
|
||||
virtual void includeMessageInCalculation(const QByteArray &message) = 0;
|
||||
virtual bool shouldRotate() = 0;
|
||||
virtual void rotate() = 0;
|
||||
virtual QIODevice::OpenMode recommendedOpenModeFlag() = 0;
|
||||
};
|
||||
|
||||
// Never rotates file, overwrites existing file.
|
||||
class NullRotationStrategy : public RotationStrategy
|
||||
class QSLOG_SHARED_OBJECT NullRotationStrategy : public RotationStrategy
|
||||
{
|
||||
public:
|
||||
virtual void setInitialInfo(const QFile &) {}
|
||||
virtual void includeMessageInCalculation(const QString &) {}
|
||||
virtual bool shouldRotate() { return false; }
|
||||
virtual void rotate() {}
|
||||
virtual QIODevice::OpenMode recommendedOpenModeFlag() { return QIODevice::Truncate; }
|
||||
void setInitialInfo(const QFile &) override {}
|
||||
void includeMessageInCalculation(const QString &) override {}
|
||||
void includeMessageInCalculation(const QByteArray &) override {}
|
||||
bool shouldRotate() override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void rotate() override {}
|
||||
QIODevice::OpenMode recommendedOpenModeFlag() override
|
||||
{
|
||||
return QIODevice::Truncate;
|
||||
}
|
||||
};
|
||||
|
||||
// Rotates after a size is reached, keeps a number of <= 10 backups, appends to existing file.
|
||||
class SizeRotationStrategy : public RotationStrategy
|
||||
class QSLOG_SHARED_OBJECT SizeRotationStrategy : public RotationStrategy
|
||||
{
|
||||
public:
|
||||
SizeRotationStrategy();
|
||||
SizeRotationStrategy() = default;
|
||||
static const int MaxBackupCount;
|
||||
|
||||
virtual void setInitialInfo(const QFile &file);
|
||||
virtual void includeMessageInCalculation(const QString &message);
|
||||
virtual bool shouldRotate();
|
||||
virtual void rotate();
|
||||
virtual QIODevice::OpenMode recommendedOpenModeFlag();
|
||||
void setInitialInfo(const QFile &file) override;
|
||||
void setInitialInfo(const QString& filePath, int fileSize);
|
||||
void includeMessageInCalculation(const QString &message) override;
|
||||
void includeMessageInCalculation(const QByteArray &message) override;
|
||||
bool shouldRotate() override;
|
||||
void rotate() override;
|
||||
QIODevice::OpenMode recommendedOpenModeFlag() override;
|
||||
|
||||
void setMaximumSizeInBytes(qint64 size);
|
||||
void setBackupCount(int backups);
|
||||
|
||||
protected:
|
||||
// can be overridden for testing
|
||||
virtual bool removeFileAtPath(const QString& path);
|
||||
virtual bool fileExistsAtPath(const QString& path);
|
||||
virtual bool renameFileFromTo(const QString& from, const QString& to);
|
||||
|
||||
private:
|
||||
QString mFileName;
|
||||
qint64 mCurrentSizeInBytes;
|
||||
qint64 mMaxSizeInBytes;
|
||||
int mBackupsCount;
|
||||
qint64 mCurrentSizeInBytes{0};
|
||||
qint64 mMaxSizeInBytes{0};
|
||||
int mBackupsCount{0};
|
||||
};
|
||||
|
||||
typedef QSharedPointer<RotationStrategy> RotationStrategyPtr;
|
||||
using RotationStrategyPtrU = std::unique_ptr<RotationStrategy>;
|
||||
|
||||
// file message sink
|
||||
class FileDestination : public Destination
|
||||
class QSLOG_SHARED_OBJECT FileDestination : public Destination
|
||||
{
|
||||
public:
|
||||
FileDestination(const QString& filePath, RotationStrategyPtr rotationStrategy);
|
||||
virtual void write(const QString& message, Level level);
|
||||
virtual bool isValid();
|
||||
static const char* const Type;
|
||||
|
||||
FileDestination(const QString& filePath, RotationStrategyPtrU &&rotationStrategy);
|
||||
void write(const LogMessage& message) override;
|
||||
bool isValid() override;
|
||||
QString type() const override;
|
||||
|
||||
private:
|
||||
QFile mFile;
|
||||
QTextStream mOutputStream;
|
||||
QSharedPointer<RotationStrategy> mRotationStrategy;
|
||||
RotationStrategyPtrU mRotationStrategy;
|
||||
};
|
||||
|
||||
}
|
||||
|
25
third_party/QsLog/QsLogDestFunctor.cpp
vendored
25
third_party/QsLog/QsLogDestFunctor.cpp
vendored
@ -27,31 +27,40 @@
|
||||
#include "QsLogDestFunctor.h"
|
||||
#include <cstddef>
|
||||
#include <QtGlobal>
|
||||
#include <QString>
|
||||
|
||||
const char* const QsLogging::FunctorDestination::Type = "functor";
|
||||
|
||||
QsLogging::FunctorDestination::FunctorDestination(LogFunction f)
|
||||
: QObject(NULL)
|
||||
: QObject(nullptr)
|
||||
, mLogFunction(f)
|
||||
{
|
||||
}
|
||||
|
||||
QsLogging::FunctorDestination::FunctorDestination(QObject* receiver, const char* member)
|
||||
: QObject(NULL)
|
||||
, mLogFunction(NULL)
|
||||
: QObject(nullptr)
|
||||
, mLogFunction(nullptr)
|
||||
{
|
||||
connect(this, SIGNAL(logMessageReady(QString,int)), receiver, member, Qt::QueuedConnection);
|
||||
connect(this, SIGNAL(logMessageReady(QsLogging::LogMessage)),
|
||||
receiver, member, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
|
||||
void QsLogging::FunctorDestination::write(const QString &message, QsLogging::Level level)
|
||||
void QsLogging::FunctorDestination::write(const LogMessage& message)
|
||||
{
|
||||
if (mLogFunction)
|
||||
mLogFunction(message, level);
|
||||
mLogFunction(message);
|
||||
|
||||
if (level > QsLogging::TraceLevel)
|
||||
emit logMessageReady(message, static_cast<int>(level));
|
||||
if (message.level > QsLogging::TraceLevel)
|
||||
emit logMessageReady(message);
|
||||
}
|
||||
|
||||
bool QsLogging::FunctorDestination::isValid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QString QsLogging::FunctorDestination::type() const
|
||||
{
|
||||
return QString::fromLatin1(Type);
|
||||
}
|
||||
|
11
third_party/QsLog/QsLogDestFunctor.h
vendored
11
third_party/QsLog/QsLogDestFunctor.h
vendored
@ -37,19 +37,22 @@ namespace QsLogging
|
||||
// called from a different thread or even a different binary. You should not access QsLog from
|
||||
// inside LogFunction and should not perform any time-consuming operations.
|
||||
// logMessageReady is connected through a queued connection and trace messages are not included
|
||||
class FunctorDestination : public QObject, public Destination
|
||||
class QSLOG_SHARED_OBJECT FunctorDestination : public QObject, public Destination
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static const char* const Type;
|
||||
|
||||
explicit FunctorDestination(LogFunction f);
|
||||
FunctorDestination(QObject* receiver, const char* member);
|
||||
|
||||
virtual void write(const QString &message, Level level);
|
||||
virtual bool isValid();
|
||||
void write(const LogMessage& message) override;
|
||||
bool isValid() override;
|
||||
QString type() const override;
|
||||
|
||||
protected:
|
||||
// int used to avoid registering a new enum type
|
||||
Q_SIGNAL void logMessageReady(const QString &message, int level);
|
||||
Q_SIGNAL void logMessageReady(const QsLogging::LogMessage& message);
|
||||
|
||||
private:
|
||||
LogFunction mLogFunction;
|
||||
|
9
third_party/QsLog/QsLogDisableForThisFile.h
vendored
9
third_party/QsLog/QsLogDisableForThisFile.h
vendored
@ -1,9 +1,14 @@
|
||||
#ifndef QSLOGDISABLEFORTHISFILE_H
|
||||
#define QSLOGDISABLEFORTHISFILE_H
|
||||
|
||||
// When included after all includes of QsLog.h (direct and indirect includes through other headers)
|
||||
// this file will disable logging in that translation unit.
|
||||
|
||||
#ifndef QLOG_TRACE
|
||||
#error "This file must be included after QsLog.h"
|
||||
#endif
|
||||
|
||||
#include <QtDebug>
|
||||
// When included AFTER QsLog.h, this file will disable logging in that C++ file. When included
|
||||
// before, it will lead to compiler warnings or errors about macro redefinitions.
|
||||
|
||||
#undef QLOG_TRACE
|
||||
#undef QLOG_DEBUG
|
||||
|
55
third_party/QsLog/QsLogLevel.cpp
vendored
Normal file
55
third_party/QsLog/QsLogLevel.cpp
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
#include "QsLogLevel.h"
|
||||
#include <QString>
|
||||
#include <QObject>
|
||||
#include <cassert>
|
||||
|
||||
static const char TraceString[] = "TRACE";
|
||||
static const char DebugString[] = "DEBUG";
|
||||
static const char InfoString[] = "INFO ";
|
||||
static const char WarnString[] = "WARN ";
|
||||
static const char ErrorString[] = "ERROR";
|
||||
static const char FatalString[] = "FATAL";
|
||||
|
||||
const char* QsLogging::LevelName(QsLogging::Level theLevel)
|
||||
{
|
||||
switch (theLevel) {
|
||||
case QsLogging::TraceLevel:
|
||||
return TraceString;
|
||||
case QsLogging::DebugLevel:
|
||||
return DebugString;
|
||||
case QsLogging::InfoLevel:
|
||||
return InfoString;
|
||||
case QsLogging::WarnLevel:
|
||||
return WarnString;
|
||||
case QsLogging::ErrorLevel:
|
||||
return ErrorString;
|
||||
case QsLogging::FatalLevel:
|
||||
return FatalString;
|
||||
case QsLogging::OffLevel:
|
||||
return "";
|
||||
default: {
|
||||
Q_ASSERT(!"bad log level");
|
||||
return InfoString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString QsLogging::LocalizedLevelName(QsLogging::Level theLevel)
|
||||
{
|
||||
switch (theLevel) {
|
||||
case QsLogging::TraceLevel:
|
||||
return QObject::tr("Trace");
|
||||
case QsLogging::DebugLevel:
|
||||
return QObject::tr("Debug");
|
||||
case QsLogging::InfoLevel:
|
||||
return QObject::tr("Info");
|
||||
case QsLogging::WarnLevel:
|
||||
return QObject::tr("Warning");
|
||||
case QsLogging::ErrorLevel:
|
||||
return QObject::tr("Error");
|
||||
case QsLogging::FatalLevel:
|
||||
return QObject::tr("Fatal");
|
||||
default:
|
||||
return QString();
|
||||
}
|
||||
}
|
5
third_party/QsLog/QsLogLevel.h
vendored
5
third_party/QsLog/QsLogLevel.h
vendored
@ -25,10 +25,10 @@
|
||||
|
||||
#ifndef QSLOGLEVEL_H
|
||||
#define QSLOGLEVEL_H
|
||||
class QString;
|
||||
|
||||
namespace QsLogging
|
||||
{
|
||||
|
||||
enum Level
|
||||
{
|
||||
TraceLevel = 0,
|
||||
@ -40,6 +40,9 @@ enum Level
|
||||
OffLevel
|
||||
};
|
||||
|
||||
const char* LevelName(Level theLevel);
|
||||
QString LocalizedLevelName(Level theLevel);
|
||||
|
||||
}
|
||||
|
||||
#endif // QSLOGLEVEL_H
|
||||
|
46
third_party/QsLog/QsLogMessage.cpp
vendored
Normal file
46
third_party/QsLog/QsLogMessage.cpp
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2015, Axel Gembe <axel@gembe.net>
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
// list of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
// * The name of the contributors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "QsLogMessage.h"
|
||||
#include "QsLogLevel.h"
|
||||
|
||||
namespace QsLogging
|
||||
{
|
||||
|
||||
// not using Qt::ISODate because we need the milliseconds too
|
||||
static const char DateTimePattern[] = "yyyy-MM-ddThh:mm:ss.zzz";
|
||||
|
||||
LogMessage::LogMessage(const QString& m, const QDateTime& t, const Level l)
|
||||
: message(m)
|
||||
, time(t)
|
||||
, level(l)
|
||||
, formatted(QString("%1 %2 %3").arg(LevelName(level))
|
||||
.arg(t.toLocalTime().toString(DateTimePattern))
|
||||
.arg(message))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
57
third_party/QsLog/QsLogMessage.h
vendored
Normal file
57
third_party/QsLog/QsLogMessage.h
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2015, Axel Gembe <axel@gembe.net>
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
// list of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
// * The name of the contributors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef QSLOGMESSAGE_H
|
||||
#define QSLOGMESSAGE_H
|
||||
|
||||
#include "QsLogLevel.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
|
||||
namespace QsLogging
|
||||
{
|
||||
|
||||
struct LogMessage
|
||||
{
|
||||
LogMessage() = default; // Needs to be accessible for qRegisterMetaType
|
||||
LogMessage(const QString& m, const QDateTime& t, const Level l); // Construct and format message
|
||||
|
||||
//! Log message
|
||||
QString message;
|
||||
|
||||
//! Time stamp in UTC, use .toLocalTime() to get local time
|
||||
QDateTime time;
|
||||
|
||||
//! Log level
|
||||
Level level;
|
||||
|
||||
//! Formatted log message ([level] [time] [message])
|
||||
const QString formatted;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QSLOGMESSAGE_H
|
12
third_party/QsLog/QsLogSharedLibrary.h
vendored
Normal file
12
third_party/QsLog/QsLogSharedLibrary.h
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef QSSHAREDLIBRARY_H
|
||||
#define QSSHAREDLIBRARY_H
|
||||
|
||||
#ifdef QSLOG_IS_SHARED_LIBRARY
|
||||
#define QSLOG_SHARED_OBJECT Q_DECL_EXPORT
|
||||
#elif QSLOG_IS_SHARED_LIBRARY_IMPORT
|
||||
#define QSLOG_SHARED_OBJECT Q_DECL_IMPORT
|
||||
#else
|
||||
#define QSLOG_SHARED_OBJECT
|
||||
#endif
|
||||
|
||||
#endif // QSSHAREDLIBRARY_H
|
25
third_party/QsLog/QsLogSharedLibrary.pro
vendored
25
third_party/QsLog/QsLogSharedLibrary.pro
vendored
@ -1,32 +1,43 @@
|
||||
# This pro file will build QsLog as a shared library
|
||||
include(QsLog.pri)
|
||||
|
||||
TARGET = QsLog
|
||||
VERSION = "2.0.0"
|
||||
VERSION = "2.1.0"
|
||||
QT -= gui
|
||||
CONFIG -= console
|
||||
CONFIG -= app_bundle
|
||||
CONFIG += shared
|
||||
CONFIG += c++11
|
||||
TEMPLATE = lib
|
||||
|
||||
DESTDIR = $$PWD/build-QsLogShared
|
||||
OBJECTS_DIR = $$DESTDIR/obj
|
||||
MOC_DIR = $$DESTDIR/moc
|
||||
QSLOG_DESTDIR=$$(QSLOG_DESTDIR)
|
||||
!isEmpty(QSLOG_DESTDIR) {
|
||||
message(Will use $${QSLOG_DESTDIR} as destdir.)
|
||||
DESTDIR = $${QSLOG_DESTDIR}/bin
|
||||
OBJECTS_DIR = $${QSLOG_DESTDIR}
|
||||
MOC_DIR = $${QSLOG_DESTDIR}
|
||||
UI_DIR = $${QSLOG_DESTDIR}
|
||||
RCC_DIR = $${QSLOG_DESTDIR}
|
||||
}
|
||||
|
||||
win32 {
|
||||
DEFINES += QSLOG_IS_SHARED_LIBRARY
|
||||
}
|
||||
|
||||
include(QsLog.pri)
|
||||
|
||||
unix:!macx {
|
||||
DISTRO = $$system(uname -a)
|
||||
|
||||
# make install will install the shared object in the appropriate folders
|
||||
headers.files = QsLog.h QsLogDest.h QsLogLevel.h
|
||||
headers.path = /usr/include/$(QMAKE_TARGET)
|
||||
|
||||
other_files.files = *.txt
|
||||
other_files.files = LICENSE.txt QsLogChanges.txt README.md
|
||||
other_files.path = /usr/local/share/$(QMAKE_TARGET)
|
||||
contains(DISTRO, .*ARCH): other_files.path = /usr/share/$(QMAKE_TARGET)
|
||||
|
||||
contains(QT_ARCH, x86_64) {
|
||||
target.path = /usr/lib64
|
||||
contains(DISTRO, .*ARCH): target.path = /usr/lib
|
||||
} else {
|
||||
target.path = /usr/lib
|
||||
}
|
||||
|
277
third_party/QsLog/QsLogWindow.cpp
vendored
Normal file
277
third_party/QsLog/QsLogWindow.cpp
vendored
Normal file
@ -0,0 +1,277 @@
|
||||
// Copyright (c) 2015, Axel Gembe <axel@gembe.net>
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
// list of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
// * The name of the contributors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "QsLogWindow.h"
|
||||
#include "QsLogWindowModel.h"
|
||||
#include "QsLog.h"
|
||||
#include "QsLogMessage.h"
|
||||
#include "ui_QsLogWindow.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QClipboard>
|
||||
#include <QKeyEvent>
|
||||
#include <QFileDialog>
|
||||
#include <QtGlobal>
|
||||
#include <cstddef>
|
||||
|
||||
static const QIcon& pauseIcon()
|
||||
{
|
||||
static QIcon icon(QString::fromLatin1(":/QsLogWindow/images/icon-pause-16.png"));
|
||||
return icon;
|
||||
}
|
||||
|
||||
static const QIcon& playIcon()
|
||||
{
|
||||
static QIcon icon(QString::fromLatin1(":/QsLogWindow/images/icon-resume-16.png"));
|
||||
return icon;
|
||||
}
|
||||
|
||||
|
||||
class QsLogging::WindowLogFilterProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
WindowLogFilterProxyModel(Level level, QObject* parent = 0)
|
||||
: QSortFilterProxyModel(parent)
|
||||
, mLevel(level)
|
||||
, mLastVisibleRow(0)
|
||||
{
|
||||
}
|
||||
|
||||
Level level() const
|
||||
{
|
||||
return mLevel;
|
||||
}
|
||||
|
||||
void setLevel(const Level level)
|
||||
{
|
||||
mLevel = level;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void setPaused(bool paused)
|
||||
{
|
||||
mLastVisibleRow = paused ? rowCount() : 0;
|
||||
if (!paused) {
|
||||
invalidateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
|
||||
{
|
||||
Q_UNUSED(source_parent);
|
||||
if (!mLastVisibleRow) {
|
||||
LogWindowModel* model = dynamic_cast<LogWindowModel*>(sourceModel());
|
||||
const LogMessage& d = model->at(source_row);
|
||||
return d.level >= mLevel;
|
||||
}
|
||||
|
||||
return source_row <= mLastVisibleRow;
|
||||
}
|
||||
|
||||
private:
|
||||
Level mLevel;
|
||||
int mLastVisibleRow;
|
||||
};
|
||||
|
||||
QsLogging::Window::Window(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, mUi(nullptr)
|
||||
, mProxyModel(nullptr)
|
||||
, mIsPaused(false)
|
||||
, mHasAutoScroll(true)
|
||||
{
|
||||
mUi.reset(new Ui::LogWindow());
|
||||
mUi->setupUi(this);
|
||||
|
||||
connect(mUi->toolButtonPause, SIGNAL(clicked()), SLOT(OnPauseClicked()));
|
||||
connect(mUi->toolButtonSave, SIGNAL(clicked()), SLOT(OnSaveClicked()));
|
||||
connect(mUi->toolButtonClear, SIGNAL(clicked()), SLOT(OnClearClicked()));
|
||||
connect(mUi->toolButtonCopy, SIGNAL(clicked()), SLOT(OnCopyClicked()));
|
||||
connect(mUi->comboBoxLevel, SIGNAL(currentIndexChanged(int)), SLOT(OnLevelChanged(int)));
|
||||
connect(mUi->checkBoxAutoScroll, SIGNAL(toggled(bool)), SLOT(OnAutoScrollChanged(bool)));
|
||||
connect(&mModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)),
|
||||
SLOT(ModelRowsInserted(const QModelIndex&, int, int)));
|
||||
|
||||
// Install the sort / filter model
|
||||
mProxyModel.reset(new WindowLogFilterProxyModel(InfoLevel, this));
|
||||
mProxyModel->setSourceModel(&mModel);
|
||||
mUi->tableViewMessages->setModel(mProxyModel.get());
|
||||
|
||||
mUi->tableViewMessages->installEventFilter(this);
|
||||
|
||||
mUi->tableViewMessages->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
#if QT_VERSION >= 0x050000
|
||||
mUi->tableViewMessages->horizontalHeader()->setSectionResizeMode(LogWindowModel::TimeColumn, QHeaderView::ResizeToContents);
|
||||
mUi->tableViewMessages->horizontalHeader()->setSectionResizeMode(LogWindowModel::LevelNameColumn, QHeaderView::ResizeToContents);
|
||||
mUi->tableViewMessages->horizontalHeader()->setSectionResizeMode(LogWindowModel::MessageColumn, QHeaderView::Stretch);
|
||||
mUi->tableViewMessages->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
#else
|
||||
mUi->tableViewMessages->horizontalHeader()->setResizeMode(LogWindowModel::TimeColumn, QHeaderView::ResizeToContents);
|
||||
mUi->tableViewMessages->horizontalHeader()->setResizeMode(LogWindowModel::LevelNameColumn, QHeaderView::ResizeToContents);
|
||||
mUi->tableViewMessages->horizontalHeader()->setResizeMode(LogWindowModel::MessageColumn, QHeaderView::Stretch);
|
||||
mUi->tableViewMessages->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
|
||||
#endif
|
||||
|
||||
// Initialize log level selection
|
||||
for (int l = TraceLevel; l < OffLevel; l++) {
|
||||
const QString ln = LocalizedLevelName(static_cast<Level>(l));
|
||||
mUi->comboBoxLevel->addItem(ln, l);
|
||||
}
|
||||
mUi->comboBoxLevel->setCurrentIndex(InfoLevel);
|
||||
}
|
||||
|
||||
QsLogging::Window::~Window() noexcept = default;
|
||||
|
||||
bool QsLogging::Window::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (obj == mUi->tableViewMessages) {
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||
if (keyEvent->key() == Qt::Key_C && (keyEvent->modifiers() & Qt::ControlModifier)) {
|
||||
copySelection();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return QDialog::eventFilter(obj, event);
|
||||
}
|
||||
}
|
||||
|
||||
void QsLogging::Window::addLogMessage(const QsLogging::LogMessage &m)
|
||||
{
|
||||
mModel.addEntry(m);
|
||||
}
|
||||
|
||||
void QsLogging::Window::OnPauseClicked()
|
||||
{
|
||||
mUi->toolButtonPause->setIcon(mIsPaused ? pauseIcon() : playIcon());
|
||||
mUi->toolButtonPause->setText(mIsPaused ? tr("&Pause") : tr("&Resume"));
|
||||
|
||||
mIsPaused = !mIsPaused;
|
||||
|
||||
mProxyModel->setPaused(mIsPaused);
|
||||
}
|
||||
|
||||
void QsLogging::Window::OnSaveClicked()
|
||||
{
|
||||
saveSelection();
|
||||
}
|
||||
|
||||
void QsLogging::Window::OnClearClicked()
|
||||
{
|
||||
mModel.clear();
|
||||
}
|
||||
|
||||
void QsLogging::Window::OnCopyClicked()
|
||||
{
|
||||
copySelection();
|
||||
}
|
||||
|
||||
void QsLogging::Window::OnLevelChanged(int value)
|
||||
{
|
||||
mProxyModel->setLevel(static_cast<Level>(value));
|
||||
}
|
||||
|
||||
void QsLogging::Window::OnAutoScrollChanged(bool checked)
|
||||
{
|
||||
mHasAutoScroll = checked;
|
||||
}
|
||||
|
||||
void QsLogging::Window::ModelRowsInserted(const QModelIndex& parent, int start, int last)
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
Q_UNUSED(start);
|
||||
Q_UNUSED(last);
|
||||
if (mHasAutoScroll && !mIsPaused) {
|
||||
mUi->tableViewMessages->scrollToBottom();
|
||||
}
|
||||
}
|
||||
|
||||
void QsLogging::Window::copySelection() const
|
||||
{
|
||||
const QString text = getSelectionText();
|
||||
if (text.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QApplication::clipboard()->setText(text);
|
||||
}
|
||||
|
||||
void QsLogging::Window::saveSelection()
|
||||
{
|
||||
const QString text = getSelectionText();
|
||||
if (text.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFileDialog dialog(this);
|
||||
dialog.setWindowTitle(tr("Save log"));
|
||||
dialog.setNameFilter(tr("Log file (*.log)"));
|
||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
dialog.setDefaultSuffix("log");
|
||||
dialog.exec();
|
||||
|
||||
const QStringList sel = dialog.selectedFiles();
|
||||
if (sel.size() < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(sel.at(0));
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
QTextStream stream(&file);
|
||||
stream << text;
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
QString QsLogging::Window::getSelectionText() const
|
||||
{
|
||||
QModelIndexList rows = mUi->tableViewMessages->selectionModel()->selectedRows();
|
||||
std::sort(rows.begin(), rows.end());
|
||||
|
||||
QString text;
|
||||
|
||||
if (rows.count() == 0) {
|
||||
for (int i = 0; i < mProxyModel->rowCount(); i++) {
|
||||
const int srow = mProxyModel->mapToSource(mProxyModel->index(i, 0)).row();
|
||||
text += mModel.at(srow).formatted + "\n";
|
||||
}
|
||||
} else {
|
||||
for (QModelIndexList::const_iterator i = rows.begin();i != rows.end();++i) {
|
||||
const int srow = mProxyModel->mapToSource(*i).row();
|
||||
text += mModel.at(srow).formatted + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
#include "QsLogWindow.moc"
|
79
third_party/QsLog/QsLogWindow.h
vendored
Normal file
79
third_party/QsLog/QsLogWindow.h
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright (c) 2015, Axel Gembe <axel@gembe.net>
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
// list of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
// * The name of the contributors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef QSLOGWINDOW_H
|
||||
#define QSLOGWINDOW_H
|
||||
|
||||
#include "QsLogWindowModel.h"
|
||||
#include <QDialog>
|
||||
#include <memory>
|
||||
class QModelIndex;
|
||||
|
||||
namespace Ui {
|
||||
class LogWindow;
|
||||
class LogMessage;
|
||||
}
|
||||
|
||||
namespace QsLogging
|
||||
{
|
||||
|
||||
class WindowLogFilterProxyModel;
|
||||
|
||||
class QSLOG_SHARED_OBJECT Window : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Window(QWidget* parent = nullptr);
|
||||
virtual ~Window() noexcept;
|
||||
|
||||
virtual bool eventFilter(QObject* obj, QEvent* event);
|
||||
|
||||
private slots:
|
||||
void addLogMessage(const QsLogging::LogMessage& m);
|
||||
|
||||
void OnPauseClicked();
|
||||
void OnSaveClicked();
|
||||
void OnClearClicked();
|
||||
void OnCopyClicked();
|
||||
void OnLevelChanged(int value);
|
||||
void OnAutoScrollChanged(bool checked);
|
||||
void ModelRowsInserted(const QModelIndex& parent, int start, int last);
|
||||
|
||||
private:
|
||||
void copySelection() const;
|
||||
void saveSelection();
|
||||
QString getSelectionText() const;
|
||||
|
||||
LogWindowModel mModel;
|
||||
std::unique_ptr<Ui::LogWindow> mUi;
|
||||
std::unique_ptr<WindowLogFilterProxyModel> mProxyModel;
|
||||
bool mIsPaused;
|
||||
bool mHasAutoScroll;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QSLOGWINDOW_H
|
9
third_party/QsLog/QsLogWindow.qrc
vendored
Normal file
9
third_party/QsLog/QsLogWindow.qrc
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<RCC>
|
||||
<qresource prefix="/QsLogWindow">
|
||||
<file>images/icon-clear-16.png</file>
|
||||
<file>images/icon-save-16.png</file>
|
||||
<file>images/icon-copy-16.png</file>
|
||||
<file>images/icon-pause-16.png</file>
|
||||
<file>images/icon-resume-16.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
173
third_party/QsLog/QsLogWindow.ui
vendored
Normal file
173
third_party/QsLog/QsLogWindow.ui
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LogWindow</class>
|
||||
<widget class="QDialog" name="LogWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>599</width>
|
||||
<height>539</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Log window</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QToolButton" name="toolButtonPause">
|
||||
<property name="text">
|
||||
<string>&Pause</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="QsLogWindow.qrc">
|
||||
<normaloff>:/QsLogWindow/images/icon-pause-16.png</normaloff>:/QsLogWindow/images/icon-pause-16.png</iconset>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="toolButtonSave">
|
||||
<property name="text">
|
||||
<string>&Save</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="QsLogWindow.qrc">
|
||||
<normaloff>:/QsLogWindow/images/icon-save-16.png</normaloff>:/QsLogWindow/images/icon-save-16.png</iconset>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="toolButtonClear">
|
||||
<property name="text">
|
||||
<string>C&lear</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="QsLogWindow.qrc">
|
||||
<normaloff>:/QsLogWindow/images/icon-clear-16.png</normaloff>:/QsLogWindow/images/icon-clear-16.png</iconset>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="toolButtonCopy">
|
||||
<property name="text">
|
||||
<string>&Copy</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="QsLogWindow.qrc">
|
||||
<normaloff>:/QsLogWindow/images/icon-copy-16.png</normaloff>:/QsLogWindow/images/icon-copy-16.png</iconset>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Level:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboBoxLevel"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="tableViewMessages">
|
||||
<property name="autoScroll">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="showGrid">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxAutoScroll">
|
||||
<property name="text">
|
||||
<string>&Auto scroll</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>toolButtonPause</tabstop>
|
||||
<tabstop>toolButtonSave</tabstop>
|
||||
<tabstop>toolButtonClear</tabstop>
|
||||
<tabstop>toolButtonCopy</tabstop>
|
||||
<tabstop>comboBoxLevel</tabstop>
|
||||
<tabstop>tableViewMessages</tabstop>
|
||||
<tabstop>checkBoxAutoScroll</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="QsLogWindow.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
152
third_party/QsLog/QsLogWindowModel.cpp
vendored
Normal file
152
third_party/QsLog/QsLogWindowModel.cpp
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
// Copyright (c) 2015, Axel Gembe <axel@gembe.net>
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
// list of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
// * The name of the contributors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "QsLogWindowModel.h"
|
||||
#include "QsLog.h"
|
||||
|
||||
#include <QColor>
|
||||
|
||||
QsLogging::LogWindowModel::LogWindowModel(size_t max_items) :
|
||||
mMaxItems(max_items)
|
||||
{
|
||||
}
|
||||
|
||||
QsLogging::LogWindowModel::~LogWindowModel() noexcept = default;
|
||||
|
||||
void QsLogging::LogWindowModel::addEntry(const LogMessage& message)
|
||||
{
|
||||
const int next_idx = static_cast<int>(mLogMessages.size());
|
||||
beginInsertRows(QModelIndex(), next_idx, next_idx);
|
||||
{
|
||||
QWriteLocker lock(&mMessagesLock);
|
||||
mLogMessages.push_back(message);
|
||||
}
|
||||
endInsertRows();
|
||||
|
||||
if (mMaxItems < std::numeric_limits<size_t>::max() && mLogMessages.size() > mMaxItems) {
|
||||
{
|
||||
QWriteLocker lock(&mMessagesLock);
|
||||
mLogMessages.pop_front();
|
||||
}
|
||||
// Every item changed
|
||||
const QModelIndex idx1 = index(0, 0);
|
||||
const QModelIndex idx2 = index(static_cast<int>(mLogMessages.size()), rowCount());
|
||||
emit dataChanged(idx1, idx2);
|
||||
}
|
||||
}
|
||||
|
||||
void QsLogging::LogWindowModel::clear()
|
||||
{
|
||||
beginResetModel();
|
||||
{
|
||||
QWriteLocker lock(&mMessagesLock);
|
||||
mLogMessages.clear();
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QsLogging::LogMessage QsLogging::LogWindowModel::at(size_t index) const
|
||||
{
|
||||
return mLogMessages[index];
|
||||
}
|
||||
|
||||
int QsLogging::LogWindowModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return 3;
|
||||
}
|
||||
|
||||
int QsLogging::LogWindowModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
QReadLocker lock(&mMessagesLock);
|
||||
|
||||
return static_cast<int>(mLogMessages.size());
|
||||
}
|
||||
|
||||
QVariant QsLogging::LogWindowModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
QReadLocker lock(&mMessagesLock);
|
||||
|
||||
const LogMessage& item = mLogMessages.at(index.row());
|
||||
|
||||
switch (index.column()) {
|
||||
case TimeColumn:
|
||||
return item.time.toLocalTime().toString();
|
||||
case LevelNameColumn:
|
||||
return LocalizedLevelName(item.level);
|
||||
case MessageColumn:
|
||||
return item.message;
|
||||
case FormattedMessageColumn:
|
||||
return item.formatted;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
if (role == Qt::BackgroundColorRole) {
|
||||
QReadLocker lock(&mMessagesLock);
|
||||
|
||||
const LogMessage& item = mLogMessages.at(index.row());
|
||||
|
||||
switch (item.level)
|
||||
{
|
||||
case QsLogging::WarnLevel:
|
||||
return QVariant(QColor(255, 255, 128));
|
||||
case QsLogging::ErrorLevel:
|
||||
return QVariant(QColor(255, 128, 128));
|
||||
case QsLogging::FatalLevel:
|
||||
return QVariant(QColor(255, 0, 0));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant QsLogging::LogWindowModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
|
||||
switch (section) {
|
||||
case TimeColumn:
|
||||
return tr("Time");
|
||||
case LevelNameColumn:
|
||||
return tr("Level");
|
||||
case MessageColumn:
|
||||
return tr("Message");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
72
third_party/QsLog/QsLogWindowModel.h
vendored
Normal file
72
third_party/QsLog/QsLogWindowModel.h
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2015, Axel Gembe <axel@gembe.net>
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
// list of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
// * The name of the contributors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef QSLOGWINDOWMODEL_H
|
||||
#define QSLOGWINDOWMODEL_H
|
||||
|
||||
#include "QsLogSharedLibrary.h"
|
||||
#include "QsLogMessage.h"
|
||||
#include <QAbstractTableModel>
|
||||
#include <QReadWriteLock>
|
||||
|
||||
#include <limits>
|
||||
#include <deque>
|
||||
|
||||
namespace QsLogging
|
||||
{
|
||||
class QSLOG_SHARED_OBJECT LogWindowModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Column
|
||||
{
|
||||
TimeColumn = 0,
|
||||
LevelNameColumn = 1,
|
||||
MessageColumn = 2,
|
||||
FormattedMessageColumn = 100
|
||||
};
|
||||
|
||||
explicit LogWindowModel(size_t max_items = std::numeric_limits<size_t>::max());
|
||||
virtual ~LogWindowModel() noexcept;
|
||||
|
||||
void addEntry(const LogMessage& message);
|
||||
void clear();
|
||||
LogMessage at(size_t index) const;
|
||||
|
||||
// QAbstractTableModel overrides
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
|
||||
private:
|
||||
std::deque<LogMessage> mLogMessages;
|
||||
mutable QReadWriteLock mMessagesLock;
|
||||
size_t mMaxItems;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QSLOGWINDOWMODEL_H
|
57
third_party/QsLog/README.md
vendored
Normal file
57
third_party/QsLog/README.md
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
## QsLog - the simple Qt logger ##
|
||||
QsLog is an easy to use logger that is based on Qt's QDebug class. QsLog is released as open source, under the BSD license.
|
||||
|
||||
###Contribution policy###
|
||||
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.
|
||||
All contributions will be credited, license of the contributions should be 3-clause BSD.
|
||||
|
||||
### Features ###
|
||||
* Six logging levels (from trace to fatal)
|
||||
* Logging level threshold configurable at runtime.
|
||||
* Minimum overhead when logging is turned off.
|
||||
* Supports multiple destinations, comes with file and debug destinations.
|
||||
* Thread-safe
|
||||
* Supports logging of common Qt types out of the box.
|
||||
* Small dependency: just drop it in your project directly.
|
||||
|
||||
### Usage ###
|
||||
Directly including the QsLog source code in a project:
|
||||
|
||||
1. Include QsLog.pri in your pro file
|
||||
2. Include QsLog.h in your C++ files. Include QsLogDest.h only where you create/add destinations.
|
||||
3. Get the instance of the logger by calling QsLogging::Logger::instance();
|
||||
4. Optionally set the logging level. Info is default.
|
||||
5. Create as many destinations as you want by using the QsLogging::DestinationFactory.
|
||||
6. Add the destinations to the logger instance by calling addDestination.
|
||||
7. Start logging!
|
||||
|
||||
Linking to QsLog dynamically:
|
||||
|
||||
1. Build QsLog using the QsLogSharedLibrary.pro.
|
||||
2. Add the QsLog shared library to your LIBS project dependencies.
|
||||
3. Follow the steps in "directly including QsLog in your project" starting with step 2.
|
||||
|
||||
Note: when you want to use QsLog both from an executable and a shared library you have to
|
||||
link QsLog dynamically due to a limitation with static variables.
|
||||
|
||||
### Configuration ###
|
||||
QsLog has several configurable parameters in its .pri file:
|
||||
|
||||
* defining QS_LOG_LINE_NUMBERS in the .pri file enables writing the file and line number
|
||||
automatically for each logging call
|
||||
* defining QS_LOG_SEPARATE_THREAD will route all log messages to a separate thread.
|
||||
* defining QS_LOG_WIN_PRINTF_CONSOLE will use fprintf instead of OutputDebugString on Windows
|
||||
|
||||
Sometimes it's necessary to turn off logging. This can be done in several ways:
|
||||
|
||||
* globally, at compile time, by enabling the QS_LOG_DISABLE macro in the supplied .pri file.
|
||||
* globally, at run time, by setting the log level to "OffLevel".
|
||||
* per file, at compile time, by including QsLogDisableForThisFile.h in the target file.
|
||||
|
||||
### Thread safety ###
|
||||
The Qt docs say:
|
||||
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.
|
||||
A **reentrant** function can also be called simultaneously from multiple threads, but only if each invocation uses its own data.
|
||||
|
||||
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. Adding and removing destinations and the instance function are likewise thread-safe.
|
||||
The setup functions (e.g: setLoggingLevel) are NOT thread-safe and are NOT reentrant, they must be called at program startup.
|
165
third_party/QsLog/cmake/FindPkgMacros.cmake
vendored
Normal file
165
third_party/QsLog/cmake/FindPkgMacros.cmake
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
#-------------------------------------------------------------------
|
||||
# This file is part of the CMake build system for OGRE
|
||||
# (Object-oriented Graphics Rendering Engine)
|
||||
# For the latest info, see http://www.ogre3d.org/
|
||||
#
|
||||
# The contents of this file are placed in the public domain. Feel
|
||||
# free to make use of it in any way you like.
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
##################################################################
|
||||
# Provides some common functionality for the FindPackage modules
|
||||
##################################################################
|
||||
|
||||
# Begin processing of package
|
||||
macro(findpkg_begin PREFIX)
|
||||
if (NOT ${PREFIX}_FIND_QUIETLY)
|
||||
message(STATUS "Looking for ${PREFIX}...")
|
||||
endif ()
|
||||
endmacro(findpkg_begin)
|
||||
|
||||
# Display a status message unless FIND_QUIETLY is set
|
||||
macro(pkg_message PREFIX)
|
||||
if (NOT ${PREFIX}_FIND_QUIETLY)
|
||||
message(STATUS ${ARGN})
|
||||
endif ()
|
||||
endmacro(pkg_message)
|
||||
|
||||
# Get environment variable, define it as ENV_$var and make sure backslashes are converted to forward slashes
|
||||
macro(getenv_path VAR)
|
||||
set(ENV_${VAR} $ENV{${VAR}})
|
||||
# replace won't work if var is blank
|
||||
if (ENV_${VAR})
|
||||
string( REGEX REPLACE "\\\\" "/" ENV_${VAR} ${ENV_${VAR}} )
|
||||
endif ()
|
||||
endmacro(getenv_path)
|
||||
|
||||
# Construct search paths for includes and libraries from a PREFIX_PATH
|
||||
macro(create_search_paths PREFIX)
|
||||
foreach(dir ${${PREFIX}_PREFIX_PATH})
|
||||
set(${PREFIX}_INC_SEARCH_PATH ${${PREFIX}_INC_SEARCH_PATH}
|
||||
${dir}/include ${dir}/Include ${dir}/include/${PREFIX} ${dir}/Headers)
|
||||
set(${PREFIX}_LIB_SEARCH_PATH ${${PREFIX}_LIB_SEARCH_PATH}
|
||||
${dir}/lib ${dir}/Lib ${dir}/lib/${PREFIX} ${dir}/Libs)
|
||||
set(${PREFIX}_BIN_SEARCH_PATH ${${PREFIX}_BIN_SEARCH_PATH}
|
||||
${dir}/bin)
|
||||
endforeach(dir)
|
||||
if(ANDROID)
|
||||
set(${PREFIX}_LIB_SEARCH_PATH ${${PREFIX}_LIB_SEARCH_PATH} ${OGRE_DEPENDENCIES_DIR}/lib/${ANDROID_ABI})
|
||||
endif()
|
||||
set(${PREFIX}_FRAMEWORK_SEARCH_PATH ${${PREFIX}_PREFIX_PATH})
|
||||
endmacro(create_search_paths)
|
||||
|
||||
# clear cache variables if a certain variable changed
|
||||
macro(clear_if_changed TESTVAR)
|
||||
# test against internal check variable
|
||||
# HACK: Apparently, adding a variable to the cache cleans up the list
|
||||
# a bit. We need to also remove any empty strings from the list, but
|
||||
# at the same time ensure that we are actually dealing with a list.
|
||||
list(APPEND ${TESTVAR} "")
|
||||
list(REMOVE_ITEM ${TESTVAR} "")
|
||||
if (NOT "${${TESTVAR}}" STREQUAL "${${TESTVAR}_INT_CHECK}")
|
||||
message(STATUS "${TESTVAR} changed.")
|
||||
foreach(var ${ARGN})
|
||||
set(${var} "NOTFOUND" CACHE STRING "x" FORCE)
|
||||
endforeach(var)
|
||||
endif ()
|
||||
set(${TESTVAR}_INT_CHECK ${${TESTVAR}} CACHE INTERNAL "x" FORCE)
|
||||
endmacro(clear_if_changed)
|
||||
|
||||
# Try to get some hints from pkg-config, if available
|
||||
macro(use_pkgconfig PREFIX PKGNAME)
|
||||
if(NOT ANDROID)
|
||||
find_package(PkgConfig)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(${PREFIX} ${PKGNAME})
|
||||
endif ()
|
||||
endif()
|
||||
endmacro (use_pkgconfig)
|
||||
|
||||
# Couple a set of release AND debug libraries (or frameworks)
|
||||
macro(make_library_set PREFIX)
|
||||
if (${PREFIX}_FWK)
|
||||
set(${PREFIX} ${${PREFIX}_FWK})
|
||||
elseif (${PREFIX}_REL AND ${PREFIX}_DBG)
|
||||
set(${PREFIX} optimized ${${PREFIX}_REL} debug ${${PREFIX}_DBG})
|
||||
elseif (${PREFIX}_REL)
|
||||
set(${PREFIX} ${${PREFIX}_REL})
|
||||
elseif (${PREFIX}_DBG)
|
||||
set(${PREFIX} ${${PREFIX}_DBG})
|
||||
endif ()
|
||||
endmacro(make_library_set)
|
||||
|
||||
# Generate debug names from given release names
|
||||
macro(get_debug_names PREFIX)
|
||||
foreach(i ${${PREFIX}})
|
||||
set(${PREFIX}_DBG ${${PREFIX}_DBG} ${i}d ${i}D ${i}_d ${i}_D ${i}_debug ${i})
|
||||
endforeach(i)
|
||||
endmacro(get_debug_names)
|
||||
|
||||
# Add the parent dir from DIR to VAR
|
||||
macro(add_parent_dir VAR DIR)
|
||||
get_filename_component(${DIR}_TEMP "${${DIR}}/.." ABSOLUTE)
|
||||
set(${VAR} ${${VAR}} ${${DIR}_TEMP})
|
||||
endmacro(add_parent_dir)
|
||||
|
||||
# Do the final processing for the package find.
|
||||
macro(findpkg_finish PREFIX)
|
||||
# skip if already processed during this run
|
||||
if (NOT ${PREFIX}_FOUND)
|
||||
if (${PREFIX}_INCLUDE_DIR AND ${PREFIX}_LIBRARY)
|
||||
set(${PREFIX}_FOUND TRUE)
|
||||
set(${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIR})
|
||||
set(${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARY})
|
||||
if (NOT ${PREFIX}_FIND_QUIETLY)
|
||||
message(STATUS "Found ${PREFIX}: ${${PREFIX}_LIBRARIES}")
|
||||
endif ()
|
||||
else ()
|
||||
if (NOT ${PREFIX}_FIND_QUIETLY)
|
||||
message(STATUS "Could not locate ${PREFIX}")
|
||||
endif ()
|
||||
if (${PREFIX}_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Required library ${PREFIX} not found! Install the library (including dev packages) and try again. If the library is already installed, set the missing variables manually in cmake.")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
mark_as_advanced(${PREFIX}_INCLUDE_DIR ${PREFIX}_LIBRARY ${PREFIX}_LIBRARY_REL ${PREFIX}_LIBRARY_DBG ${PREFIX}_LIBRARY_FWK)
|
||||
endif ()
|
||||
endmacro(findpkg_finish)
|
||||
|
||||
|
||||
# Slightly customised framework finder
|
||||
macro(findpkg_framework fwk)
|
||||
if(APPLE)
|
||||
set(${fwk}_FRAMEWORK_PATH
|
||||
${${fwk}_FRAMEWORK_SEARCH_PATH}
|
||||
${CMAKE_FRAMEWORK_PATH}
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/System/Library/Frameworks
|
||||
/Network/Library/Frameworks
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lib/macosx/Release
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lib/macosx/Debug
|
||||
)
|
||||
# These could be arrays of paths, add each individually to the search paths
|
||||
foreach(i ${OGRE_PREFIX_PATH})
|
||||
set(${fwk}_FRAMEWORK_PATH ${${fwk}_FRAMEWORK_PATH} ${i}/lib/macosx/Release ${i}/lib/macosx/Debug)
|
||||
endforeach(i)
|
||||
|
||||
foreach(i ${OGRE_PREFIX_BUILD})
|
||||
set(${fwk}_FRAMEWORK_PATH ${${fwk}_FRAMEWORK_PATH} ${i}/lib/macosx/Release ${i}/lib/macosx/Debug)
|
||||
endforeach(i)
|
||||
|
||||
foreach(dir ${${fwk}_FRAMEWORK_PATH})
|
||||
set(fwkpath ${dir}/${fwk}.framework)
|
||||
if(EXISTS ${fwkpath})
|
||||
set(${fwk}_FRAMEWORK_INCLUDES ${${fwk}_FRAMEWORK_INCLUDES}
|
||||
${fwkpath}/Headers ${fwkpath}/PrivateHeaders)
|
||||
set(${fwk}_FRAMEWORK_PATH ${dir})
|
||||
if (NOT ${fwk}_LIBRARY_FWK)
|
||||
set(${fwk}_LIBRARY_FWK "-framework ${fwk}")
|
||||
endif ()
|
||||
endif(EXISTS ${fwkpath})
|
||||
endforeach(dir)
|
||||
endif(APPLE)
|
||||
endmacro(findpkg_framework)
|
50
third_party/QsLog/cmake/FindQsLog.cmake
vendored
Normal file
50
third_party/QsLog/cmake/FindQsLog.cmake
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
#-------------------------------------------------------------------
|
||||
# CMake build support courtesy of A.Gembe
|
||||
# The contents of this file are placed in the public domain. Feel
|
||||
# free to make use of it in any way you like.
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
# - Try to find QsLog
|
||||
# Once done, this will define
|
||||
#
|
||||
# QsLog_FOUND - system has QsLog
|
||||
# QsLog_INCLUDE_DIRS - the QsLog include directories
|
||||
# QsLog_LIBRARIES - link these to use QsLog
|
||||
# QsLog_BINARY_REL
|
||||
# QsLog_BINARY_DBG
|
||||
|
||||
include(FindPkgMacros)
|
||||
findpkg_begin(QsLog)
|
||||
|
||||
# Get path, convert backslashes as ${ENV_${var}}
|
||||
getenv_path(QsLog_HOME)
|
||||
|
||||
# construct search paths
|
||||
set(QsLog_PREFIX_PATH ${QsLog_HOME} ${ENV_QsLog_HOME})
|
||||
|
||||
create_search_paths(QsLog)
|
||||
|
||||
# redo search if prefix path changed
|
||||
clear_if_changed(
|
||||
QsLog_PREFIX_PATH
|
||||
QsLog_LIBRARY_REL
|
||||
QsLog_LIBRARY_DBG
|
||||
QsLog_BINARY_REL
|
||||
QsLog_BINARY_DBG
|
||||
QsLog_INCLUDE_DIR
|
||||
)
|
||||
|
||||
set(QsLog_LIBRARY_NAMES QsLog)
|
||||
get_debug_names(QsLog_LIBRARY_NAMES)
|
||||
|
||||
use_pkgconfig(QsLog_PKGC QsLog)
|
||||
|
||||
find_path(QsLog_INCLUDE_DIR NAMES QsLog.h HINTS ${QsLog_INC_SEARCH_PATH} ${QsLog_PKGC_INCLUDE_DIRS} PATH_SUFFIXES QsLog)
|
||||
find_library(QsLog_LIBRARY_REL NAMES ${QsLog_LIBRARY_NAMES} HINTS ${QsLog_LIB_SEARCH_PATH} ${QsLog_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" release relwithdebinfo minsizerel)
|
||||
find_library(QsLog_LIBRARY_DBG NAMES ${QsLog_LIBRARY_NAMES_DBG} HINTS ${QsLog_LIB_SEARCH_PATH} ${QsLog_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" debug)
|
||||
find_file(QsLog_BINARY_REL NAMES QsLog.dll HINTS ${QsLog_PREFIX_PATH}/bin PATH_SUFFIXES "" release relwithdebinfo minsizerel)
|
||||
find_file(QsLog_BINARY_DBG NAMES QsLog_d.dll HINTS ${QsLog_PREFIX_PATH}/bin PATH_SUFFIXES "" debug)
|
||||
make_library_set(QsLog_LIBRARY)
|
||||
|
||||
findpkg_finish(QsLog)
|
||||
add_parent_dir(QsLog_INCLUDE_DIRS QsLog_INCLUDE_DIR)
|
52
third_party/QsLog/cmake/QsLogConfigTargets.cmake
vendored
Normal file
52
third_party/QsLog/cmake/QsLogConfigTargets.cmake
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
# CMake build support courtesy of A.Gembe
|
||||
|
||||
if (WIN32)
|
||||
set(QSLOG_RELEASE_PATH "/Release")
|
||||
set(QSLOG_RELWDBG_PATH "/RelWithDebInfo")
|
||||
set(QSLOG_MINSIZE_PATH "/MinSizeRel")
|
||||
set(QSLOG_DEBUG_PATH "/Debug")
|
||||
set(QSLOG_LIB_RELEASE_PATH "/Release")
|
||||
set(QSLOG_LIB_RELWDBG_PATH "/RelWithDebInfo")
|
||||
set(QSLOG_LIB_MINSIZE_PATH "/MinSizeRel")
|
||||
set(QSLOG_LIB_DEBUG_PATH "/Debug")
|
||||
elseif (UNIX)
|
||||
set(QSLOG_RELEASE_PATH "")
|
||||
set(QSLOG_RELWDBG_PATH "")
|
||||
set(QSLOG_MINSIZE_PATH "")
|
||||
set(QSLOG_DEBUG_PATH "/debug")
|
||||
set(QSLOG_LIB_RELEASE_PATH "")
|
||||
set(QSLOG_LIB_RELWDBG_PATH "")
|
||||
set(QSLOG_LIB_MINSIZE_PATH "")
|
||||
set(QSLOG_LIB_DEBUG_PATH "")
|
||||
endif ()
|
||||
if (APPLE)
|
||||
set(QSLOG_FRAMEWORK_PATH /Library/Frameworks)
|
||||
endif ()
|
||||
|
||||
# install targets according to current build type
|
||||
function(QsLog_install_target TARGETNAME SUFFIX)
|
||||
install(TARGETS ${TARGETNAME}
|
||||
RUNTIME DESTINATION "bin${QSLOG_RELEASE_PATH}" CONFIGURATIONS Release None ""
|
||||
LIBRARY DESTINATION "lib${QSLOG_LIB_RELEASE_PATH}${SUFFIX}" CONFIGURATIONS Release None ""
|
||||
ARCHIVE DESTINATION "lib${QSLOG_LIB_RELEASE_PATH}${SUFFIX}" CONFIGURATIONS Release None ""
|
||||
FRAMEWORK DESTINATION "${QSLOG_FRAMEWORK_PATH}" CONFIGURATIONS Release None ""
|
||||
)
|
||||
install(TARGETS ${TARGETNAME}
|
||||
RUNTIME DESTINATION "bin${QSLOG_RELWDBG_PATH}" CONFIGURATIONS RelWithDebInfo
|
||||
LIBRARY DESTINATION "lib${QSLOG_LIB_RELWDBG_PATH}${SUFFIX}" CONFIGURATIONS RelWithDebInfo
|
||||
ARCHIVE DESTINATION "lib${QSLOG_LIB_RELWDBG_PATH}${SUFFIX}" CONFIGURATIONS RelWithDebInfo
|
||||
FRAMEWORK DESTINATION "${QSLOG_FRAMEWORK_PATH}" CONFIGURATIONS RelWithDebInfo
|
||||
)
|
||||
install(TARGETS ${TARGETNAME}
|
||||
RUNTIME DESTINATION "bin${QSLOG_MINSIZE_PATH}" CONFIGURATIONS MinSizeRel
|
||||
LIBRARY DESTINATION "lib${QSLOG_LIB_MINSIZE_PATH}${SUFFIX}" CONFIGURATIONS MinSizeRel
|
||||
ARCHIVE DESTINATION "lib${QSLOG_LIB_MINSIZE_PATH}${SUFFIX}" CONFIGURATIONS MinSizeRel
|
||||
FRAMEWORK DESTINATION "${QSLOG_FRAMEWORK_PATH}" CONFIGURATIONS MinSizeRel
|
||||
)
|
||||
install(TARGETS ${TARGETNAME}
|
||||
RUNTIME DESTINATION "bin${QSLOG_DEBUG_PATH}" CONFIGURATIONS Debug
|
||||
LIBRARY DESTINATION "lib${QSLOG_LIB_DEBUG_PATH}${SUFFIX}" CONFIGURATIONS Debug
|
||||
ARCHIVE DESTINATION "lib${QSLOG_LIB_DEBUG_PATH}${SUFFIX}" CONFIGURATIONS Debug
|
||||
FRAMEWORK DESTINATION "${QSLOG_FRAMEWORK_PATH}" CONFIGURATIONS Debug
|
||||
)
|
||||
endfunction(QsLog_install_target)
|
BIN
third_party/QsLog/images/icon-clear-16.png
vendored
Normal file
BIN
third_party/QsLog/images/icon-clear-16.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 231 B |
BIN
third_party/QsLog/images/icon-copy-16.png
vendored
Normal file
BIN
third_party/QsLog/images/icon-copy-16.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 310 B |
BIN
third_party/QsLog/images/icon-pause-16.png
vendored
Normal file
BIN
third_party/QsLog/images/icon-pause-16.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 269 B |
BIN
third_party/QsLog/images/icon-resume-16.png
vendored
Normal file
BIN
third_party/QsLog/images/icon-resume-16.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 316 B |
BIN
third_party/QsLog/images/icon-save-16.png
vendored
Normal file
BIN
third_party/QsLog/images/icon-save-16.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 186 B |
29
third_party/QsLog/unittest/CMakeLists.txt
vendored
Normal file
29
third_party/QsLog/unittest/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
set(PROJECTNAME QsLogUnitTest)
|
||||
project(${PROJECTNAME})
|
||||
|
||||
find_package(Qt5Test REQUIRED)
|
||||
|
||||
include_directories(${QsLogUnitTest_SOURCE_DIR} ${QsLog_SOURCE_DIR})
|
||||
|
||||
if(QS_LOG_IS_SHARED_LIBRARY)
|
||||
# Ugh, ugly hack
|
||||
add_definitions(-UQSLOG_IS_SHARED_LIBRARY)
|
||||
add_definitions(-DQSLOG_IS_SHARED_LIBRARY_IMPORT)
|
||||
endif()
|
||||
|
||||
set(HEADER_FILES
|
||||
TestLog.h
|
||||
QtTestUtil/QtTestUtil.h
|
||||
QtTestUtil/TestRegistration.h
|
||||
QtTestUtil/TestRegistry.h
|
||||
)
|
||||
|
||||
set(SOURCE_FILES
|
||||
TestLog.cpp
|
||||
QtTestUtil/SimpleChecker.cpp
|
||||
QtTestUtil/TestRegistry.cpp
|
||||
)
|
||||
|
||||
add_executable(${PROJECTNAME} ${SOURCE_FILES} ${HEADER_FILES})
|
||||
|
||||
target_link_libraries(${PROJECTNAME} QsLog Qt5::Core Qt5::Test)
|
31
third_party/QsLog/unittest/QtTestUtil/QtTestUtil.h
vendored
Normal file
31
third_party/QsLog/unittest/QtTestUtil/QtTestUtil.h
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Remko Troncon
|
||||
* Licensed under the MIT license.
|
||||
* See COPYING for license details.
|
||||
*/
|
||||
|
||||
#ifndef QtTestUtil_H
|
||||
#define QtTestUtil_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QtTest/QtTest>
|
||||
#include "QtTestUtil/TestRegistration.h"
|
||||
|
||||
/**
|
||||
* A macro to register a test class.
|
||||
*
|
||||
* This macro will create a static variable which registers the
|
||||
* testclass with the TestRegistry, and creates an instance of the
|
||||
* test class.
|
||||
*
|
||||
* Execute this macro in the body of your unit test's .cpp file, e.g.
|
||||
* class MyTest {
|
||||
* ...
|
||||
* };
|
||||
*
|
||||
* QTTESTUTIL_REGISTER_TEST(MyTest)
|
||||
*/
|
||||
#define QTTESTUTIL_REGISTER_TEST(TestClass) \
|
||||
static QtTestUtil::TestRegistration<TestClass> TestClass##Registration
|
||||
|
||||
#endif
|
17
third_party/QsLog/unittest/QtTestUtil/SimpleChecker.cpp
vendored
Normal file
17
third_party/QsLog/unittest/QtTestUtil/SimpleChecker.cpp
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Remko Troncon
|
||||
* Licensed under the MIT license.
|
||||
* See COPYING for license details.
|
||||
*/
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "QtTestUtil/TestRegistry.h"
|
||||
|
||||
/**
|
||||
* Runs all tests registered with the QtTestUtil registry.
|
||||
*/
|
||||
int main(int argc, char* argv[]) {
|
||||
QCoreApplication application(argc, argv);
|
||||
return QtTestUtil::TestRegistry::getInstance()->runTests(argc, argv);
|
||||
}
|
38
third_party/QsLog/unittest/QtTestUtil/TestRegistration.h
vendored
Normal file
38
third_party/QsLog/unittest/QtTestUtil/TestRegistration.h
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Remko Troncon
|
||||
* Licensed under the MIT license.
|
||||
* See COPYING for license details.
|
||||
*/
|
||||
|
||||
#ifndef QtTestUtil_TestRegistration_H
|
||||
#define QtTestUtil_TestRegistration_H
|
||||
|
||||
#include "QtTestUtil/TestRegistry.h"
|
||||
|
||||
namespace QtTestUtil {
|
||||
|
||||
/**
|
||||
* A wrapper class around a test to manage registration and static
|
||||
* creation of an instance of the test class.
|
||||
* This class is used by QTTESTUTIL_REGISTER_TEST(), and you should not
|
||||
* use this class directly.
|
||||
*/
|
||||
template<typename TestClass>
|
||||
class TestRegistration {
|
||||
public:
|
||||
TestRegistration() {
|
||||
test_ = new TestClass();
|
||||
TestRegistry::getInstance()->registerTest(test_);
|
||||
}
|
||||
|
||||
~TestRegistration() {
|
||||
delete test_;
|
||||
}
|
||||
|
||||
private:
|
||||
TestClass* test_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
30
third_party/QsLog/unittest/QtTestUtil/TestRegistry.cpp
vendored
Normal file
30
third_party/QsLog/unittest/QtTestUtil/TestRegistry.cpp
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Remko Troncon
|
||||
* Licensed under the MIT license.
|
||||
* See COPYING for license details.
|
||||
*/
|
||||
|
||||
#include "QtTestUtil/TestRegistry.h"
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
namespace QtTestUtil {
|
||||
|
||||
TestRegistry* TestRegistry::getInstance() {
|
||||
static TestRegistry registry;
|
||||
return ®istry;
|
||||
}
|
||||
|
||||
void TestRegistry::registerTest(QObject* test) {
|
||||
tests_ += test;
|
||||
}
|
||||
|
||||
int TestRegistry::runTests(int argc, char* argv[]) {
|
||||
int result = 0;
|
||||
foreach(QObject* test, tests_) {
|
||||
result |= QTest::qExec(test, argc, argv);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
49
third_party/QsLog/unittest/QtTestUtil/TestRegistry.h
vendored
Normal file
49
third_party/QsLog/unittest/QtTestUtil/TestRegistry.h
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Remko Troncon
|
||||
* Licensed under the MIT license.
|
||||
* See COPYING for license details.
|
||||
*/
|
||||
|
||||
#ifndef QtTestUtil_TestRegistry_H
|
||||
#define QtTestUtil_TestRegistry_H
|
||||
|
||||
#include <QList>
|
||||
|
||||
class QObject;
|
||||
|
||||
namespace QtTestUtil {
|
||||
|
||||
/**
|
||||
* A registry of QtTest test classes.
|
||||
* All test classes registered with QTTESTUTIL_REGISTER_TEST add
|
||||
* themselves to this registry. All registered tests can then be run at
|
||||
* once using runTests().
|
||||
*/
|
||||
class TestRegistry {
|
||||
public:
|
||||
/**
|
||||
* Retrieve the single instance of the registry.
|
||||
*/
|
||||
static TestRegistry* getInstance();
|
||||
|
||||
/**
|
||||
* Register a QtTest test.
|
||||
* This method is called by QTTESTUTIL_REGISTER_TEST, and you should
|
||||
* not use this method directly.
|
||||
*/
|
||||
void registerTest(QObject*);
|
||||
|
||||
/**
|
||||
* Run all registered tests using QTest::qExec()
|
||||
*/
|
||||
int runTests(int argc, char* argv[]);
|
||||
|
||||
private:
|
||||
TestRegistry() {}
|
||||
|
||||
private:
|
||||
QList<QObject*> tests_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
307
third_party/QsLog/unittest/TestLog.cpp
vendored
Normal file
307
third_party/QsLog/unittest/TestLog.cpp
vendored
Normal file
@ -0,0 +1,307 @@
|
||||
#include "TestLog.h"
|
||||
#include "QtTestUtil/QtTestUtil.h"
|
||||
#include "QsLog.h"
|
||||
#include "QsLogDest.h"
|
||||
#include "QsLogDestFile.h"
|
||||
#include "QsLogDestConsole.h"
|
||||
#include "QsLogDestFile.h"
|
||||
#include "QsLogDestFunctor.h"
|
||||
#include <QTest>
|
||||
#include <QSharedPointer>
|
||||
#include <QtGlobal>
|
||||
|
||||
const QLatin1String destinationName1("mock1");
|
||||
const QLatin1String destinationName2("mock2");
|
||||
using MockDestinationPtrU = std::unique_ptr<MockDestination>;
|
||||
|
||||
// Needed to convert from removeDestination return value to the type that we initially added.
|
||||
MockDestinationPtrU unique_cast(QsLogging::DestinationPtrU&& d)
|
||||
{
|
||||
MockDestinationPtrU md(dynamic_cast<MockDestination*>(d.release()));
|
||||
Q_ASSERT(md.get());
|
||||
return md;
|
||||
}
|
||||
|
||||
void DummyLogFunction(const QsLogging::LogMessage&)
|
||||
{
|
||||
}
|
||||
|
||||
// Autotests for QsLog.
|
||||
// These tests are based on using a mock destination to check what was logged. Destinations are
|
||||
// owned by the log, that's why the add/remove ping-pong is needed in the tests.
|
||||
class TestLog : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TestLog()
|
||||
{
|
||||
}
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void testAllLevels();
|
||||
void testMessageText();
|
||||
void testLevelChanges();
|
||||
void testLevelParsing();
|
||||
void testDestinationRemove();
|
||||
void testWillRotate();
|
||||
void testRotation_data();
|
||||
void testRotation();
|
||||
void testRotationNoBackup();
|
||||
void testDestinationType();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
void TestLog::initTestCase()
|
||||
{
|
||||
using namespace QsLogging;
|
||||
QCOMPARE(Logger::instance().loggingLevel(), InfoLevel);
|
||||
Logger::instance().setLoggingLevel(TraceLevel);
|
||||
QCOMPARE(Logger::instance().loggingLevel(), TraceLevel);
|
||||
}
|
||||
|
||||
void TestLog::testAllLevels()
|
||||
{
|
||||
using namespace QsLogging;
|
||||
MockDestinationPtrU mockDest(new MockDestination(destinationName1));
|
||||
Logger::instance().addDestination(std::move(mockDest));
|
||||
|
||||
QLOG_TRACE() << "trace level";
|
||||
QLOG_DEBUG() << "debug level";
|
||||
QLOG_INFO() << "info level";
|
||||
QLOG_WARN() << "warn level";
|
||||
QLOG_ERROR() << "error level";
|
||||
QLOG_FATAL() << "fatal level";
|
||||
|
||||
mockDest = unique_cast(Logger::instance().removeDestination(destinationName1));
|
||||
QCOMPARE(mockDest->messageCount(), 6);
|
||||
QCOMPARE(mockDest->messageCountForLevel(TraceLevel), 1);
|
||||
QCOMPARE(mockDest->messageCountForLevel(DebugLevel), 1);
|
||||
QCOMPARE(mockDest->messageCountForLevel(InfoLevel), 1);
|
||||
QCOMPARE(mockDest->messageCountForLevel(WarnLevel), 1);
|
||||
QCOMPARE(mockDest->messageCountForLevel(ErrorLevel), 1);
|
||||
QCOMPARE(mockDest->messageCountForLevel(FatalLevel), 1);
|
||||
}
|
||||
|
||||
void TestLog::testMessageText()
|
||||
{
|
||||
using namespace QsLogging;
|
||||
MockDestinationPtrU mockDest(new MockDestination(destinationName1));
|
||||
Logger::instance().addDestination(std::move(mockDest));
|
||||
|
||||
QLOG_DEBUG() << "foobar";
|
||||
QLOG_WARN() << "eiszeit";
|
||||
QLOG_FATAL() << "ruh-roh!";
|
||||
|
||||
mockDest = unique_cast(Logger::instance().removeDestination(destinationName1));
|
||||
QVERIFY(mockDest->hasMessage("foobar", DebugLevel));
|
||||
QVERIFY(mockDest->hasMessage("eiszeit", WarnLevel));
|
||||
QVERIFY(mockDest->hasMessage("ruh-roh!", FatalLevel));
|
||||
QCOMPARE(mockDest->messageCount(), 3);
|
||||
}
|
||||
|
||||
void TestLog::testLevelChanges()
|
||||
{
|
||||
using namespace QsLogging;
|
||||
MockDestinationPtrU mockDest1(new MockDestination(destinationName1));
|
||||
MockDestinationPtrU mockDest2(new MockDestination(destinationName2));
|
||||
Logger::instance().addDestination(std::move(mockDest1));
|
||||
Logger::instance().addDestination(std::move(mockDest2));
|
||||
|
||||
using namespace QsLogging;
|
||||
Logger::instance().setLoggingLevel(WarnLevel);
|
||||
QCOMPARE(Logger::instance().loggingLevel(), WarnLevel);
|
||||
|
||||
QLOG_TRACE() << "one";
|
||||
QLOG_DEBUG() << "two";
|
||||
QLOG_INFO() << "three";
|
||||
|
||||
mockDest1 = unique_cast(Logger::instance().removeDestination(destinationName1));
|
||||
mockDest2 = unique_cast(Logger::instance().removeDestination(destinationName2));
|
||||
|
||||
QCOMPARE(mockDest1->messageCount(), 0);
|
||||
QCOMPARE(mockDest2->messageCount(), 0);
|
||||
|
||||
Logger::instance().addDestination(std::move(mockDest1));
|
||||
Logger::instance().addDestination(std::move(mockDest2));
|
||||
|
||||
QLOG_WARN() << "warning";
|
||||
QLOG_ERROR() << "error";
|
||||
QLOG_FATAL() << "fatal";
|
||||
|
||||
mockDest1 = unique_cast(Logger::instance().removeDestination(destinationName1));
|
||||
mockDest2 = unique_cast(Logger::instance().removeDestination(destinationName2));
|
||||
|
||||
QCOMPARE(mockDest1->messageCountForLevel(WarnLevel), 1);
|
||||
QCOMPARE(mockDest1->messageCountForLevel(ErrorLevel), 1);
|
||||
QCOMPARE(mockDest1->messageCountForLevel(FatalLevel), 1);
|
||||
QCOMPARE(mockDest1->messageCount(), 3);
|
||||
QCOMPARE(mockDest2->messageCountForLevel(WarnLevel), 1);
|
||||
QCOMPARE(mockDest2->messageCountForLevel(ErrorLevel), 1);
|
||||
QCOMPARE(mockDest2->messageCountForLevel(FatalLevel), 1);
|
||||
QCOMPARE(mockDest2->messageCount(), 3);
|
||||
}
|
||||
|
||||
void TestLog::testLevelParsing()
|
||||
{
|
||||
using namespace QsLogging;
|
||||
MockDestinationPtrU mockDest(new MockDestination(destinationName1));
|
||||
Logger::instance().addDestination(std::move(mockDest));
|
||||
|
||||
QLOG_TRACE() << "one";
|
||||
QLOG_DEBUG() << "two";
|
||||
QLOG_INFO() << "three";
|
||||
QLOG_WARN() << "warning";
|
||||
QLOG_ERROR() << "error";
|
||||
QLOG_FATAL() << "fatal";
|
||||
|
||||
mockDest = unique_cast(Logger::instance().removeDestination(destinationName1));
|
||||
|
||||
using namespace QsLogging;
|
||||
for(int i = 0;i < mockDest->messageCount();++i) {
|
||||
bool conversionOk = false;
|
||||
const MockDestination::Message& m = mockDest->messageAt(i);
|
||||
QCOMPARE(Logger::levelFromLogMessage(m.text, &conversionOk), m.level);
|
||||
QCOMPARE(Logger::levelFromLogMessage(m.text), m.level);
|
||||
QCOMPARE(conversionOk, true);
|
||||
}
|
||||
}
|
||||
|
||||
void TestLog::testDestinationRemove()
|
||||
{
|
||||
using namespace QsLogging;
|
||||
MockDestinationPtrU mockDest(new MockDestination(destinationName1));
|
||||
MockDestinationPtrU toAddAndRemove(new MockDestination(destinationName2));
|
||||
Logger::instance().addDestination(std::move(mockDest));
|
||||
Logger::instance().addDestination(std::move(toAddAndRemove));
|
||||
Logger::instance().setLoggingLevel(DebugLevel);
|
||||
QLOG_INFO() << "one for all";
|
||||
|
||||
mockDest = unique_cast(Logger::instance().removeDestination(destinationName1));
|
||||
toAddAndRemove = unique_cast(Logger::instance().removeDestination(destinationName2));
|
||||
QCOMPARE(mockDest->messageCount(), 1);
|
||||
QCOMPARE(toAddAndRemove->messageCount(), 1);
|
||||
|
||||
Logger::instance().addDestination(std::move(mockDest));
|
||||
QLOG_INFO() << "one for (almost) all";
|
||||
|
||||
mockDest = unique_cast(Logger::instance().removeDestination(destinationName1));
|
||||
QCOMPARE(mockDest->messageCount(), 2);
|
||||
QCOMPARE(toAddAndRemove->messageCount(), 1);
|
||||
QCOMPARE(toAddAndRemove->messageCountForLevel(InfoLevel), 1);
|
||||
|
||||
Logger::instance().addDestination(std::move(mockDest));
|
||||
Logger::instance().addDestination(std::move(toAddAndRemove));
|
||||
QLOG_INFO() << "another one for all";
|
||||
|
||||
mockDest = unique_cast(Logger::instance().removeDestination(destinationName1));
|
||||
toAddAndRemove = unique_cast(Logger::instance().removeDestination(destinationName2));
|
||||
QCOMPARE(mockDest->messageCount(), 3);
|
||||
QCOMPARE(toAddAndRemove->messageCount(), 2);
|
||||
QCOMPARE(toAddAndRemove->messageCountForLevel(InfoLevel), 2);
|
||||
}
|
||||
|
||||
void TestLog::testWillRotate()
|
||||
{
|
||||
using namespace QsLogging;
|
||||
MockSizeRotationStrategy rotationStrategy;
|
||||
rotationStrategy.setBackupCount(1);
|
||||
rotationStrategy.setMaximumSizeInBytes(10);
|
||||
QCOMPARE(rotationStrategy.shouldRotate(), false);
|
||||
|
||||
rotationStrategy.includeMessageInCalculation(QLatin1String("12345"));
|
||||
QCOMPARE(rotationStrategy.shouldRotate(), false);
|
||||
|
||||
rotationStrategy.includeMessageInCalculation(QLatin1String("12345"));
|
||||
QCOMPARE(rotationStrategy.shouldRotate(), false);
|
||||
|
||||
rotationStrategy.includeMessageInCalculation(QLatin1String("1"));
|
||||
QCOMPARE(rotationStrategy.shouldRotate(), true);
|
||||
}
|
||||
|
||||
void TestLog::testRotation_data()
|
||||
{
|
||||
QTest::addColumn<int>("backupCount");
|
||||
|
||||
QTest::newRow("one backup") << 1;
|
||||
QTest::newRow("three backups") << 3;
|
||||
QTest::newRow("five backups") << 5;
|
||||
QTest::newRow("ten backups") << 10;
|
||||
}
|
||||
|
||||
void TestLog::testRotation()
|
||||
{
|
||||
using namespace QsLogging;
|
||||
|
||||
QFETCH(int, backupCount);
|
||||
MockSizeRotationStrategy rotationStrategy;
|
||||
rotationStrategy.setBackupCount(backupCount);
|
||||
for (int i = 0;i < backupCount;++i) {
|
||||
rotationStrategy.rotate();
|
||||
QCOMPARE(rotationStrategy.filesList().size(), 1 + i + 1); // 1 log + "rotation count" backups
|
||||
}
|
||||
|
||||
rotationStrategy.rotate();
|
||||
QCOMPARE(rotationStrategy.filesList().size(), backupCount + 1); // 1 log + backup count
|
||||
}
|
||||
|
||||
void TestLog::testRotationNoBackup()
|
||||
{
|
||||
using namespace QsLogging;
|
||||
MockSizeRotationStrategy rotationStrategy;
|
||||
rotationStrategy.setBackupCount(0);
|
||||
rotationStrategy.setMaximumSizeInBytes(10);
|
||||
|
||||
rotationStrategy.rotate();
|
||||
QCOMPARE(rotationStrategy.filesList().size(), 1); // log
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TestLog::testDestinationType()
|
||||
{
|
||||
using namespace QsLogging;
|
||||
|
||||
DestinationPtrU console = DestinationFactory::MakeDebugOutputDestination();
|
||||
DestinationPtrU file = DestinationFactory::MakeFileDestination("test.log",
|
||||
LogRotationOption::DisableLogRotation, MaxSizeBytes(5000), MaxOldLogCount(1));
|
||||
DestinationPtrU func = DestinationFactory::MakeFunctorDestination(&DummyLogFunction);
|
||||
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(DebugOutputDestination::Type), false);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(FileDestination::Type), false);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(FunctorDestination::Type), false);
|
||||
|
||||
Logger::instance().addDestination(std::move(console));
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(DebugOutputDestination::Type), true);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(FileDestination::Type), false);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(FunctorDestination::Type), false);
|
||||
|
||||
Logger::instance().addDestination(std::move(file));
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(DebugOutputDestination::Type), true);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(FileDestination::Type), true);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(FunctorDestination::Type), false);
|
||||
|
||||
Logger::instance().addDestination(std::move(func));
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(DebugOutputDestination::Type), true);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(FileDestination::Type), true);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(FunctorDestination::Type), true);
|
||||
|
||||
Logger::instance().removeDestination(DebugOutputDestination::Type);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(DebugOutputDestination::Type), false);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(FileDestination::Type), true);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(FunctorDestination::Type), true);
|
||||
|
||||
Logger::instance().removeDestination(FileDestination::Type);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(DebugOutputDestination::Type), false);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(FileDestination::Type), false);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(FunctorDestination::Type), true);
|
||||
|
||||
Logger::instance().removeDestination(FunctorDestination::Type);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(DebugOutputDestination::Type), false);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(FileDestination::Type), false);
|
||||
QCOMPARE(Logger::instance().hasDestinationOfType(FunctorDestination::Type), false);
|
||||
}
|
||||
|
||||
QTTESTUTIL_REGISTER_TEST(TestLog);
|
||||
#include "TestLog.moc"
|
158
third_party/QsLog/unittest/TestLog.h
vendored
Normal file
158
third_party/QsLog/unittest/TestLog.h
vendored
Normal file
@ -0,0 +1,158 @@
|
||||
#ifndef TESTLOG_H
|
||||
#define TESTLOG_H
|
||||
|
||||
#include "QsLogDest.h"
|
||||
#include "QsLogDestFile.h"
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QDir>
|
||||
|
||||
// A destination that tracks log messages
|
||||
class MockDestination : public QsLogging::Destination
|
||||
{
|
||||
public:
|
||||
struct Message
|
||||
{
|
||||
Message() : level(QsLogging::TraceLevel) {}
|
||||
QString text;
|
||||
QsLogging::Level level;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit MockDestination(const QLatin1String& myType = QLatin1String("mock"))
|
||||
: mMyType(myType)
|
||||
{
|
||||
}
|
||||
|
||||
void write(const QsLogging::LogMessage& message) override
|
||||
{
|
||||
Message m;
|
||||
m.text = message.formatted;
|
||||
m.level = message.level;
|
||||
mMessages.push_back(m);
|
||||
++mCountByLevel[message.level];
|
||||
}
|
||||
|
||||
bool isValid() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QString type() const override
|
||||
{
|
||||
return mMyType;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
mMessages.clear();
|
||||
mCountByLevel.clear();
|
||||
}
|
||||
|
||||
int messageCount() const
|
||||
{
|
||||
return mMessages.count();
|
||||
}
|
||||
|
||||
int messageCountForLevel(QsLogging::Level level) const
|
||||
{
|
||||
return mCountByLevel.value(level);
|
||||
}
|
||||
|
||||
bool hasMessage(const QString &messageContent, QsLogging::Level level) const
|
||||
{
|
||||
Q_FOREACH (const Message &m, mMessages) {
|
||||
if (m.level == level && m.text.contains(messageContent))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const Message& messageAt(int index)
|
||||
{
|
||||
Q_ASSERT(index >= 0 && index < messageCount());
|
||||
return mMessages.at(index);
|
||||
}
|
||||
|
||||
private:
|
||||
QHash<QsLogging::Level,int> mCountByLevel;
|
||||
QList<Message> mMessages;
|
||||
QLatin1String mMyType;
|
||||
};
|
||||
|
||||
// A rotation strategy that simulates file rotations.
|
||||
// Stores a "file system" inside a string list and can perform some operations on it.
|
||||
class MockSizeRotationStrategy : public QsLogging::SizeRotationStrategy
|
||||
{
|
||||
public:
|
||||
MockSizeRotationStrategy()
|
||||
: fakePath("FAKEPATH")
|
||||
, logName("QsLog.txt")
|
||||
{
|
||||
setInitialInfo(QDir(fakePath).filePath(logName), 0);
|
||||
files.append(logName);
|
||||
}
|
||||
|
||||
const QStringList& filesList() {
|
||||
return files;
|
||||
}
|
||||
|
||||
void rotate() override {
|
||||
SizeRotationStrategy::rotate();
|
||||
files.append(logName);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool removeFileAtPath(const QString& path) override {
|
||||
QString editedPath = path;
|
||||
if (editedPath.startsWith(fakePath)) {
|
||||
editedPath.remove(0, fakePath.size() + 1);
|
||||
const int indexOfPath = files.indexOf(editedPath);
|
||||
if (indexOfPath != -1) {
|
||||
files.removeAt(indexOfPath);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool fileExistsAtPath(const QString& path) override {
|
||||
QString editedPath = path;
|
||||
if (editedPath.startsWith(fakePath)) {
|
||||
editedPath.remove(0, fakePath.size() + 1);
|
||||
return files.indexOf(editedPath) != -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool renameFileFromTo(const QString& from, const QString& to) override {
|
||||
QString editedFromPath = from;
|
||||
QString editedToPath = to;
|
||||
|
||||
if (editedFromPath.startsWith(fakePath) && editedToPath.startsWith(fakePath)) {
|
||||
editedFromPath.remove(0, fakePath.size() + 1);
|
||||
editedToPath.remove(0, fakePath.size() + 1);
|
||||
const int ind = files.indexOf(editedFromPath);
|
||||
if (ind != -1) {
|
||||
files.removeAll(editedFromPath);
|
||||
files.append(editedToPath);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
QStringList files;
|
||||
const QString fakePath;
|
||||
const QString logName;
|
||||
};
|
||||
|
||||
|
||||
#endif // TESTLOG_H
|
||||
|
29
third_party/QsLog/unittest/unittest.pro
vendored
Normal file
29
third_party/QsLog/unittest/unittest.pro
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
QT += core
|
||||
|
||||
TARGET = QsLogUnitTest
|
||||
CONFIG += console qtestlib c++11
|
||||
CONFIG -= app_bundle
|
||||
TEMPLATE = app
|
||||
|
||||
# optionally enable address sanitizer
|
||||
linux-g++|macx {
|
||||
QMAKE_CXXFLAGS += -fsanitize=address
|
||||
QMAKE_LFLAGS += -fsanitize=address
|
||||
}
|
||||
|
||||
# test-case sources
|
||||
SOURCES += TestLog.cpp
|
||||
|
||||
HEADERS += TestLog.h
|
||||
|
||||
# component sources
|
||||
include(../QsLog.pri)
|
||||
|
||||
SOURCES += \
|
||||
./QtTestUtil/TestRegistry.cpp \
|
||||
./QtTestUtil/SimpleChecker.cpp
|
||||
|
||||
HEADERS += \
|
||||
./QtTestUtil/TestRegistry.h \
|
||||
./QtTestUtil/TestRegistration.h \
|
||||
./QtTestUtil/QtTestUtil.h
|
Loading…
x
Reference in New Issue
Block a user