Commit 13df26c37b0e553e59fac829980e99b69b226b94

Authored by Steven
0 parents

Static Logger class - initial push

.gitignore 0 → 100644
  1 +++ a/.gitignore
  1 +build/
  2 +CMakeLists.txt.user
  3 +
  4 +cmake/
  5 +versioning/
  6 +logutils/
  7 +pugixml/
  8 +config/
  9 +global/
  10 +
  11 +
  12 +.gitmodules
.gitmodules 0 → 100644
  1 +++ a/.gitmodules
  1 +[submodule "submodules/versioning"]
  2 + path = submodules/versioning
  3 + url = http://gitlab.osdev.nl/open_source/versioning.git
  4 +[submodule "submodules/cmake"]
  5 + path = submodules/cmake
  6 + url = http://gitlab.osdev.nl/open_source/cmake.git
CMakeLists.txt 0 → 100644
  1 +++ a/CMakeLists.txt
  1 +cmake_minimum_required(VERSION 3.0)
  2 +project(osdev_logger)
  3 +
  4 +LIST( APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/submodules/cmake )
  5 +LIST( APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/submodules/versioning/cmake )
  6 +
  7 +include(projectheader)
  8 +project_header(osdev_logger)
  9 +
  10 +add_subdirectory(src)
  11 +add_subdirectory(tests)
  12 +
  13 +#include(packaging)
  14 +#package_component()
README.md 0 → 100644
  1 +++ a/README.md
