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