view Utils/Log.h @ 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 source

//////////////////////////////////////////////////////////////////////////////
/// \file   Log.h
/// \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.
//
//////////////////////////////////////////////////////////////////////////////
// HISTORY
//  2013-07-01  jDG: Creation.
//  2016-05-24  jDG: BSD-2 version.

#ifndef LOG_H
#define LOG_H

#include <QString>
#include <QStringList>
#include <QByteArray>

//class QStringList;
//class QByteArray;

#define LOG_MAX_MESSAGE_LENGTH 2048

//////////////////////////////////////////////////////////////////////////////
/// \brief  Basic logging tool
///
///
/// Provides easy and centralized log messages for the application.
/// Typical usage:
/// \code
///     main(int argc, char* argv[])
///     {
///         Log::autoLoad(argc, argv);  // Read XML configuration.
///         LOG_TRACE("... ");          // Just a tick where we are.
///
///         LOG_INFO("Main started");   // Visible message (users can see it).
///         LOG_TRACE("Now argc=" << argc);
///         LOG_TRACE("Invisible message, only for log files");
///         LOG_DEBUG("Invisible, and logged only if run with a "-d" argument");
///     }
/// \endcode
///
/// \note that message destination can be multiple, and are the responsability
/// of the LogAppender class hierarchy.
///
/// \sa LogAppender, LogConsole, LogFile.
class  Log
{
    /// Application's reference.
    static QString _applicationPath;
    static QString _applicationName;

public:
    //////////////////////////////////////////////////////////////////////////
    /// \{
    /// \name Record message and context

    //------------------------------------------------------------------------
    /// \brief Log level: severity scale.
    enum Level {
        LEVEL_NOERROR = 0,
        LEVEL_DEBUG,        ///< The most verbose one, used only during debug session.
        LEVEL_TRACE,        ///< Messages to be put in silent log files, for post-mortem analysis.
        LEVEL_INFO,         ///< General information send to the final user.
        LEVEL_WARNING,      ///< Error reported to the user (eg. with a Qt warning box. \sa LogAppenderWindow).
        LEVEL_THROW,        ///< Error that is mean to be catched, and corrected automatically.
        LEVEL_ERROR         ///< Fatal error that cannot be recovered. The program should halt.
    };

    //------------------------------------------------------------------------
    const Level       level;            ///< Event's log level.
    const QString     file;             ///< Source file that fired the log event.
    const int         line;             ///< Source line that fired the log event.
    const QString     function;         ///< Function (and class) that fired the event.
    QString           message;          ///< The log message itself.

    /// \}
    //////////////////////////////////////////////////////////////////////////
    /// \{
    /// \name Global services

    //------------------------------------------------------------------------
    /// \brief Minimal error level to log.
    ///
    /// Defaults to LEVEL_TRACE.
    static Level minLevel;

    //------------------------------------------------------------------------
    /// \brief Initialize the log system, by loading some XML config.
    ///
    /// Might be used to change logging configuration of installed
    /// applications.
    //------------------------------------------------------------------------
    /// Initialize the log system, by loading some XML config.
    static void autoLoad(int argc, char *argv[]);

    //------------------------------------------------------------------------
    /// \brief Initialize the log system, without configurations.
    ///
    /// Then one can instanciate LogAppender classes in a static way.
    static void init(int& argc, char* argv[]);

    //------------------------------------------------------------------------
    /// \brief End the log systems, closing all appenders.
    static void close();

    //------------------------------------------------------------------------
    /// \brief Utility to retrieve where the executable was installed.
    static inline QString applicationPath();

    /// \brief Utility to retrieve the executable's name.
    static inline QString applicationName();

    /// \}

protected:
    /// \brief Constructor
    ///
    /// All message are to be created by a LogAction instance, responsible
    /// to build-up the message, and to send it to LogAppender instances.
    Log(Level level, const char *file, int line, const char *function);
};

inline QString Log::applicationPath() { return _applicationPath; }
inline QString Log::applicationName() { return _applicationName; }

