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