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