blob: 1622426c98d03f32f675f4dedb599cee5f205e8b [file] [log] [blame]
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001#pragma once
2
Sunny Srivastava5779d972025-08-08 01:45:23 -05003#include "types.hpp"
4
Souvik Roya8c3c092025-09-11 10:49:29 +00005#include <filesystem>
6#include <fstream>
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05007#include <iostream>
Sunny Srivastava5779d972025-08-08 01:45:23 -05008#include <memory>
Souvik Roy0fb5c3b2025-09-15 08:18:25 +00009#include <mutex>
10#include <queue>
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050011#include <source_location>
12#include <string_view>
13
14namespace vpd
15{
Sunny Srivastava5779d972025-08-08 01:45:23 -050016
17/**
18 * @brief Enum class defining placeholder tags.
19 *
20 * The tag will be used by APIs to identify the endpoint for a given log
21 * message.
22 */
23enum class PlaceHolder
24{
Souvik Roya5e18b82025-09-25 05:59:56 +000025 DEFAULT, /* logs to the journal */
26 PEL, /* Creates a PEL */
27 COLLECTION, /* Logs collection messages */
28 VPD_WRITE /* Logs VPD write details */
Sunny Srivastava5779d972025-08-08 01:45:23 -050029};
30
31/**
32 * @brief Class to handle file operations w.r.t logging.
33 * Based on the placeholder the class will handle different file operations to
34 * log error messages.
35 */
Souvik Roya5e18b82025-09-25 05:59:56 +000036class ILogFileHandler
Sunny Srivastava5779d972025-08-08 01:45:23 -050037{
Souvik Roya8c3c092025-09-11 10:49:29 +000038 protected:
39 // absolute file path of log file
40 std::filesystem::path m_filePath{};
41
42 // max number of log entries in file
43 size_t m_maxEntries{256};
44
Souvik Roy6bd74ad2025-09-12 06:24:06 +000045 // file stream object to do file operations
46 std::fstream m_fileStream;
47
48 // current number of log entries in file
49 size_t m_currentNumEntries{0};
50
Sunny Srivastava5779d972025-08-08 01:45:23 -050051 /**
Souvik Roya8c3c092025-09-11 10:49:29 +000052 * @brief API to rotate file.
Sunny Srivastava5779d972025-08-08 01:45:23 -050053 *
Souvik Roya8c3c092025-09-11 10:49:29 +000054 * This API rotates the logs within a file by deleting specified number of
55 * oldest entries.
Sunny Srivastava5779d972025-08-08 01:45:23 -050056 *
Souvik Roya8c3c092025-09-11 10:49:29 +000057 * @param[in] i_numEntriesToDelete - Number of entries to delete.
58 *
59 * @throw std::runtime_error
Sunny Srivastava5779d972025-08-08 01:45:23 -050060 */
Souvik Roya8c3c092025-09-11 10:49:29 +000061 virtual void rotateFile(
62 [[maybe_unused]] const unsigned i_numEntriesToDelete = 5);
63
64 /**
65 * @brief Constructor.
66 * Private so that can't be initialized by class(es) other than friends.
67 *
68 * @param[in] i_filePath - Absolute path of the log file.
69 * @param[in] i_maxEntries - Maximum number of entries in the log file after
70 * which the file will be rotated.
71 */
72 ILogFileHandler(const std::filesystem::path& i_filePath,
73 const size_t i_maxEntries) :
74 m_filePath{i_filePath}, m_maxEntries{i_maxEntries}
Sunny Srivastava5779d972025-08-08 01:45:23 -050075 {
Souvik Roy6bd74ad2025-09-12 06:24:06 +000076 // open the file in append mode
77 m_fileStream.open(m_filePath, std::ios::out | std::ios::app);
78
79 // enable exception mask to throw on badbit and failbit
80 m_fileStream.exceptions(std::ios_base::badbit | std::ios_base::failbit);
Sunny Srivastava5779d972025-08-08 01:45:23 -050081 }
82
Sunny Srivastava5779d972025-08-08 01:45:23 -050083 /**
Souvik Roya8c3c092025-09-11 10:49:29 +000084 * @brief API to generate timestamp in string format.
85 *
86 * @return Returns timestamp in string format on success, otherwise returns
87 * empty string in case of any error.
Sunny Srivastava5779d972025-08-08 01:45:23 -050088 */
Souvik Roya8c3c092025-09-11 10:49:29 +000089 static inline std::string timestamp() noexcept
90 {
Souvik Roy6bd74ad2025-09-12 06:24:06 +000091 try
92 {
93 const auto l_now = std::chrono::system_clock::now();
94 const auto l_in_time_t =
95 std::chrono::system_clock::to_time_t(l_now);
96 const auto l_ms =
97 std::chrono::duration_cast<std::chrono::milliseconds>(
98 l_now.time_since_epoch()) %
99 1000;
100
101 std::stringstream l_ss;
102 l_ss << std::put_time(std::localtime(&l_in_time_t),
103 "%Y-%m-%d %H:%M:%S")
104 << "." << std::setfill('0') << std::setw(3) << l_ms.count();
105 return l_ss.str();
106 }
107 catch (const std::exception& l_ex)
108 {
109 return std::string{};
110 }
Souvik Roya8c3c092025-09-11 10:49:29 +0000111 }
Sunny Srivastava5779d972025-08-08 01:45:23 -0500112
Souvik Roya8c3c092025-09-11 10:49:29 +0000113 public:
114 // deleted methods
115 ILogFileHandler() = delete;
116 ILogFileHandler(const ILogFileHandler&) = delete;
117 ILogFileHandler(const ILogFileHandler&&) = delete;
118 ILogFileHandler operator=(const ILogFileHandler&) = delete;
119 ILogFileHandler operator=(const ILogFileHandler&&) = delete;
120
121 /**
122 * @brief API to log a message to file.
123 *
124 * @param[in] i_message - Message to log.
125 *
126 * @throw std::runtime_error
127 */
128 virtual void logMessage(
129 [[maybe_unused]] const std::string_view& i_message) = 0;
130
131 // destructor
132 virtual ~ILogFileHandler()
133 {
Souvik Roy6bd74ad2025-09-12 06:24:06 +0000134 if (m_fileStream.is_open())
135 {
136 m_fileStream.close();
137 }
Souvik Roya8c3c092025-09-11 10:49:29 +0000138 }
Sunny Srivastava5779d972025-08-08 01:45:23 -0500139};
140
141/**
Souvik Roy6bd74ad2025-09-12 06:24:06 +0000142 * @brief A class to handle logging messages to file synchronously
143 *
144 * This class handles logging messages to a specific file in a synchronous
145 * manner.
146 * Note: The logMessage API of this class is not multi-thread safe.
147 */
148class SyncFileLogger final : public ILogFileHandler
149{
150 /**
151 * @brief Parameterized constructor.
152 * Private so that can't be initialized by class(es) other than friends.
153 *
154 * @param[in] i_filePath - Absolute path of the log file.
155 * @param[in] i_maxEntries - Maximum number of entries in the log file after
156 * which the file will be rotated.
157 */
158 SyncFileLogger(const std::filesystem::path& i_filePath,
159 const size_t i_maxEntries) :
160 ILogFileHandler(i_filePath, i_maxEntries)
161 {}
162
163 public:
164 // Friend class Logger.
165 friend class Logger;
166
167 // deleted methods
168 SyncFileLogger() = delete;
169 SyncFileLogger(const SyncFileLogger&) = delete;
170 SyncFileLogger(const SyncFileLogger&&) = delete;
171 SyncFileLogger operator=(const SyncFileLogger&) = delete;
172 SyncFileLogger operator=(const SyncFileLogger&&) = delete;
173
174 /**
175 * @brief API to log a message to file
176 *
177 * This API logs messages to file in a synchronous manner.
178 * Note: This API is not multi-thread safe.
179 *
180 * @param[in] i_message - Message to log
181 *
182 * @throw std::runtime_error
183 */
184 void logMessage(const std::string_view& i_message) override;
185
186 // destructor
187 ~SyncFileLogger() = default;
188};
189
190/**
Souvik Roy0fb5c3b2025-09-15 08:18:25 +0000191 * @brief A class to handle asynchronous logging of messages to file
192 *
193 * This class implements methods to log messages asynchronously to a desired
194 * file in the filesystem. It uses a queue for buffering the messages from
195 * caller. The actual file operations are handled by a worker thread.
196 */
197class AsyncFileLogger final : public ILogFileHandler
198{
199 /**
200 * @brief Constructor
201 * Private so that can't be initialized by class(es) other than friends.
202 *
203 * @param[in] i_fileName - Name of the log file
204 * @param[in] i_maxEntries - Maximum number of entries in the log file after
205 * which the file will be rotated
206 */
207 AsyncFileLogger(const std::filesystem::path& i_fileName,
208 const size_t i_maxEntries) :
209 ILogFileHandler(i_fileName, i_maxEntries)
210 {
211 // start worker thread in detached mode
212 std::thread{[this]() { this->fileWorker(); }}.detach();
213 }
214
215 /**
216 * @brief Logger worker thread body
217 */
218 void fileWorker() noexcept;
219
220 public:
221 // Friend class Logger.
222 friend class Logger;
223
224 // deleted methods
225 AsyncFileLogger() = delete;
226 AsyncFileLogger(const AsyncFileLogger&) = delete;
227 AsyncFileLogger(const AsyncFileLogger&&) = delete;
228 AsyncFileLogger operator=(const AsyncFileLogger&) = delete;
229 AsyncFileLogger operator=(const AsyncFileLogger&&) = delete;
230
231 /**
232 * @brief API to log a message to file
233 *
234 * @param[in] i_message - Message to log
235 *
236 * @throw std::runtime_error
237 */
238 void logMessage(const std::string_view& i_message) override;
239
240 // destructor
241 ~AsyncFileLogger()
242 {
243 /* TODO
244 - acquire lock
245 - set log stop flag to true
246 - notify log worker thread
247 */
248 if (m_fileStream.is_open())
249 {
250 m_fileStream.close();
251 }
252 }
253};
254
255/**
Sunny Srivastava5779d972025-08-08 01:45:23 -0500256 * @brief Singleton class to handle error logging for the repository.
257 */
258class Logger
259{
260 public:
261 /**
262 * @brief Deleted Methods
263 */
Souvik Roya5e18b82025-09-25 05:59:56 +0000264 Logger(const Logger&) = delete; // Copy constructor
265 Logger(const Logger&&) = delete; // Move constructor
266 Logger operator=(const Logger&) = delete; // Copy assignment operator
267 Logger operator=(const Logger&&) = delete; // Move assignment operator
Sunny Srivastava5779d972025-08-08 01:45:23 -0500268
269 /**
270 * @brief Method to get instance of Logger class.
271 */
272 static std::shared_ptr<Logger> getLoggerInstance()
273 {
274 if (!m_loggerInstance)
275 {
276 m_loggerInstance = std::shared_ptr<Logger>(new Logger());
277 }
278 return m_loggerInstance;
279 }
280
281 /**
282 * @brief API to log a given error message.
283 *
284 * @param[in] i_message - Message to be logged.
285 * @param[in] i_placeHolder - States where the message needs to be logged.
286 * Default is journal.
287 * @param[in] i_pelTuple - A structure only required in case message needs
288 * to be logged as PEL.
289 * @param[in] i_location - Locatuon from where message needs to be logged.
290 */
291 void logMessage(std::string_view i_message,
292 const PlaceHolder& i_placeHolder = PlaceHolder::DEFAULT,
293 const types::PelInfoTuple* i_pelTuple = nullptr,
294 const std::source_location& i_location =
295 std::source_location::current());
296
Souvik Roya5e18b82025-09-25 05:59:56 +0000297 /**
298 * @brief API to initiate VPD collection logging.
299 *
300 * This API initiates VPD collection logging. It checks for existing
301 * collection log files and if 3 such files are found, it deletes the oldest
302 * file and initiates a VPD collection logger object, so that every new VPD
303 * collection flow always gets logged into a new file.
304 */
305 void initiateVpdCollectionLogging() noexcept;
306
307 /**
308 * @brief API to terminate VPD collection logging.
309 *
310 * This API terminates the VPD collection logging by destroying the
311 * associated VPD collection logger object.
312 */
313 void terminateVpdCollectionLogging() noexcept
314 {
Souvik Roy0fb5c3b2025-09-15 08:18:25 +0000315 m_collectionLogger.reset();
Souvik Roya5e18b82025-09-25 05:59:56 +0000316 }
317
Sunny Srivastava5779d972025-08-08 01:45:23 -0500318 private:
319 /**
320 * @brief Constructor
321 */
Souvik Roya5e18b82025-09-25 05:59:56 +0000322 Logger() : m_vpdWriteLogger(nullptr), m_collectionLogger(nullptr)
Sunny Srivastava5779d972025-08-08 01:45:23 -0500323 {
Souvik Roy6bd74ad2025-09-12 06:24:06 +0000324 m_vpdWriteLogger.reset(
325 new SyncFileLogger("/var/lib/vpd/vpdWrite.log", 128));
Sunny Srivastava5779d972025-08-08 01:45:23 -0500326 }
327
328 // Instance to the logger class.
329 static std::shared_ptr<Logger> m_loggerInstance;
330
Souvik Roya5e18b82025-09-25 05:59:56 +0000331 // logger object to handle VPD write logs
332 std::unique_ptr<ILogFileHandler> m_vpdWriteLogger;
333
334 // logger object to handle VPD collection logs
335 std::unique_ptr<ILogFileHandler> m_collectionLogger;
Sunny Srivastava5779d972025-08-08 01:45:23 -0500336};
337
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500338/**
339 * @brief The namespace defines logging related methods for VPD.
Sunny Srivastava5779d972025-08-08 01:45:23 -0500340 * Only for backward compatibility till new logger class comes up.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500341 */
342namespace logging
343{
344
345/**
346 * @brief An api to log message.
347 * This API should be called to log message. It will auto append information
348 * like file name, line and function name to the message being logged.
349 *
350 * @param[in] message - Information that we want to log.
351 * @param[in] location - Object of source_location class.
352 */
353void logMessage(std::string_view message, const std::source_location& location =
354 std::source_location::current());
355} // namespace logging
356} // namespace vpd