xref: /openbmc/openpower-vpd-parser/vpd-manager/src/event_logger.cpp (revision 565e1140c9fbefa79b4fdd9fa16f24adbf30602c)
1 #include "event_logger.hpp"
2 
3 #include "exceptions.hpp"
4 #include "logger.hpp"
5 
6 #include <systemd/sd-bus.h>
7 
8 namespace vpd
9 {
10 const std::unordered_map<types::SeverityType, std::string>
11     EventLogger::m_severityMap = {
12         {types::SeverityType::Notice,
13          "xyz.openbmc_project.Logging.Entry.Level.Notice"},
14         {types::SeverityType::Informational,
15          "xyz.openbmc_project.Logging.Entry.Level.Informational"},
16         {types::SeverityType::Debug,
17          "xyz.openbmc_project.Logging.Entry.Level.Debug"},
18         {types::SeverityType::Warning,
19          "xyz.openbmc_project.Logging.Entry.Level.Warning"},
20         {types::SeverityType::Critical,
21          "xyz.openbmc_project.Logging.Entry.Level.Critical"},
22         {types::SeverityType::Emergency,
23          "xyz.openbmc_project.Logging.Entry.Level.Emergency"},
24         {types::SeverityType::Alert,
25          "xyz.openbmc_project.Logging.Entry.Level.Alert"},
26         {types::SeverityType::Error,
27          "xyz.openbmc_project.Logging.Entry.Level.Error"}};
28 
29 const std::unordered_map<types::ErrorType, std::string>
30     EventLogger::m_errorMsgMap = {
31         {types::ErrorType::DefaultValue, "com.ibm.VPD.Error.DefaultValue"},
32         {types::ErrorType::InvalidVpdMessage, "com.ibm.VPD.Error.InvalidVPD"},
33         {types::ErrorType::VpdMismatch, "com.ibm.VPD.Error.Mismatch"},
34         {types::ErrorType::InvalidEeprom,
35          "com.ibm.VPD.Error.InvalidEepromPath"},
36         {types::ErrorType::EccCheckFailed, "com.ibm.VPD.Error.EccCheckFailed"},
37         {types::ErrorType::JsonFailure, "com.ibm.VPD.Error.InvalidJson"},
38         {types::ErrorType::DbusFailure, "com.ibm.VPD.Error.DbusFailure"},
39         {types::ErrorType::InvalidSystem,
40          "com.ibm.VPD.Error.UnknownSystemType"},
41         {types::ErrorType::EssentialFru,
42          "com.ibm.VPD.Error.RequiredFRUMissing"},
43         {types::ErrorType::GpioError, "com.ibm.VPD.Error.GPIOError"},
44         {types::ErrorType::InternalFailure,
45          "xyz.openbmc_project.Common.Error.InternalFailure"},
46         {types::ErrorType::FruMissing, "com.ibm.VPD.Error.RequiredFRUMissing"},
47         {types::ErrorType::SystemTypeMismatch,
48          "com.ibm.VPD.Error.SystemTypeMismatch"},
49         {types::ErrorType::UnknownSystemSettings,
50          "com.ibm.VPD.Error.UnknownSystemSettings"},
51         {types::ErrorType::FirmwareError, "com.ibm.VPD.Error.FirmwareError"}};
52 
53 const std::unordered_map<types::CalloutPriority, std::string>
54     EventLogger::m_priorityMap = {
55         {types::CalloutPriority::High, "H"},
56         {types::CalloutPriority::Medium, "M"},
57         {types::CalloutPriority::MediumGroupA, "A"},
58         {types::CalloutPriority::MediumGroupB, "B"},
59         {types::CalloutPriority::MediumGroupC, "C"},
60         {types::CalloutPriority::Low, "L"}};
61 
62 void EventLogger::createAsyncPelWithInventoryCallout(
63     const types::ErrorType& i_errorType, const types::SeverityType& i_severity,
64     const std::vector<types::InventoryCalloutData>& i_callouts,
65     const std::string& i_fileName, const std::string& i_funcName,
66     const uint8_t i_internalRc, const std::string& i_description,
67     const std::optional<std::string> i_userData1,
68     const std::optional<std::string> i_userData2,
69     const std::optional<std::string> i_symFru,
70     const std::optional<std::string> i_procedure)
71 {
72     (void)i_symFru;
73     (void)i_procedure;
74 
75     try
76     {
77         if (i_callouts.empty())
78         {
79             logging::logMessage("Callout information is missing to create PEL");
80             // TODO: Revisit this instead of simpley returning.
81             return;
82         }
83 
84         if (m_errorMsgMap.find(i_errorType) == m_errorMsgMap.end())
85         {
86             throw std::runtime_error(
87                 "Error type not found in the error message map to create PEL");
88             // TODO: Need to handle, instead of throwing exception. Create
89             // default message in message_registry.json.
90         }
91 
92         const std::string& l_message = m_errorMsgMap.at(i_errorType);
93 
94         const std::string& l_severity =
95             (m_severityMap.find(i_severity) != m_severityMap.end()
96                  ? m_severityMap.at(i_severity)
97                  : m_severityMap.at(types::SeverityType::Informational));
98 
99         std::string l_description =
100             (!i_description.empty() ? i_description : "VPD generic error");
101 
102         std::string l_userData1 = (i_userData1) ? (*i_userData1) : "";
103 
104         std::string l_userData2 = (i_userData2) ? (*i_userData2) : "";
105 
106         const types::InventoryCalloutData& l_invCallout = i_callouts[0];
107         // TODO: Need to handle multiple inventory path callout's, when multiple
108         // callout's is supported by "Logging" service.
109 
110         const types::CalloutPriority& l_priorityEnum = get<1>(l_invCallout);
111 
112         const std::string& l_priority =
113             (m_priorityMap.find(l_priorityEnum) != m_priorityMap.end()
114                  ? m_priorityMap.at(l_priorityEnum)
115                  : m_priorityMap.at(types::CalloutPriority::Low));
116 
117         sd_bus* l_sdBus = nullptr;
118         sd_bus_default(&l_sdBus);
119 
120         const uint8_t l_additionalDataCount = 8;
121         auto l_rc = sd_bus_call_method_async(
122             l_sdBus, NULL, constants::eventLoggingServiceName,
123             constants::eventLoggingObjectPath, constants::eventLoggingInterface,
124             "Create", NULL, NULL, "ssa{ss}", l_message.c_str(),
125             l_severity.c_str(), l_additionalDataCount, "FileName",
126             i_fileName.c_str(), "FunctionName", i_funcName.c_str(),
127             "InternalRc", std::to_string(i_internalRc).c_str(), "DESCRIPTION",
128             l_description.c_str(), "UserData1", l_userData1.c_str(),
129             "UserData2", l_userData2.c_str(), "CALLOUT_INVENTORY_PATH",
130             get<0>(l_invCallout).c_str(), "CALLOUT_PRIORITY",
131             l_priority.c_str());
132 
133         if (l_rc < 0)
134         {
135             logging::logMessage(
136                 "Error calling sd_bus_call_method_async, Message = " +
137                 std::string(strerror(-l_rc)));
138         }
139     }
140     catch (const std::exception& l_ex)
141     {
142         logging::logMessage(
143             "Create PEL failed with error: " + std::string(l_ex.what()));
144     }
145 }
146 
147 void EventLogger::createAsyncPelWithI2cDeviceCallout(
148     const types::ErrorType i_errorType, const types::SeverityType i_severity,
149     const std::vector<types::DeviceCalloutData>& i_callouts,
150     const std::string& i_fileName, const std::string& i_funcName,
151     const uint8_t i_internalRc,
152     const std::optional<std::pair<std::string, std::string>> i_userData1,
153     const std::optional<std::pair<std::string, std::string>> i_userData2)
154 {
155     // TODO, implementation needs to be added.
156     (void)i_errorType;
157     (void)i_severity;
158     (void)i_callouts;
159     (void)i_fileName;
160     (void)i_funcName;
161     (void)i_internalRc;
162     (void)i_userData1;
163     (void)i_userData2;
164 }
165 
166 void EventLogger::createAsyncPelWithI2cBusCallout(
167     const types::ErrorType i_errorType, const types::SeverityType i_severity,
168     const std::vector<types::I2cBusCalloutData>& i_callouts,
169     const std::string& i_fileName, const std::string& i_funcName,
170     const uint8_t i_internalRc,
171     const std::optional<std::pair<std::string, std::string>> i_userData1,
172     const std::optional<std::pair<std::string, std::string>> i_userData2)
173 {
174     // TODO, implementation needs to be added.
175     (void)i_errorType;
176     (void)i_severity;
177     (void)i_callouts;
178     (void)i_fileName;
179     (void)i_funcName;
180     (void)i_internalRc;
181     (void)i_userData1;
182     (void)i_userData2;
183 }
184 
185 void EventLogger::createAsyncPel(
186     const types::ErrorType& i_errorType, const types::SeverityType& i_severity,
187     const std::string& i_fileName, const std::string& i_funcName,
188     const uint8_t i_internalRc, const std::string& i_description,
189     const std::optional<std::string> i_userData1,
190     const std::optional<std::string> i_userData2,
191     const std::optional<std::string> i_symFru,
192     const std::optional<std::string> i_procedure)
193 {
194     (void)i_symFru;
195     (void)i_procedure;
196     try
197     {
198         if (m_errorMsgMap.find(i_errorType) == m_errorMsgMap.end())
199         {
200             throw std::runtime_error("Unsupported error type received");
201             // TODO: Need to handle, instead of throwing an exception.
202         }
203 
204         const std::string& l_message = m_errorMsgMap.at(i_errorType);
205 
206         const std::string& l_severity =
207             (m_severityMap.find(i_severity) != m_severityMap.end()
208                  ? m_severityMap.at(i_severity)
209                  : m_severityMap.at(types::SeverityType::Informational));
210 
211         const std::string l_description =
212             ((!i_description.empty() ? i_description : "VPD generic error"));
213 
214         const std::string l_userData1 = ((i_userData1) ? (*i_userData1) : "");
215 
216         const std::string l_userData2 = ((i_userData2) ? (*i_userData2) : "");
217 
218         sd_bus* l_sdBus = nullptr;
219         sd_bus_default(&l_sdBus);
220 
221         // VALUE_6 represents the additional data pair count passing to create
222         // PEL. If there any change in additional data, we need to pass the
223         // correct number.
224         auto l_rc = sd_bus_call_method_async(
225             l_sdBus, NULL, constants::eventLoggingServiceName,
226             constants::eventLoggingObjectPath, constants::eventLoggingInterface,
227             "Create", NULL, NULL, "ssa{ss}", l_message.c_str(),
228             l_severity.c_str(), constants::VALUE_6, "FileName",
229             i_fileName.c_str(), "FunctionName", i_funcName.c_str(),
230             "InternalRc", std::to_string(i_internalRc).c_str(), "DESCRIPTION",
231             l_description.c_str(), "UserData1", l_userData1.c_str(),
232             "UserData2", l_userData2.c_str());
233 
234         if (l_rc < 0)
235         {
236             logging::logMessage(
237                 "Error calling sd_bus_call_method_async, Message = " +
238                 std::string(strerror(-l_rc)));
239         }
240     }
241     catch (const sdbusplus::exception::SdBusError& l_ex)
242     {
243         logging::logMessage("Async PEL creation failed with an error: " +
244                             std::string(l_ex.what()));
245     }
246 }
247 
248 void EventLogger::createSyncPel(
249     const types::ErrorType& i_errorType, const types::SeverityType& i_severity,
250     const std::string& i_fileName, const std::string& i_funcName,
251     const uint8_t i_internalRc, const std::string& i_description,
252     const std::optional<std::string> i_userData1,
253     const std::optional<std::string> i_userData2,
254     const std::optional<std::string> i_symFru,
255     const std::optional<std::string> i_procedure)
256 {
257     (void)i_symFru;
258     (void)i_procedure;
259     try
260     {
261         if (m_errorMsgMap.find(i_errorType) == m_errorMsgMap.end())
262         {
263             throw std::runtime_error("Unsupported error type received");
264             // TODO: Need to handle, instead of throwing an exception.
265         }
266 
267         const std::string& l_message = m_errorMsgMap.at(i_errorType);
268 
269         const std::string& l_severity =
270             (m_severityMap.find(i_severity) != m_severityMap.end()
271                  ? m_severityMap.at(i_severity)
272                  : m_severityMap.at(types::SeverityType::Informational));
273 
274         const std::string l_description =
275             ((!i_description.empty() ? i_description : "VPD generic error"));
276 
277         const std::string l_userData1 = ((i_userData1) ? (*i_userData1) : "");
278 
279         const std::string l_userData2 = ((i_userData2) ? (*i_userData2) : "");
280 
281         std::map<std::string, std::string> l_additionalData{
282             {"FileName", i_fileName},
283             {"FunctionName", i_funcName},
284             {"DESCRIPTION", l_description},
285             {"InteranlRc", std::to_string(i_internalRc)},
286             {"UserData1", l_userData1.c_str()},
287             {"UserData2", l_userData2.c_str()}};
288 
289         auto l_bus = sdbusplus::bus::new_default();
290         auto l_method =
291             l_bus.new_method_call(constants::eventLoggingServiceName,
292                                   constants::eventLoggingObjectPath,
293                                   constants::eventLoggingInterface, "Create");
294         l_method.append(l_message, l_severity, l_additionalData);
295         l_bus.call(l_method);
296     }
297     catch (const sdbusplus::exception::SdBusError& l_ex)
298     {
299         logging::logMessage("Sync PEL creation failed with an error: " +
300                             std::string(l_ex.what()));
301     }
302 }
303 
304 types::ExceptionDataMap EventLogger::getExceptionData(
305     const std::exception& i_exception)
306 {
307     types::ExceptionDataMap l_errorInfo{
308         {"ErrorType", types::ErrorType::FirmwareError},
309         {"ErrorMsg", i_exception.what()}};
310 
311     try
312     {
313         if (typeid(i_exception) == typeid(DataException))
314         {
315             const DataException& l_ex =
316                 dynamic_cast<const DataException&>(i_exception);
317             l_errorInfo["ErrorType"] = l_ex.getErrorType();
318             l_errorInfo["ErrorMsg"] =
319                 std::string("Data Exception. Reason: ") + i_exception.what();
320         }
321         else if (typeid(i_exception) == typeid(EccException))
322         {
323             const EccException& l_ex =
324                 dynamic_cast<const EccException&>(i_exception);
325             l_errorInfo["ErrorType"] = l_ex.getErrorType();
326             l_errorInfo["ErrorMsg"] =
327                 std::string("Ecc Exception. Reason: ") + i_exception.what();
328         }
329         else if (typeid(i_exception) == typeid(JsonException))
330         {
331             const JsonException& l_ex =
332                 dynamic_cast<const JsonException&>(i_exception);
333             l_errorInfo["ErrorType"] = l_ex.getErrorType();
334             l_errorInfo["ErrorMsg"] =
335                 std::string("Json Exception. Reason: ") + i_exception.what();
336         }
337         else if (typeid(i_exception) == typeid(GpioException))
338         {
339             const GpioException& l_ex =
340                 dynamic_cast<const GpioException&>(i_exception);
341             l_errorInfo["ErrorType"] = l_ex.getErrorType();
342             l_errorInfo["ErrorMsg"] =
343                 std::string("Gpio Exception. Reason: ") + i_exception.what();
344         }
345         else if (typeid(i_exception) == typeid(DbusException))
346         {
347             const DbusException& l_ex =
348                 dynamic_cast<const DbusException&>(i_exception);
349             l_errorInfo["ErrorType"] = l_ex.getErrorType();
350             l_errorInfo["ErrorMsg"] =
351                 std::string("Dbus Exception. Reason: ") + i_exception.what();
352         }
353         else if (typeid(i_exception) == typeid(FirmwareException))
354         {
355             const FirmwareException& l_ex =
356                 dynamic_cast<const FirmwareException&>(i_exception);
357             l_errorInfo["ErrorType"] = l_ex.getErrorType();
358             l_errorInfo["ErrorMsg"] =
359                 std::string("Firmware Exception. Reason: ") +
360                 i_exception.what();
361         }
362         else if (typeid(i_exception) == typeid(EepromException))
363         {
364             const EepromException& l_ex =
365                 dynamic_cast<const EepromException&>(i_exception);
366             l_errorInfo["ErrorType"] = l_ex.getErrorType();
367             l_errorInfo["ErrorMsg"] =
368                 std::string("Eeprom Exception. Reason: ") + i_exception.what();
369         }
370     }
371     catch (const std::exception& l_ex)
372     {
373         logging::logMessage(
374             "Failed to get error info, reason: " + std::string(l_ex.what()));
375     }
376     return l_errorInfo;
377 }
378 
379 types::ErrorType EventLogger::getErrorType(const std::exception& i_exception)
380 {
381     const auto& l_exceptionDataMap = getExceptionData(i_exception);
382 
383     auto l_itrToErrType = l_exceptionDataMap.find("ErrorType");
384     if (l_itrToErrType == l_exceptionDataMap.end())
385     {
386         return types::ErrorType::FirmwareError;
387     }
388 
389     auto l_ptrToErrType =
390         std::get_if<types::ErrorType>(&l_itrToErrType->second);
391     if (!l_ptrToErrType)
392     {
393         return types::ErrorType::FirmwareError;
394     }
395 
396     return *l_ptrToErrType;
397 }
398 
399 std::string EventLogger::getErrorMsg(const std::exception& i_exception)
400 {
401     const auto& l_exceptionDataMap = getExceptionData(i_exception);
402 
403     auto l_itrToErrMsg = l_exceptionDataMap.find("ErrorMsg");
404     if (l_itrToErrMsg == l_exceptionDataMap.end())
405     {
406         return i_exception.what();
407     }
408 
409     auto l_ptrToErrMsg = std::get_if<std::string>(&l_itrToErrMsg->second);
410     if (!l_ptrToErrMsg)
411     {
412         return i_exception.what();
413     }
414 
415     return *l_ptrToErrMsg;
416 }
417 } // namespace vpd
418