scripts/setup_submodules 0 → 100755
  1 +++ a/scripts/setup_submodules
  1 +#!/bin/bash
  2 +
  3 +# ===============================================
  4 +# == Setting some environment variables
  5 +# ===============================================
  6 +GIT_URL_OPEN="http://gitlab.osdev.nl/open_source"
  7 +GIT_URL_CLOSED="git@gitlab.osdev.nl:closed_source"
  8 +
  9 +FUNC_RESULT="-1"
  10 +
  11 +# Name : print_usage_exit()
  12 +# Description : Print the way this script is intended to be used and exit.
  13 +# Parameters : None.
  14 +# Returns : err_code 1 to the Operating System
  15 +# --------------------------------------------------------------------------------------
  16 +function print_usage_exit()
  17 +{
  18 + echo "Usage $0 -i|--install|-u|--update"
  19 + echo " -i or --install Install the submodules mentioned in the submodules.list"
  20 + echo " -u or --update Update the submodules mentioned in the submodules.list"
  21 + echo " "
  22 + exit 1
  23 +}
  24 +
  25 +# Name : check_top_or_sub
  26 +# Description : Determine if we're running in a "single" lib-build or part of a
  27 +# "meta"-repository ( submodule ).
  28 +# Parameters : None
  29 +# Returns : Updates the value FUNC_RESULT.
  30 +# -1 - We're neither a git-repo or submodule.
  31 +# 0 - We're a submodule
  32 +# 1 - We're a top-repo ( Single library )
  33 +# --------------------------------------------------------------------------------------
  34 +function check_top_or_sub()
  35 +{
  36 + # This function checks if we're the top-repository.
  37 + # In that case we need the submodules.. If we're already a submodule,
  38 + # we simply exit this script with a message
  39 + if [ -e ./.git ]; then
  40 + FUNC_RESULT="1"
  41 + return
  42 + elif [ -e ../.git ]; then
  43 + if [ -e ../.submodules ]; then
  44 + echo "Seems like we're already a submodule. Nothing to do here."
  45 + FUNC_RESULT="0"
  46 + return
  47 + fi
  48 + fi
  49 + FUNC_RESULT="-1"
  50 + return
  51 +}
  52 +
  53 +# Name : check_working_dir
  54 +# Description : If we're in the top of our repo, we can run this script further.
  55 +# Parameters : None.
  56 +# Returns : Updates the value FUNC_RESULT.
  57 +# -1 - Not used.
  58 +# 0 - We're not on the top-level
  59 +# 1 - We're at the top-level. Good to go.
  60 +# --------------------------------------------------------------------------------------
  61 +function check_working_dir()
  62 +{
  63 + FUNC_RESULT="-1"
  64 + # Check if we're in the top-level directory of our repository.
  65 + if [ -f ./scripts/submodules.list ]; then
  66 + # We're good to go
  67 + FUNC_RESULT="1"
  68 + return
  69 + fi
  70 + FUNC_RESULT="0"
  71 + return
  72 +}
  73 +
  74 +# Name : read_submodules
  75 +# Description : Read the list of submodules needed for this project
  76 +# Parameters : None
  77 +# Returns : Updates the value FUNC_RESULT
  78 +# 0 - Module list was not found
  79 +# 1 - Module list was found and read.
  80 +# --------------------------------------------------------------------------------------
  81 +function read_submodules()
  82 +{
  83 + FUNC_RESULT="-1"
  84 + if [ -e ./scripts/submodules.list ]; then
  85 + source ./scripts/submodules.list
  86 + FUNC_RESULT="1"
  87 + return
  88 + fi
  89 +
  90 + echo "Submodules list not found...."
  91 + FUNC_RESULT="0"
  92 + return
  93 +}
  94 +
  95 +# Name : add_submodules
  96 +# Description : Configure the repo to add the submodules.
  97 +# Parameters : None.
  98 +# Returns : None.
  99 +# --------------------------------------------------------------------------------------
  100 +function add_submodules()
  101 +{
  102 + echo -e "Adding SubModule(s)."
  103 + for SUB_MODULE in ${SUB_MODULES_OPEN}
  104 + do
  105 + git submodule add -f ${GIT_URL_OPEN}/${SUB_MODULE}.git submodules/${SUB_MODULE}
  106 + git config submodule.${SUB_MODULE}.url ${GIT_URL_OPEN}/${SUB_MODULE}.git
  107 + done
  108 +
  109 + for SUB_MODULE in ${SUB_MODULES_CLOSED}
  110 + do
  111 + echo {GIT_URL_CLOSED}/${SUB_MODULE}.git
  112 + git submodule add -f ${GIT_URL_CLOSED}/${SUB_MODULE}.git submodules/${SUB_MODULE}
  113 + git config submodule.${SUB_MODULE}.url ${GIT_URL_CLOSED}/${SUB_MODULE}.git
  114 + done
  115 +
  116 +}
  117 +
  118 +# Name : get_submodules
  119 +# Description : Actually get the submodules from gitlab and add them.
  120 +# Parameters : None
  121 +# Returns : None
  122 +# --------------------------------------------------------------------------------------
  123 +function get_submodules()
  124 +{
  125 + git submodule update --init --recursive
  126 +}
  127 +
  128 +# Name : update_submodules
  129 +# Description : Update the submodules already added.
  130 +# Parameters : None
  131 +# Returns : None
  132 +# --------------------------------------------------------------------------------------
  133 +function update_submodules()
  134 +{
  135 + git submodule update --recursive
  136 +}
  137 +
  138 +# =============================================================================
  139 +# == T H E M A I N E N T R Y O F T H I S S C R I P T ==
  140 +# =============================================================================
  141 +check_top_or_sub
  142 +if [ "${FUNC_RESULT}" == "0" ]; then
  143 + echo "Seems like we're a submodule already or not part of a repository."
  144 + exit 0
  145 +fi
  146 +
  147 +check_working_dir
  148 +if [ "${FUNC_RESULT}" == "0" ]; then
  149 + echo "Go to the top of this repository and type : scripts/setup_submodules [-i|--install]"
  150 + exit 0
  151 +fi
  152 +
  153 +read_submodules
  154 +
  155 +case "$1" in
  156 + -i*|--install*)
  157 + echo "Installing submodules for this repository ( ${PWD} )"
  158 + add_submodules
  159 + get_submodules
  160 + ;;
  161 + -u*|--update*)
  162 + echo "Update submodules : ${SUB_MODULES}"
  163 + update_submodules
  164 + ;;
  165 + *)
  166 + echo "No parameters found..."
  167 + print_usage_exit
  168 + ;;
  169 +esac
  170 +
