blob: 6b91dc893af0e711b95a9fb63556ce87d867cbdf [file] [log] [blame]
Sunny Srivastava6046c372025-06-06 12:13:19 +05301#include "config.h"
2
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05003#include "event_logger.hpp"
4
Anupama B Rb53d97c2025-02-24 03:37:34 -06005#include "exceptions.hpp"
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05006#include "logger.hpp"
7
8#include <systemd/sd-bus.h>
9
Sunny Srivastava6046c372025-06-06 12:13:19 +053010#include <utility/json_utility.hpp>
11
12#include <filesystem>
13
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050014namespace vpd
15{
16const std::unordered_map<types::SeverityType, std::string>
17 EventLogger::m_severityMap = {
18 {types::SeverityType::Notice,
19 "xyz.openbmc_project.Logging.Entry.Level.Notice"},
20 {types::SeverityType::Informational,
21 "xyz.openbmc_project.Logging.Entry.Level.Informational"},
22 {types::SeverityType::Debug,
23 "xyz.openbmc_project.Logging.Entry.Level.Debug"},
24 {types::SeverityType::Warning,
25 "xyz.openbmc_project.Logging.Entry.Level.Warning"},
26 {types::SeverityType::Critical,
27 "xyz.openbmc_project.Logging.Entry.Level.Critical"},
28 {types::SeverityType::Emergency,
29 "xyz.openbmc_project.Logging.Entry.Level.Emergency"},
30 {types::SeverityType::Alert,
31 "xyz.openbmc_project.Logging.Entry.Level.Alert"},
32 {types::SeverityType::Error,
33 "xyz.openbmc_project.Logging.Entry.Level.Error"}};
34
35const std::unordered_map<types::ErrorType, std::string>
36 EventLogger::m_errorMsgMap = {
37 {types::ErrorType::DefaultValue, "com.ibm.VPD.Error.DefaultValue"},
Sunny Srivastavac09e2102025-04-23 10:47:06 +053038 {types::ErrorType::UndefinedError, "com.ibm.VPD.Error.UndefinedError"},
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050039 {types::ErrorType::InvalidVpdMessage, "com.ibm.VPD.Error.InvalidVPD"},
40 {types::ErrorType::VpdMismatch, "com.ibm.VPD.Error.Mismatch"},
41 {types::ErrorType::InvalidEeprom,
42 "com.ibm.VPD.Error.InvalidEepromPath"},
43 {types::ErrorType::EccCheckFailed, "com.ibm.VPD.Error.EccCheckFailed"},
44 {types::ErrorType::JsonFailure, "com.ibm.VPD.Error.InvalidJson"},
45 {types::ErrorType::DbusFailure, "com.ibm.VPD.Error.DbusFailure"},
46 {types::ErrorType::InvalidSystem,
47 "com.ibm.VPD.Error.UnknownSystemType"},
48 {types::ErrorType::EssentialFru,
49 "com.ibm.VPD.Error.RequiredFRUMissing"},
Sunny Srivastavaa88a2982025-01-23 12:03:21 +053050 {types::ErrorType::GpioError, "com.ibm.VPD.Error.GPIOError"},
51 {types::ErrorType::InternalFailure,
52 "xyz.openbmc_project.Common.Error.InternalFailure"},
Rekha Aparnaffdff312025-03-25 01:10:56 -050053 {types::ErrorType::FruMissing, "com.ibm.VPD.Error.RequiredFRUMissing"},
54 {types::ErrorType::SystemTypeMismatch,
55 "com.ibm.VPD.Error.SystemTypeMismatch"},
56 {types::ErrorType::UnknownSystemSettings,
Sunny Srivastava4fa796c2025-04-01 10:27:02 +053057 "com.ibm.VPD.Error.UnknownSystemSettings"},
58 {types::ErrorType::FirmwareError, "com.ibm.VPD.Error.FirmwareError"}};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050059
60const std::unordered_map<types::CalloutPriority, std::string>
61 EventLogger::m_priorityMap = {
62 {types::CalloutPriority::High, "H"},
63 {types::CalloutPriority::Medium, "M"},
64 {types::CalloutPriority::MediumGroupA, "A"},
65 {types::CalloutPriority::MediumGroupB, "B"},
66 {types::CalloutPriority::MediumGroupC, "C"},
67 {types::CalloutPriority::Low, "L"}};
68
69void EventLogger::createAsyncPelWithInventoryCallout(
70 const types::ErrorType& i_errorType, const types::SeverityType& i_severity,
71 const std::vector<types::InventoryCalloutData>& i_callouts,
72 const std::string& i_fileName, const std::string& i_funcName,
73 const uint8_t i_internalRc, const std::string& i_description,
74 const std::optional<std::string> i_userData1,
75 const std::optional<std::string> i_userData2,
76 const std::optional<std::string> i_symFru,
77 const std::optional<std::string> i_procedure)
78{
79 (void)i_symFru;
80 (void)i_procedure;
81
82 try
83 {
84 if (i_callouts.empty())
85 {
86 logging::logMessage("Callout information is missing to create PEL");
87 // TODO: Revisit this instead of simpley returning.
88 return;
89 }
90
91 if (m_errorMsgMap.find(i_errorType) == m_errorMsgMap.end())
92 {
93 throw std::runtime_error(
94 "Error type not found in the error message map to create PEL");
95 // TODO: Need to handle, instead of throwing exception. Create
96 // default message in message_registry.json.
97 }
98
99 const std::string& l_message = m_errorMsgMap.at(i_errorType);
100
101 const std::string& l_severity =
102 (m_severityMap.find(i_severity) != m_severityMap.end()
103 ? m_severityMap.at(i_severity)
104 : m_severityMap.at(types::SeverityType::Informational));
105
106 std::string l_description =
107 (!i_description.empty() ? i_description : "VPD generic error");
108
109 std::string l_userData1 = (i_userData1) ? (*i_userData1) : "";
110
111 std::string l_userData2 = (i_userData2) ? (*i_userData2) : "";
112
113 const types::InventoryCalloutData& l_invCallout = i_callouts[0];
114 // TODO: Need to handle multiple inventory path callout's, when multiple
115 // callout's is supported by "Logging" service.
116
117 const types::CalloutPriority& l_priorityEnum = get<1>(l_invCallout);
118
119 const std::string& l_priority =
120 (m_priorityMap.find(l_priorityEnum) != m_priorityMap.end()
121 ? m_priorityMap.at(l_priorityEnum)
122 : m_priorityMap.at(types::CalloutPriority::Low));
123
124 sd_bus* l_sdBus = nullptr;
125 sd_bus_default(&l_sdBus);
126
127 const uint8_t l_additionalDataCount = 8;
128 auto l_rc = sd_bus_call_method_async(
129 l_sdBus, NULL, constants::eventLoggingServiceName,
130 constants::eventLoggingObjectPath, constants::eventLoggingInterface,
131 "Create", NULL, NULL, "ssa{ss}", l_message.c_str(),
132 l_severity.c_str(), l_additionalDataCount, "FileName",
133 i_fileName.c_str(), "FunctionName", i_funcName.c_str(),
134 "InternalRc", std::to_string(i_internalRc).c_str(), "DESCRIPTION",
135 l_description.c_str(), "UserData1", l_userData1.c_str(),
136 "UserData2", l_userData2.c_str(), "CALLOUT_INVENTORY_PATH",
137 get<0>(l_invCallout).c_str(), "CALLOUT_PRIORITY",
138 l_priority.c_str());
139
140 if (l_rc < 0)
141 {
142 logging::logMessage(
143 "Error calling sd_bus_call_method_async, Message = " +
144 std::string(strerror(-l_rc)));
145 }
146 }
147 catch (const std::exception& l_ex)
148 {
149 logging::logMessage(
150 "Create PEL failed with error: " + std::string(l_ex.what()));
151 }
152}
153
154void EventLogger::createAsyncPelWithI2cDeviceCallout(
155 const types::ErrorType i_errorType, const types::SeverityType i_severity,
156 const std::vector<types::DeviceCalloutData>& i_callouts,
157 const std::string& i_fileName, const std::string& i_funcName,
158 const uint8_t i_internalRc,
159 const std::optional<std::pair<std::string, std::string>> i_userData1,
160 const std::optional<std::pair<std::string, std::string>> i_userData2)
161{
162 // TODO, implementation needs to be added.
163 (void)i_errorType;
164 (void)i_severity;
165 (void)i_callouts;
166 (void)i_fileName;
167 (void)i_funcName;
168 (void)i_internalRc;
169 (void)i_userData1;
170 (void)i_userData2;
171}
172
173void EventLogger::createAsyncPelWithI2cBusCallout(
174 const types::ErrorType i_errorType, const types::SeverityType i_severity,
175 const std::vector<types::I2cBusCalloutData>& i_callouts,
176 const std::string& i_fileName, const std::string& i_funcName,
177 const uint8_t i_internalRc,
178 const std::optional<std::pair<std::string, std::string>> i_userData1,
179 const std::optional<std::pair<std::string, std::string>> i_userData2)
180{
181 // TODO, implementation needs to be added.
182 (void)i_errorType;
183 (void)i_severity;
184 (void)i_callouts;
185 (void)i_fileName;
186 (void)i_funcName;
187 (void)i_internalRc;
188 (void)i_userData1;
189 (void)i_userData2;
190}
191
192void EventLogger::createAsyncPel(
193 const types::ErrorType& i_errorType, const types::SeverityType& i_severity,
194 const std::string& i_fileName, const std::string& i_funcName,
195 const uint8_t i_internalRc, const std::string& i_description,
196 const std::optional<std::string> i_userData1,
197 const std::optional<std::string> i_userData2,
198 const std::optional<std::string> i_symFru,
199 const std::optional<std::string> i_procedure)
200{
201 (void)i_symFru;
202 (void)i_procedure;
203 try
204 {
205 if (m_errorMsgMap.find(i_errorType) == m_errorMsgMap.end())
206 {
207 throw std::runtime_error("Unsupported error type received");
208 // TODO: Need to handle, instead of throwing an exception.
209 }
210
211 const std::string& l_message = m_errorMsgMap.at(i_errorType);
212
213 const std::string& l_severity =
214 (m_severityMap.find(i_severity) != m_severityMap.end()
215 ? m_severityMap.at(i_severity)
216 : m_severityMap.at(types::SeverityType::Informational));
217
218 const std::string l_description =
219 ((!i_description.empty() ? i_description : "VPD generic error"));
220
221 const std::string l_userData1 = ((i_userData1) ? (*i_userData1) : "");
222
223 const std::string l_userData2 = ((i_userData2) ? (*i_userData2) : "");
224
225 sd_bus* l_sdBus = nullptr;
226 sd_bus_default(&l_sdBus);
227
228 // VALUE_6 represents the additional data pair count passing to create
229 // PEL. If there any change in additional data, we need to pass the
230 // correct number.
231 auto l_rc = sd_bus_call_method_async(
232 l_sdBus, NULL, constants::eventLoggingServiceName,
233 constants::eventLoggingObjectPath, constants::eventLoggingInterface,
234 "Create", NULL, NULL, "ssa{ss}", l_message.c_str(),
235 l_severity.c_str(), constants::VALUE_6, "FileName",
236 i_fileName.c_str(), "FunctionName", i_funcName.c_str(),
237 "InternalRc", std::to_string(i_internalRc).c_str(), "DESCRIPTION",
238 l_description.c_str(), "UserData1", l_userData1.c_str(),
239 "UserData2", l_userData2.c_str());
240
241 if (l_rc < 0)
242 {
243 logging::logMessage(
244 "Error calling sd_bus_call_method_async, Message = " +
245 std::string(strerror(-l_rc)));
246 }
247 }
248 catch (const sdbusplus::exception::SdBusError& l_ex)
249 {
250 logging::logMessage("Async PEL creation failed with an error: " +
251 std::string(l_ex.what()));
252 }
253}
254
255void EventLogger::createSyncPel(
256 const types::ErrorType& i_errorType, const types::SeverityType& i_severity,
257 const std::string& i_fileName, const std::string& i_funcName,
258 const uint8_t i_internalRc, const std::string& i_description,
259 const std::optional<std::string> i_userData1,
260 const std::optional<std::string> i_userData2,
261 const std::optional<std::string> i_symFru,
262 const std::optional<std::string> i_procedure)
263{
264 (void)i_symFru;
265 (void)i_procedure;
266 try
267 {
268 if (m_errorMsgMap.find(i_errorType) == m_errorMsgMap.end())
269 {
270 throw std::runtime_error("Unsupported error type received");
271 // TODO: Need to handle, instead of throwing an exception.
272 }
273
274 const std::string& l_message = m_errorMsgMap.at(i_errorType);
275
276 const std::string& l_severity =
277 (m_severityMap.find(i_severity) != m_severityMap.end()
278 ? m_severityMap.at(i_severity)
279 : m_severityMap.at(types::SeverityType::Informational));
280
281 const std::string l_description =
282 ((!i_description.empty() ? i_description : "VPD generic error"));
283
284 const std::string l_userData1 = ((i_userData1) ? (*i_userData1) : "");
285
286 const std::string l_userData2 = ((i_userData2) ? (*i_userData2) : "");
287
288 std::map<std::string, std::string> l_additionalData{
289 {"FileName", i_fileName},
290 {"FunctionName", i_funcName},
291 {"DESCRIPTION", l_description},
292 {"InteranlRc", std::to_string(i_internalRc)},
293 {"UserData1", l_userData1.c_str()},
294 {"UserData2", l_userData2.c_str()}};
295
296 auto l_bus = sdbusplus::bus::new_default();
297 auto l_method =
298 l_bus.new_method_call(constants::eventLoggingServiceName,
299 constants::eventLoggingObjectPath,
300 constants::eventLoggingInterface, "Create");
301 l_method.append(l_message, l_severity, l_additionalData);
302 l_bus.call(l_method);
303 }
304 catch (const sdbusplus::exception::SdBusError& l_ex)
305 {
306 logging::logMessage("Sync PEL creation failed with an error: " +
307 std::string(l_ex.what()));
308 }
309}
Anupama B Rb53d97c2025-02-24 03:37:34 -0600310
Sunny Srivastava6046c372025-06-06 12:13:19 +0530311void EventLogger::createSyncPelWithInvCallOut(
312 const types::ErrorType& i_errorType, const types::SeverityType& i_severity,
313 const std::string& i_fileName, const std::string& i_funcName,
314 const uint8_t i_internalRc, const std::string& i_description,
315 const std::vector<types::InventoryCalloutData>& i_callouts,
316 const std::optional<std::string> i_userData1,
317 const std::optional<std::string> i_userData2,
318 [[maybe_unused]] const std::optional<std::string> i_symFru,
319 [[maybe_unused]] const std::optional<std::string> i_procedure)
320{
321 try
322 {
323 if (i_callouts.empty())
324 {
325 createSyncPel(i_errorType, i_severity, i_fileName, i_funcName,
326 i_internalRc, i_description, i_userData1, i_userData2,
327 i_symFru, i_procedure);
328 logging::logMessage(
329 "Callout list is empty, creating PEL without call out");
330 return;
331 }
332
333 if (m_errorMsgMap.find(i_errorType) == m_errorMsgMap.end())
334 {
335 throw std::runtime_error("Unsupported error type received");
336 }
337
338 // Path to hold callout inventory path.
339 std::string l_calloutInvPath;
340
341 // check if callout path is a valid inventory path. if not, get the JSON
342 // object to get inventory path.
343 if (std::get<0>(i_callouts[0])
344 .compare(constants::VALUE_0, strlen(constants::pimPath),
345 constants::pimPath) != constants::STR_CMP_SUCCESS)
346 {
347 std::error_code l_ec;
348 // implies json dependent execution.
349 if (std::filesystem::exists(INVENTORY_JSON_SYM_LINK, l_ec))
350 {
351 if (!l_ec)
352 {
353 l_calloutInvPath = jsonUtility::getInventoryObjPathFromJson(
354 jsonUtility::getParsedJson(INVENTORY_JSON_SYM_LINK),
355 std::get<0>(i_callouts[0]));
356 }
357 else
358 {
359 logging::logMessage(
360 "Error finding symlink. Continue with given path");
361 }
362 }
363 }
364
365 if (l_calloutInvPath.empty())
366 {
367 l_calloutInvPath = std::get<0>(i_callouts[0]);
368 }
369
370 const std::map<std::string, std::string> l_additionalData{
371 {"FileName", i_fileName},
372 {"FunctionName", i_funcName},
373 {"DESCRIPTION",
374 (!i_description.empty() ? i_description : "VPD generic error")},
375 {"CALLOUT_INVENTORY_PATH", l_calloutInvPath},
376 {"InteranlRc", std::to_string(i_internalRc)},
377 {"UserData1", ((i_userData1) ? (*i_userData1) : "").c_str()},
378 {"UserData2", ((i_userData2) ? (*i_userData2) : "").c_str()}};
379
380 const std::string& l_severity =
381 (m_severityMap.find(i_severity) != m_severityMap.end()
382 ? m_severityMap.at(i_severity)
383 : m_severityMap.at(types::SeverityType::Informational));
384
385 auto l_bus = sdbusplus::bus::new_default();
386 auto l_method =
387 l_bus.new_method_call(constants::eventLoggingServiceName,
388 constants::eventLoggingObjectPath,
389 constants::eventLoggingInterface, "Create");
390 l_method.append(m_errorMsgMap.at(i_errorType), l_severity,
391 l_additionalData);
392 l_bus.call(l_method);
393 }
394 catch (const std::exception& l_ex)
395 {
396 logging::logMessage(
397 "Sync PEL creation with inventory path failed with error: " +
398 std::string(l_ex.what()));
399 }
400}
401
Anupama B Rb53d97c2025-02-24 03:37:34 -0600402types::ExceptionDataMap EventLogger::getExceptionData(
403 const std::exception& i_exception)
404{
405 types::ExceptionDataMap l_errorInfo{
Sunny Srivastavac09e2102025-04-23 10:47:06 +0530406 {"ErrorType", types::ErrorType::UndefinedError},
Anupama B Rb53d97c2025-02-24 03:37:34 -0600407 {"ErrorMsg", i_exception.what()}};
408
409 try
410 {
411 if (typeid(i_exception) == typeid(DataException))
412 {
413 const DataException& l_ex =
414 dynamic_cast<const DataException&>(i_exception);
415 l_errorInfo["ErrorType"] = l_ex.getErrorType();
416 l_errorInfo["ErrorMsg"] =
417 std::string("Data Exception. Reason: ") + i_exception.what();
418 }
419 else if (typeid(i_exception) == typeid(EccException))
420 {
421 const EccException& l_ex =
422 dynamic_cast<const EccException&>(i_exception);
423 l_errorInfo["ErrorType"] = l_ex.getErrorType();
424 l_errorInfo["ErrorMsg"] =
425 std::string("Ecc Exception. Reason: ") + i_exception.what();
426 }
427 else if (typeid(i_exception) == typeid(JsonException))
428 {
429 const JsonException& l_ex =
430 dynamic_cast<const JsonException&>(i_exception);
431 l_errorInfo["ErrorType"] = l_ex.getErrorType();
432 l_errorInfo["ErrorMsg"] =
433 std::string("Json Exception. Reason: ") + i_exception.what();
434 }
435 else if (typeid(i_exception) == typeid(GpioException))
436 {
437 const GpioException& l_ex =
438 dynamic_cast<const GpioException&>(i_exception);
439 l_errorInfo["ErrorType"] = l_ex.getErrorType();
440 l_errorInfo["ErrorMsg"] =
441 std::string("Gpio Exception. Reason: ") + i_exception.what();
442 }
443 else if (typeid(i_exception) == typeid(DbusException))
444 {
445 const DbusException& l_ex =
446 dynamic_cast<const DbusException&>(i_exception);
447 l_errorInfo["ErrorType"] = l_ex.getErrorType();
448 l_errorInfo["ErrorMsg"] =
449 std::string("Dbus Exception. Reason: ") + i_exception.what();
450 }
451 else if (typeid(i_exception) == typeid(FirmwareException))
452 {
453 const FirmwareException& l_ex =
454 dynamic_cast<const FirmwareException&>(i_exception);
455 l_errorInfo["ErrorType"] = l_ex.getErrorType();
456 l_errorInfo["ErrorMsg"] =
457 std::string("Firmware Exception. Reason: ") +
458 i_exception.what();
459 }
460 else if (typeid(i_exception) == typeid(EepromException))
461 {
462 const EepromException& l_ex =
463 dynamic_cast<const EepromException&>(i_exception);
464 l_errorInfo["ErrorType"] = l_ex.getErrorType();
465 l_errorInfo["ErrorMsg"] =
466 std::string("Eeprom Exception. Reason: ") + i_exception.what();
467 }
Sunny Srivastavac09e2102025-04-23 10:47:06 +0530468 else if (typeid(i_exception) == typeid(std::runtime_error))
469 {
470 // Since it is a standard exception no casting is required and error
471 // type is hardcoded.
472 l_errorInfo["ErrorType"] = types::ErrorType::FirmwareError;
473 l_errorInfo["ErrorMsg"] =
474 std::string("Eeprom Exception. Reason: ") + i_exception.what();
475 }
Anupama B Rb53d97c2025-02-24 03:37:34 -0600476 }
477 catch (const std::exception& l_ex)
478 {
479 logging::logMessage(
480 "Failed to get error info, reason: " + std::string(l_ex.what()));
481 }
482 return l_errorInfo;
483}
Sunny Srivastava15a189a2025-02-26 16:53:19 +0530484
485types::ErrorType EventLogger::getErrorType(const std::exception& i_exception)
486{
487 const auto& l_exceptionDataMap = getExceptionData(i_exception);
488
489 auto l_itrToErrType = l_exceptionDataMap.find("ErrorType");
490 if (l_itrToErrType == l_exceptionDataMap.end())
491 {
Sunny Srivastavac09e2102025-04-23 10:47:06 +0530492 return types::ErrorType::UndefinedError;
Sunny Srivastava15a189a2025-02-26 16:53:19 +0530493 }
494
495 auto l_ptrToErrType =
496 std::get_if<types::ErrorType>(&l_itrToErrType->second);
497 if (!l_ptrToErrType)
498 {
Sunny Srivastavac09e2102025-04-23 10:47:06 +0530499 return types::ErrorType::UndefinedError;
Sunny Srivastava15a189a2025-02-26 16:53:19 +0530500 }
501
502 return *l_ptrToErrType;
503}
504
505std::string EventLogger::getErrorMsg(const std::exception& i_exception)
506{
507 const auto& l_exceptionDataMap = getExceptionData(i_exception);
508
509 auto l_itrToErrMsg = l_exceptionDataMap.find("ErrorMsg");
510 if (l_itrToErrMsg == l_exceptionDataMap.end())
511 {
512 return i_exception.what();
513 }
514
515 auto l_ptrToErrMsg = std::get_if<std::string>(&l_itrToErrMsg->second);
516 if (!l_ptrToErrMsg)
517 {
518 return i_exception.what();
519 }
520
521 return *l_ptrToErrMsg;
522}
Souvik Roy612bce82025-04-16 02:22:33 -0500523
524std::string EventLogger::getErrorTypeString(
525 const types::ErrorType& i_errorType) noexcept
526{
527 const auto l_entry = m_errorMsgMap.find(i_errorType);
528 return (l_entry != m_errorMsgMap.end()
529 ? l_entry->second
530 : m_errorMsgMap.at(types::ErrorType::UndefinedError));
531}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500532} // namespace vpd