//////////////////////////////////////////////////////////////////////////////
/// \brief Creates a Log event.
///
/// Uses object's destructor to send the Log into all registered log appenders.
class  LogAction
  : public Log
{
public:
    /// Starts a log line, with timestamp and source-stamp.
    LogAction(Level level, const char* file, int line, const char* function);

    /// Finish (and print) a log line.
    ~LogAction();

    /// Appends a single char to the log line.
    LogAction& operator<<(char msg);
    /// Appends a single char to the log line.
    LogAction& operator<<(unsigned char msg);

    /// Appends a C string to the log line.
    LogAction& operator<<(const char* msg);
    /// Appends a Qt's wide-char string to the log line, converted to Latin1.
    LogAction& operator<<(const QString& msg);
    /// Appends a list of Qt's wide-char strings.
    LogAction& operator<<(const QStringList& msg);
    /// Appends a Qt's single-byte-string to the log line.
    LogAction& operator<<(const QByteArray& msg);

    /// Appends a float/double to the log line.
    LogAction& operator<<(double value);
    /// Appends a signed int/short/byte to the log line.
    LogAction& operator<<(int value);
    /// Appends an unsigned int/short/byte to the log line.
    LogAction& operator<<(unsigned int value);

    // Resole ambiguities for the C++ compiler.
    /// Appends a signed long to the log line.
    LogAction& operator<<(long value);
    /// Appends an unsigned long to the log line.
    LogAction& operator<<(unsigned long value);
    /// Appends a signed long long to the log line.
    LogAction& operator<<(long long value);
    /// Appends an unsigned long long to the log line.
    LogAction& operator<<(unsigned long long value);

    /// Print any pointer as an Hex address:
    LogAction& operator<<(const void* ptr);
};

#ifndef LOG_FUNCTION_
#   if defined __PRETTY_FUNCTION__
#       define LOG_FUNCTION_ __PRETTY_FUNCTION__
#   elif defined __FUNCSIG__
#       define LOG_FUNCTION_ __FUNCSIG__
#   elif defined __FUNCTION__
#       define LOG_FUNCTION_ __FUNCTION__
#   elif defined __func__
#       define LOG_FUNCTION_ __func__
#   elif defined LINUX
#       define LOG_FUNCTION_ __PRETTY_FUNCTION__
#   else
#       define LOG_FUNCTION_ __FILE__
#   endif
#endif

#define LOG_DEBUG(msg)   do { if( Log::minLevel <= Log::LEVEL_DEBUG  ) LogAction(Log::LEVEL_DEBUG,   __FILE__, __LINE__, LOG_FUNCTION_ ) << msg; } while(0)
#define LOG_TRACE(msg)   do { if( Log::minLevel <= Log::LEVEL_TRACE  ) LogAction(Log::LEVEL_TRACE,   __FILE__, __LINE__, LOG_FUNCTION_ ) << msg; } while(0)
#define LOG_INFO(msg)    do { if( Log::minLevel <= Log::LEVEL_INFO   ) LogAction(Log::LEVEL_INFO,    __FILE__, __LINE__, LOG_FUNCTION_ ) << msg; } while(0)
#define LOG_WARNING(msg) do { if( Log::minLevel <= Log::LEVEL_WARNING) LogAction(Log::LEVEL_WARNING, __FILE__, __LINE__, LOG_FUNCTION_ ) << msg; } while(0)
#define LOG_ERROR(msg)   do { if( Log::minLevel <= Log::LEVEL_ERROR  ) LogAction(Log::LEVEL_ERROR,   __FILE__, __LINE__, LOG_FUNCTION_ ) << msg; } while(0)

#include <sstream>   // Für std::ostringstream
#include "Exception.h"

// Hilfsmakros für stringification
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)

#define LOG_THROW_E(EXCEPTION, msg) \
    do { \
        LogAction log(Log::LEVEL_THROW, __FILE__, __LINE__, LOG_FUNCTION_ ); \
        log << msg; \
        throw EXCEPTION(log.message); \
    } while(0)

#define LOG_THROW(msg) \
    do { \
        LogAction log(Log::LEVEL_THROW, __FILE__, __LINE__, LOG_FUNCTION_ ); \
        log << msg; \
        throw ::Exception(log.message); \
    } while(0)

#define assert(e) \
    do { if( !(e) )                 \
        LOG_THROW("Assert: " #e);   \
    } while(0)

#endif // LOG_H