scripts/submodules.list 0 → 100644
  1 +++ a/scripts/submodules.list
  1 +SUB_MODULES_OPEN="versioning
  2 +cmake"
  3 +
  4 +SUB_MODULES_CLOSED=""
src/CMakeLists.txt 0 → 100644
  1 +++ a/src/CMakeLists.txt
  1 +cmake_minimum_required(VERSION 3.12)
  2 +include(projectheader)
  3 +project_header(logger)
  4 +
  5 +include_directories( SYSTEM
  6 +)
  7 +
  8 +include(compiler)
  9 +
  10 +set(SRC_LIST
  11 + #${CMAKE_CURRENT_SOURCE_DIR}/logger.cpp
  12 + ${CMAKE_CURRENT_SOURCE_DIR}/threadcontext.cpp
  13 + ${CMAKE_CURRENT_SOURCE_DIR}/log.cpp
  14 +)
  15 +
  16 +include(library)
  17 +add_libraries(
  18 +)
  19 +
  20 +include(installation)
  21 +install_component()
src/log.cpp 0 → 100644
  1 +++ a/src/log.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +
  23 +// std
  24 +#include <ios>
  25 +#include <iomanip>
  26 +#include <iostream>
  27 +#include <sstream>
  28 +#include <thread>
  29 +
  30 +#include "log.h"
  31 +#include "threadcontext.h"
  32 +
  33 +namespace osdev {
  34 +namespace components {
  35 +namespace log {
  36 +
  37 +int toInt( LogLevel level )
  38 +{
  39 + switch( level )
  40 + {
  41 + case LogLevel::Emergency:
  42 + return 0;
  43 + case LogLevel::Alert:
  44 + return 1;
  45 + case LogLevel::Critical:
  46 + return 2;
  47 + case LogLevel::Error:
  48 + return 3;
  49 + case LogLevel::Warning:
  50 + return 4;
  51 + case LogLevel::Notice:
  52 + return 5;
  53 + case LogLevel::Info:
  54 + return 6;
  55 + case LogLevel::Debug:
  56 + return 7;
  57 + }
  58 + return -1;
  59 +}
  60 +
  61 +std::string Log::s_context = std::string();
  62 +std::string Log::s_fileName = std::string();
  63 +LogLevel Log::s_logLevel = LogLevel::Error;
  64 +LogMask Log::s_logMask = LogMask::None;
  65 +
  66 +std::mutex Log::m_mutex = std::mutex();
  67 +
  68 +void Log::init( const std::string& context, const std::string& logFile, LogLevel logDepth )
  69 +{
  70 + s_logLevel = logDepth;
  71 + s_context = context;
  72 +
  73 + if ( !logFile.empty() )
  74 + {
  75 + s_fileName = logFile;
  76 + }
  77 +}
  78 +
  79 +void Log::terminate()
  80 +{
  81 + s_context.clear();
  82 + s_fileName.clear();
  83 + s_logLevel = LogLevel::Debug;
  84 + s_logMask = LogMask::None;
  85 +}
  86 +
  87 +void Log::write( const int &priority, const std::string &message, const std::string& context )
  88 +{
  89 + switch( s_logMask )
  90 + {
  91 + case LogMask::Mask:
  92 + setlogmask( LOG_MASK( toInt( s_logLevel ) ) );
  93 + break;
  94 + case LogMask::Upto:
  95 + setlogmask( LOG_UPTO( toInt( s_logLevel ) ) );
  96 + break;
  97 + case LogMask::None:
  98 + setlogmask( LOG_UPTO( toInt( LogLevel::Debug ) ) );
  99 + break;
  100 + default:
  101 + break;
  102 + }
  103 +
  104 + if( !context.empty() )
  105 + {
  106 + s_context = context;
  107 + openlog( s_context.c_str(), LOG_PID, LOG_USER );
  108 + }
  109 + else
  110 + {
  111 + openlog( NULL, LOG_PID, LOG_USER );
  112 + }
  113 +
  114 + syslog( priority, "%s", message.c_str() );
  115 + closelog();
  116 +}
  117 +
  118 +std::string Log::fileinfoMessage( const char* file, int line, const std::string& message )
  119 +{
  120 + (void)file;
  121 + (void)line;
  122 +
  123 +// static const std::string templ("%1:%2| %3");
  124 +// QFileInfo fi(file);
  125 +// return templ.arg( fi.fileName() ).arg(line).arg(message);
  126 +
  127 + return message;
  128 +}
  129 +
  130 +void Log::log( const std::string &category, const std::string &message, LogLevel level )
  131 +{
  132 + std::lock_guard<std::mutex> lock(m_mutex);
  133 +
  134 + std::string logCategory = category;
  135 + std::string logMessage = message;
  136 + if( logMessage.empty() )
  137 + {
  138 + static const std::string emptyMessage( "--" );
  139 + logMessage = emptyMessage;
  140 + }
  141 + else
  142 + {
  143 + // Replace % signs
  144 + ReplaceAll( logMessage, "%", "%%" );
  145 + }
  146 +
  147 + write( toInt( level ), logCategory, logMessage );
  148 +}
  149 +
  150 +// Static functions
  151 +void Log::emergency( const char *file, int line, const std::string &category, const std::string &message )
  152 +{
  153 + log( category, fileinfoMessage( file, line, message ), LogLevel::Emergency );
  154 +}
  155 +
  156 +void Log::alert( const char *file, int line, const std::string &category, const std::string &message )
  157 +{
  158 + log( category, fileinfoMessage( file, line, message ), LogLevel::Alert );
  159 +}
  160 +
  161 +void Log::critical( const char *file, int line, const std::string &category, const std::string &message )
  162 +{
  163 + log( category, fileinfoMessage( file, line, message ), LogLevel::Critical );
  164 +}
  165 +
  166 +void Log::error( const char *file, int line, const std::string &category, const std::string &message )
  167 +{
  168 + log( category, fileinfoMessage( file, line, message ), LogLevel::Error );
  169 +}
  170 +
  171 +void Log::warning( const char *file, int line, const std::string &category, const std::string &message )
  172 +{
  173 + log( category, fileinfoMessage( file, line, message ), LogLevel::Warning );
  174 +}
  175 +
  176 +void Log::notice( const char *file, int line, const std::string &category, const std::string &message )
  177 +{
  178 + log( category, fileinfoMessage( file, line, message ), LogLevel::Notice );
  179 +}
  180 +
  181 +void Log::info( const char *file, int line, const std::string &category, const std::string &message )
  182 +{
  183 + log( category, fileinfoMessage( file, line, message ), LogLevel::Info );
  184 +}
  185 +
  186 +void Log::debug( const char *file, int line, const std::string &category, const std::string &message )
  187 +{
  188 + log( category, fileinfoMessage( file, line, message ), LogLevel::Debug );
  189 +}
  190 +
  191 +// Protected functions
  192 +void Log::emergency( const std::string &category, const std::string &message )
  193 +{
  194 + write( toInt( LogLevel::Emergency ), message, category );
  195 +}
  196 +
  197 +void Log::alert( const std::string &category, const std::string &message )
  198 +{
  199 + write( toInt( LogLevel::Alert ), message, category );
  200 +}
  201 +
  202 +void Log::critical( const std::string &category, const std::string &message )
  203 +{
  204 + write( toInt( LogLevel::Critical ), message, category );
  205 +}
  206 +
  207 +void Log::error( const std::string &category, const std::string &message )
  208 +{
  209 + write( toInt( LogLevel::Error ), message, category );
  210 +}
  211 +
  212 +void Log::warning( const std::string &category, const std::string &message )
  213 +{
  214 + write( toInt( LogLevel::Warning ), message, category );
  215 +}
  216 +
  217 +void Log::notice( const std::string &category, const std::string &message )
  218 +{
  219 + write( toInt( LogLevel::Notice ), message, category );
  220 +}
  221 +
  222 +void Log::info( const std::string &category, const std::string &message )
  223 +{
  224 + write( toInt( LogLevel::Info ), message, category );
  225 +}
  226 +
  227 +void Log::debug( const std::string &category, const std::string &message )
  228 +{
  229 + write( toInt( LogLevel::Debug ), message, category );
  230 +}
  231 +
  232 +void Log::ReplaceAll( std::string &strToReplace, const std::string& from_chars, const std::string& to_chars )
  233 +{
  234 + size_t start_pos = 0;
  235 + while( ( start_pos = strToReplace.find( from_chars, start_pos ) ) != std::string::npos )
  236 + {
  237 + strToReplace.replace( start_pos, from_chars.length(), to_chars );
  238 + start_pos += to_chars.length(); // Handles case where 'to' is a substring of 'from'
  239 + }
  240 +}
  241 +
  242 +} /* End namespace log */
  243 +} /* End namespace components */
  244 +} /* End namespace osdev */
