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