Mercurial > public > ostc_companion
diff Utils/Log.cpp @ 1:0b3630a29ad8
Initial version based on previous repository.
Project was ported to QT6 and in now cmake based.
| author | Ideenmodellierer <tiefenrauscher@web.de> |
|---|---|
| date | Thu, 27 Nov 2025 18:40:28 +0100 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Utils/Log.cpp Thu Nov 27 18:40:28 2025 +0100 @@ -0,0 +1,281 @@ +////////////////////////////////////////////////////////////////////////////// +/// \file Log.cpp +/// \brief Basic logging tool +/// \author JD Gascuel. +/// \copyright (c) 2011-2016 JD Gascuel. All rights reserved. +/// $Id$ +////////////////////////////////////////////////////////////////////////////// +// +// BSD 2-Clause License: +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. 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. +// +// 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 "Utils/Log.h" + +#include "Utils/Exception.h" +#include "Utils/LogConsole.h" +#include "Utils/LogFile.h" + +#include "Utils/LogAppender.h" + +#include <QDir> +#include <QStringList> +#include <QRegularExpression> + +// 2013-08-30 jDG: Because of Linux compile, +// we need to keep some minimal Qt4.8 compatibility... +#if !defined(NO_WIDGETS) && QT_VERSION > 0x050100 +# include <QWindow> +#endif + +// Will be automaticallt set more verbose by File or Console appender, +// if needed. +Log::Level Log::minLevel = Log::LEVEL_WARNING; +QString Log::_applicationPath; +QString Log::_applicationName; + +////////////////////////////////////////////////////////////////////////////// + +static QtMessageHandler forwarder = 0; +static void Qt5Error(QtMsgType type, const QMessageLogContext &ctx, const QString &msg) +{ + // Spurious error from Qt 5.4.1, when we DO NOT USE any SSL socket... + if( ctx.category && strcmp(ctx.category, "qt.network.ssl") == 0 ) + return; + + switch(type) { + case QtDebugMsg: LogAction(Log::LEVEL_DEBUG, ctx.file, ctx.line, ctx.function) << msg; break; + case QtInfoMsg: LogAction(Log::LEVEL_TRACE, ctx.file, ctx.line, ctx.function) << msg; break; + case QtWarningMsg: LogAction(Log::LEVEL_WARNING, ctx.file, ctx.line, ctx.function) << msg; break; + case QtCriticalMsg: LogAction(Log::LEVEL_ERROR, ctx.file, ctx.line, ctx.function) << msg; break; + case QtFatalMsg: LogAction(Log::LEVEL_ERROR, ctx.file, ctx.line, ctx.function) << msg; break; + } +} + +////////////////////////////////////////////////////////////////////////////// + +void Log::init(int& argc, char* argv[]) +{ + minLevel = Log::LEVEL_WARNING; + + //---- Get the current application name ---------------------------------- + if( argc > 0 && _applicationPath.isEmpty() ) + { + _applicationPath = QDir::current().absoluteFilePath( + QString::fromLatin1(argv[0]) + .replace('\\', '/')); + _applicationName = _applicationPath.section('/', -1); + _applicationPath = _applicationPath.section('/', 0, -2); + +#ifdef Q_OS_WIN32 + if( _applicationName.endsWith(".exe") ) + _applicationName = _applicationName.section('.', 0, -2); +#elif defined(Q_OS_MACX) + if( _applicationPath.endsWith("/MacOS") ) + _applicationPath = _applicationPath.section('/', 0, -2); +#elif defined(Q_OS_LINUX) + // Nothing special, yet. +#else +# error Unknown OS not yet implemented +#endif + + // Pop "/build/kitName" tail added by the QtCreator build process: + if( _applicationPath.section('/', -2, -2) == "build" ) + _applicationPath = _applicationPath.section('/', 0, -3); + if( _applicationPath.section('/', -1, -1) == "build" ) + _applicationPath = _applicationPath.section('/', 0, -2); + + // Pop /debug or /release tail too (Unix, Visual): + // QRegExp tail("[.]?(debug|release)", Qt::CaseInsensitive); + QRegularExpression tail( + R"([.]?(debug|release))", + QRegularExpression::CaseInsensitiveOption + ); + + // if( tail.exactMatch(_applicationPath.section('/', -1, -1)) ) + QRegularExpressionMatch match = + tail.match(_applicationPath.section('/', -1, -1)); + if (match.hasMatch()) + _applicationPath = _applicationPath.section('/', 0, -2); + if( _applicationName.endsWith(" DEBUG", Qt::CaseInsensitive) ) + _applicationName = _applicationName.left(_applicationName.length()-6); + + // Pop "/bin/" tail added by the configured build process: + if( _applicationPath.section('/', -1) == "bin" ) + _applicationPath = _applicationPath.section('/', 0, -2); + + if( _applicationName.isEmpty() ) + _applicationName = "log"; + } + + //---- Forward Qt's messages --------------------------------------------- + forwarder = qInstallMessageHandler(Qt5Error); + + //---- Instanciate 2 appenders ------------------------------------------- + new LogConsole(argc, argv); + new LogFile(argc, argv); +} + +////////////////////////////////////////////////////////////////////////////// + +void Log::close() +{ + LOG_TRACE("Closing logs."); + foreach(LogAppender* i, LogAppender::list()) + delete i; +} + +////////////////////////////////////////////////////////////////////////////// + +Log::Log(Level level, const char *f, int line, const char *function) +: level(level), + line(line), + function(function) +{ + // Skip trailing "../" in file name (due to QtCreator build dir): + while( f && f[0] == '.' && f[1] == '.' && (f[2] == '\\' || f[2] == '/') ) + f += 3; + const_cast<QString&>(file) = QString::fromLatin1(f).replace('\\', '/'); +} + +LogAction::LogAction(Level level, const char *file, int line, const char *function) +: Log(level, file, line, function) +{} + +////////////////////////////////////////////////////////////////////////////// +LogAction::~LogAction() +{ + LogAppender::all(*this); +} + +////////////////////////////////////////////////////////////////////////////// +LogAction &LogAction::operator<<(char msg) +{ + if( message.length() < (LOG_MAX_MESSAGE_LENGTH-1) ) + message += QChar(msg); // UTF-8 by default. + return *this; +} + +LogAction &LogAction::operator<<(unsigned char msg) +{ + if( message.length() < (LOG_MAX_MESSAGE_LENGTH-1) ) + message += QChar(msg); // UTF-8 by default. + return *this; +} + +LogAction& LogAction::operator<<(const char* msg) +{ + if( message.length()+strlen(msg) < (LOG_MAX_MESSAGE_LENGTH) ) + message += QString::fromUtf8(msg); + return *this; +} + +////////////////////////////////////////////////////////////////////////////// +LogAction& LogAction::operator<<(const QString& msg) +{ + if( message.length()+msg.length() < (LOG_MAX_MESSAGE_LENGTH) ) + message += msg; + return *this; +} + +LogAction &LogAction::operator <<(const QStringList& list) +{ + *this << "{"; + for(int i=0; i<list.count(); ++i) + { + if( i > 0 ) + *this << ", "; + *this << list[i]; + } + *this << "}"; + + return *this; +} + + +////////////////////////////////////////////////////////////////////////////// +LogAction& LogAction::operator<<(const QByteArray& msg) +{ + operator<<(QString::fromUtf8(msg)); + return *this; +} + +////////////////////////////////////////////////////////////////////////////// +LogAction& LogAction::operator<<(double value) +{ + operator<<(QString::number(value)); + return *this; +} + +////////////////////////////////////////////////////////////////////////////// +LogAction& LogAction::operator<<(int value) +{ + operator<<(QString::number(value)); + return *this; +} + +LogAction& LogAction::operator<<(unsigned int value) +{ + operator<<(QString::number(value)); + return *this; +} + +////////////////////////////////////////////////////////////////////////////// + +LogAction &LogAction::operator <<(unsigned long value) +{ + operator<<(QString::number((qulonglong)value)); + return *this; +} + +LogAction &LogAction::operator <<(long value) +{ + operator<<(QString::number((qlonglong)value)); + return *this; +} + +////////////////////////////////////////////////////////////////////////////// + +LogAction &LogAction::operator <<(unsigned long long value) +{ + operator<<(QString::number(value)); + return *this; +} + +LogAction &LogAction::operator <<(long long value) +{ + operator<<(QString::number(value)); + return *this; +} + +////////////////////////////////////////////////////////////////////////////// +LogAction &LogAction::operator <<(const void *ptr) +{ + operator<<("0x"); + operator<<(QString::number((qulonglong)ptr, 16)); + + return *this; +}