src/log.h 0 → 100644
  1 +++ a/src/log.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#pragma once
  23 +
  24 +#include <string>
  25 +#include <mutex>
  26 +#include <syslog.h>
  27 +
  28 +namespace osdev {
  29 +namespace components {
  30 +namespace log {
  31 +
  32 +#define LogEmergency(context, text) \
  33 + if (osdev::components::log::Log::level() >= osdev::components::log::LogLevel::Emergency)\
  34 + { \
  35 + osdev::components::log::Log::emergency(__FILE__, __LINE__, context, text); \
  36 + }
  37 +
  38 +#define LogAlert(context, text) \
  39 + if (osdev::components::log::Log::level() >= osdev::components::log::LogLevel::Alert) \
  40 + { \
  41 + osdev::components::log::Log::alert(__FILE__, __LINE__, context, text); \
  42 + }
  43 +
  44 +#define LogCritical(context, text) \
  45 + if (osdev::components::log::Log::level() >= osdev::components::log::LogLevel::Critical) \
  46 + { \
  47 + osdev::components::log::Log::critical(__FILE__, __LINE__, context, text); \
  48 + }
  49 +
  50 +#define LogError(context, text) \
  51 + if (osdev::components::log::Log::level() >= osdev::components::log::LogLevel::Error) \
  52 + { \
  53 + osdev::components::log::Log::error(__FILE__, __LINE__, context, text); \
  54 + }
  55 +
  56 +#define LogWarning(context, text) \
  57 + if (osdev::components::log::Log::level() >= osdev::components::log::LogLevel::Warning) \
  58 + { \
  59 + osdev::components::log::Log::warning(__FILE__, __LINE__, context, text); \
  60 + }
  61 +
  62 +#define LogNotice(context, text) \
  63 + if (osdev::components::log::Log::level() >= osdev::components::log::LogLevel::Notice) \
  64 + { \
  65 + osdev::components::log::Log::notice(__FILE__, __LINE__, context, text); \
  66 + }
  67 +
  68 +#define LogInfo(context, text) \
  69 + if (osdev::components::log::Log::level() >= osdev::components::log::LogLevel::Info) \
  70 + { \
  71 + osdev::components::log::Log::info(__FILE__, __LINE__, context, text); \
  72 + }
  73 +
  74 +#define LogDebug(context, text) \
  75 + if (osdev::components::log::Log::level() >= osdev::components::log::LogLevel::Debug) \
  76 + { \
  77 + osdev::components::log::Log::debug(__FILE__, __LINE__, context, text); \
  78 + }
  79 +
  80 +enum class LogLevel
  81 +{
  82 + Emergency = 0,
  83 + Alert,
  84 + Critical,
  85 + Error,
  86 + Warning,
  87 + Notice,
  88 + Info,
  89 + Debug
  90 +};
  91 +
  92 +enum class LogMask
  93 +{
  94 + Mask = 0,
  95 + Upto,
  96 + None
  97 +};
  98 +
  99 +/*! \class Log
  100 + \brief Basic logging mechanism.
  101 +*/
  102 +class Log
  103 +{
  104 +public:
  105 + static void init( const std::string& context,
  106 + const std::string& logFile = std::string(),
  107 + LogLevel logDepth = LogLevel::Info );
  108 +
  109 + static void terminate();
  110 +
  111 + static void write( const int &priority, const std::string &message, const std::string &context = std::string() );
  112 +
  113 + static void emergency( const char* file, int line, const std::string& category, const std::string& message );
  114 + static void alert ( const char* file, int line, const std::string& category, const std::string& message );
  115 + static void critical ( const char* file, int line, const std::string& category, const std::string& message );
  116 + static void error ( const char* file, int line, const std::string& category, const std::string& message );
  117 + static void warning ( const char* file, int line, const std::string& category, const std::string& message );
  118 + static void notice ( const char* file, int line, const std::string& category, const std::string& message );
  119 + static void info ( const char* file, int line, const std::string& category, const std::string& message );
  120 + static void debug ( const char* file, int line, const std::string& category, const std::string& message );
  121 +
  122 + /**
  123 + * @return The current log level.
  124 + */
  125 + static LogLevel level()
  126 + {
  127 + if( s_logMask == LogMask::None )
  128 + {
  129 + return LogLevel::Debug;
  130 + }
  131 + return s_logLevel;
  132 + }
  133 +
  134 + static void setMask ( LogMask logMask ) { s_logMask = logMask; }
  135 + static void setLogLevel( LogLevel logLevel ) { s_logLevel = logLevel; }
  136 + static void setContext ( std::string context ) { s_context = context; }
  137 +
  138 +protected:
  139 + static void emergency( const std::string& category, const std::string& message );
  140 + static void alert ( const std::string& category, const std::string& message );
  141 + static void critical ( const std::string& category, const std::string& message );
  142 + static void error ( const std::string& category, const std::string& message );
  143 + static void warning ( const std::string& category, const std::string& message );
  144 + static void notice ( const std::string& category, const std::string& message );
  145 + static void info ( const std::string& category, const std::string& message );
  146 + static void debug ( const std::string& category, const std::string& message );
  147 +
  148 + /**
  149 + * @brief Log an error message in a category.
  150 + * @param category The category of the message.
  151 + * @param message The string to print.
  152 + * @param level Selected log level
  153 + */
  154 + static void log( const std::string &category,
  155 + const std::string &message,
  156 + LogLevel level );
  157 +
  158 +private:
  159 + /**
  160 + * @brief Replace the characters in a std::string with other characters.
  161 + * @param strToReplace The string we want to replace characters in
  162 + * @param from_chars The characters we want to replace
  163 + * @param to_chars The characters we want to replace with.
  164 + * @return strToReplace This is the original string with the replaced characters.
  165 + */
  166 + static void ReplaceAll( std::string &strToReplace, const std::string& from_chars, const std::string& to_chars );
  167 +
  168 + /**
  169 + * @brief Put filename, line-number and message in one string
  170 + * @param file Source-file
  171 + * @param line Line in source-file
  172 + * @param message The string to print
  173 + * @return Formatted string with file, line and message
  174 + */
  175 + static std::string fileinfoMessage(const char* file, int line,
  176 + const std::string& message);
  177 +
  178 + //! The main context.
  179 + static std::string s_context;
  180 +
  181 + //! The name of the LogFile.
  182 + static std::string s_fileName;
  183 +
  184 + //! The amount of logging
  185 + static LogLevel s_logLevel;
  186 +
  187 + //! The mask
  188 + static LogMask s_logMask;
  189 +
  190 + //! Mutex to keep the logger thread-safe
  191 + static std::mutex m_mutex;
  192 +};
  193 +
  194 +} // End namespace log
  195 +} // End namespace components
  196 +} // End namespace osdev
  197 +
