xref: /openbmc/phosphor-debug-collector/elog_watch.cpp (revision 316a2277f2a8e4c6e56377538d88cdaa38a9f261)
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 
Watch(sdbusplus::bus_t & bus,Mgr & mgr)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 
addCallback(sdbusplus::message_t & msg)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 
delCallback(sdbusplus::message_t & msg)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