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 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, Mgr& mgr) : 36 mgr(mgr), 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 auto etype = findErrorType(data); 113 if (!etype.has_value()) 114 { 115 // error not supported in the configuration 116 return; 117 } 118 119 auto errorType = etype.value(); 120 121 DumpCreateParams params; 122 using DumpIntr = sdbusplus::common::xyz::openbmc_project::dump::Create; 123 using CreateParameters = 124 sdbusplus::common::xyz::openbmc_project::dump::Create::CreateParameters; 125 using DumpType = 126 sdbusplus::common::xyz::openbmc_project::dump::Create::DumpType; 127 params[DumpIntr::convertCreateParametersToString( 128 CreateParameters::FilePath)] = objectPath; 129 params[DumpIntr::convertCreateParametersToString( 130 CreateParameters::DumpType)] = 131 DumpIntr::convertDumpTypeToString(DumpType::ErrorLog); 132 params[DumpIntr::convertCreateParametersToString( 133 CreateParameters::ErrorType)] = errorType; 134 try 135 { 136 // Save the elog information. This is to avoid dump requests 137 // in elog restore path. 138 elogList.insert(eId); 139 140 phosphor::dump::elog::serialize(elogList); 141 mgr.Mgr::createDump(params); 142 } 143 catch (const QuotaExceeded& e) 144 { 145 // No action now 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