src/threadcontext.cpp 0 → 100644
  1 +++ a/src/threadcontext.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +
  23 +#include "threadcontext.h"
  24 +
  25 +// std
  26 +#include <thread>
  27 +
  28 +using namespace osdev::components;
  29 +
  30 +ThreadContextScope::ThreadContextScope(const std::string& _context)
  31 + : m_previousContext(ThreadContext::instance().context())
  32 +{
  33 + ThreadContext::instance().setContext(_context);
  34 +}
  35 +
  36 +ThreadContextScope::~ThreadContextScope()
  37 +{
  38 + ThreadContext::instance().setContext(m_previousContext);
  39 +}
  40 +
  41 +// static
  42 +ThreadContext& ThreadContext::instance()
  43 +{
  44 + static thread_local ThreadContext tc;
  45 + return tc;
  46 +}
  47 +
  48 +ThreadContext::ThreadContext()
  49 + : m_context("default")
  50 +{
  51 +}
  52 +
src/threadcontext.h 0 → 100644
  1 +++ a/src/threadcontext.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef OSDEV_COMPONENTS_THREADCONTEXT_H
  23 +#define OSDEV_COMPONENTS_THREADCONTEXT_H
  24 +
  25 +// Qt
  26 +#include <string>
  27 +
  28 +namespace osdev {
  29 +namespace components {
  30 +
  31 +/**
  32 + * @brief Set the current thread context.
  33 + * The context is restored to the previous context when this object goes out of scope.
  34 + * @note This object is meant to be used on the stack.
  35 + */
  36 +class ThreadContextScope
  37 +{
  38 +public:
  39 + /**
  40 + * @brief Construct a scoped object that sets the current thread context.
  41 + * @param context The context that will be used by the logging framework.
  42 + */
  43 + explicit ThreadContextScope(const std::string& context);
  44 + ~ThreadContextScope();
  45 +
  46 + // Non copyable and non movable
  47 + ThreadContextScope(const ThreadContextScope&) = delete;
  48 + ThreadContextScope& operator=(const ThreadContextScope&) = delete;
  49 + ThreadContextScope(ThreadContextScope&&) = delete;
  50 + ThreadContextScope& operator=(ThreadContextScope&&) = delete;
  51 +
  52 +private:
  53 + std::string m_previousContext; ///< Copy of the previous context.
  54 +};
  55 +
  56 +/**
  57 + * @brief Add context to a thread.
  58 + * For every thread only one specific instance of this object will exist.
  59 + * @note Contexts can only be set by using a ThreadContextScope object.
  60 + */
  61 +class ThreadContext
  62 +{
  63 +
  64 +// Contexts can only be set by using a ThreadContextScope object.
  65 +friend class ThreadContextScope;
  66 +
  67 +public:
  68 + static ThreadContext& instance();
  69 +
  70 + /**
  71 + * @brief Return the thread context.
  72 + */
  73 + const std::string& context() const
  74 + {
  75 + return m_context;
  76 + }
  77 +
  78 +private:
  79 + /**
  80 + * @brief Set the thread context.
  81 + */
  82 + void setContext(const std::string& contextString)
  83 + {
  84 + m_context = contextString;
  85 + }
  86 +
  87 + /**
  88 + * Construct a ThreadContext object.
  89 + * The context is set to "default"
  90 + */
  91 + ThreadContext();
  92 +
  93 + // Non copyable and non movable
  94 + ThreadContext(const ThreadContext&) = delete;
  95 + ThreadContext& operator=(const ThreadContext&) = delete;
  96 + ThreadContext(ThreadContext&&) = delete;
  97 + ThreadContext& operator=(ThreadContext&&) = delete;
  98 +
  99 + std::string m_context; ///< The context string
  100 +};
  101 +
  102 +} /* End namespace components */
  103 +} /* End namespace osdev */
  104 +
  105 +#endif // OSDEV_COMPONENTS_THREADCONTEXT_H
  1 +++ a/submodules/cmake
  1 +Subproject commit 89c657f53805ad26083d433c44ea3b89f1d60350
  1 +++ a/submodules/versioning
  1 +Subproject commit 30644644f07d1cd9d794d466597ba5861d0e34fd
