xref: /openbmc/phosphor-debug-collector/elog_watch.cpp (revision e57ee7623b4e4a5e6987879548ce4f201eabe685)
1 #include "config.h"
2 
3 #include "elog_watch.hpp"
4 
5 #include "dump_internal.hpp"
6 #include "dump_serialize.hpp"
7 #include "xyz/openbmc_project/Dump/Create/error.hpp"
8 
9 #include <cereal/cereal.hpp>
10 #include <phosphor-logging/elog.hpp>
11 #include <sdbusplus/exception.hpp>
12 
13 // Register class version with Cereal
14 CEREAL_CLASS_VERSION(phosphor::dump::elog::Watch, CLASS_VERSION);
15 
16 namespace phosphor
17 {
18 namespace dump
19 {
20 namespace elog
21 {
22 
23 using namespace phosphor::logging;
24 constexpr auto LOG_PATH = "/xyz/openbmc_project/logging";
25 constexpr auto INTERNAL_FAILURE =
26     "xyz.openbmc_project.Common.Error.InternalFailure";
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 Type =
61         sdbusplus::xyz::openbmc_project::Dump::Internal::server::Create::Type;
62     using QuotaExceeded =
63         sdbusplus::xyz::openbmc_project::Dump::Create::Error::QuotaExceeded;
64 
65     sdbusplus::message::object_path objectPath;
66     PropertyMap propertyMap;
67     try
68     {
69         msg.read(objectPath, propertyMap);
70     }
71     catch (const sdbusplus::exception::SdBusError& e)
72     {
73         log<level::ERR>("Failed to parse elog add signal",
74                         entry("ERROR=%s", e.what()),
75                         entry("REPLY_SIG=%s", msg.get_signature()));
76         return;
77     }
78 
79     std::size_t found = objectPath.str.find("entry");
80     if (found == std::string::npos)
81     {
82         // Not a new error entry skip
83         return;
84     }
85 
86     auto eId = getEid(objectPath);
87 
88     auto search = elogList.find(eId);
89     if (search != elogList.end())
90     {
91         // elog exists in the list, Skip the dump
92         return;
93     }
94 
95     auto iter = propertyMap.find("xyz.openbmc_project.Logging.Entry");
96     if (iter == propertyMap.end())
97     {
98         return;
99     }
100 
101     auto attr = iter->second.find("Message");
102     if (attr == iter->second.end())
103     {
104         return;
105     }
106 
107     auto& data =
108         sdbusplus::message::variant_ns::get<PropertyName>(attr->second);
109     if (data.empty())
110     {
111         // No Message skip
112         return;
113     }
114 
115     if (data != INTERNAL_FAILURE)
116     {
117         // Not a InternalFailure, skip
118         return;
119     }
120 
121     std::vector<std::string> fullPaths;
122     fullPaths.push_back(objectPath);
123 
124     try
125     {
126         // Save the elog information. This is to avoid dump requests
127         // in elog restore path.
128         elogList.insert(eId);
129 
130         phosphor::dump::elog::serialize(elogList);
131 
132         // Call internal create function to initiate dump
133         iMgr.IMgr::create(Type::InternalFailure, fullPaths);
134     }
135     catch (QuotaExceeded& e)
136     {
137         // No action now
138     }
139     return;
140 }
141 
142 void Watch::delCallback(sdbusplus::message::message& msg)
143 {
144     sdbusplus::message::object_path objectPath;
145     try
146     {
147         msg.read(objectPath);
148     }
149     catch (const sdbusplus::exception::SdBusError& e)
150     {
151         log<level::ERR>("Failed to parse elog del signal",
152                         entry("ERROR=%s", e.what()),
153                         entry("REPLY_SIG=%s", msg.get_signature()));
154         return;
155     }
156 
157     // Get elog id
158     auto eId = getEid(objectPath);
159 
160     // Delete the elog entry from the list and serialize
161     auto search = elogList.find(eId);
162     if (search != elogList.end())
163     {
164         elogList.erase(search);
165         phosphor::dump::elog::serialize(elogList);
166     }
167 }
168 
169 } // namespace elog
170 } // namespace dump
171 } // namespace phosphor
172