FileLogger:Implement synchronous file logging
This commit implements synchronous safe file logging. Certain traces,
for example VPD write action, in the repo need to be logged into
specific files. FileLogger class facilitates this. Note: this
synchronous file logging implementation is not multi-thread safe.
Change-Id: Ifdd8cdf601ec34fc57710fb201d24ebff41d8f99
Signed-off-by: Souvik Roy <souvikroyofficial10@gmail.com>
diff --git a/vpd-manager/include/logger.hpp b/vpd-manager/include/logger.hpp
index 4200052..a28e73e 100644
--- a/vpd-manager/include/logger.hpp
+++ b/vpd-manager/include/logger.hpp
@@ -6,7 +6,6 @@
#include <fstream>
#include <iostream>
#include <memory>
-#include <mutex>
#include <source_location>
#include <string_view>
@@ -41,6 +40,12 @@
// max number of log entries in file
size_t m_maxEntries{256};
+ // file stream object to do file operations
+ std::fstream m_fileStream;
+
+ // current number of log entries in file
+ size_t m_currentNumEntries{0};
+
/**
* @brief API to rotate file.
*
@@ -66,7 +71,11 @@
const size_t i_maxEntries) :
m_filePath{i_filePath}, m_maxEntries{i_maxEntries}
{
- // TODO: open the file in append mode
+ // open the file in append mode
+ m_fileStream.open(m_filePath, std::ios::out | std::ios::app);
+
+ // enable exception mask to throw on badbit and failbit
+ m_fileStream.exceptions(std::ios_base::badbit | std::ios_base::failbit);
}
/**
@@ -77,8 +86,26 @@
*/
static inline std::string timestamp() noexcept
{
- // TODO: generate timestamp.
- return std::string{};
+ try
+ {
+ const auto l_now = std::chrono::system_clock::now();
+ const auto l_in_time_t =
+ std::chrono::system_clock::to_time_t(l_now);
+ const auto l_ms =
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ l_now.time_since_epoch()) %
+ 1000;
+
+ std::stringstream l_ss;
+ l_ss << std::put_time(std::localtime(&l_in_time_t),
+ "%Y-%m-%d %H:%M:%S")
+ << "." << std::setfill('0') << std::setw(3) << l_ms.count();
+ return l_ss.str();
+ }
+ catch (const std::exception& l_ex)
+ {
+ return std::string{};
+ }
}
public:
@@ -102,11 +129,63 @@
// destructor
virtual ~ILogFileHandler()
{
- // TODO: close the filestream
+ if (m_fileStream.is_open())
+ {
+ m_fileStream.close();
+ }
}
};
/**
+ * @brief A class to handle logging messages to file synchronously
+ *
+ * This class handles logging messages to a specific file in a synchronous
+ * manner.
+ * Note: The logMessage API of this class is not multi-thread safe.
+ */
+class SyncFileLogger final : public ILogFileHandler
+{
+ /**
+ * @brief Parameterized constructor.
+ * Private so that can't be initialized by class(es) other than friends.
+ *
+ * @param[in] i_filePath - Absolute path of the log file.
+ * @param[in] i_maxEntries - Maximum number of entries in the log file after
+ * which the file will be rotated.
+ */
+ SyncFileLogger(const std::filesystem::path& i_filePath,
+ const size_t i_maxEntries) :
+ ILogFileHandler(i_filePath, i_maxEntries)
+ {}
+
+ public:
+ // Friend class Logger.
+ friend class Logger;
+
+ // deleted methods
+ SyncFileLogger() = delete;
+ SyncFileLogger(const SyncFileLogger&) = delete;
+ SyncFileLogger(const SyncFileLogger&&) = delete;
+ SyncFileLogger operator=(const SyncFileLogger&) = delete;
+ SyncFileLogger operator=(const SyncFileLogger&&) = delete;
+
+ /**
+ * @brief API to log a message to file
+ *
+ * This API logs messages to file in a synchronous manner.
+ * Note: This API is not multi-thread safe.
+ *
+ * @param[in] i_message - Message to log
+ *
+ * @throw std::runtime_error
+ */
+ void logMessage(const std::string_view& i_message) override;
+
+ // destructor
+ ~SyncFileLogger() = default;
+};
+
+/**
* @brief Singleton class to handle error logging for the repository.
*/
class Logger
@@ -175,7 +254,8 @@
*/
Logger() : m_vpdWriteLogger(nullptr), m_collectionLogger(nullptr)
{
- // TODO: initiate synchronous logger for VPD write logs
+ m_vpdWriteLogger.reset(
+ new SyncFileLogger("/var/lib/vpd/vpdWrite.log", 128));
}
// Instance to the logger class.
diff --git a/vpd-manager/src/logger.cpp b/vpd-manager/src/logger.cpp
index b951314..254a177 100644
--- a/vpd-manager/src/logger.cpp
+++ b/vpd-manager/src/logger.cpp
@@ -64,9 +64,33 @@
}
}
+void SyncFileLogger::logMessage(const std::string_view& i_message)
+{
+ try
+ {
+ if (++m_currentNumEntries > m_maxEntries)
+ {
+ rotateFile();
+ }
+ m_fileStream << timestamp() << " : " << i_message << std::endl;
+ }
+ catch (const std::exception& l_ex)
+ {
+ // log message to journal if we fail to log to file
+ auto l_logger = Logger::getLoggerInstance();
+ l_logger->logMessage(i_message);
+ }
+}
+
void ILogFileHandler::rotateFile(
[[maybe_unused]] const unsigned i_numEntriesToDelete)
-{}
+{
+ /* TODO:
+ - delete specified number of oldest entries from beginning of file
+ - rewrite file to move existing logs to beginning of file
+ */
+ m_currentNumEntries = m_maxEntries - i_numEntriesToDelete;
+}
namespace logging
{
void logMessage(std::string_view message, const std::source_location& location)