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