log.h 13.7 KB
/* ****************************************************************************
 * Copyright 2019 Open Systems Development BV                                 *
 *                                                                            *
 * Permission is hereby granted, free of charge, to any person obtaining a    *
 * copy of this software and associated documentation files (the "Software"), *
 * to deal in the Software without restriction, including without limitation  *
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
 * and/or sell copies of the Software, and to permit persons to whom the      *
 * Software is furnished to do so, subject to the following conditions:       *
 *                                                                            *
 * The above copyright notice and this permission notice shall be included in *
 * all copies or substantial portions of the Software.                        *
 *                                                                            *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING    *
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER        *
 * DEALINGS IN THE SOFTWARE.                                                  *
 * ***************************************************************************/
#pragma once

#include <string>
#include <syslog.h>

namespace osdev      {
namespace components {
namespace log        {

#define LogEmergency(context, text)                                                         \
    if (osdev::components::log::Log::level() >= osdev::components::log::LogLevel::Emergency)\
    {                                                                                       \
        osdev::components::log::Log::emergency(__FILE__, __LINE__, context, text);          \
    }

#define LogAlert(context, text)                                                             \
    if (osdev::components::log::Log::level() >= osdev::components::log::LogLevel::Alert)    \
    {                                                                                       \
        osdev::components::log::Log::alert(__FILE__, __LINE__, context, text);              \
    }

#define LogCritical(context, text)                                                          \
    if (osdev::components::log::Log::level() >= osdev::components::log::LogLevel::Critical) \
    {                                                                                       \
        osdev::components::log::Log::critical(__FILE__, __LINE__, context, text);           \
    }

#define LogError(context, text)                                                             \
    if (osdev::components::log::Log::level() >= osdev::components::log::LogLevel::Error)    \
    {                                                                                       \
        osdev::components::log::Log::error(__FILE__, __LINE__, context, text);              \
    }

#define LogWarning(context, text)                                                           \
    if (osdev::components::log::Log::level() >= osdev::components::log::LogLevel::Warning)  \
    {                                                                                       \
        osdev::components::log::Log::warning(__FILE__, __LINE__, context, text);            \
    }

#define LogNotice(context, text)                                                            \
    if (osdev::components::log::Log::level() >= osdev::components::log::LogLevel::Notice)   \
    {                                                                                       \
        osdev::components::log::Log::notice(__FILE__, __LINE__, context, text);             \
    }

#define LogInfo(context, text)                                                              \
    if (osdev::components::log::Log::level() >= osdev::components::log::LogLevel::Info)     \
    {                                                                                       \
        osdev::components::log::Log::info(__FILE__, __LINE__, context, text);               \
    }

#define LogDebug(context, text)                                                             \
    if (osdev::components::log::Log::level() >= osdev::components::log::LogLevel::Debug)    \
    {                                                                                       \
        osdev::components::log::Log::debug(__FILE__, __LINE__, context, text);              \
    }

/*!
 * \brief The LogLevel enum
 * Enumeration class dealing with LogLevels.
 * Used to convert to syslog macro's.
 */
enum class LogLevel
{
    Emergency = 0,
    Alert,
    Critical,
    Error,
    Warning,
    Notice,
    Info,
    Debug
};

/*!
 * \brief The LogMask enum
 * Enumeration class dealing with LogMask.
 * Used to convert to syslog macro's.
 */
enum class LogMask
{
    Mask = 0,
    Upto,
    None
};

struct LogSettings
{
    LogLevel level = LogLevel::Info;
    LogMask mask = LogMask::Upto;
};

/*! \class Log
    \brief Basic logging mechanism.
*/
class Log
{
public:
    /**
     *  @brief  Initialize the logging mechanism
     *  @param  context     - The main context
     *  @param  logFile     - Logfile if available
     *  @param  logDepth    - Initial log-depth
     */
    static void init( const std::string& context,
                      const std::string& logFile = std::string(),
                      LogLevel logDepth = LogLevel::Info );

    //! Shutdown the logging mechanism
    static void terminate();

    /*!
     * \brief Write to syslog
     * \param priority      - priority level [from debug up to emergency]
     * \param message       - The string to print
     * \param context       - The context name. default name is the name of the executable.
     */
    static void write( const int &priority, const std::string &message, const std::string &context = std::string() );

