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