#include #include #include #include "elog_watch.hpp" #include "dump_internal.hpp" #include "xyz/openbmc_project/Dump/Create/error.hpp" #include "dump_serialize.hpp" #include "config.h" // Register class version with Cereal CEREAL_CLASS_VERSION(phosphor::dump::elog::Watch, CLASS_VERSION); namespace phosphor { namespace dump { namespace elog { using namespace phosphor::logging; constexpr auto LOG_PATH = "/xyz/openbmc_project/logging"; constexpr auto INTERNAL_FAILURE = "xyz.openbmc_project.Common.Error.InternalFailure"; using Message = std::string; using Attributes = sdbusplus::message::variant; using AttributeName = std::string; using AttributeMap = std::map; using PropertyName = std::string; using PropertyMap = std::map; using LogEntryMsg = std::pair; Watch::Watch(sdbusplus::bus::bus& bus, IMgr& iMgr): iMgr(iMgr), addMatch( bus, sdbusplus::bus::match::rules::interfacesAdded() + sdbusplus::bus::match::rules::path_namespace( OBJ_LOGGING), std::bind(std::mem_fn(&Watch::addCallback), this, std::placeholders::_1)), delMatch( bus, sdbusplus::bus::match::rules::interfacesRemoved() + sdbusplus::bus::match::rules::path_namespace( OBJ_LOGGING), std::bind(std::mem_fn(&Watch::delCallback), this, std::placeholders::_1)) { fs::path file(ELOG_ID_PERSIST_PATH); if (fs::exists(file)) { if (!deserialize(ELOG_ID_PERSIST_PATH, elogList)) { log("Error occurred during error id deserialize"); } } } void Watch::addCallback(sdbusplus::message::message& msg) { using Type = sdbusplus::xyz::openbmc_project::Dump::Internal::server::Create::Type; using QuotaExceeded = sdbusplus::xyz::openbmc_project::Dump::Create::Error::QuotaExceeded; LogEntryMsg logEntry; try { msg.read(logEntry); } catch (const sdbusplus::exception::SdBusError& e) { log("Failed to parse elog add signal", entry("ERROR=%s", e.what()), entry("REPLY_SIG=%s", msg.get_signature())); return; } std::string objectPath(std::move(logEntry.first)); std::size_t found = objectPath.find("entry"); if (found == std::string::npos) { //Not a new error entry skip return; } auto eId = getEid(objectPath); auto search = elogList.find(eId); if (search != elogList.end()) { //elog exists in the list, Skip the dump return; } auto iter = logEntry.second.find("xyz.openbmc_project.Logging.Entry"); if (iter == logEntry.second.end()) { return; } auto attr = iter->second.find("Message"); if (attr == iter->second.end()) { return; } auto& data = sdbusplus::message::variant_ns::get(attr->second); if (data.empty()) { //No Message skip return; } if (data != INTERNAL_FAILURE) { //Not a InternalFailure, skip return; } std::vector fullPaths; fullPaths.push_back(objectPath); try { //Save the elog information. This is to avoid dump requests //in elog restore path. elogList.insert(eId); phosphor::dump::elog::serialize(elogList); //Call internal create function to initiate dump iMgr.IMgr::create(Type::InternalFailure, fullPaths); } catch (QuotaExceeded& e) { //No action now } return; } void Watch::delCallback(sdbusplus::message::message& msg) { sdbusplus::message::object_path logEntry; try { msg.read(logEntry); } catch (const sdbusplus::exception::SdBusError& e) { log("Failed to parse elog del signal", entry("ERROR=%s", e.what()), entry("REPLY_SIG=%s", msg.get_signature())); return; } //Get elog entry message string. std::string objectPath(logEntry); //Get elog id auto eId = getEid(objectPath); //Delete the elog entry from the list and serialize auto search = elogList.find(eId); if (search != elogList.end()) { elogList.erase(search); phosphor::dump::elog::serialize(elogList); } } }//namespace elog }//namespace dump }//namespace phosphor