diff --git a/inc/ECSS_Definitions.hpp b/inc/ECSS_Definitions.hpp index 2fe9218df54d72b0c965e75983ec99bb312d0f7d..c129487243e458ba0fd119b92fa73d286e569f02 100644 --- a/inc/ECSS_Definitions.hpp +++ b/inc/ECSS_Definitions.hpp @@ -53,4 +53,9 @@ #define ECSS_MAX_DELTA_OF_RELEASE_TIME 60 // release time and the actual release time +/** + * @brief The maximum size of a log message + */ +#define LOGGER_MAX_MESSAGE_SIZE 512 + #endif // ECSS_SERVICES_ECSS_DEFINITIONS_H diff --git a/inc/Logger.hpp b/inc/Logger.hpp new file mode 100644 index 0000000000000000000000000000000000000000..730ab5df1539e7688d6d3ee1899b2d814b993fa9 --- /dev/null +++ b/inc/Logger.hpp @@ -0,0 +1,110 @@ +#ifndef ECSS_SERVICES_LOGGER_HPP +#define ECSS_SERVICES_LOGGER_HPP + +#include <cstdint> +#include <etl/String.hpp> +#include <ECSS_Definitions.hpp> + +#if defined LOGLEVEL_TRACE + #define LOGLEVEL Logger::trace +#elif defined LOGLEVEL_DEBUG + #define LOGLEVEL Logger::debug +#elif defined LOGLEVEL_INFO + #define LOGLEVEL Logger::info +#elif defined LOGLEVEL_NOTICE + #define LOGLEVEL Logger::notice +#elif defined LOGLEVEL_WARNING + #define LOGLEVEL Logger::warning +#elif defined LOGLEVEL_ERROR + #define LOGLEVEL Logger::error +#elif defined LOGLEVEL_EMERGENCY + #define LOGLEVEL Logger::emergency +#else + #define LOGLEVEL Logger::disabled +#endif + +#define _ac_LOGGER_ENABLED_LEVEL(level) (( (Logger::LogLevelType) LOGLEVEL) >= ( (Logger::LogLevelType) level)) + +#define LOG(level, message) Logger::log(level, message) + +#define LOG_TRACE(message) LOG(Logger::trace, message) +#define LOG_DEBUG(message) LOG(Logger::debug, message) +#define LOG_INFO(message) LOG(Logger::info, message) +#define LOG_NOTICE(message) LOG(Logger::notice, message) +#define LOG_WARNING(message) LOG(Logger::warning, message) +#define LOG_ERROR(message) LOG(Logger::error, message) +#define LOG_EMERGENCY(message) LOG(Logger::emergency, message) + +/** + * A logging class for ECSS Services that supports ETL's String and is lightweight enough to be used in embedded + * development. + */ +class Logger { +private: + +protected: + + /** + * Default protected constructor for this Logger + */ + Logger() = default; + +public: + /** + * The underlying type to be used for values of Logger::LogLevel. + */ + typedef uint8_t LogLevelType; + + /** + * Log levels supported by the logger. Each level represents a different severity of the logged Message, + * and messages of lower severities can be filtered on top of more significant ones. + * + * Each severity is tied to a number. The higher the number, the higher the severity. + */ + enum LogLevel { + trace = 32, ///< Very detailed information, useful for tracking the individual steps of an operation + debug = 64, ///< General debugging information + info = 96, ///< Noteworthy or periodical events + notice = 128, ///< Uncommon but expected events + warning = 160, ///< Unexpected events that do not compromise the operability of a function + error = 192, ///< Unexpected failure of an operation + emergency = 254, ///< Unexpected failure that renders the entire system unusable + disabled = 255, ///< Use this log level to disable logging entirely. No message should be logged as disabled. + }; + + /** + * @brief Unimplemented copy constructor + * + * Does not allow Loggers should be copied. There should be only one instance for each Logger. + */ + Logger(Logger const&) = delete; + + /** + * Unimplemented assignment operation + * + * Does not allow changing the instances of Loggers, as Loggers are singletons. + */ + void operator=(Logger const&) = delete; + + /** + * Default destructor + */ + ~Logger() = default; + + /** + * Default move constructor + */ + Logger(Logger&& service) noexcept = default; + + /** + * Default move assignment operator + */ + Logger& operator=(Logger&& service) noexcept = default; + + /** + * Store a new log message + */ + static void log(LogLevel level, String<LOGGER_MAX_MESSAGE_SIZE> message); +}; + +#endif //ECSS_SERVICES_LOGGER_HPP diff --git a/src/Platform/x86/Logger.cpp b/src/Platform/x86/Logger.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f97705ea85745738e733341b3963f0c89d523df0 --- /dev/null +++ b/src/Platform/x86/Logger.cpp @@ -0,0 +1,61 @@ +#include <Logger.hpp> +#include <etl/String.hpp> +#include <iostream> +#include <ECSS_Definitions.hpp> + +#include <chrono> +#include <iomanip> + +// The implementation of this function appends ANSI codes that should add colours to a compatible terminal +void Logger::log(Logger::LogLevel level, String<LOGGER_MAX_MESSAGE_SIZE> message) { + // Get the current time & date + std::time_t t = std::time(nullptr); + std::tm tm = *std::localtime(&t); + + // Get the log level and its colour + std::string name; + std::string colour; + bool keepColour = false; // Whether to keep the colour in the rest of the message + + if (level <= Logger::trace) { + name = "trace"; + colour = "90"; // bright black + keepColour = true; + } else if (level <= Logger::debug) { + name = "debug"; + colour = "90"; // bright black + keepColour = true; + } else if (level <= Logger::info) { + name = "info"; + colour = "32"; // green + } else if (level <= Logger::notice) { + name = "notice"; + colour = "36"; // cyan + } else if (level <= Logger::warning) { + name = "warning"; + colour = "33"; // yellow + } else if (level <= Logger::error) { + name = "error"; + colour = "31"; // red + } else { + name = "emergency"; + colour = "31"; // red + keepColour = true; + } + + std::ostringstream ss; // A string stream to create the log message + ss << "\033[0;90m" << std::put_time(&tm, "%FT%T%z") << "\033[0m "; // The date + ss << "[\033[1;" << colour << "m" << std::setfill(' ') << std::setw(7) << std::right + << name << std::setw(0) << "\033[0m] "; // The log level + + if (keepColour) { + ss << "\033[0;" << colour << "m"; + } + ss << message.c_str(); // The message itself + if (keepColour) { + ss << "\033[0m"; + } + + ss << "\n"; + std::cerr << ss.str(); +} diff --git a/src/Platform/x86/main.cpp b/src/Platform/x86/main.cpp index aed43a835568e32cffa5c32ba04f5dcbcb8ce5a6..251b7ae5a8d70a19833477d41252c5125fb424a1 100644 --- a/src/Platform/x86/main.cpp +++ b/src/Platform/x86/main.cpp @@ -1,5 +1,6 @@ #include <iostream> #include <ServicePool.hpp> +#include <Logger.hpp> #include "Helpers/CRCHelper.hpp" #include "Helpers/TimeHelper.hpp" #include "Services/TestService.hpp" @@ -20,6 +21,8 @@ #include "etl/String.hpp" int main() { + LOG_NOTICE("ECSS Services test application"); + Message packet = Message(0, 0, Message::TC, 1); packet.appendString<5>("hello");