xref: /openbmc/openpower-vpd-parser/vpd-manager/include/utility/event_logger_utility.hpp (revision a39aafa337352262596e07577fdf88cc294284c9)
1 #pragma once
2 
3 #include "config.h"
4 
5 #include "common_utility.hpp"
6 #include "constants.hpp"
7 #include "exceptions.hpp"
8 #include "json_utility.hpp"
9 #include "logger.hpp"
10 #include "types.hpp"
11 
12 #include <systemd/sd-bus.h>
13 
14 #include <filesystem>
15 #include <iostream>
16 #include <optional>
17 #include <string>
18 #include <unordered_map>
19 
20 namespace vpd
21 {
22 namespace EventLogger
23 {
24 const std::unordered_map<types::SeverityType, std::string> severityMap = {
25     {types::SeverityType::Notice,
26      "xyz.openbmc_project.Logging.Entry.Level.Notice"},
27     {types::SeverityType::Informational,
28      "xyz.openbmc_project.Logging.Entry.Level.Informational"},
29     {types::SeverityType::Debug,
30      "xyz.openbmc_project.Logging.Entry.Level.Debug"},
31     {types::SeverityType::Warning,
32      "xyz.openbmc_project.Logging.Entry.Level.Warning"},
33     {types::SeverityType::Critical,
34      "xyz.openbmc_project.Logging.Entry.Level.Critical"},
35     {types::SeverityType::Emergency,
36      "xyz.openbmc_project.Logging.Entry.Level.Emergency"},
37     {types::SeverityType::Alert,
38      "xyz.openbmc_project.Logging.Entry.Level.Alert"},
39     {types::SeverityType::Error,
40      "xyz.openbmc_project.Logging.Entry.Level.Error"}};
41 
42 const std::unordered_map<types::ErrorType, std::string> errorMsgMap = {
43     {types::ErrorType::DefaultValue, "com.ibm.VPD.Error.DefaultValue"},
44     {types::ErrorType::UndefinedError, "com.ibm.VPD.Error.UndefinedError"},
45     {types::ErrorType::InvalidVpdMessage, "com.ibm.VPD.Error.InvalidVPD"},
46     {types::ErrorType::VpdMismatch, "com.ibm.VPD.Error.Mismatch"},
47     {types::ErrorType::InvalidEeprom, "com.ibm.VPD.Error.InvalidEepromPath"},
48     {types::ErrorType::EccCheckFailed, "com.ibm.VPD.Error.EccCheckFailed"},
49     {types::ErrorType::JsonFailure, "com.ibm.VPD.Error.InvalidJson"},
50     {types::ErrorType::DbusFailure, "com.ibm.VPD.Error.DbusFailure"},
51     {types::ErrorType::InvalidSystem, "com.ibm.VPD.Error.UnknownSystemType"},
52     {types::ErrorType::EssentialFru, "com.ibm.VPD.Error.RequiredFRUMissing"},
53     {types::ErrorType::GpioError, "com.ibm.VPD.Error.GPIOError"},
54     {types::ErrorType::InternalFailure,
55      "xyz.openbmc_project.Common.Error.InternalFailure"},
56     {types::ErrorType::FruMissing, "com.ibm.VPD.Error.RequiredFRUMissing"},
57     {types::ErrorType::SystemTypeMismatch,
58      "com.ibm.VPD.Error.SystemTypeMismatch"},
59     {types::ErrorType::UnknownSystemSettings,
60      "com.ibm.VPD.Error.UnknownSystemSettings"},
61     {types::ErrorType::FirmwareError, "com.ibm.VPD.Error.FirmwareError"},
62     {types::ErrorType::VpdParseError, "com.ibm.VPD.Error.VPDParseError"}};
63 
64 const std::unordered_map<types::CalloutPriority, std::string> priorityMap = {
65     {types::CalloutPriority::High, "H"},
66     {types::CalloutPriority::Medium, "M"},
67     {types::CalloutPriority::MediumGroupA, "A"},
68     {types::CalloutPriority::MediumGroupB, "B"},
69     {types::CalloutPriority::MediumGroupC, "C"},
70     {types::CalloutPriority::Low, "L"}};
71 
72 /**
73  * @brief API to get error info based on the exception.
74  *
75  * @param[in] i_exception - Exception object.
76  *
77  * @return - Valid ExceptionDataMap on success, otherwise map having
78  * default value.
79  */
getExceptionData(const std::exception & i_exception)80 inline types::ExceptionDataMap getExceptionData(
81     const std::exception& i_exception)
82 {
83     types::ExceptionDataMap l_errorInfo{
84         {"ErrorType", types::ErrorType::UndefinedError},
85         {"ErrorMsg", i_exception.what()}};
86 
87     try
88     {
89         if (typeid(i_exception) == typeid(DataException))
90         {
91             const DataException& l_ex =
92                 dynamic_cast<const DataException&>(i_exception);
93             l_errorInfo["ErrorType"] = l_ex.getErrorType();
94             l_errorInfo["ErrorMsg"] =
95                 std::string("Data Exception. Reason: ") + i_exception.what();
96         }
97         else if (typeid(i_exception) == typeid(EccException))
98         {
99             const EccException& l_ex =
100                 dynamic_cast<const EccException&>(i_exception);
101             l_errorInfo["ErrorType"] = l_ex.getErrorType();
102             l_errorInfo["ErrorMsg"] =
103                 std::string("Ecc Exception. Reason: ") + i_exception.what();
104         }
105         else if (typeid(i_exception) == typeid(JsonException))
106         {
107             const JsonException& l_ex =
108                 dynamic_cast<const JsonException&>(i_exception);
109             l_errorInfo["ErrorType"] = l_ex.getErrorType();
110             l_errorInfo["ErrorMsg"] =
111                 std::string("Json Exception. Reason: ") + i_exception.what();
112         }
113         else if (typeid(i_exception) == typeid(GpioException))
114         {
115             const GpioException& l_ex =
116                 dynamic_cast<const GpioException&>(i_exception);
117             l_errorInfo["ErrorType"] = l_ex.getErrorType();
118             l_errorInfo["ErrorMsg"] =
119                 std::string("Gpio Exception. Reason: ") + i_exception.what();
120         }
121         else if (typeid(i_exception) == typeid(DbusException))
122         {
123             const DbusException& l_ex =
124                 dynamic_cast<const DbusException&>(i_exception);
125             l_errorInfo["ErrorType"] = l_ex.getErrorType();
126             l_errorInfo["ErrorMsg"] =
127                 std::string("Dbus Exception. Reason: ") + i_exception.what();
128         }
129         else if (typeid(i_exception) == typeid(FirmwareException))
130         {
131             const FirmwareException& l_ex =
132                 dynamic_cast<const FirmwareException&>(i_exception);
133             l_errorInfo["ErrorType"] = l_ex.getErrorType();
134             l_errorInfo["ErrorMsg"] =
135                 std::string("Firmware Exception. Reason: ") +
136                 i_exception.what();
137         }
138         else if (typeid(i_exception) == typeid(EepromException))
139         {
140             const EepromException& l_ex =
141                 dynamic_cast<const EepromException&>(i_exception);
142             l_errorInfo["ErrorType"] = l_ex.getErrorType();
143             l_errorInfo["ErrorMsg"] =
144                 std::string("Eeprom Exception. Reason: ") + i_exception.what();
145         }
146         else if (typeid(i_exception) == typeid(std::runtime_error))
147         {
148             // Since it is a standard exception no casting is required and error
149             // type is hardcoded.
150             l_errorInfo["ErrorType"] = types::ErrorType::FirmwareError;
151             l_errorInfo["ErrorMsg"] =
152                 std::string("Standard runtime exception. Reason: ") +
153                 i_exception.what();
154         }
155     }
156     catch (const std::exception& l_ex)
157     {
158         logging::logMessage(
159             "Failed to get error info, reason: " + std::string(l_ex.what()));
160     }
161     return l_errorInfo;
162 }
163 
164 /**
165  * @brief API to get Error type.
166  *
167  * @param[in] i_exception - Exception object.
168  *
169  * @return Error type set for the exception.
170  * types::ErrorType::InternalFailure otherwise.
171  */
getErrorType(const std::exception & i_exception)172 inline types::ErrorType getErrorType(const std::exception& i_exception)
173 {
174     const auto& l_exceptionDataMap = getExceptionData(i_exception);
175 
176     auto l_itrToErrType = l_exceptionDataMap.find("ErrorType");
177     if (l_itrToErrType == l_exceptionDataMap.end())
178     {
179         return types::ErrorType::UndefinedError;
180     }
181 
182     auto l_ptrToErrType =
183         std::get_if<types::ErrorType>(&l_itrToErrType->second);
184     if (!l_ptrToErrType)
185     {
186         return types::ErrorType::UndefinedError;
187     }
188 
189     return *l_ptrToErrType;
190 }
191 
192 /**
193  * @brief API to get Error msg.
194  *
195  * @param[in] i_exception - Exception object.
196  *
197  * @return Error msg set for the specific exception. Default error msg
198  * otherwise.
199  */
getErrorMsg(const std::exception & i_exception)200 inline std::string getErrorMsg(const std::exception& i_exception)
201 {
202     const auto& l_exceptionDataMap = getExceptionData(i_exception);
203 
204     auto l_itrToErrMsg = l_exceptionDataMap.find("ErrorMsg");
205     if (l_itrToErrMsg == l_exceptionDataMap.end())
206     {
207         return i_exception.what();
208     }
209 
210     auto l_ptrToErrMsg = std::get_if<std::string>(&l_itrToErrMsg->second);
211     if (!l_ptrToErrMsg)
212     {
213         return i_exception.what();
214     }
215 
216     return *l_ptrToErrMsg;
217 }
218 
219 /**
220  * @brief API to get string representation of a Error type enum.
221  *
222  * @param[in] i_exception - Exception object.
223  *
224  * @return Error msg set for the specific error type. Default error msg
225  * otherwise.
226  */
getErrorTypeString(const types::ErrorType & i_errorType)227 inline std::string getErrorTypeString(
228     const types::ErrorType& i_errorType) noexcept
229 {
230     const auto l_entry = errorMsgMap.find(i_errorType);
231     return (l_entry != errorMsgMap.end()
232                 ? l_entry->second
233                 : errorMsgMap.at(types::ErrorType::UndefinedError));
234 }
235 
236 /**
237  * @brief An API to create a PEL with inventory path callout.
238  *
239  * This API calls an async method to create PEL, and also handles inventory
240  * path callout.
241  *
242  * Note: If inventory path callout info is not provided, it will create a
243  * PEL without any callout. Currently only one callout is handled in this
244  * API.
245  *
246  * @todo: Symbolic FRU and procedure callout needs to be handled in this
247  * API.
248  *
249  * @param[in] i_errorType - Enum to map with event message name.
250  * @param[in] i_severity - Severity of the event.
251  * @param[in] i_callouts - Callout information, list of tuple having
252  * inventory path and priority as input [optional].
253  * @param[in] i_fileName - File name.
254  * @param[in] i_funcName - Function name.
255  * @param[in] i_internalRc - Internal return code.
256  * @param[in] i_description - Error description.
257  * @param[in] i_userData1 - Additional user data [optional].
258  * @param[in] i_userData2 - Additional user data [optional].
259  * @param[in] i_symFru - Symblolic FRU callout data [optional].
260  * @param[in] i_procedure - Procedure callout data [optional].
261  *
262  * @throw exception in case of error.
263  */
createAsyncPelWithInventoryCallout(const types::ErrorType & i_errorType,const types::SeverityType & i_severity,const std::vector<types::InventoryCalloutData> & i_callouts,const std::string & i_fileName,const std::string & i_funcName,const uint8_t i_internalRc,const std::string & i_description,const std::optional<std::string> i_userData1,const std::optional<std::string> i_userData2,const std::optional<std::string> i_symFru,const std::optional<std::string> i_procedure)264 inline void createAsyncPelWithInventoryCallout(
265     const types::ErrorType& i_errorType, const types::SeverityType& i_severity,
266     const std::vector<types::InventoryCalloutData>& i_callouts,
267     const std::string& i_fileName, const std::string& i_funcName,
268     const uint8_t i_internalRc, const std::string& i_description,
269     const std::optional<std::string> i_userData1,
270     const std::optional<std::string> i_userData2,
271     const std::optional<std::string> i_symFru,
272     const std::optional<std::string> i_procedure)
273 {
274     (void)i_symFru;
275     (void)i_procedure;
276 
277     try
278     {
279         if (i_callouts.empty())
280         {
281             logging::logMessage("Callout information is missing to create PEL");
282             // TODO: Revisit this instead of simpley returning.
283             return;
284         }
285 
286         if (errorMsgMap.find(i_errorType) == errorMsgMap.end())
287         {
288             throw std::runtime_error(
289                 "Error type not found in the error message map to create PEL");
290             // TODO: Need to handle, instead of throwing exception. Create
291             // default message in message_registry.json.
292         }
293 
294         const std::string& l_message = errorMsgMap.at(i_errorType);
295 
296         const std::string& l_severity =
297             (severityMap.find(i_severity) != severityMap.end()
298                  ? severityMap.at(i_severity)
299                  : severityMap.at(types::SeverityType::Informational));
300 
301         std::string l_description =
302             (!i_description.empty() ? i_description : "VPD generic error");
303 
304         std::string l_userData1 = (i_userData1) ? (*i_userData1) : "";
305 
306         std::string l_userData2 = (i_userData2) ? (*i_userData2) : "";
307 
308         const types::InventoryCalloutData& l_invCallout = i_callouts[0];
309         // TODO: Need to handle multiple inventory path callout's, when multiple
310         // callout's is supported by "Logging" service.
311 
312         const types::CalloutPriority& l_priorityEnum = get<1>(l_invCallout);
313 
314         const std::string& l_priority =
315             (priorityMap.find(l_priorityEnum) != priorityMap.end()
316                  ? priorityMap.at(l_priorityEnum)
317                  : priorityMap.at(types::CalloutPriority::Low));
318 
319         sd_bus* l_sdBus = nullptr;
320         sd_bus_default(&l_sdBus);
321 
322         const uint8_t l_additionalDataCount = 8;
323         auto l_rc = sd_bus_call_method_async(
324             l_sdBus, NULL, constants::eventLoggingServiceName,
325             constants::eventLoggingObjectPath, constants::eventLoggingInterface,
326             "Create", NULL, NULL, "ssa{ss}", l_message.c_str(),
327             l_severity.c_str(), l_additionalDataCount, "FileName",
328             i_fileName.c_str(), "FunctionName", i_funcName.c_str(),
329             "InternalRc", std::to_string(i_internalRc).c_str(), "DESCRIPTION",
330             l_description.c_str(), "UserData1", l_userData1.c_str(),
331             "UserData2", l_userData2.c_str(), "CALLOUT_INVENTORY_PATH",
332             get<0>(l_invCallout).c_str(), "CALLOUT_PRIORITY",
333             l_priority.c_str());
334 
335         if (l_rc < 0)
336         {
337             logging::logMessage(
338                 "Error calling sd_bus_call_method_async, Message = " +
339                 std::string(strerror(-l_rc)));
340         }
341     }
342     catch (const std::exception& l_ex)
343     {
344         logging::logMessage(
345             "Create PEL failed with error: " + std::string(l_ex.what()));
346     }
347 }
348 
349 /**
350  * @brief An API to create a PEL with device path callout.
351  *
352  * @param[in] i_errorType - Enum to map with event message name.
353  * @param[in] i_severity - Severity of the event.
354  * @param[in] i_callouts - Callout information, list of tuple having device
355  * path and error number as input.
356  * @param[in] i_fileName - File name.
357  * @param[in] i_funcName - Function name.
358  * @param[in] i_internalRc - Internal return code.
359  * @param[in] i_userData1 - Additional user data [optional].
360  * @param[in] i_userData2 - Additional user data [optional].
361  */
362 inline void createAsyncPelWithI2cDeviceCallout(
363     const types::ErrorType i_errorType, const types::SeverityType i_severity,
364     const std::vector<types::DeviceCalloutData>& i_callouts,
365     const std::string& i_fileName, const std::string& i_funcName,
366     const uint8_t i_internalRc,
367     const std::optional<std::pair<std::string, std::string>> i_userData1,
368     const std::optional<std::pair<std::string, std::string>> i_userData2);
369 
370 /**
371  * @brief An API to create a PEL with I2c bus callout.
372  *
373  * @param[in] i_errorType - Enum to map with event message name.
374  * @param[in] i_severity - Severity of the event.
375  * @param[in] i_callouts - Callout information, list of tuple having i2c
376  * bus, i2c address and error number as input.
377  * @param[in] i_fileName - File name.
378  * @param[in] i_funcName - Function name.
379  * @param[in] i_internalRc - Internal return code.
380  * @param[in] i_userData1 - Additional user data [optional].
381  * @param[in] i_userData2 - Additional user data [optional].
382  */
383 inline void createAsyncPelWithI2cBusCallout(
384     const types::ErrorType i_errorType, const types::SeverityType i_severity,
385     const std::vector<types::I2cBusCalloutData>& i_callouts,
386     const std::string& i_fileName, const std::string& i_funcName,
387     const uint8_t i_internalRc,
388     const std::optional<std::pair<std::string, std::string>> i_userData1,
389     const std::optional<std::pair<std::string, std::string>> i_userData2);
390 
391 /**
392  * @brief An API to create a PEL.
393  *
394  * @param[in] i_errorType - Enum to map with event message name.
395  * @param[in] i_severity - Severity of the event.
396  * @param[in] i_fileName - File name.
397  * @param[in] i_funcName - Function name.
398  * @param[in] i_internalRc - Internal return code.
399  * @param[in] i_description - Error description.
400  * @param[in] i_userData1 - Additional user data [optional].
401  * @param[in] i_userData2 - Additional user data [optional].
402  * @param[in] i_symFru - Symblolic FRU callout data [optional].
403  * @param[in] i_procedure - Procedure callout data [optional].
404  *
405  * @todo: Symbolic FRU and procedure callout needs to be handled in this
406  * API.
407  */
createAsyncPel(const types::ErrorType & i_errorType,const types::SeverityType & i_severity,const std::string & i_fileName,const std::string & i_funcName,const uint8_t i_internalRc,const std::string & i_description,const std::optional<std::string> i_userData1,const std::optional<std::string> i_userData2,const std::optional<std::string> i_symFru,const std::optional<std::string> i_procedure)408 inline void createAsyncPel(
409     const types::ErrorType& i_errorType, const types::SeverityType& i_severity,
410     const std::string& i_fileName, const std::string& i_funcName,
411     const uint8_t i_internalRc, const std::string& i_description,
412     const std::optional<std::string> i_userData1,
413     const std::optional<std::string> i_userData2,
414     const std::optional<std::string> i_symFru,
415     const std::optional<std::string> i_procedure)
416 {
417     (void)i_symFru;
418     (void)i_procedure;
419     try
420     {
421         if (errorMsgMap.find(i_errorType) == errorMsgMap.end())
422         {
423             throw std::runtime_error("Unsupported error type received");
424             // TODO: Need to handle, instead of throwing an exception.
425         }
426 
427         const std::string& l_message = errorMsgMap.at(i_errorType);
428 
429         const std::string& l_severity =
430             (severityMap.find(i_severity) != severityMap.end()
431                  ? severityMap.at(i_severity)
432                  : severityMap.at(types::SeverityType::Informational));
433 
434         const std::string l_description =
435             ((!i_description.empty() ? i_description : "VPD generic error"));
436 
437         const std::string l_userData1 = ((i_userData1) ? (*i_userData1) : "");
438 
439         const std::string l_userData2 = ((i_userData2) ? (*i_userData2) : "");
440 
441         sd_bus* l_sdBus = nullptr;
442         sd_bus_default(&l_sdBus);
443 
444         // VALUE_6 represents the additional data pair count passing to create
445         // PEL. If there any change in additional data, we need to pass the
446         // correct number.
447         auto l_rc = sd_bus_call_method_async(
448             l_sdBus, NULL, constants::eventLoggingServiceName,
449             constants::eventLoggingObjectPath, constants::eventLoggingInterface,
450             "Create", NULL, NULL, "ssa{ss}", l_message.c_str(),
451             l_severity.c_str(), constants::VALUE_6, "FileName",
452             i_fileName.c_str(), "FunctionName", i_funcName.c_str(),
453             "InternalRc", std::to_string(i_internalRc).c_str(), "DESCRIPTION",
454             l_description.c_str(), "UserData1", l_userData1.c_str(),
455             "UserData2", l_userData2.c_str());
456 
457         if (l_rc < 0)
458         {
459             logging::logMessage(
460                 "Error calling sd_bus_call_method_async, Message = " +
461                 std::string(strerror(-l_rc)));
462         }
463     }
464     catch (const sdbusplus::exception::SdBusError& l_ex)
465     {
466         logging::logMessage("Async PEL creation failed with an error: " +
467                             std::string(l_ex.what()));
468     }
469 }
470 
471 /**
472  * @brief An API to create PEL.
473  *
474  * This API makes synchronous call to phosphor-logging Create method.
475  *
476  * @param[in] i_errorType - Enum to map with event message name.
477  * @param[in] i_severity - Severity of the event.
478  * @param[in] i_fileName - File name.
479  * @param[in] i_funcName - Function name.
480  * @param[in] i_internalRc - Internal return code.
481  * @param[in] i_description - Error description.
482  * @param[in] i_userData1 - Additional user data [optional].
483  * @param[in] i_userData2 - Additional user data [optional].
484  * @param[in] i_symFru - Symblolic FRU callout data [optional].s
485  * @param[in] i_procedure - Procedure callout data [optional].
486  *
487  * @todo: Symbolic FRU and procedure callout needs to be handled in this
488  * API.
489  */
createSyncPel(const types::ErrorType & i_errorType,const types::SeverityType & i_severity,const std::string & i_fileName,const std::string & i_funcName,const uint8_t i_internalRc,const std::string & i_description,const std::optional<std::string> i_userData1,const std::optional<std::string> i_userData2,const std::optional<std::string> i_symFru,const std::optional<std::string> i_procedure)490 inline void createSyncPel(
491     const types::ErrorType& i_errorType, const types::SeverityType& i_severity,
492     const std::string& i_fileName, const std::string& i_funcName,
493     const uint8_t i_internalRc, const std::string& i_description,
494     const std::optional<std::string> i_userData1,
495     const std::optional<std::string> i_userData2,
496     const std::optional<std::string> i_symFru,
497     const std::optional<std::string> i_procedure)
498 {
499     (void)i_symFru;
500     (void)i_procedure;
501     try
502     {
503         if (errorMsgMap.find(i_errorType) == errorMsgMap.end())
504         {
505             throw std::runtime_error("Unsupported error type received");
506             // TODO: Need to handle, instead of throwing an exception.
507         }
508 
509         const std::string& l_message = errorMsgMap.at(i_errorType);
510 
511         const std::string& l_severity =
512             (severityMap.find(i_severity) != severityMap.end()
513                  ? severityMap.at(i_severity)
514                  : severityMap.at(types::SeverityType::Informational));
515 
516         const std::string l_description =
517             ((!i_description.empty() ? i_description : "VPD generic error"));
518 
519         const std::string l_userData1 = ((i_userData1) ? (*i_userData1) : "");
520 
521         const std::string l_userData2 = ((i_userData2) ? (*i_userData2) : "");
522 
523         std::map<std::string, std::string> l_additionalData{
524             {"FileName", i_fileName},
525             {"FunctionName", i_funcName},
526             {"DESCRIPTION", l_description},
527             {"InteranlRc", std::to_string(i_internalRc)},
528             {"UserData1", l_userData1.c_str()},
529             {"UserData2", l_userData2.c_str()}};
530 
531         auto l_bus = sdbusplus::bus::new_default();
532         auto l_method =
533             l_bus.new_method_call(constants::eventLoggingServiceName,
534                                   constants::eventLoggingObjectPath,
535                                   constants::eventLoggingInterface, "Create");
536         l_method.append(l_message, l_severity, l_additionalData);
537         l_bus.call(l_method);
538     }
539     catch (const sdbusplus::exception::SdBusError& l_ex)
540     {
541         logging::logMessage("Sync PEL creation failed with an error: " +
542                             std::string(l_ex.what()));
543     }
544 }
545 
546 /**
547  * @brief An API to create a synchronus PEL with inventory path callout.
548  *
549  * This API calls phosphor-logging method to create PEL, and also handles
550  * inventory path callout. In case called with EEPROM path, will look for
551  * JSON at symbolic link and if present will fetch inventory path for that
552  * EEPROM.
553  *
554  * Note: In case of any error in fetching JSON or converting the EEPROM
555  * path, the API will log PEL with path passed in callout parameter.
556  * If inventory/EEPROM path is not provided in the callout, it will create
557  * PEL without call out. Currently only one callout is handled in this API.
558  *
559  * @todo: Symbolic FRU and procedure callout needs to be handled in this
560  * API.
561  *
562  * @param[in] i_errorType - Enum to map with event message name.
563  * @param[in] i_severity - Severity of the event.
564  * @param[in] i_fileName - File name.
565  * @param[in] i_funcName - Function name.
566  * @param[in] i_internalRc - Internal return code.
567  * @param[in] i_description - Error description.
568  * @param[in] i_callouts - Callout information.
569  * @param[in] i_userData1 - Additional user data [optional].
570  * @param[in] i_userData2 - Additional user data [optional].
571  * @param[in] i_symFru - Symblolic FRU callout data [optional].
572  * @param[in] i_procedure - Procedure callout data [optional].
573  *
574  */
createSyncPelWithInvCallOut(const types::ErrorType & i_errorType,const types::SeverityType & i_severity,const std::string & i_fileName,const std::string & i_funcName,const uint8_t i_internalRc,const std::string & i_description,const std::vector<types::InventoryCalloutData> & i_callouts,const std::optional<std::string> i_userData1,const std::optional<std::string> i_userData2,const std::optional<std::string> i_symFru,const std::optional<std::string> i_procedure)575 inline void createSyncPelWithInvCallOut(
576     const types::ErrorType& i_errorType, const types::SeverityType& i_severity,
577     const std::string& i_fileName, const std::string& i_funcName,
578     const uint8_t i_internalRc, const std::string& i_description,
579     const std::vector<types::InventoryCalloutData>& i_callouts,
580     const std::optional<std::string> i_userData1,
581     const std::optional<std::string> i_userData2,
582     [[maybe_unused]] const std::optional<std::string> i_symFru,
583     [[maybe_unused]] const std::optional<std::string> i_procedure)
584 {
585     try
586     {
587         if (i_callouts.empty())
588         {
589             createSyncPel(i_errorType, i_severity, i_fileName, i_funcName,
590                           i_internalRc, i_description, i_userData1, i_userData2,
591                           i_symFru, i_procedure);
592             logging::logMessage(
593                 "Callout list is empty, creating PEL without call out");
594             return;
595         }
596 
597         if (errorMsgMap.find(i_errorType) == errorMsgMap.end())
598         {
599             throw std::runtime_error("Unsupported error type received");
600         }
601 
602         // Path to hold callout inventory path.
603         std::string l_calloutInvPath;
604 
605         uint16_t l_errCode = 0;
606 
607         // check if callout path is a valid inventory path. if not, get the JSON
608         // object to get inventory path.
609         if (std::get<0>(i_callouts[0])
610                 .compare(constants::VALUE_0, strlen(constants::pimPath),
611                          constants::pimPath) != constants::STR_CMP_SUCCESS)
612         {
613             std::error_code l_ec;
614             // implies json dependent execution.
615             if (std::filesystem::exists(INVENTORY_JSON_SYM_LINK, l_ec))
616             {
617                 if (!l_ec)
618                 {
619                     nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
620                         INVENTORY_JSON_SYM_LINK, l_errCode);
621 
622                     if (l_errCode)
623                     {
624                         logging::logMessage(
625                             "Failed to parse JSON file [ " +
626                             std::string(INVENTORY_JSON_SYM_LINK) +
627                             " ], error : " +
628                             commonUtility::getErrCodeMsg(l_errCode));
629                     }
630 
631                     l_calloutInvPath = jsonUtility::getInventoryObjPathFromJson(
632                         l_parsedJson, std::get<0>(i_callouts[0]), l_errCode);
633                 }
634                 else
635                 {
636                     logging::logMessage(
637                         "Error finding symlink. Continue with given path");
638                 }
639             }
640         }
641 
642         if (l_calloutInvPath.empty())
643         {
644             l_calloutInvPath = std::get<0>(i_callouts[0]);
645 
646             if (l_errCode)
647             {
648                 logging::logMessage(
649                     "Failed to get inventory object path from JSON for FRU [" +
650                     std::get<0>(i_callouts[0]) +
651                     "], error : " + commonUtility::getErrCodeMsg(l_errCode));
652             }
653         }
654 
655         const std::map<std::string, std::string> l_additionalData{
656             {"FileName", i_fileName},
657             {"FunctionName", i_funcName},
658             {"DESCRIPTION",
659              (!i_description.empty() ? i_description : "VPD generic error")},
660             {"CALLOUT_INVENTORY_PATH", l_calloutInvPath},
661             {"InteranlRc", std::to_string(i_internalRc)},
662             {"UserData1", ((i_userData1) ? (*i_userData1) : "").c_str()},
663             {"UserData2", ((i_userData2) ? (*i_userData2) : "").c_str()}};
664 
665         const std::string& l_severity =
666             (severityMap.find(i_severity) != severityMap.end()
667                  ? severityMap.at(i_severity)
668                  : severityMap.at(types::SeverityType::Informational));
669 
670         auto l_bus = sdbusplus::bus::new_default();
671         auto l_method =
672             l_bus.new_method_call(constants::eventLoggingServiceName,
673                                   constants::eventLoggingObjectPath,
674                                   constants::eventLoggingInterface, "Create");
675         l_method.append(errorMsgMap.at(i_errorType), l_severity,
676                         l_additionalData);
677         l_bus.call(l_method);
678     }
679     catch (const std::exception& l_ex)
680     {
681         logging::logMessage(
682             "Sync PEL creation with inventory path failed with error: " +
683             std::string(l_ex.what()));
684     }
685 }
686 } // namespace EventLogger
687 } // namespace vpd
688