Initial commit of source code
This commit is contained in:
172
src/core/logger/logger.cpp
Normal file
172
src/core/logger/logger.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
#include "logger.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <syncstream>
|
||||
|
||||
using namespace std;
|
||||
using namespace core::logger;
|
||||
//--------------------------------------------------------------
|
||||
/* Constructor */
|
||||
Logger::Logger(dBus::Bus &bus)
|
||||
: Node(bus)
|
||||
{
|
||||
// Initialize the log printing loop
|
||||
runPrintingLoop();
|
||||
|
||||
// Initialize the bus listener thread
|
||||
runBusListener();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Default destructor */
|
||||
Logger::~Logger()
|
||||
{
|
||||
// Stop the bus listener thread if it's running
|
||||
stopBusListener();
|
||||
|
||||
// Stop the log printing loop if it's running
|
||||
stopPrintingLoop();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Run the loop that periodically prints log entries to the console */
|
||||
void Logger::runPrintingLoop()
|
||||
{
|
||||
/* Start the printing thread to periodically print log entries to the console.
|
||||
* The thread will continuously wait for messages and process them until a stop is requested */
|
||||
// clang-format off
|
||||
m_printingThread = std::jthread([this](const std::stop_token &stopToken)
|
||||
{
|
||||
while (!stopToken.stop_requested())
|
||||
{
|
||||
// Sleep for a short duration to avoid busy waiting and reduce CPU usage
|
||||
this_thread::sleep_for(100ms);
|
||||
|
||||
// Print the log entries after processing the message
|
||||
if (m_logEntries.timer.isElapsed(LOG_PRINT_INTERVAL, true))
|
||||
printLogEntries();
|
||||
}
|
||||
});
|
||||
// clang-format on
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Stop the log printing loop */
|
||||
void Logger::stopPrintingLoop()
|
||||
{
|
||||
// Stop printing thread loop
|
||||
m_printingThread.request_stop();
|
||||
|
||||
// Despite a jthread will automatically join in its destructor, we
|
||||
// can explicitly join here to ensure that the thread has finished
|
||||
// executing before the Logger object is destroyed.
|
||||
// This is especially important if the thread is still running and
|
||||
// may access resources that are being cleaned up in the destructor.
|
||||
// By joining the thread, we can ensure a clean shutdown of the Logger
|
||||
// and avoid potential issues with dangling threads or accessing invalid resources.
|
||||
if (m_printingThread.joinable())
|
||||
m_printingThread.join();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Print the log entries to the console */
|
||||
void Logger::printLogEntries()
|
||||
{
|
||||
// Move the log entries to a local variable and clear the
|
||||
// original vector to minimize the time the mutex is locked
|
||||
std::vector<std::string> logEntries;
|
||||
{
|
||||
scoped_lock lock(m_logEntries.mtx);
|
||||
logEntries = std::move(m_logEntries.entries);
|
||||
m_logEntries.entries.clear();
|
||||
}
|
||||
|
||||
for (const auto &entry : logEntries)
|
||||
{
|
||||
// Use osyncstream to ensure thread-safe output to the console
|
||||
std::osyncstream syncOut(std::cout);
|
||||
syncOut << entry << std::endl;
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Process a log message received from the bus */
|
||||
void Logger::processUserMessage(const LogMessage_ptr &logMessage)
|
||||
{
|
||||
// Sanity check
|
||||
if (!logMessage)
|
||||
return;
|
||||
|
||||
// Add the log entry to the vector of log entries
|
||||
std::scoped_lock lock(m_logEntries.mtx);
|
||||
m_logEntries.entries.push_back(logMessage->toString());
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Process a system log message received from the bus */
|
||||
void Logger::processSystemMessage(const std::string &logMessage)
|
||||
{
|
||||
// Sanity check
|
||||
if (logMessage.empty())
|
||||
return;
|
||||
|
||||
// Add the log entry to the vector of log entries
|
||||
std::scoped_lock lock(m_logEntries.mtx);
|
||||
m_logEntries.entries.push_back(logMessage);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Run the bus listener thread */
|
||||
void Logger::runBusListener()
|
||||
{
|
||||
// Subscribe to the bus in broadcast mode to receive all messages posted to the bus
|
||||
m_bus.subscribeToBroadcast(this);
|
||||
|
||||
/* Start the bus listener thread to process incoming messages related to requirements.
|
||||
* The thread will continuously wait for messages and process them until a stop is requested */
|
||||
// clang-format off
|
||||
m_busListenerThread = std::jthread([this](const std::stop_token &stopToken)
|
||||
{
|
||||
while (!stopToken.stop_requested())
|
||||
{
|
||||
// Wait for a message to be received
|
||||
syncWaitForMessage();
|
||||
|
||||
// Process all received messages
|
||||
while (getMessageCount() > 0)
|
||||
{
|
||||
auto message = popNextMessage();
|
||||
if (message)
|
||||
processMessageBus(message);
|
||||
}
|
||||
}
|
||||
});
|
||||
// clang-format on
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Stop the bus listener thread */
|
||||
void Logger::stopBusListener()
|
||||
{
|
||||
// Stop event thread loop
|
||||
m_busListenerThread.request_stop();
|
||||
|
||||
// Wake up event thread if waiting
|
||||
notifyMessageQueue();
|
||||
|
||||
// Join the bus listener thread to ensure it has finished
|
||||
// executing before the Logger object is destroyed
|
||||
if (m_busListenerThread.joinable())
|
||||
m_busListenerThread.join();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Process a message received from the bus */
|
||||
void Logger::processMessageBus(const Message_ptr &message)
|
||||
{
|
||||
// Check the message type and process accordingly
|
||||
const auto messageType = message->getMessageTypeID();
|
||||
|
||||
if (messageType == dBus::makeID("log.message"))
|
||||
{
|
||||
// Process log message
|
||||
processUserMessage(message->as<dBus::EventMessage<api::log::LogMessage>>());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Process system log message (for any other message type, we will log it as a system message)
|
||||
processSystemMessage(message->toString());
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
Reference in New Issue
Block a user