blob: a28e73ec9c35b07a914fb6dc5262e8c072921e95 [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>
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05009#include <source_location>
10#include <string_view>
11
12namespace vpd
13{
Sunny Srivastava5779d972025-08-08 01:45:23 -050014
15/**
16 * @brief Enum class defining placeholder tags.
17 *
18 * The tag will be used by APIs to identify the endpoint for a given log
19 * message.
20 */
21enum class PlaceHolder
22{
Souvik Roya5e18b82025-09-25 05:59:56 +000023 DEFAULT, /* logs to the journal */
24 PEL, /* Creates a PEL */
25 COLLECTION, /* Logs collection messages */
26 VPD_WRITE /* Logs VPD write details */
Sunny Srivastava5779d972025-08-08 01:45:23 -050027};
28
29/**
30 * @brief Class to handle file operations w.r.t logging.
31 * Based on the placeholder the class will handle different file operations to
32 * log error messages.
33 */
Souvik Roya5e18b82025-09-25 05:59:56 +000034class ILogFileHandler
Sunny Srivastava5779d972025-08-08 01:45:23 -050035{
Souvik Roya8c3c092025-09-11 10:49:29 +000036 protected:
37 // absolute file path of log file
38 std::filesystem::path m_filePath{};
39
40 // max number of log entries in file
41 size_t m_maxEntries{256};
42
Souvik Roy6bd74ad2025-09-12 06:24:06 +000043 // file stream object to do file operations
44 std::fstream m_fileStream;
45
46 // current number of log entries in file
47 size_t m_currentNumEntries{0};
48
Sunny Srivastava5779d972025-08-08 01:45:23 -050049 /**
Souvik Roya8c3c092025-09-11 10:49:29 +000050 * @brief API to rotate file.
Sunny Srivastava5779d972025-08-08 01:45:23 -050051 *
Souvik Roya8c3c092025-09-11 10:49:29 +000052 * This API rotates the logs within a file by deleting specified number of
53 * oldest entries.
Sunny Srivastava5779d972025-08-08 01:45:23 -050054 *
Souvik Roya8c3c092025-09-11 10:49:29 +000055 * @param[in] i_numEntriesToDelete - Number of entries to delete.
56 *
57 * @throw std::runtime_error
Sunny Srivastava5779d972025-08-08 01:45:23 -050058 */
Souvik Roya8c3c092025-09-11 10:49:29 +000059 virtual void rotateFile(
60 [[maybe_unused]] const unsigned i_numEntriesToDelete = 5);
61
62 /**
63 * @brief Constructor.
64 * Private so that can't be initialized by class(es) other than friends.
65 *
66 * @param[in] i_filePath - Absolute path of the log file.
67 * @param[in] i_maxEntries - Maximum number of entries in the log file after
68 * which the file will be rotated.
69 */
70 ILogFileHandler(const std::filesystem::path& i_filePath,
71 const size_t i_maxEntries) :
72 m_filePath{i_filePath}, m_maxEntries{i_maxEntries}
Sunny Srivastava5779d972025-08-08 01:45:23 -050073 {
Souvik Roy6bd74ad2025-09-12 06:24:06 +000074 // open the file in append mode
75 m_fileStream.open(m_filePath, std::ios::out | std::ios::app);
76
77 // enable exception mask to throw on badbit and failbit
78 m_fileStream.exceptions(std::ios_base::badbit | std::ios_base::failbit);
Sunny Srivastava5779d972025-08-08 01:45:23 -050079 }
80
Sunny Srivastava5779d972025-08-08 01:45:23 -050081 /**
Souvik Roya8c3c092025-09-11 10:49:29 +000082 * @brief API to generate timestamp in string format.
83 *
84 * @return Returns timestamp in string format on success, otherwise returns
85 * empty string in case of any error.
Sunny Srivastava5779d972025-08-08 01:45:23 -050086 */
Souvik Roya8c3c092025-09-11 10:49:29 +000087 static inline std::string timestamp() noexcept
88 {
Souvik Roy6bd74ad2025-09-12 06:24:06 +000089 try
90 {
91 const auto l_now = std::chrono::system_clock::now();
92 const auto l_in_time_t =
93 std::chrono::system_clock::to_time_t(l_now);
94 const auto l_ms =
95 std::chrono::duration_cast<std::chrono::milliseconds>(
96 l_now.time_since_epoch()) %
97 1000;
98
99 std::stringstream l_ss;
100 l_ss << std::put_time(std::localtime(&l_in_time_t),
101 "%Y-%m-%d %H:%M:%S")
102 << "." << std::setfill('0') << std::setw(3) << l_ms.count();
103 return l_ss.str();
104 }
105 catch (const std::exception& l_ex)
106 {
107 return std::string{};
108 }
Souvik Roya8c3c092025-09-11 10:49:29 +0000109 }
Sunny Srivastava5779d972025-08-08 01:45:23 -0500110
Souvik Roya8c3c092025-09-11 10:49:29 +0000111 public:
112 // deleted methods
113 ILogFileHandler() = delete;
114 ILogFileHandler(const ILogFileHandler&) = delete;
115 ILogFileHandler(const ILogFileHandler&&) = delete;
116 ILogFileHandler operator=(const ILogFileHandler&) = delete;
117 ILogFileHandler operator=(const ILogFileHandler&&) = delete;
118
119 /**
120 * @brief API to log a message to file.
121 *
122 * @param[in] i_message - Message to log.
123 *
124 * @throw std::runtime_error
125 */
126 virtual void logMessage(
127 [[maybe_unused]] const std::string_view& i_message) = 0;
128
129 // destructor
130 virtual ~ILogFileHandler()
131 {
Souvik Roy6bd74ad2025-09-12 06:24:06 +0000132 if (m_fileStream.is_open())
133 {
134 m_fileStream.close();
135 }
Souvik Roya8c3c092025-09-11 10:49:29 +0000136 }
Sunny Srivastava5779d972025-08-08 01:45:23 -0500137};
138
139/**
Souvik Roy6bd74ad2025-09-12 06:24:06 +0000140 * @brief A class to handle logging messages to file synchronously
141 *
142 * This class handles logging messages to a specific file in a synchronous
143 * manner.
144 * Note: The logMessage API of this class is not multi-thread safe.
145 */
146class SyncFileLogger final : public ILogFileHandler
147{
148 /**
149 * @brief Parameterized constructor.
150 * Private so that can't be initialized by class(es) other than friends.
151 *
152 * @param[in] i_filePath - Absolute path of the log file.
153 * @param[in] i_maxEntries - Maximum number of entries in the log file after
154 * which the file will be rotated.
155 */
156 SyncFileLogger(const std::filesystem::path& i_filePath,
157 const size_t i_maxEntries) :
158 ILogFileHandler(i_filePath, i_maxEntries)
159 {}
160
161 public:
162 // Friend class Logger.
163 friend class Logger;
164
165 // deleted methods
166 SyncFileLogger() = delete;
167 SyncFileLogger(const SyncFileLogger&) = delete;
168 SyncFileLogger(const SyncFileLogger&&) = delete;
169 SyncFileLogger operator=(const SyncFileLogger&) = delete;
170 SyncFileLogger operator=(const SyncFileLogger&&) = delete;
171
172 /**
173 * @brief API to log a message to file
174 *
175 * This API logs messages to file in a synchronous manner.
176 * Note: This API is not multi-thread safe.
177 *
178 * @param[in] i_message - Message to log
179 *
180 * @throw std::runtime_error
181 */
182 void logMessage(const std::string_view& i_message) override;
183
184 // destructor
185 ~SyncFileLogger() = default;
186};
187
188/**
Sunny Srivastava5779d972025-08-08 01:45:23 -0500189 * @brief Singleton class to handle error logging for the repository.
190 */
191class Logger
192{
193 public:
194 /**
195 * @brief Deleted Methods
196 */
Souvik Roya5e18b82025-09-25 05:59:56 +0000197 Logger(const Logger&) = delete; // Copy constructor
198 Logger(const Logger&&) = delete; // Move constructor
199 Logger operator=(const Logger&) = delete; // Copy assignment operator
200 Logger operator=(const Logger&&) = delete; // Move assignment operator
Sunny Srivastava5779d972025-08-08 01:45:23 -0500201
202 /**
203 * @brief Method to get instance of Logger class.
204 */
205 static std::shared_ptr<Logger> getLoggerInstance()
206 {
207 if (!m_loggerInstance)
208 {
209 m_loggerInstance = std::shared_ptr<Logger>(new Logger());
210 }
211 return m_loggerInstance;
212 }
213
214 /**
215 * @brief API to log a given error message.
216 *
217 * @param[in] i_message - Message to be logged.
218 * @param[in] i_placeHolder - States where the message needs to be logged.
219 * Default is journal.
220 * @param[in] i_pelTuple - A structure only required in case message needs
221 * to be logged as PEL.
222 * @param[in] i_location - Locatuon from where message needs to be logged.
223 */
224 void logMessage(std::string_view i_message,
225 const PlaceHolder& i_placeHolder = PlaceHolder::DEFAULT,
226 const types::PelInfoTuple* i_pelTuple = nullptr,
227 const std::source_location& i_location =
228 std::source_location::current());
229
Souvik Roya5e18b82025-09-25 05:59:56 +0000230 /**
231 * @brief API to initiate VPD collection logging.
232 *
233 * This API initiates VPD collection logging. It checks for existing
234 * collection log files and if 3 such files are found, it deletes the oldest
235 * file and initiates a VPD collection logger object, so that every new VPD
236 * collection flow always gets logged into a new file.
237 */
238 void initiateVpdCollectionLogging() noexcept;
239
240 /**
241 * @brief API to terminate VPD collection logging.
242 *
243 * This API terminates the VPD collection logging by destroying the
244 * associated VPD collection logger object.
245 */
246 void terminateVpdCollectionLogging() noexcept
247 {
248 // TODO: reset VPD collection logger
249 }
250
Sunny Srivastava5779d972025-08-08 01:45:23 -0500251 private:
252 /**
253 * @brief Constructor
254 */
Souvik Roya5e18b82025-09-25 05:59:56 +0000255 Logger() : m_vpdWriteLogger(nullptr), m_collectionLogger(nullptr)
Sunny Srivastava5779d972025-08-08 01:45:23 -0500256 {
Souvik Roy6bd74ad2025-09-12 06:24:06 +0000257 m_vpdWriteLogger.reset(
258 new SyncFileLogger("/var/lib/vpd/vpdWrite.log", 128));
Sunny Srivastava5779d972025-08-08 01:45:23 -0500259 }
260
261 // Instance to the logger class.
262 static std::shared_ptr<Logger> m_loggerInstance;
263
Souvik Roya5e18b82025-09-25 05:59:56 +0000264 // logger object to handle VPD write logs
265 std::unique_ptr<ILogFileHandler> m_vpdWriteLogger;
266
267 // logger object to handle VPD collection logs
268 std::unique_ptr<ILogFileHandler> m_collectionLogger;
Sunny Srivastava5779d972025-08-08 01:45:23 -0500269};
270
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500271/**
272 * @brief The namespace defines logging related methods for VPD.
Sunny Srivastava5779d972025-08-08 01:45:23 -0500273 * Only for backward compatibility till new logger class comes up.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500274 */
275namespace logging
276{
277
278/**
279 * @brief An api to log message.
280 * This API should be called to log message. It will auto append information
281 * like file name, line and function name to the message being logged.
282 *
283 * @param[in] message - Information that we want to log.
284 * @param[in] location - Object of source_location class.
285 */
286void logMessage(std::string_view message, const std::source_location& location =
287 std::source_location::current());
288} // namespace logging
289} // namespace vpd