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