1 #include "config.h" 2 3 #include "elog_watch.hpp" 4 5 #include "dump_serialize.hpp" 6 #include "dump_types.hpp" 7 #include "xyz/openbmc_project/Dump/Create/error.hpp" 8 9 #include <cereal/cereal.hpp> 10 #include <phosphor-logging/elog.hpp> 11 #include <phosphor-logging/lg2.hpp> 12 #include <sdbusplus/exception.hpp> 13 #include <xyz/openbmc_project/Dump/Create/common.hpp> 14 15 #include <fstream> 16 17 // Register class version with Cereal 18 CEREAL_CLASS_VERSION(phosphor::dump::elog::Watch, CLASS_VERSION) 19 20 namespace phosphor 21 { 22 namespace dump 23 { 24 namespace elog 25 { 26 27 using Message = std::string; 28 using Attributes = std::variant<Message>; 29 using AttributeName = std::string; 30 using AttributeMap = std::map<AttributeName, Attributes>; 31 using PropertyName = std::string; 32 using PropertyMap = std::map<PropertyName, AttributeMap>; 33 34 Watch::Watch(sdbusplus::bus_t& bus, Mgr& mgr) : 35 mgr(mgr), 36 addMatch(bus, 37 sdbusplus::bus::match::rules::interfacesAdded() + 38 sdbusplus::bus::match::rules::path_namespace(OBJ_LOGGING), 39 std::bind(std::mem_fn(&Watch::addCallback), this, 40 std::placeholders::_1)), 41 delMatch(bus, 42 sdbusplus::bus::match::rules::interfacesRemoved() + 43 sdbusplus::bus::match::rules::path_namespace(OBJ_LOGGING), 44 std::bind(std::mem_fn(&Watch::delCallback), this, 45 std::placeholders::_1)) 46 { 47 std::filesystem::path file(ELOG_ID_PERSIST_PATH); 48 if (std::filesystem::exists(file)) 49 { 50 if (!deserialize(ELOG_ID_PERSIST_PATH, elogList)) 51 { 52 lg2::error("Error occurred during error id deserialize"); 53 } 54 } 55 } 56 57 void Watch::addCallback(sdbusplus::message_t& msg) 58 { 59 using QuotaExceeded = 60 sdbusplus::xyz::openbmc_project::Dump::Create::Error::QuotaExceeded; 61 62 sdbusplus::message::object_path objectPath; 63 PropertyMap propertyMap; 64 try 65 { 66 msg.read(objectPath, propertyMap); 67 } 68 catch (const sdbusplus::exception_t& e) 69 { 70 lg2::error("Failed to parse elog add signal, errormsg: {ERROR}, " 71 "REPLY_SIG: {REPLY_SIG}", 72 "ERROR", e, "REPLY_SIG", msg.get_signature()); 73 return; 74 } 75 76 std::size_t found = objectPath.str.find("entry"); 77 if (found == std::string::npos) 78 { 79 // Not a new error entry skip 80 return; 81 } 82 83 auto eId = getEid(objectPath); 84 85 auto search = elogList.find(eId); 86 if (search != elogList.end()) 87 { 88 // elog exists in the list, Skip the dump 89 return; 90 } 91 92 auto iter = propertyMap.find("xyz.openbmc_project.Logging.Entry"); 93 if (iter == propertyMap.end()) 94 { 95 return; 96 } 97 98 auto attr = iter->second.find("Message"); 99 if (attr == iter->second.end()) 100 { 101 return; 102 } 103 104 auto& data = std::get<PropertyName>(attr->second); 105 if (data.empty()) 106 { 107 // No Message skip 108 return; 109 } 110 111 auto etype = findErrorType(data); 112 if (!etype.has_value()) 113 { 114 // error not supported in the configuration 115 return; 116 } 117 118 auto errorType = etype.value(); 119 120 DumpCreateParams params; 121 using DumpIntr = sdbusplus::common::xyz::openbmc_project::dump::Create; 122 using CreateParameters = 123 sdbusplus::common::xyz::openbmc_project::dump::Create::CreateParameters; 124 using DumpType = 125 sdbusplus::common::xyz::openbmc_project::dump::Create::DumpType; 126 params[DumpIntr::convertCreateParametersToString( 127 CreateParameters::FilePath)] = objectPath; 128 params[DumpIntr::convertCreateParametersToString( 129 CreateParameters::DumpType)] = 130 DumpIntr::convertDumpTypeToString(DumpType::ErrorLog); 131 params[DumpIntr::convertCreateParametersToString( 132 CreateParameters::ErrorType)] = errorType; 133 try 134 { 135 // Save the elog information. This is to avoid dump requests 136 // in elog restore path. 137 elogList.insert(eId); 138 139 phosphor::dump::elog::serialize(elogList); 140 mgr.Mgr::createDump(params); 141 } 142 catch (const QuotaExceeded& e) 143 { 144 // No action needed 145 lg2::warning("Skipping exception: QuotaExceeded during createDump"); 146 } 147 return; 148 } 149 150 void Watch::delCallback(sdbusplus::message_t& msg) 151 { 152 sdbusplus::message::object_path objectPath; 153 try 154 { 155 msg.read(objectPath); 156 } 157 catch (const sdbusplus::exception_t& e) 158 { 159 lg2::error("Failed to parse elog del signal, errormsg: {ERROR}, " 160 "REPLY_SIG: {REPLY_SIG}", 161 "ERROR", e, "REPLY_SIG", msg.get_signature()); 162 return; 163 } 164 165 std::size_t found = objectPath.str.find("entry"); 166 if (found == std::string::npos) 167 { 168 // Not a error entry so skip 169 return; 170 } 171 172 // Get elog id 173 auto eId = getEid(objectPath); 174 175 // Delete the elog entry from the list and serialize 176 auto search = elogList.find(eId); 177 if (search != elogList.end()) 178 { 179 elogList.erase(search); 180 phosphor::dump::elog::serialize(elogList); 181 } 182 } 183 184 } // namespace elog 185 } // namespace dump 186 } // namespace phosphor 187