log.h 7.65 KB
#pragma once

// std
#include <mutex>
#include <syslog.h>
#include <string>
#include <unistd.h>

namespace osdev {
namespace components {
namespace mqtt {

#define LogTrace(context, text)                                                                 \
    if ( osdev::components::mqtt::Log::level() <= osdev::components::mqtt::LogLevel::Trace ) {  \
         osdev::components::mqtt::Log::trace(__FILE__, __LINE__, context, text);                \
    }

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

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

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

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

enum class LogLevel
{
    Trace,
    Debug,
    Info,
    Warning,
    Error
};

/*! \class  Log
 *  \brief  Basic logging mechanism.
 */
class Log
{
public:
    /**
     *  @brief  String that identifies the start of the program in the logging.
     */
    static const std::string s_startMarker;

    /**
     *  @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,
                      LogLevel logDepth = LogLevel::Info);

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

    /**
     *  @brief  Log a trace 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 trace( 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 );

    /**
     *  @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 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 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 );

    /**
     *  @return The current log level.
     */
    static LogLevel level()
    {
        return s_logLevel;
    }

protected:
    /**
     * @brief Log a debug message in a category.
     * @param category The category of the message.
     * @param message The string to print.
     */
    static void trace(const std::string &category, const std::string &message);

    /**
     * @brief Log a 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 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 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 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);

    //! Create a convenient timestamp
    static std::string getDateTime();

    /**
     * @brief Write the message to the logfile
     * @param category The category of the message.
     * @param message The string to print.
     * @param level Selected log level
     */
    static void writeLog(const std::string &category,
        const std::string &message,
        LogLevel level);

    /**
     * @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 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);

    /**
     * @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 );


    //! 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;

    //! Mutex to keep the logger thread-safe
    static std::mutex   m_mutex;
};

}   /* End namespace mqtt */
}   /* End namespace components */
}   /* End namespace osdev */