diff --git b/.gitignore a/.gitignore new file mode 100644 index 0000000..b231a7e --- /dev/null +++ a/.gitignore @@ -0,0 +1,12 @@ +build/ +CMakeLists.txt.user + +cmake/ +versioning/ +logutils/ +pugixml/ +config/ +global/ + + +.gitmodules diff --git b/.gitmodules a/.gitmodules new file mode 100644 index 0000000..0748abc --- /dev/null +++ a/.gitmodules @@ -0,0 +1,6 @@ +[submodule "submodules/versioning"] + path = submodules/versioning + url = http://gitlab.osdev.nl/open_source/versioning.git +[submodule "submodules/cmake"] + path = submodules/cmake + url = http://gitlab.osdev.nl/open_source/cmake.git diff --git b/CMakeLists.txt a/CMakeLists.txt new file mode 100644 index 0000000..e44054b --- /dev/null +++ a/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.0) +project(osdev_logger) + +LIST( APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/submodules/cmake ) +LIST( APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/submodules/versioning/cmake ) + +include(projectheader) +project_header(osdev_logger) + +add_subdirectory(src) +add_subdirectory(tests) + +#include(packaging) +#package_component() diff --git b/README.md a/README.md new file mode 100644 index 0000000..e69de29 --- /dev/null +++ a/README.md diff --git b/scripts/setup_submodules a/scripts/setup_submodules new file mode 100755 index 0000000..0aad384 --- /dev/null +++ a/scripts/setup_submodules @@ -0,0 +1,170 @@ +#!/bin/bash + +# =============================================== +# == Setting some environment variables +# =============================================== +GIT_URL_OPEN="http://gitlab.osdev.nl/open_source" +GIT_URL_CLOSED="git@gitlab.osdev.nl:closed_source" + +FUNC_RESULT="-1" + +# Name : print_usage_exit() +# Description : Print the way this script is intended to be used and exit. +# Parameters : None. +# Returns : err_code 1 to the Operating System +# -------------------------------------------------------------------------------------- +function print_usage_exit() +{ + echo "Usage $0 -i|--install|-u|--update" + echo " -i or --install Install the submodules mentioned in the submodules.list" + echo " -u or --update Update the submodules mentioned in the submodules.list" + echo " " + exit 1 +} + +# Name : check_top_or_sub +# Description : Determine if we're running in a "single" lib-build or part of a +# "meta"-repository ( submodule ). +# Parameters : None +# Returns : Updates the value FUNC_RESULT. +# -1 - We're neither a git-repo or submodule. +# 0 - We're a submodule +# 1 - We're a top-repo ( Single library ) +# -------------------------------------------------------------------------------------- +function check_top_or_sub() +{ + # This function checks if we're the top-repository. + # In that case we need the submodules.. If we're already a submodule, + # we simply exit this script with a message + if [ -e ./.git ]; then + FUNC_RESULT="1" + return + elif [ -e ../.git ]; then + if [ -e ../.submodules ]; then + echo "Seems like we're already a submodule. Nothing to do here." + FUNC_RESULT="0" + return + fi + fi + FUNC_RESULT="-1" + return +} + +# Name : check_working_dir +# Description : If we're in the top of our repo, we can run this script further. +# Parameters : None. +# Returns : Updates the value FUNC_RESULT. +# -1 - Not used. +# 0 - We're not on the top-level +# 1 - We're at the top-level. Good to go. +# -------------------------------------------------------------------------------------- +function check_working_dir() +{ + FUNC_RESULT="-1" + # Check if we're in the top-level directory of our repository. + if [ -f ./scripts/submodules.list ]; then + # We're good to go + FUNC_RESULT="1" + return + fi + FUNC_RESULT="0" + return +} + +# Name : read_submodules +# Description : Read the list of submodules needed for this project +# Parameters : None +# Returns : Updates the value FUNC_RESULT +# 0 - Module list was not found +# 1 - Module list was found and read. +# -------------------------------------------------------------------------------------- +function read_submodules() +{ + FUNC_RESULT="-1" + if [ -e ./scripts/submodules.list ]; then + source ./scripts/submodules.list + FUNC_RESULT="1" + return + fi + + echo "Submodules list not found...." + FUNC_RESULT="0" + return +} + +# Name : add_submodules +# Description : Configure the repo to add the submodules. +# Parameters : None. +# Returns : None. +# -------------------------------------------------------------------------------------- +function add_submodules() +{ + echo -e "Adding SubModule(s)." + for SUB_MODULE in ${SUB_MODULES_OPEN} + do + git submodule add -f ${GIT_URL_OPEN}/${SUB_MODULE}.git submodules/${SUB_MODULE} + git config submodule.${SUB_MODULE}.url ${GIT_URL_OPEN}/${SUB_MODULE}.git + done + + for SUB_MODULE in ${SUB_MODULES_CLOSED} + do + echo {GIT_URL_CLOSED}/${SUB_MODULE}.git + git submodule add -f ${GIT_URL_CLOSED}/${SUB_MODULE}.git submodules/${SUB_MODULE} + git config submodule.${SUB_MODULE}.url ${GIT_URL_CLOSED}/${SUB_MODULE}.git + done + +} + +# Name : get_submodules +# Description : Actually get the submodules from gitlab and add them. +# Parameters : None +# Returns : None +# -------------------------------------------------------------------------------------- +function get_submodules() +{ + git submodule update --init --recursive +} + +# Name : update_submodules +# Description : Update the submodules already added. +# Parameters : None +# Returns : None +# -------------------------------------------------------------------------------------- +function update_submodules() +{ + git submodule update --recursive +} + +# ============================================================================= +# == T H E M A I N E N T R Y O F T H I S S C R I P T == +# ============================================================================= +check_top_or_sub +if [ "${FUNC_RESULT}" == "0" ]; then + echo "Seems like we're a submodule already or not part of a repository." + exit 0 +fi + +check_working_dir +if [ "${FUNC_RESULT}" == "0" ]; then + echo "Go to the top of this repository and type : scripts/setup_submodules [-i|--install]" + exit 0 +fi + +read_submodules + +case "$1" in + -i*|--install*) + echo "Installing submodules for this repository ( ${PWD} )" + add_submodules + get_submodules + ;; + -u*|--update*) + echo "Update submodules : ${SUB_MODULES}" + update_submodules + ;; + *) + echo "No parameters found..." + print_usage_exit + ;; +esac + diff --git b/scripts/submodules.list a/scripts/submodules.list new file mode 100644 index 0000000..32253f2 --- /dev/null +++ a/scripts/submodules.list @@ -0,0 +1,4 @@ +SUB_MODULES_OPEN="versioning +cmake" + +SUB_MODULES_CLOSED="" diff --git b/src/CMakeLists.txt a/src/CMakeLists.txt new file mode 100644 index 0000000..5ea4c55 --- /dev/null +++ a/src/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.12) +include(projectheader) +project_header(logger) + +include_directories( SYSTEM +) + +include(compiler) + +set(SRC_LIST + #${CMAKE_CURRENT_SOURCE_DIR}/logger.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/threadcontext.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/log.cpp +) + +include(library) +add_libraries( +) + +include(installation) +install_component() diff --git b/src/log.cpp a/src/log.cpp new file mode 100644 index 0000000..74bdf17 --- /dev/null +++ a/src/log.cpp @@ -0,0 +1,244 @@ +/* **************************************************************************** + * 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. * + * ***************************************************************************/ + +// std +#include +#include +#include +#include +#include + +#include "log.h" +#include "threadcontext.h" + +namespace osdev { +namespace components { +namespace log { + +int toInt( LogLevel level ) +{ + switch( level ) + { + case LogLevel::Emergency: + return 0; + case LogLevel::Alert: + return 1; + case LogLevel::Critical: + return 2; + case LogLevel::Error: + return 3; + case LogLevel::Warning: + return 4; + case LogLevel::Notice: + return 5; + case LogLevel::Info: + return 6; + case LogLevel::Debug: + return 7; + } + return -1; +} + +std::string Log::s_context = std::string(); +std::string Log::s_fileName = std::string(); +LogLevel Log::s_logLevel = LogLevel::Error; +LogMask Log::s_logMask = LogMask::None; + +std::mutex Log::m_mutex = std::mutex(); + +void Log::init( const std::string& context, const std::string& logFile, LogLevel logDepth ) +{ + s_logLevel = logDepth; + s_context = context; + + if ( !logFile.empty() ) + { + s_fileName = logFile; + } +} + +void Log::terminate() +{ + s_context.clear(); + s_fileName.clear(); + s_logLevel = LogLevel::Debug; + s_logMask = LogMask::None; +} + +void Log::write( const int &priority, const std::string &message, const std::string& context ) +{ + switch( s_logMask ) + { + case LogMask::Mask: + setlogmask( LOG_MASK( toInt( s_logLevel ) ) ); + break; + case LogMask::Upto: + setlogmask( LOG_UPTO( toInt( s_logLevel ) ) ); + break; + case LogMask::None: + setlogmask( LOG_UPTO( toInt( LogLevel::Debug ) ) ); + break; + default: + break; + } + + if( !context.empty() ) + { + s_context = context; + openlog( s_context.c_str(), LOG_PID, LOG_USER ); + } + else + { + openlog( NULL, LOG_PID, LOG_USER ); + } + + syslog( priority, "%s", message.c_str() ); + closelog(); +} + +std::string Log::fileinfoMessage( const char* file, int line, const std::string& message ) +{ + (void)file; + (void)line; + +// static const std::string templ("%1:%2| %3"); +// QFileInfo fi(file); +// return templ.arg( fi.fileName() ).arg(line).arg(message); + + return message; +} + +void Log::log( const std::string &category, const std::string &message, LogLevel level ) +{ + std::lock_guard lock(m_mutex); + + std::string logCategory = category; + std::string logMessage = message; + if( logMessage.empty() ) + { + static const std::string emptyMessage( "--" ); + logMessage = emptyMessage; + } + else + { + // Replace % signs + ReplaceAll( logMessage, "%", "%%" ); + } + + write( toInt( level ), logCategory, logMessage ); +} + +// Static functions +void Log::emergency( const char *file, int line, const std::string &category, const std::string &message ) +{ + log( category, fileinfoMessage( file, line, message ), LogLevel::Emergency ); +} + +void Log::alert( const char *file, int line, const std::string &category, const std::string &message ) +{ + log( category, fileinfoMessage( file, line, message ), LogLevel::Alert ); +} + +void Log::critical( const char *file, int line, const std::string &category, const std::string &message ) +{ + log( category, fileinfoMessage( file, line, message ), LogLevel::Critical ); +} + +void Log::error( const char *file, int line, const std::string &category, const std::string &message ) +{ + log( category, fileinfoMessage( file, line, message ), LogLevel::Error ); +} + +void Log::warning( const char *file, int line, const std::string &category, const std::string &message ) +{ + log( category, fileinfoMessage( file, line, message ), LogLevel::Warning ); +} + +void Log::notice( const char *file, int line, const std::string &category, const std::string &message ) +{ + log( category, fileinfoMessage( file, line, message ), LogLevel::Notice ); +} + +void Log::info( const char *file, int line, const std::string &category, const std::string &message ) +{ + log( category, fileinfoMessage( file, line, message ), LogLevel::Info ); +} + +void Log::debug( const char *file, int line, const std::string &category, const std::string &message ) +{ + log( category, fileinfoMessage( file, line, message ), LogLevel::Debug ); +} + +// Protected functions +void Log::emergency( const std::string &category, const std::string &message ) +{ + write( toInt( LogLevel::Emergency ), message, category ); +} + +void Log::alert( const std::string &category, const std::string &message ) +{ + write( toInt( LogLevel::Alert ), message, category ); +} + +void Log::critical( const std::string &category, const std::string &message ) +{ + write( toInt( LogLevel::Critical ), message, category ); +} + +void Log::error( const std::string &category, const std::string &message ) +{ + write( toInt( LogLevel::Error ), message, category ); +} + +void Log::warning( const std::string &category, const std::string &message ) +{ + write( toInt( LogLevel::Warning ), message, category ); +} + +void Log::notice( const std::string &category, const std::string &message ) +{ + write( toInt( LogLevel::Notice ), message, category ); +} + +void Log::info( const std::string &category, const std::string &message ) +{ + write( toInt( LogLevel::Info ), message, category ); +} + +void Log::debug( const std::string &category, const std::string &message ) +{ + write( toInt( LogLevel::Debug ), message, category ); +} + +void Log::ReplaceAll( std::string &strToReplace, const std::string& from_chars, const std::string& to_chars ) +{ + size_t start_pos = 0; + while( ( start_pos = strToReplace.find( from_chars, start_pos ) ) != std::string::npos ) + { + strToReplace.replace( start_pos, from_chars.length(), to_chars ); + start_pos += to_chars.length(); // Handles case where 'to' is a substring of 'from' + } +} + +} /* End namespace log */ +} /* End namespace components */ +} /* End namespace osdev */ diff --git b/src/log.h a/src/log.h new file mode 100644 index 0000000..47b2b81 --- /dev/null +++ a/src/log.h @@ -0,0 +1,197 @@ +/* **************************************************************************** + * 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 +#include +#include + +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); \ + } + +enum class LogLevel +{ + Emergency = 0, + Alert, + Critical, + Error, + Warning, + Notice, + Info, + Debug +}; + +enum class LogMask +{ + Mask = 0, + Upto, + None +}; + +/*! \class Log + \brief Basic logging mechanism. +*/ +class Log +{ +public: + static void init( const std::string& context, + const std::string& logFile = std::string(), + LogLevel logDepth = LogLevel::Info ); + + static void terminate(); + + static void write( const int &priority, const std::string &message, const std::string &context = std::string() ); + + static void emergency( const char* file, int line, const std::string& category, const std::string& message ); + static void alert ( const char* file, int line, const std::string& category, const std::string& message ); + static void critical ( const char* file, int line, const std::string& category, const std::string& message ); + static void error ( const char* file, int line, const std::string& category, const std::string& message ); + static void warning ( const char* file, int line, const std::string& category, const std::string& message ); + static void notice ( const char* file, int line, const std::string& category, const std::string& message ); + static void info ( const char* file, int line, const std::string& category, const std::string& message ); + 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; + } + + static void setMask ( LogMask logMask ) { s_logMask = logMask; } + static void setLogLevel( LogLevel logLevel ) { s_logLevel = logLevel; } + static void setContext ( std::string context ) { s_context = context; } + +protected: + static void emergency( const std::string& category, const std::string& message ); + static void alert ( const std::string& category, const std::string& message ); + static void critical ( const std::string& category, const std::string& message ); + static void error ( const std::string& category, const std::string& message ); + static void warning ( const std::string& category, const std::string& message ); + static void notice ( const std::string& category, const std::string& message ); + static void info ( const std::string& category, const std::string& message ); + 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; + + //! Mutex to keep the logger thread-safe + static std::mutex m_mutex; +}; + +} // End namespace log +} // End namespace components +} // End namespace osdev + diff --git b/src/threadcontext.cpp a/src/threadcontext.cpp new file mode 100644 index 0000000..1e05d2e --- /dev/null +++ a/src/threadcontext.cpp @@ -0,0 +1,52 @@ +/* **************************************************************************** + * 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. * + * ***************************************************************************/ + +#include "threadcontext.h" + +// std +#include + +using namespace osdev::components; + +ThreadContextScope::ThreadContextScope(const std::string& _context) + : m_previousContext(ThreadContext::instance().context()) +{ + ThreadContext::instance().setContext(_context); +} + +ThreadContextScope::~ThreadContextScope() +{ + ThreadContext::instance().setContext(m_previousContext); +} + +// static +ThreadContext& ThreadContext::instance() +{ + static thread_local ThreadContext tc; + return tc; +} + +ThreadContext::ThreadContext() + : m_context("default") +{ +} + diff --git b/src/threadcontext.h a/src/threadcontext.h new file mode 100644 index 0000000..bb4a434 --- /dev/null +++ a/src/threadcontext.h @@ -0,0 +1,105 @@ +/* **************************************************************************** + * 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. * + * ***************************************************************************/ +#ifndef OSDEV_COMPONENTS_THREADCONTEXT_H +#define OSDEV_COMPONENTS_THREADCONTEXT_H + +// Qt +#include + +namespace osdev { +namespace components { + +/** + * @brief Set the current thread context. + * The context is restored to the previous context when this object goes out of scope. + * @note This object is meant to be used on the stack. + */ +class ThreadContextScope +{ +public: + /** + * @brief Construct a scoped object that sets the current thread context. + * @param context The context that will be used by the logging framework. + */ + explicit ThreadContextScope(const std::string& context); + ~ThreadContextScope(); + + // Non copyable and non movable + ThreadContextScope(const ThreadContextScope&) = delete; + ThreadContextScope& operator=(const ThreadContextScope&) = delete; + ThreadContextScope(ThreadContextScope&&) = delete; + ThreadContextScope& operator=(ThreadContextScope&&) = delete; + +private: + std::string m_previousContext; ///< Copy of the previous context. +}; + +/** + * @brief Add context to a thread. + * For every thread only one specific instance of this object will exist. + * @note Contexts can only be set by using a ThreadContextScope object. + */ +class ThreadContext +{ + +// Contexts can only be set by using a ThreadContextScope object. +friend class ThreadContextScope; + +public: + static ThreadContext& instance(); + + /** + * @brief Return the thread context. + */ + const std::string& context() const + { + return m_context; + } + +private: + /** + * @brief Set the thread context. + */ + void setContext(const std::string& contextString) + { + m_context = contextString; + } + + /** + * Construct a ThreadContext object. + * The context is set to "default" + */ + ThreadContext(); + + // Non copyable and non movable + ThreadContext(const ThreadContext&) = delete; + ThreadContext& operator=(const ThreadContext&) = delete; + ThreadContext(ThreadContext&&) = delete; + ThreadContext& operator=(ThreadContext&&) = delete; + + std::string m_context; ///< The context string +}; + +} /* End namespace components */ +} /* End namespace osdev */ + +#endif // OSDEV_COMPONENTS_THREADCONTEXT_H diff --git b/submodules/cmake a/submodules/cmake new file mode 160000 index 0000000..89c657f --- /dev/null +++ a/submodules/cmake @@ -0,0 +1 @@ +Subproject commit 89c657f53805ad26083d433c44ea3b89f1d60350 diff --git b/submodules/versioning a/submodules/versioning new file mode 160000 index 0000000..3064464 --- /dev/null +++ a/submodules/versioning @@ -0,0 +1 @@ +Subproject commit 30644644f07d1cd9d794d466597ba5861d0e34fd diff --git b/tests/CMakeLists.txt a/tests/CMakeLists.txt new file mode 100644 index 0000000..af991de --- /dev/null +++ a/tests/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.12) +LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) + +include(projectheader) +project_header(test_logger) + +include_directories( SYSTEM + ${CMAKE_CURRENT_SOURCE_DIR}/../src +) + +include(compiler) +set(SRC_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/logtest.cpp +) + +add_executable( ${PROJECT_NAME} + ${SRC_LIST} +) + +target_link_libraries( + ${PROJECT_NAME} + logger +) + +set_target_properties( ${PROJECT_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/archive +) + +include(installation) +install_application() diff --git b/tests/logtest.cpp a/tests/logtest.cpp new file mode 100644 index 0000000..897f1e7 --- /dev/null +++ a/tests/logtest.cpp @@ -0,0 +1,25 @@ +#include "logtest.h" + +LogTest::LogTest() +{ + +} + +void LogTest::writeTest() +{ + osdev::components::log::Log::setMask( osdev::components::log::LogMask::Upto ); + + LogError ( "testcase", "testing the error message" ); + LogCritical ( "testcase", "testing the critical message" ); + LogAlert ( "testcase", "testing the alert message" ); + LogEmergency( "testcase", "testing the emergency message" ); + + osdev::components::log::Log::setMask( osdev::components::log::LogMask::None ); + + LogDebug ( "testcase", "testing the debug message" ); + LogDebug ( "testcase", "testing a second debug message" ); + LogInfo ( "testcase", "testing the info message" ); + LogNotice ( "testcase", "testing the notice message" ); + LogWarning ( "testcase", "testing the warning message" ); + +} diff --git b/tests/logtest.h a/tests/logtest.h new file mode 100644 index 0000000..7208e13 --- /dev/null +++ a/tests/logtest.h @@ -0,0 +1,14 @@ +#ifndef LOGTEST_H +#define LOGTEST_H + +#include "log.h" + +class LogTest +{ +public: + LogTest(); + + void writeTest(); +}; + +#endif // LOGTEST_H diff --git b/tests/main.cpp a/tests/main.cpp new file mode 100644 index 0000000..236b331 --- /dev/null +++ a/tests/main.cpp @@ -0,0 +1,12 @@ +#include + +#include "logtest.h" + +int main( int argc, char* argv[] ) +{ + (void)argc; + (void)argv; + + LogTest pLogTest; + pLogTest.writeTest(); +}