tests/CMakeLists.txt 0 → 100644
  1 +++ a/tests/CMakeLists.txt
  1 +cmake_minimum_required(VERSION 3.12)
  2 +LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake)
  3 +
  4 +include(projectheader)
  5 +project_header(test_logger)
  6 +
  7 +include_directories( SYSTEM
  8 + ${CMAKE_CURRENT_SOURCE_DIR}/../src
  9 +)
  10 +
  11 +include(compiler)
  12 +set(SRC_LIST
  13 + ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
  14 + ${CMAKE_CURRENT_SOURCE_DIR}/logtest.cpp
  15 +)
  16 +
  17 +add_executable( ${PROJECT_NAME}
  18 + ${SRC_LIST}
  19 +)
  20 +
  21 +target_link_libraries(
  22 + ${PROJECT_NAME}
  23 + logger
  24 +)
  25 +
  26 +set_target_properties( ${PROJECT_NAME} PROPERTIES
  27 + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
  28 + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
  29 + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/archive
  30 +)
  31 +
  32 +include(installation)
  33 +install_application()
tests/logtest.cpp 0 → 100644
  1 +++ a/tests/logtest.cpp
  1 +#include "logtest.h"
  2 +
  3 +LogTest::LogTest()
  4 +{
  5 +
  6 +}
  7 +
  8 +void LogTest::writeTest()
  9 +{
  10 + osdev::components::log::Log::setMask( osdev::components::log::LogMask::Upto );
  11 +
  12 + LogError ( "testcase", "testing the error message" );
  13 + LogCritical ( "testcase", "testing the critical message" );
  14 + LogAlert ( "testcase", "testing the alert message" );
  15 + LogEmergency( "testcase", "testing the emergency message" );
  16 +
  17 + osdev::components::log::Log::setMask( osdev::components::log::LogMask::None );
  18 +
  19 + LogDebug ( "testcase", "testing the debug message" );
  20 + LogDebug ( "testcase", "testing a second debug message" );
  21 + LogInfo ( "testcase", "testing the info message" );
  22 + LogNotice ( "testcase", "testing the notice message" );
  23 + LogWarning ( "testcase", "testing the warning message" );
  24 +
  25 +}
tests/logtest.h 0 → 100644
  1 +++ a/tests/logtest.h
  1 +#ifndef LOGTEST_H
  2 +#define LOGTEST_H
  3 +
  4 +#include "log.h"
  5 +
  6 +class LogTest
  7 +{
  8 +public:
  9 + LogTest();
  10 +
  11 + void writeTest();
  12 +};
  13 +
  14 +#endif // LOGTEST_H
tests/main.cpp 0 → 100644
  1 +++ a/tests/main.cpp
  1 +#include <iostream>
  2 +
  3 +#include "logtest.h"
  4 +
  5 +int main( int argc, char* argv[] )
  6 +{
  7 + (void)argc;
  8 + (void)argv;
  9 +
  10 + LogTest pLogTest;
  11 + pLogTest.writeTest();
  12 +}