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