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