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