xref: /openbmc/phosphor-debug-collector/elog_watch.cpp (revision 0deb287cc1cd0acccc38e9333a87842134e87be3)
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 <fstream>
12 #include <phosphor-logging/elog.hpp>
13 #include <sdbusplus/exception.hpp>
14 
15 // Register class version with Cereal
16 CEREAL_CLASS_VERSION(phosphor::dump::elog::Watch, CLASS_VERSION);
17 
18 namespace phosphor
19 {
20 namespace dump
21 {
22 namespace elog
23 {
24 
25 using namespace phosphor::logging;
26 constexpr auto LOG_PATH = "/xyz/openbmc_project/logging";
27 using Message = std::string;
28 using Attributes = sdbusplus::message::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::bus& bus, IMgr& iMgr) :
35     iMgr(iMgr),
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 
48     fs::path file(ELOG_ID_PERSIST_PATH);
49     if (fs::exists(file))
50     {
51         if (!deserialize(ELOG_ID_PERSIST_PATH, elogList))
52         {
53             log<level::ERR>("Error occurred during error id deserialize");
54         }
55     }
56 }
57 
58 void Watch::addCallback(sdbusplus::message::message& 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::SdBusError& e)
70     {
71         log<level::ERR>("Failed to parse elog add signal",
72                         entry("ERROR=%s", e.what()),
73                         entry("REPLY_SIG=%s", 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 =
106         sdbusplus::message::variant_ns::get<PropertyName>(attr->second);
107     if (data.empty())
108     {
109         // No Message skip
110         return;
111     }
112 
113     EType errorType;
114     for (const auto& [type, errorList] : errorMap)
115     {
116         auto error = std::find(errorList.begin(), errorList.end(), data);
117         if (error != errorList.end())
118         {
119             errorType = type;
120             break;
121         }
122     }
123 
124     // error not supported in the configuration
125     if (errorType.empty())
126     {
127         return;
128     }
129 
130     std::vector<std::string> fullPaths;
131     fullPaths.push_back(objectPath);
132 
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 
141         auto item = std::find_if(
142             TypeMap.begin(), TypeMap.end(),
143             [errorType](const auto& err) { return (err.second == errorType); });
144         if (item != TypeMap.end())
145         {
146             iMgr.IMgr::create((*item).first, fullPaths);
147         }
148     }
149     catch (QuotaExceeded& e)
150     {
151         // No action now
152     }
153     return;
154 }
155 
156 void Watch::delCallback(sdbusplus::message::message& msg)
157 {
158     sdbusplus::message::object_path objectPath;
159     try
160     {
161         msg.read(objectPath);
162     }
163     catch (const sdbusplus::exception::SdBusError& e)
164     {
165         log<level::ERR>("Failed to parse elog del signal",
166                         entry("ERROR=%s", e.what()),
167                         entry("REPLY_SIG=%s", msg.get_signature()));
168         return;
169     }
170 
171     // Get elog id
172     auto eId = getEid(objectPath);
173 
174     // Delete the elog entry from the list and serialize
175     auto search = elogList.find(eId);
176     if (search != elogList.end())
177     {
178         elogList.erase(search);
179         phosphor::dump::elog::serialize(elogList);
180     }
181 }
182 
183 } // namespace elog
184 } // namespace dump
185 } // namespace phosphor
186