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