    /**
     *  @brief  Log an emergency message in a category.
     *  @param  file        - Name of the source-file
     *  @param  line        - The line number in the source-file
     *  @param  category    - The category of the message.
     *  @param  message     - The string to print
     */
    static void emergency( const char* file, int line, const std::string& category, const std::string& message );
    /**
     *  @brief  Log an alert message in a category.
     *  @param  file        - Name of the source-file
     *  @param  line        - The line number in the source-file
     *  @param  category    - The category of the message.
     *  @param  message     - The string to print
     */
    static void alert    ( const char* file, int line, const std::string& category, const std::string& message );
    /**
     *  @brief  Log a critical message in a category.
     *  @param  file        - Name of the source-file
     *  @param  line        - The line number in the source-file
     *  @param  category    - The category of the message.
     *  @param  message     - The string to print
     */
    static void critical ( const char* file, int line, const std::string& category, const std::string& message );
    /**
     *  @brief  Log an error message in a category.
     *  @param  file        - Name of the source-file
     *  @param  line        - The line number in the source-file
     *  @param  category    - The category of the message.
     *  @param  message     - The string to print
     */
    static void error    ( const char* file, int line, const std::string& category, const std::string& message );
    /**
     *  @brief  Log a warning message in a category.
     *  @param  file        - Name of the source-file
     *  @param  line        - The line number in the source-file
     *  @param  category    - The category of the message.
     *  @param  message     - The string to print
     */
    static void warning  ( const char* file, int line, const std::string& category, const std::string& message );
    /**
     *  @brief  Log a notice message in a category.
     *  @param  file        - Name of the source-file
     *  @param  line        - The line number in the source-file
     *  @param  category    - The category of the message.
     *  @param  message     - The string to print
     */
    static void notice   ( const char* file, int line, const std::string& category, const std::string& message );
    /**
     *  @brief  Log an info message in a category.
     *  @param  file        - Name of the source-file
     *  @param  line        - The line number in the source-file
     *  @param  category    - The category of the message.
     *  @param  message     - The string to print
     */
    static void info     ( const char* file, int line, const std::string& category, const std::string& message );
    /**
     *  @brief  Log a debug message in a category.
     *  @param  file        - Name of the source-file
     *  @param  line        - The line number in the source-file
     *  @param  category    - The category of the message.
     *  @param  message     - The string to print
     */
    static void debug    ( const char* file, int line, const std::string& category, const std::string& message );

    /**
     *  @return The current log level.
     */
    static LogLevel level()
    {
        if( s_logMask == LogMask::None )
        {
            return LogLevel::Debug;
        }
        return s_logLevel;
    }

    /*!
     * \brief setMask update the current logMask
     * \param logMask   - Enum defining the logmask used.
     */
    static void setMask    ( LogMask logMask )     { s_logMask = logMask;   }
    /*!
     * \brief setLogLevel update the current logLevel
     * \param logLevel  - Enum defining the logLevel used, in combination with Mask.
     */
    static void setLogLevel( LogLevel logLevel )   { s_logLevel = logLevel; }
    /*!
     * \brief setContext update the current context
     * \param context   - String containing the new context name.
     */
    static void setContext ( std::string context ) { s_context = context;   }

protected:
    /**
     * @brief Log an emergency message in a category.
     * @param category The category of the message.
     * @param message The string to print.
     */
    static void emergency( const std::string& category, const std::string& message );
    /**
     * @brief Log an alert message in a category.
     * @param category The category of the message.
     * @param message The string to print.
     */
    static void alert    ( const std::string& category, const std::string& message );
    /**
     * @brief Log a critical message in a category.
     * @param category The category of the message.
     * @param message The string to print.
     */
    static void critical ( const std::string& category, const std::string& message );
    /**
     * @brief Log an error message in a category.
     * @param category The category of the message.
     * @param message The string to print.
     */
    static void error    ( const std::string& category, const std::string& message );
    /**
     * @brief Log a warning message in a category.
     * @param category The category of the message.
     * @param message The string to print.
     */
    static void warning  ( const std::string& category, const std::string& message );
    /**
     * @brief Log a notice message in a category.
     * @param category The category of the message.
     * @param message The string to print.
     */
    static void notice   ( const std::string& category, const std::string& message );
    /**
     * @brief Log an info message in a category.
     * @param category The category of the message.
     * @param message The string to print.
     */
    static void info     ( const std::string& category, const std::string& message );
    /**
     * @brief Log an debug message in a category.
     * @param category The category of the message.
     * @param message The string to print.
     */
    static void debug    ( const std::string& category, const std::string& message );

    /**
     * @brief Log an error message in a category.
     * @param category The category of the message.
     * @param message The string to print.
     * @param level Selected log level
     */
    static void log( const std::string &category,
        const std::string &message,
        LogLevel level );

private:
    /**
     * @brief Replace the characters in a std::string with other characters.
     * @param strToReplace  The string we want to replace characters in
     * @param from_chars    The characters we want to replace
     * @param to_chars      The characters we want to replace with.
     * @return strToReplace This is the original string with the replaced characters.
     */
    static void ReplaceAll( std::string &strToReplace, const std::string& from_chars, const std::string& to_chars );

    /**
     * @brief Put filename, line-number and message in one string
     * @param file Source-file
     * @param line Line in source-file
     * @param message The string to print
     * @return Formatted string with file, line and message
     */
    static std::string fileinfoMessage(const char* file, int line,
                                   const std::string& message);

    //! The main context.
    static std::string  s_context;

    //! The name of the LogFile.
    static std::string  s_fileName;

    //! The amount of logging
    static LogLevel     s_logLevel;

    //! The mask
    static LogMask      s_logMask;
};

} // End namespace log
} // End namespace components
} // End namespace osdev