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;
+}