#include "config.h" #include "event_logger.hpp" #include "exceptions.hpp" #include "logger.hpp" #include #include #include #include namespace vpd { const std::unordered_map EventLogger::m_severityMap = { {types::SeverityType::Notice, "xyz.openbmc_project.Logging.Entry.Level.Notice"}, {types::SeverityType::Informational, "xyz.openbmc_project.Logging.Entry.Level.Informational"}, {types::SeverityType::Debug, "xyz.openbmc_project.Logging.Entry.Level.Debug"}, {types::SeverityType::Warning, "xyz.openbmc_project.Logging.Entry.Level.Warning"}, {types::SeverityType::Critical, "xyz.openbmc_project.Logging.Entry.Level.Critical"}, {types::SeverityType::Emergency, "xyz.openbmc_project.Logging.Entry.Level.Emergency"}, {types::SeverityType::Alert, "xyz.openbmc_project.Logging.Entry.Level.Alert"}, {types::SeverityType::Error, "xyz.openbmc_project.Logging.Entry.Level.Error"}}; const std::unordered_map EventLogger::m_errorMsgMap = { {types::ErrorType::DefaultValue, "com.ibm.VPD.Error.DefaultValue"}, {types::ErrorType::UndefinedError, "com.ibm.VPD.Error.UndefinedError"}, {types::ErrorType::InvalidVpdMessage, "com.ibm.VPD.Error.InvalidVPD"}, {types::ErrorType::VpdMismatch, "com.ibm.VPD.Error.Mismatch"}, {types::ErrorType::InvalidEeprom, "com.ibm.VPD.Error.InvalidEepromPath"}, {types::ErrorType::EccCheckFailed, "com.ibm.VPD.Error.EccCheckFailed"}, {types::ErrorType::JsonFailure, "com.ibm.VPD.Error.InvalidJson"}, {types::ErrorType::DbusFailure, "com.ibm.VPD.Error.DbusFailure"}, {types::ErrorType::InvalidSystem, "com.ibm.VPD.Error.UnknownSystemType"}, {types::ErrorType::EssentialFru, "com.ibm.VPD.Error.RequiredFRUMissing"}, {types::ErrorType::GpioError, "com.ibm.VPD.Error.GPIOError"}, {types::ErrorType::InternalFailure, "xyz.openbmc_project.Common.Error.InternalFailure"}, {types::ErrorType::FruMissing, "com.ibm.VPD.Error.RequiredFRUMissing"}, {types::ErrorType::SystemTypeMismatch, "com.ibm.VPD.Error.SystemTypeMismatch"}, {types::ErrorType::UnknownSystemSettings, "com.ibm.VPD.Error.UnknownSystemSettings"}, {types::ErrorType::FirmwareError, "com.ibm.VPD.Error.FirmwareError"}, {types::ErrorType::VpdParseError, "com.ibm.VPD.Error.VPDParseError"}}; const std::unordered_map EventLogger::m_priorityMap = { {types::CalloutPriority::High, "H"}, {types::CalloutPriority::Medium, "M"}, {types::CalloutPriority::MediumGroupA, "A"}, {types::CalloutPriority::MediumGroupB, "B"}, {types::CalloutPriority::MediumGroupC, "C"}, {types::CalloutPriority::Low, "L"}}; void EventLogger::createAsyncPelWithInventoryCallout( const types::ErrorType& i_errorType, const types::SeverityType& i_severity, const std::vector& i_callouts, const std::string& i_fileName, const std::string& i_funcName, const uint8_t i_internalRc, const std::string& i_description, const std::optional i_userData1, const std::optional i_userData2, const std::optional i_symFru, const std::optional i_procedure) { (void)i_symFru; (void)i_procedure; try { if (i_callouts.empty()) { logging::logMessage("Callout information is missing to create PEL"); // TODO: Revisit this instead of simpley returning. return; } if (m_errorMsgMap.find(i_errorType) == m_errorMsgMap.end()) { throw std::runtime_error( "Error type not found in the error message map to create PEL"); // TODO: Need to handle, instead of throwing exception. Create // default message in message_registry.json. } const std::string& l_message = m_errorMsgMap.at(i_errorType); const std::string& l_severity = (m_severityMap.find(i_severity) != m_severityMap.end() ? m_severityMap.at(i_severity) : m_severityMap.at(types::SeverityType::Informational)); std::string l_description = (!i_description.empty() ? i_description : "VPD generic error"); std::string l_userData1 = (i_userData1) ? (*i_userData1) : ""; std::string l_userData2 = (i_userData2) ? (*i_userData2) : ""; const types::InventoryCalloutData& l_invCallout = i_callouts[0]; // TODO: Need to handle multiple inventory path callout's, when multiple // callout's is supported by "Logging" service. const types::CalloutPriority& l_priorityEnum = get<1>(l_invCallout); const std::string& l_priority = (m_priorityMap.find(l_priorityEnum) != m_priorityMap.end() ? m_priorityMap.at(l_priorityEnum) : m_priorityMap.at(types::CalloutPriority::Low)); sd_bus* l_sdBus = nullptr; sd_bus_default(&l_sdBus); const uint8_t l_additionalDataCount = 8; auto l_rc = sd_bus_call_method_async( l_sdBus, NULL, constants::eventLoggingServiceName, constants::eventLoggingObjectPath, constants::eventLoggingInterface, "Create", NULL, NULL, "ssa{ss}", l_message.c_str(), l_severity.c_str(), l_additionalDataCount, "FileName", i_fileName.c_str(), "FunctionName", i_funcName.c_str(), "InternalRc", std::to_string(i_internalRc).c_str(), "DESCRIPTION", l_description.c_str(), "UserData1", l_userData1.c_str(), "UserData2", l_userData2.c_str(), "CALLOUT_INVENTORY_PATH", get<0>(l_invCallout).c_str(), "CALLOUT_PRIORITY", l_priority.c_str()); if (l_rc < 0) { logging::logMessage( "Error calling sd_bus_call_method_async, Message = " + std::string(strerror(-l_rc))); } } catch (const std::exception& l_ex) { logging::logMessage( "Create PEL failed with error: " + std::string(l_ex.what())); } } void EventLogger::createAsyncPelWithI2cDeviceCallout( const types::ErrorType i_errorType, const types::SeverityType i_severity, const std::vector& i_callouts, const std::string& i_fileName, const std::string& i_funcName, const uint8_t i_internalRc, const std::optional> i_userData1, const std::optional> i_userData2) { // TODO, implementation needs to be added. (void)i_errorType; (void)i_severity; (void)i_callouts; (void)i_fileName; (void)i_funcName; (void)i_internalRc; (void)i_userData1; (void)i_userData2; } void EventLogger::createAsyncPelWithI2cBusCallout( const types::ErrorType i_errorType, const types::SeverityType i_severity, const std::vector& i_callouts, const std::string& i_fileName, const std::string& i_funcName, const uint8_t i_internalRc, const std::optional> i_userData1, const std::optional> i_userData2) { // TODO, implementation needs to be added. (void)i_errorType; (void)i_severity; (void)i_callouts; (void)i_fileName; (void)i_funcName; (void)i_internalRc; (void)i_userData1; (void)i_userData2; } void EventLogger::createAsyncPel( const types::ErrorType& i_errorType, const types::SeverityType& i_severity, const std::string& i_fileName, const std::string& i_funcName, const uint8_t i_internalRc, const std::string& i_description, const std::optional i_userData1, const std::optional i_userData2, const std::optional i_symFru, const std::optional i_procedure) { (void)i_symFru; (void)i_procedure; try { if (m_errorMsgMap.find(i_errorType) == m_errorMsgMap.end()) { throw std::runtime_error("Unsupported error type received"); // TODO: Need to handle, instead of throwing an exception. } const std::string& l_message = m_errorMsgMap.at(i_errorType); const std::string& l_severity = (m_severityMap.find(i_severity) != m_severityMap.end() ? m_severityMap.at(i_severity) : m_severityMap.at(types::SeverityType::Informational)); const std::string l_description = ((!i_description.empty() ? i_description : "VPD generic error")); const std::string l_userData1 = ((i_userData1) ? (*i_userData1) : ""); const std::string l_userData2 = ((i_userData2) ? (*i_userData2) : ""); sd_bus* l_sdBus = nullptr; sd_bus_default(&l_sdBus); // VALUE_6 represents the additional data pair count passing to create // PEL. If there any change in additional data, we need to pass the // correct number. auto l_rc = sd_bus_call_method_async( l_sdBus, NULL, constants::eventLoggingServiceName, constants::eventLoggingObjectPath, constants::eventLoggingInterface, "Create", NULL, NULL, "ssa{ss}", l_message.c_str(), l_severity.c_str(), constants::VALUE_6, "FileName", i_fileName.c_str(), "FunctionName", i_funcName.c_str(), "InternalRc", std::to_string(i_internalRc).c_str(), "DESCRIPTION", l_description.c_str(), "UserData1", l_userData1.c_str(), "UserData2", l_userData2.c_str()); if (l_rc < 0) { logging::logMessage( "Error calling sd_bus_call_method_async, Message = " + std::string(strerror(-l_rc))); } } catch (const sdbusplus::exception::SdBusError& l_ex) { logging::logMessage("Async PEL creation failed with an error: " + std::string(l_ex.what())); } } void EventLogger::createSyncPel( const types::ErrorType& i_errorType, const types::SeverityType& i_severity, const std::string& i_fileName, const std::string& i_funcName, const uint8_t i_internalRc, const std::string& i_description, const std::optional i_userData1, const std::optional i_userData2, const std::optional i_symFru, const std::optional i_procedure) { (void)i_symFru; (void)i_procedure; try { if (m_errorMsgMap.find(i_errorType) == m_errorMsgMap.end()) { throw std::runtime_error("Unsupported error type received"); // TODO: Need to handle, instead of throwing an exception. } const std::string& l_message = m_errorMsgMap.at(i_errorType); const std::string& l_severity = (m_severityMap.find(i_severity) != m_severityMap.end() ? m_severityMap.at(i_severity) : m_severityMap.at(types::SeverityType::Informational)); const std::string l_description = ((!i_description.empty() ? i_description : "VPD generic error")); const std::string l_userData1 = ((i_userData1) ? (*i_userData1) : ""); const std::string l_userData2 = ((i_userData2) ? (*i_userData2) : ""); std::map l_additionalData{ {"FileName", i_fileName}, {"FunctionName", i_funcName}, {"DESCRIPTION", l_description}, {"InteranlRc", std::to_string(i_internalRc)}, {"UserData1", l_userData1.c_str()}, {"UserData2", l_userData2.c_str()}}; auto l_bus = sdbusplus::bus::new_default(); auto l_method = l_bus.new_method_call(constants::eventLoggingServiceName, constants::eventLoggingObjectPath, constants::eventLoggingInterface, "Create"); l_method.append(l_message, l_severity, l_additionalData); l_bus.call(l_method); } catch (const sdbusplus::exception::SdBusError& l_ex) { logging::logMessage("Sync PEL creation failed with an error: " + std::string(l_ex.what())); } } void EventLogger::createSyncPelWithInvCallOut( const types::ErrorType& i_errorType, const types::SeverityType& i_severity, const std::string& i_fileName, const std::string& i_funcName, const uint8_t i_internalRc, const std::string& i_description, const std::vector& i_callouts, const std::optional i_userData1, const std::optional i_userData2, [[maybe_unused]] const std::optional i_symFru, [[maybe_unused]] const std::optional i_procedure) { try { if (i_callouts.empty()) { createSyncPel(i_errorType, i_severity, i_fileName, i_funcName, i_internalRc, i_description, i_userData1, i_userData2, i_symFru, i_procedure); logging::logMessage( "Callout list is empty, creating PEL without call out"); return; } if (m_errorMsgMap.find(i_errorType) == m_errorMsgMap.end()) { throw std::runtime_error("Unsupported error type received"); } // Path to hold callout inventory path. std::string l_calloutInvPath; uint16_t l_errCode = 0; // check if callout path is a valid inventory path. if not, get the JSON // object to get inventory path. if (std::get<0>(i_callouts[0]) .compare(constants::VALUE_0, strlen(constants::pimPath), constants::pimPath) != constants::STR_CMP_SUCCESS) { std::error_code l_ec; // implies json dependent execution. if (std::filesystem::exists(INVENTORY_JSON_SYM_LINK, l_ec)) { if (!l_ec) { nlohmann::json l_parsedJson = jsonUtility::getParsedJson( INVENTORY_JSON_SYM_LINK, l_errCode); if (l_errCode) { logging::logMessage( "Failed to parse JSON file [ " + std::string(INVENTORY_JSON_SYM_LINK) + " ], error : " + vpdSpecificUtility::getErrCodeMsg(l_errCode)); } l_calloutInvPath = jsonUtility::getInventoryObjPathFromJson( l_parsedJson, std::get<0>(i_callouts[0]), l_errCode); } else { logging::logMessage( "Error finding symlink. Continue with given path"); } } } if (l_calloutInvPath.empty()) { l_calloutInvPath = std::get<0>(i_callouts[0]); if (l_errCode) { logging::logMessage( "Failed to get inventory object path from JSON for FRU [" + std::get<0>(i_callouts[0]) + "], error : " + vpdSpecificUtility::getErrCodeMsg(l_errCode)); } } const std::map l_additionalData{ {"FileName", i_fileName}, {"FunctionName", i_funcName}, {"DESCRIPTION", (!i_description.empty() ? i_description : "VPD generic error")}, {"CALLOUT_INVENTORY_PATH", l_calloutInvPath}, {"InteranlRc", std::to_string(i_internalRc)}, {"UserData1", ((i_userData1) ? (*i_userData1) : "").c_str()}, {"UserData2", ((i_userData2) ? (*i_userData2) : "").c_str()}}; const std::string& l_severity = (m_severityMap.find(i_severity) != m_severityMap.end() ? m_severityMap.at(i_severity) : m_severityMap.at(types::SeverityType::Informational)); auto l_bus = sdbusplus::bus::new_default(); auto l_method = l_bus.new_method_call(constants::eventLoggingServiceName, constants::eventLoggingObjectPath, constants::eventLoggingInterface, "Create"); l_method.append(m_errorMsgMap.at(i_errorType), l_severity, l_additionalData); l_bus.call(l_method); } catch (const std::exception& l_ex) { logging::logMessage( "Sync PEL creation with inventory path failed with error: " + std::string(l_ex.what())); } } types::ExceptionDataMap EventLogger::getExceptionData( const std::exception& i_exception) { types::ExceptionDataMap l_errorInfo{ {"ErrorType", types::ErrorType::UndefinedError}, {"ErrorMsg", i_exception.what()}}; try { if (typeid(i_exception) == typeid(DataException)) { const DataException& l_ex = dynamic_cast(i_exception); l_errorInfo["ErrorType"] = l_ex.getErrorType(); l_errorInfo["ErrorMsg"] = std::string("Data Exception. Reason: ") + i_exception.what(); } else if (typeid(i_exception) == typeid(EccException)) { const EccException& l_ex = dynamic_cast(i_exception); l_errorInfo["ErrorType"] = l_ex.getErrorType(); l_errorInfo["ErrorMsg"] = std::string("Ecc Exception. Reason: ") + i_exception.what(); } else if (typeid(i_exception) == typeid(JsonException)) { const JsonException& l_ex = dynamic_cast(i_exception); l_errorInfo["ErrorType"] = l_ex.getErrorType(); l_errorInfo["ErrorMsg"] = std::string("Json Exception. Reason: ") + i_exception.what(); } else if (typeid(i_exception) == typeid(GpioException)) { const GpioException& l_ex = dynamic_cast(i_exception); l_errorInfo["ErrorType"] = l_ex.getErrorType(); l_errorInfo["ErrorMsg"] = std::string("Gpio Exception. Reason: ") + i_exception.what(); } else if (typeid(i_exception) == typeid(DbusException)) { const DbusException& l_ex = dynamic_cast(i_exception); l_errorInfo["ErrorType"] = l_ex.getErrorType(); l_errorInfo["ErrorMsg"] = std::string("Dbus Exception. Reason: ") + i_exception.what(); } else if (typeid(i_exception) == typeid(FirmwareException)) { const FirmwareException& l_ex = dynamic_cast(i_exception); l_errorInfo["ErrorType"] = l_ex.getErrorType(); l_errorInfo["ErrorMsg"] = std::string("Firmware Exception. Reason: ") + i_exception.what(); } else if (typeid(i_exception) == typeid(EepromException)) { const EepromException& l_ex = dynamic_cast(i_exception); l_errorInfo["ErrorType"] = l_ex.getErrorType(); l_errorInfo["ErrorMsg"] = std::string("Eeprom Exception. Reason: ") + i_exception.what(); } else if (typeid(i_exception) == typeid(std::runtime_error)) { // Since it is a standard exception no casting is required and error // type is hardcoded. l_errorInfo["ErrorType"] = types::ErrorType::FirmwareError; l_errorInfo["ErrorMsg"] = std::string("Standard runtime exception. Reason: ") + i_exception.what(); } } catch (const std::exception& l_ex) { logging::logMessage( "Failed to get error info, reason: " + std::string(l_ex.what())); } return l_errorInfo; } types::ErrorType EventLogger::getErrorType(const std::exception& i_exception) { const auto& l_exceptionDataMap = getExceptionData(i_exception); auto l_itrToErrType = l_exceptionDataMap.find("ErrorType"); if (l_itrToErrType == l_exceptionDataMap.end()) { return types::ErrorType::UndefinedError; } auto l_ptrToErrType = std::get_if(&l_itrToErrType->second); if (!l_ptrToErrType) { return types::ErrorType::UndefinedError; } return *l_ptrToErrType; } std::string EventLogger::getErrorMsg(const std::exception& i_exception) { const auto& l_exceptionDataMap = getExceptionData(i_exception); auto l_itrToErrMsg = l_exceptionDataMap.find("ErrorMsg"); if (l_itrToErrMsg == l_exceptionDataMap.end()) { return i_exception.what(); } auto l_ptrToErrMsg = std::get_if(&l_itrToErrMsg->second); if (!l_ptrToErrMsg) { return i_exception.what(); } return *l_ptrToErrMsg; } std::string EventLogger::getErrorTypeString( const types::ErrorType& i_errorType) noexcept { const auto l_entry = m_errorMsgMap.find(i_errorType); return (l_entry != m_errorMsgMap.end() ? l_entry->second : m_errorMsgMap.at(types::ErrorType::UndefinedError)); } } // namespace vpd