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