Commit 25b0d2f8ec5d44d1ed96076b33a185337c0a3ad1

Authored by Peter M. Groen
1 parent f23cf8e6

Setting up Logging mechanism

CMakeLists.txt
... ... @@ -35,3 +35,5 @@ add_subdirectory(examples/sub)
35 35  
36 36 include(packaging)
37 37 package_component()
  38 +
  39 +add_subdirectory(test)
... ...
include/log.h
1 1 #pragma once
2 2  
  3 +// std
3 4 #include <syslog.h>
4 5 #include <unistd.h>
  6 +#include <string>
5 7  
6 8 namespace osdev {
7 9 namespace components {
8 10 namespace mqtt {
9 11  
10   -static void LogTrace();
  12 +#define LogTrace(context, text) \
  13 + if ( osdev::components::mqtt::Log::level() <= osdev::components::mqtt::LogLevel::Trace ) { \
  14 + osdev::components::mqtt::Log::trace(__FILE__, __LINE__, context, text); \
  15 + }
11 16  
12   -static void LogDebug();
  17 +#define LogDebug(context, text) \
  18 + if ( osdev::components::mqtt::Log::level() <= osdev::components::mqtt::LogLevel::Debug ) { \
  19 + osdev::components::mqtt::Log::debug(__FILE__, __LINE__, context, text); \
  20 + }
13 21  
14   -static void LogInfo();
  22 +#define LogInfo(context, text) \
  23 + if ( osdev::components::mqtt::Log::level() <= osdev::components::mqtt::LogLevel::Info ) { \
  24 + osdev::components::mqtt::Log::info(__FILE__, __LINE__, context, text); \
  25 + }
15 26  
16   -static void LogWarning();
  27 +#define LogWarning(context, text) \
  28 + if ( osdev::components::mqtt::Log::level() <= osdev::components::mqtt::LogLevel::Warning ) {\
  29 + osdev::components::mqtt::Log::warning(__FILE__, __LINE__, context, text); \
  30 + }
17 31  
18   -static void LogError();
  32 +#define LogError(context, text) \
  33 + if ( osdev::components::mqtt::Log::level() <= osdev::components::mqtt::LogLevel::Error ) { \
  34 + osdev::components::mqtt::Log::error(__FILE__, __LINE__, context, text); \
  35 + }
  36 +
  37 +enum class LogLevel
  38 +{
  39 + Trace,
  40 + Debug,
  41 + Info,
  42 + Warning,
  43 + Error
  44 +};
  45 +
  46 +/*! \class Log
  47 + * \brief Basic logging mechanism.
  48 + */
  49 +class Log
  50 +{
  51 +public:
  52 + /**
  53 + * @brief String that identifies the start of the program in the logging.
  54 + */
  55 + static const std::string s_startMarker;
  56 +
  57 + /**
  58 + * @brief Initialize the logging mechanism
  59 + * @param context - The main context
  60 + * @param logFile - Logfile if available
  61 + * @param logDepth - Initial log-depth
  62 + */
  63 + static void init( const std::string &context,
  64 + const std::string &logFile,
  65 + LogLevel logDepth = LogLevel::Info);
  66 +
  67 + //! Shutdown the logging mechanism
  68 + static void terminate();
  69 +
  70 + /**
  71 + * @brief Log a trace message in a category.
  72 + * @param file - Name of the source-file
  73 + * @param line - The line number in the source-file
  74 + * @param category - The category of the message.
  75 + * @param message - The string to print
  76 + */
  77 + static void trace( const char *file, int line,
  78 + const std::string &category, const std::string &message );
  79 +
  80 + /**
  81 + * @brief Log a debug message in a category.
  82 + * @param file - Name of the source-file
  83 + * @param line - The line number in the source-file
  84 + * @param category - The category of the message.
  85 + * @param message - The string to print
  86 + */
  87 + static void debug( const char *file, int line,
  88 + const std::string &category, const std::string &message );
  89 +
  90 + /**
  91 + * @brief Log an info message in a category.
  92 + * @param file - Name of the source-file
  93 + * @param line - The line number in the source-file
  94 + * @param category - The category of the message.
  95 + * @param message - The string to print
  96 + */
  97 + static void info( const char *file, int line,
  98 + const std::string &category, const std::string &message );
  99 +
  100 + /**
  101 + * @brief Log a warning message in a category.
  102 + * @param file - Name of the source-file
  103 + * @param line - The line number in the source-file
  104 + * @param category - The category of the message.
  105 + * @param message - The string to print
  106 + */
  107 + static void warning( const char *file, int line,
  108 + const std::string &category, const std::string &message );
  109 +
  110 + /**
  111 + * @brief Log an error message in a category.
  112 + * @param file - Name of the source-file
  113 + * @param line - The line number in the source-file
  114 + * @param category - The category of the message.
  115 + * @param message - The string to print
  116 + */
  117 + static void error( const char *file, int line,
  118 + const std::string &category, const std::string &message );
  119 +
  120 + /**
  121 + * @return The current log level.
  122 + */
  123 + static LogLevel level()
  124 + {
  125 + return s_logLevel;
  126 + }
  127 +
  128 +protected:
  129 + /**
  130 + * @brief Log a debug message in a category.
  131 + * @param category The category of the message.
  132 + * @param message The string to print.
  133 + */
  134 + static void trace(const std::string &category, const std::string &message);
  135 +
  136 + /**
  137 + * @brief Log a debug message in a category.
  138 + * @param category The category of the message.
  139 + * @param message The string to print.
  140 + */
  141 + static void debug(const std::string &category, const std::string &message);
  142 +
  143 + /**
  144 + * @brief Log an info message in a category.
  145 + * @param category The category of the message.
  146 + * @param message The string to print.
  147 + */
  148 + static void info(const std::string &category, const std::string &message);
  149 +
  150 + /**
  151 + * @brief Log a warning message in a category.
  152 + * @param category The category of the message.
  153 + * @param message The string to print.
  154 + */
  155 + static void warning(const std::string &category, const std::string &message);
  156 +
  157 + /**
  158 + * @brief Log an error message in a category.
  159 + * @param category The category of the message.
  160 + * @param message The string to print.
  161 + */
  162 + static void error(const std::string &category, const std::string &message);
  163 +
  164 + //! Create a convenient timestamp
  165 + static std::string getDateTime();
  166 +
  167 + /**
  168 + * @brief Write the message to the logfile
  169 + * @param category The category of the message.
  170 + * @param message The string to print.
  171 + * @param level Selected log level
  172 + */
  173 + static void writeLog(const std::string &category,
  174 + const std::string &message,
  175 + LogLevel level);
  176 +
  177 + /**
  178 + * @brief Log an error message in a category.
  179 + * @param category The category of the message.
  180 + * @param message The string to print.
  181 + * @param level Selected log level
  182 + */
  183 + static void log(const std::string &category,
  184 + const std::string &message,
  185 + LogLevel level);
  186 +
  187 +private:
  188 + /**
  189 + * @brief Put filename, line-number and message in one string
  190 + * @param file Source-file
  191 + * @param line Line in source-file
  192 + * @param message The string to print
  193 + * @return Formatted string with file, line and message
  194 + */
  195 + static std::string fileinfoMessage(const char* file, int line,
  196 + const std::string &message);
  197 +
  198 + //! The main context.
  199 + static std::string s_context;
  200 +
  201 + //! The name of the LogFile.
  202 + static std::string s_fileName;
  203 +
  204 + //! The amount of logging
  205 + static LogLevel s_logLevel;
  206 +};
19 207  
20 208 } /* End namespace mqtt */
21 209 } /* End namespace components */
... ...
include/threadcontext.h 0 โ†’ 100644
  1 +#pragma once
  2 +
  3 +// std
  4 +#include <string>
  5 +
  6 +namespace osdev {
  7 +namespace components {
  8 +namespace mqtt {
  9 +
  10 +/**
  11 + * @brief Set the current thread context
  12 + * The context is restored to the previous context when this object goes out of scope.
  13 + * @note This object is meat to be used on the stack.
  14 + */
  15 +class ThreadContextScope
  16 +{
  17 +public:
  18 + /**
  19 + * @brief Construct a scoped object that sets the current thread context.
  20 + * @param context The context that will be used by the loggin framework.
  21 + */
  22 + explicit ThreadContextScope( const std::string &context );
  23 + ~ThreadContextScope();
  24 +
  25 + // Non copyable and non movable
  26 + ThreadContextScope( const ThreadContextScope& ) = delete;
  27 + ThreadContextScope& operator=( const ThreadContextScope& ) = delete;
  28 + ThreadContextScope( ThreadContextScope&& ) = delete;
  29 + ThreadContextScope& operator=( ThreadContextScope&& ) = delete;
  30 +
  31 +private:
  32 + std::string m_previousContext; ///< Copy of the previous context.
  33 +};
  34 +
  35 +/**
  36 + * @brief Add context to a thread.
  37 + * For every thread only one specific instance of this object will exist.
  38 + * @note Contexts can only be set by using a ThreadContextScope object.
  39 + */
  40 +class ThreadContext
  41 +{
  42 + // Contexts can only be set by using the ThreadContextScope object.
  43 + friend class ThreadContextScope;
  44 +
  45 +public:
  46 + static ThreadContext& instance();
  47 +
  48 + /**
  49 + * @briefReturn the thread context.
  50 + */
  51 + void setContext( const std::string &contextString)
  52 + {
  53 + m_context = contextString;
  54 + }
  55 +
  56 + /**
  57 + * Construct a ThreadContext object.
  58 + * The context is set to "default"
  59 + */
  60 + ThreadContext();
  61 +
  62 + // Non copyable and non moveable
  63 + ThreadContext(const ThreadContext&) = delete;
  64 + ThreadContext& operator=(const ThreadContext&) = delete;
  65 + ThreadContext(ThreadContext&&) = delete;
  66 + ThreadContext& operator=(ThreadContext&&) = delete;
  67 +
  68 + std::string m_context; ///< The context string
  69 +};
  70 +
  71 +} // End namespace mqtt
  72 +} // End namespace components
  73 +} // End namespace osdev
... ...
src/CMakeLists.txt
... ... @@ -59,6 +59,8 @@ set(SRC_LIST
59 59 ${CMAKE_CURRENT_SOURCE_DIR}/sharedreaderlock.cpp
60 60 ${CMAKE_CURRENT_SOURCE_DIR}/stringutils.cpp
61 61 ${CMAKE_CURRENT_SOURCE_DIR}/uriparser.cpp
  62 + ${CMAKE_CURRENT_SOURCE_DIR}/log.cpp
  63 + ${CMAKE_CURRENT_SOURCE_DIR}/threadcontext.cpp
62 64 )
63 65  
64 66 include(library)
... ...
src/log.cpp 0 โ†’ 100644
  1 +#include "log.h"
  2 +
  3 +// std
  4 +
  5 +
  6 +
  7 +using namespace osdev::components::mqtt;
  8 +
  9 +namespace {
  10 +
  11 +std::string toString( LogLevel level )
  12 +{
  13 + switch (level)
  14 + {
  15 + case LogLevel::Trace:
  16 + return "T";
  17 + case LogLevel::Debug:
  18 + return "D";
  19 + case LogLevel::Info:
  20 + return "I";
  21 + case LogLevel::Warning:
  22 + return "W";
  23 + case LogLevel::Error:
  24 + return "E";
  25 + }
  26 + return "U";
  27 +}
  28 +
  29 +} // namespace
  30 +
  31 +const std::string Log::s_startMarker = std::string("|________________________________________________________________________________________________________________________________|");
  32 +std::string Log::s_context = std::string();
  33 +std::string Log::s_fileName = std::string();
  34 +LogLevel Log::s_logLevel = LogLevel::Info;
  35 +
  36 +void Log::init( const std::string &context, const std::string &logFile, LogLevel logDepth )
  37 +{
  38 + s_logLevel = logDepth;
  39 + s_context = context;
  40 +
  41 + if( !logFile.empty())
  42 + {
  43 + s_fileName = logFile;
  44 + }
  45 +}
  46 +
  47 +void Log::terminate()
  48 +{
  49 + s_context.clear();
  50 + s_fileName.clear();
  51 + s_logLevel = LogLevel::Info;
  52 +}
  53 +
  54 +void Log::log( const std::string &category, const std::string &message, LogLevel level )
  55 +{
  56 + std::string logCategory = s_context + '|' + toString( level ) + '|' + ThreadContext::instance().context() + '|' + category;
  57 + std::string logMessage = message;
  58 + if( logMessage.empty() )
  59 + {
  60 + static const std::string emptyMessage( "--" );
  61 + logMessage = emptyMessage;
  62 + }
  63 + else
  64 + {
  65 + // Replace % signs
  66 + logMessage.replace( '%', "%%");
  67 + }
  68 +
  69 + writeLog( logCategory, logMessage, level );
  70 +}
... ...
src/threadcontext.cpp 0 โ†’ 100644
  1 +#include "threadcontext.h"
  2 +
  3 +// std
  4 +#include <thread>
  5 +
  6 +using namespace osdev::components::mqtt;
  7 +
  8 +ThreadContextScope::ThreadContextScope( const std::string &_context )
  9 + : m_previousContext( ThreadContext::instance().context() )
  10 +{
  11 + ThreadContext::instance().setContext( _context );
  12 +}
  13 +
  14 +ThreadContextScope::~ThreadContextScope()
  15 +{
  16 + ThreadContext::instance().setContext( m_previousContext );
  17 +}
  18 +
  19 +// static
  20 +ThreadContext& ThreadContext::instance()
  21 +{
  22 + static thread_local ThreadContext tc;
  23 + return tc;
  24 +}
  25 +
  26 +ThreadContext::ThreadContext()
  27 + : m_context( "default" )
  28 +{
  29 +
  30 +}
... ...
test/CMakeLists.txt 0 โ†’ 100644
  1 +cmake_minimum_required(VERSION 3.10)
  2 +LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake)
  3 +
  4 +include(projectheader)
  5 +project_header(mqtt_test)
  6 +
  7 +find_package(GTest)
  8 +
  9 +include_directories( SYSTEM
  10 + ${CMAKE_CURRENT_SOURCE_DIR}/../include
  11 +)
  12 +
  13 +include (compiler)
  14 +set(SRC_LIST
  15 + ${CMAKE_CURRENT_SOURCE_DIR}/mqtt_test.cpp
  16 +)
  17 +
  18 +add_executable( ${PROJECT_NAME}
  19 + ${SRC_LIST}
  20 +)
  21 +
  22 +target_link_libraries(
  23 + ${PROJECT_NAME}
  24 + mqtt-cpp
  25 +)
  26 +
  27 +set_target_properties( ${PROJECT_NAME} PROPERTIES
  28 + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
  29 + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
  30 + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/archive
  31 +)
  32 +
  33 +include(installation)
  34 +install_application()
  35 +
... ...
test/mqtt_test.cpp 0 โ†’ 100644
  1 +#include <gtest/gtest.h>
  2 +
  3 +TEST(MqttTest PublishWithoutConnect)
  4 +{
  5 +
  6 +}
... ...