// -------------------------------------------------------------------------------------------------------------------- /// \file logger.cpp /// \brief Description // -------------------------------------------------------------------------------------------------------------------- // // vbchaos software design // // -------------------------------------------------------------------------------------------------------------------- /// $Revision: $ /// $Author: $ /// $Date: $ // (c) 2023 vbchaos // -------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------- // Include files // -------------------------------------------------------------------------------------------------------------------- #include #include #include #include // -------------------------------------------------------------------------------------------------------------------- // Constant and macro definitions // -------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------- // Type definitions // -------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------- // File-scope variables // -------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------- // Function declarations // -------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------- // Function definitions // -------------------------------------------------------------------------------------------------------------------- std::list logger::queue; uint32_t logger::queuesize = 16; uint32_t logger::numberOfLostMessages = 0; bool logger::overflowRecovery = false; logger::logger(uint32_t queuesize, ISerialBus& serialPort) : port {serialPort} { numberOfLostMessages = 0; // Compose the debug type level list composeTypeParameterList(); } FunctionStatus logger::log(const char* fileName, const char* functionName, int lineNumber, LogType logType, const char* format, ...) { FunctionStatus returnValue = FUNCTION_STATUS_OK; #if defined(ENABLE_SERIAL_LOGGING) int nrOfMessages; struct LogQueueItem logQueueItem; va_list ap; nrOfMessages = queue.size(); if((nrOfMessages >= queuesize - 1) && !overflowRecovery) { // Queue almost full, only one entry left. Log a warning instead composeLogQueueItem(&logQueueItem, __FILE__, __func__, __LINE__, LOGTYPE_WARNING, "Log queue overflow"); queue.push_back(logQueueItem); overflowRecovery = true; numberOfLostMessages = 1; } else if((nrOfMessages == 0) && overflowRecovery) { // Queue empty again after an overflow std::string str = std::to_string(numberOfLostMessages) + " messages were lost in the logger due to QUEUE overflow"; composeLogQueueItem(&logQueueItem, __FILE__, __func__, __LINE__, LOGTYPE_WARNING, str); queue.push_back(logQueueItem); overflowRecovery = false; } else if(!overflowRecovery) { // Normal behaviour, queue not full char str[128]; va_start(ap, format); vsnprintf(str, sizeof(str) / sizeof(str[0]), format, ap); va_end(ap); composeLogQueueItem(&logQueueItem, fileName, functionName, lineNumber, logType, str); queue.push_back(logQueueItem); } else { // Count number of lost messages ++numberOfLostMessages; } #endif return returnValue; } void logger::composeTypeParameterList(void) { typeParameterList.clear(); // Add Debug information typeParameterList.push_back({LOGTYPE_DEBUG, "\033[33m", "DBG", "\033[0m"}); // Add Warning information typeParameterList.push_back({LOGTYPE_WARNING, "\033[35m", "WRN", "\033[0m"}); // Add Error information typeParameterList.push_back({LOGTYPE_ERROR, "\033[31m", "ERR", "\033[0m"}); // Add Success information typeParameterList.push_back({LOGTYPE_SUCCESS, "\033[32m", "SCS", "\033[0m"}); // Add Information information typeParameterList.push_back({LOGTYPE_INFO, "\033[33m", "INF", "\033[0m"}); // Add Print information typeParameterList.push_back({LOGTYPE_PRINT, "", "DBG", "\033[0m"}); } #if defined(ENABLE_SERIAL_LOGGING) void logger::composeLogQueueItem(struct LogQueueItem* logQueueItem, const std::string& fileName, const std::string& functionName, int lineNumber, LogType logType, const std::string& context) { logQueueItem->logType = logType; logQueueItem->context = context; logQueueItem->fileName = fileName; logQueueItem->functionName = functionName; logQueueItem->lineNumber = lineNumber; } #endif void logger::task() { struct LogQueueItem logQueueItem; // Check if there is anything in the queue // If queue is empty, return to scheduler if (queue.empty()) { return; } // Get the first log item from queue logQueueItem = queue.front(); // Remove the item from the queue queue.pop_front(); if(logQueueItem.logType == LOGTYPE_PRINT) { // Raw print #if defined(ENABLE_SERIAL_LOGGING) port.write(NO_DEVICE_ADDRESS, NO_REGISTER_ADDRESS, (uint8_t*)logQueueItem.context.c_str(), logQueueItem.context.length()); #endif } else { unsigned int seconds = 0; #if defined(ENABLE_SERIAL_LOGGING) // Formatted print // Find the correct Log level type auto it = std::find_if(typeParameterList.begin(), typeParameterList.end(), [&logQueueItem](const struct typeParameters& obj) {return obj.logType == logQueueItem.logType;}); std::string outputString = "\n\r" + it->vt100Prefix + " " + it->vt100Prefix + " " + std::to_string(seconds) + " " + logQueueItem.fileName + " " + logQueueItem.functionName + " " + "(line " + std::to_string(logQueueItem.lineNumber) + "): " + logQueueItem.context + " " + it->vt100Postfix; port.write(NO_DEVICE_ADDRESS, NO_REGISTER_ADDRESS, (uint8_t*)outputString.c_str(), outputString.length() + 1); #endif } }