xref: /openbmc/openpower-vpd-parser/vpd-manager/src/event_logger.cpp (revision 10a6ac958a6b947e7b10621959119058ce209e2e)
1 #include "config.h"
2 
3 #include "event_logger.hpp"
4 
5 #include "exceptions.hpp"
6 #include "logger.hpp"
7 
8 #include <systemd/sd-bus.h>
9 
10 #include <utility/json_utility.hpp>
11 
12 #include <filesystem>
13 
14 namespace vpd
15 {
16 const std::unordered_map<types::SeverityType, std::string>
17     EventLogger::m_severityMap = {
18         {types::SeverityType::Notice,
19          "xyz.openbmc_project.Logging.Entry.Level.Notice"},
20         {types::SeverityType::Informational,
21          "xyz.openbmc_project.Logging.Entry.Level.Informational"},
22         {types::SeverityType::Debug,
23          "xyz.openbmc_project.Logging.Entry.Level.Debug"},
24         {types::SeverityType::Warning,
25          "xyz.openbmc_project.Logging.Entry.Level.Warning"},
26         {types::SeverityType::Critical,
27          "xyz.openbmc_project.Logging.Entry.Level.Critical"},
28         {types::SeverityType::Emergency,
29          "xyz.openbmc_project.Logging.Entry.Level.Emergency"},
30         {types::SeverityType::Alert,
31          "xyz.openbmc_project.Logging.Entry.Level.Alert"},
32         {types::SeverityType::Error,
33          "xyz.openbmc_project.Logging.Entry.Level.Error"}};
34 
35 const std::unordered_map<types::ErrorType, std::string>
36     EventLogger::m_errorMsgMap = {
37         {types::ErrorType::DefaultValue, "com.ibm.VPD.Error.DefaultValue"},
38         {types::ErrorType::UndefinedError, "com.ibm.VPD.Error.UndefinedError"},
39         {types::ErrorType::InvalidVpdMessage, "com.ibm.VPD.Error.InvalidVPD"},
40         {types::ErrorType::VpdMismatch, "com.ibm.VPD.Error.Mismatch"},
41         {types::ErrorType::InvalidEeprom,
42          "com.ibm.VPD.Error.InvalidEepromPath"},
43         {types::ErrorType::EccCheckFailed, "com.ibm.VPD.Error.EccCheckFailed"},
44         {types::ErrorType::JsonFailure, "com.ibm.VPD.Error.InvalidJson"},
45         {types::ErrorType::DbusFailure, "com.ibm.VPD.Error.DbusFailure"},
46         {types::ErrorType::InvalidSystem,
47          "com.ibm.VPD.Error.UnknownSystemType"},
48         {types::ErrorType::EssentialFru,
49          "com.ibm.VPD.Error.RequiredFRUMissing"},
50         {types::ErrorType::GpioError, "com.ibm.VPD.Error.GPIOError"},
51         {types::ErrorType::InternalFailure,
52          "xyz.openbmc_project.Common.Error.InternalFailure"},
53         {types::ErrorType::FruMissing, "com.ibm.VPD.Error.RequiredFRUMissing"},
54         {types::ErrorType::SystemTypeMismatch,
55          "com.ibm.VPD.Error.SystemTypeMismatch"},
56         {types::ErrorType::UnknownSystemSettings,
57          "com.ibm.VPD.Error.UnknownSystemSettings"},
58         {types::ErrorType::FirmwareError, "com.ibm.VPD.Error.FirmwareError"},
59         {types::ErrorType::VpdParseError, "com.ibm.VPD.Error.VPDParseError"}};
60 
61 const std::unordered_map<types::CalloutPriority, std::string>
62     EventLogger::m_priorityMap = {
63         {types::CalloutPriority::High, "H"},
64         {types::CalloutPriority::Medium, "M"},
65         {types::CalloutPriority::MediumGroupA, "A"},
66         {types::CalloutPriority::MediumGroupB, "B"},
67         {types::CalloutPriority::MediumGroupC, "C"},
68         {types::CalloutPriority::Low, "L"}};
69 
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)70 void EventLogger::createAsyncPelWithInventoryCallout(
71     const types::ErrorType& i_errorType, const types::SeverityType& i_severity,
72     const std::vector<types::InventoryCalloutData>& i_callouts,
73     const std::string& i_fileName, const std::string& i_funcName,
74     const uint8_t i_internalRc, const std::string& i_description,
75     const std::optional<std::string> i_userData1,
76     const std::optional<std::string> i_userData2,
77     const std::optional<std::string> i_symFru,
78     const std::optional<std::string> i_procedure)
79 {
80     (void)i_symFru;
81     (void)i_procedure;
82 
83     try
84     {
85         if (i_callouts.empty())
86         {
87             logging::logMessage("Callout information is missing to create PEL");
88             // TODO: Revisit this instead of simpley returning.
89             return;
90         }
91 
92         if (m_errorMsgMap.find(i_errorType) == m_errorMsgMap.end())
93         {
94             throw std::runtime_error(
95                 "Error type not found in the error message map to create PEL");
96             // TODO: Need to handle, instead of throwing exception. Create
97             // default message in message_registry.json.
98         }
99 
100         const std::string& l_message = m_errorMsgMap.at(i_errorType);
101 
102         const std::string& l_severity =
103             (m_severityMap.find(i_severity) != m_severityMap.end()
104                  ? m_severityMap.at(i_severity)
105                  : m_severityMap.at(types::SeverityType::Informational));
106 
107         std::string l_description =
108             (!i_description.empty() ? i_description : "VPD generic error");
109 
110         std::string l_userData1 = (i_userData1) ? (*i_userData1) : "";
111 
112         std::string l_userData2 = (i_userData2) ? (*i_userData2) : "";
113 
114         const types::InventoryCalloutData& l_invCallout = i_callouts[0];
115         // TODO: Need to handle multiple inventory path callout's, when multiple
116         // callout's is supported by "Logging" service.
117 
118         const types::CalloutPriority& l_priorityEnum = get<1>(l_invCallout);
119 
120         const std::string& l_priority =
121             (m_priorityMap.find(l_priorityEnum) != m_priorityMap.end()
122                  ? m_priorityMap.at(l_priorityEnum)
123                  : m_priorityMap.at(types::CalloutPriority::Low));
124 
125         sd_bus* l_sdBus = nullptr;
126         sd_bus_default(&l_sdBus);
127 
128         const uint8_t l_additionalDataCount = 8;
129         auto l_rc = sd_bus_call_method_async(
130             l_sdBus, NULL, constants::eventLoggingServiceName,
131             constants::eventLoggingObjectPath, constants::eventLoggingInterface,
132             "Create", NULL, NULL, "ssa{ss}", l_message.c_str(),
133             l_severity.c_str(), l_additionalDataCount, "FileName",
134             i_fileName.c_str(), "FunctionName", i_funcName.c_str(),
135             "InternalRc", std::to_string(i_internalRc).c_str(), "DESCRIPTION",
136             l_description.c_str(), "UserData1", l_userData1.c_str(),
137             "UserData2", l_userData2.c_str(), "CALLOUT_INVENTORY_PATH",
138             get<0>(l_invCallout).c_str(), "CALLOUT_PRIORITY",
139             l_priority.c_str());
140 
141         if (l_rc < 0)
142         {
143             logging::logMessage(
144                 "Error calling sd_bus_call_method_async, Message = " +
145                 std::string(strerror(-l_rc)));
146         }
147     }
148     catch (const std::exception& l_ex)
149     {
150         logging::logMessage(
151             "Create PEL failed with error: " + std::string(l_ex.what()));
152     }
153 }
154 
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)155 void EventLogger::createAsyncPelWithI2cDeviceCallout(
156     const types::ErrorType i_errorType, const types::SeverityType i_severity,
157     const std::vector<types::DeviceCalloutData>& i_callouts,
158     const std::string& i_fileName, const std::string& i_funcName,
159     const uint8_t i_internalRc,
160     const std::optional<std::pair<std::string, std::string>> i_userData1,
161     const std::optional<std::pair<std::string, std::string>> i_userData2)
162 {
163     // TODO, implementation needs to be added.
164     (void)i_errorType;
165     (void)i_severity;
166     (void)i_callouts;
167     (void)i_fileName;
168     (void)i_funcName;
169     (void)i_internalRc;
170     (void)i_userData1;
171     (void)i_userData2;
172 }
173 
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)174 void EventLogger::createAsyncPelWithI2cBusCallout(
175     const types::ErrorType i_errorType, const types::SeverityType i_severity,
176     const std::vector<types::I2cBusCalloutData>& i_callouts,
177     const std::string& i_fileName, const std::string& i_funcName,
178     const uint8_t i_internalRc,
179     const std::optional<std::pair<std::string, std::string>> i_userData1,
180     const std::optional<std::pair<std::string, std::string>> i_userData2)
181 {
182     // TODO, implementation needs to be added.
183     (void)i_errorType;
184     (void)i_severity;
185     (void)i_callouts;
186     (void)i_fileName;
187     (void)i_funcName;
188     (void)i_internalRc;
189     (void)i_userData1;
190     (void)i_userData2;
191 }
192 
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)193 void EventLogger::createAsyncPel(
194     const types::ErrorType& i_errorType, const types::SeverityType& i_severity,
195     const std::string& i_fileName, const std::string& i_funcName,
196     const uint8_t i_internalRc, const std::string& i_description,
197     const std::optional<std::string> i_userData1,
198     const std::optional<std::string> i_userData2,
199     const std::optional<std::string> i_symFru,
200     const std::optional<std::string> i_procedure)
201 {
202     (void)i_symFru;
203     (void)i_procedure;
204     try
205     {
206         if (m_errorMsgMap.find(i_errorType) == m_errorMsgMap.end())
207         {
208             throw std::runtime_error("Unsupported error type received");
209             // TODO: Need to handle, instead of throwing an exception.
210         }
211 
212         const std::string& l_message = m_errorMsgMap.at(i_errorType);
213 
214         const std::string& l_severity =
215             (m_severityMap.find(i_severity) != m_severityMap.end()
216                  ? m_severityMap.at(i_severity)
217                  : m_severityMap.at(types::SeverityType::Informational));
218 
219         const std::string l_description =
220             ((!i_description.empty() ? i_description : "VPD generic error"));
221 
222         const std::string l_userData1 = ((i_userData1) ? (*i_userData1) : "");
223 
224         const std::string l_userData2 = ((i_userData2) ? (*i_userData2) : "");
225 
226         sd_bus* l_sdBus = nullptr;
227         sd_bus_default(&l_sdBus);
228 
229         // VALUE_6 represents the additional data pair count passing to create
230         // PEL. If there any change in additional data, we need to pass the
231         // correct number.
232         auto l_rc = sd_bus_call_method_async(
233             l_sdBus, NULL, constants::eventLoggingServiceName,
234             constants::eventLoggingObjectPath, constants::eventLoggingInterface,
235             "Create", NULL, NULL, "ssa{ss}", l_message.c_str(),
236             l_severity.c_str(), constants::VALUE_6, "FileName",
237             i_fileName.c_str(), "FunctionName", i_funcName.c_str(),
238             "InternalRc", std::to_string(i_internalRc).c_str(), "DESCRIPTION",
239             l_description.c_str(), "UserData1", l_userData1.c_str(),
240             "UserData2", l_userData2.c_str());
241 
242         if (l_rc < 0)
243         {
244             logging::logMessage(
245                 "Error calling sd_bus_call_method_async, Message = " +
246                 std::string(strerror(-l_rc)));
247         }
248     }
249     catch (const sdbusplus::exception::SdBusError& l_ex)
250     {
251         logging::logMessage("Async PEL creation failed with an error: " +
252                             std::string(l_ex.what()));
253     }
254 }
255 
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)256 void EventLogger::createSyncPel(
257     const types::ErrorType& i_errorType, const types::SeverityType& i_severity,
258     const std::string& i_fileName, const std::string& i_funcName,
259     const uint8_t i_internalRc, const std::string& i_description,
260     const std::optional<std::string> i_userData1,
261     const std::optional<std::string> i_userData2,
262     const std::optional<std::string> i_symFru,
263     const std::optional<std::string> i_procedure)
264 {
265     (void)i_symFru;
266     (void)i_procedure;
267     try
268     {
269         if (m_errorMsgMap.find(i_errorType) == m_errorMsgMap.end())
270         {
271             throw std::runtime_error("Unsupported error type received");
272             // TODO: Need to handle, instead of throwing an exception.
273         }
274 
275         const std::string& l_message = m_errorMsgMap.at(i_errorType);
276 
277         const std::string& l_severity =
278             (m_severityMap.find(i_severity) != m_severityMap.end()
279                  ? m_severityMap.at(i_severity)
280                  : m_severityMap.at(types::SeverityType::Informational));
281 
282         const std::string l_description =
283             ((!i_description.empty() ? i_description : "VPD generic error"));
284 
285         const std::string l_userData1 = ((i_userData1) ? (*i_userData1) : "");
286 
287         const std::string l_userData2 = ((i_userData2) ? (*i_userData2) : "");
288 
289         std::map<std::string, std::string> l_additionalData{
290             {"FileName", i_fileName},
291             {"FunctionName", i_funcName},
292             {"DESCRIPTION", l_description},
293             {"InteranlRc", std::to_string(i_internalRc)},
294             {"UserData1", l_userData1.c_str()},
295             {"UserData2", l_userData2.c_str()}};
296 
297         auto l_bus = sdbusplus::bus::new_default();
298         auto l_method =
299             l_bus.new_method_call(constants::eventLoggingServiceName,
300                                   constants::eventLoggingObjectPath,
301                                   constants::eventLoggingInterface, "Create");
302         l_method.append(l_message, l_severity, l_additionalData);
303         l_bus.call(l_method);
304     }
305     catch (const sdbusplus::exception::SdBusError& l_ex)
306     {
307         logging::logMessage("Sync PEL creation failed with an error: " +
308                             std::string(l_ex.what()));
309     }
310 }
311 
createSyncPelWithInvCallOut(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::vector<types::InventoryCalloutData> & i_callouts,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)312 void EventLogger::createSyncPelWithInvCallOut(
313     const types::ErrorType& i_errorType, const types::SeverityType& i_severity,
314     const std::string& i_fileName, const std::string& i_funcName,
315     const uint8_t i_internalRc, const std::string& i_description,
316     const std::vector<types::InventoryCalloutData>& i_callouts,
317     const std::optional<std::string> i_userData1,
318     const std::optional<std::string> i_userData2,
319     [[maybe_unused]] const std::optional<std::string> i_symFru,
320     [[maybe_unused]] const std::optional<std::string> i_procedure)
321 {
322     try
323     {
324         if (i_callouts.empty())
325         {
326             createSyncPel(i_errorType, i_severity, i_fileName, i_funcName,
327                           i_internalRc, i_description, i_userData1, i_userData2,
328                           i_symFru, i_procedure);
329             logging::logMessage(
330                 "Callout list is empty, creating PEL without call out");
331             return;
332         }
333 
334         if (m_errorMsgMap.find(i_errorType) == m_errorMsgMap.end())
335         {
336             throw std::runtime_error("Unsupported error type received");
337         }
338 
339         // Path to hold callout inventory path.
340         std::string l_calloutInvPath;
341 
342         // check if callout path is a valid inventory path. if not, get the JSON
343         // object to get inventory path.
344         if (std::get<0>(i_callouts[0])
345                 .compare(constants::VALUE_0, strlen(constants::pimPath),
346                          constants::pimPath) != constants::STR_CMP_SUCCESS)
347         {
348             std::error_code l_ec;
349             // implies json dependent execution.
350             if (std::filesystem::exists(INVENTORY_JSON_SYM_LINK, l_ec))
351             {
352                 if (!l_ec)
353                 {
354                     l_calloutInvPath = jsonUtility::getInventoryObjPathFromJson(
355                         jsonUtility::getParsedJson(INVENTORY_JSON_SYM_LINK),
356                         std::get<0>(i_callouts[0]));
357                 }
358                 else
359                 {
360                     logging::logMessage(
361                         "Error finding symlink. Continue with given path");
362                 }
363             }
364         }
365 
366         if (l_calloutInvPath.empty())
367         {
368             l_calloutInvPath = std::get<0>(i_callouts[0]);
369         }
370 
371         const std::map<std::string, std::string> l_additionalData{
372             {"FileName", i_fileName},
373             {"FunctionName", i_funcName},
374             {"DESCRIPTION",
375              (!i_description.empty() ? i_description : "VPD generic error")},
376             {"CALLOUT_INVENTORY_PATH", l_calloutInvPath},
377             {"InteranlRc", std::to_string(i_internalRc)},
378             {"UserData1", ((i_userData1) ? (*i_userData1) : "").c_str()},
379             {"UserData2", ((i_userData2) ? (*i_userData2) : "").c_str()}};
380 
381         const std::string& l_severity =
382             (m_severityMap.find(i_severity) != m_severityMap.end()
383                  ? m_severityMap.at(i_severity)
384                  : m_severityMap.at(types::SeverityType::Informational));
385 
386         auto l_bus = sdbusplus::bus::new_default();
387         auto l_method =
388             l_bus.new_method_call(constants::eventLoggingServiceName,
389                                   constants::eventLoggingObjectPath,
390                                   constants::eventLoggingInterface, "Create");
391         l_method.append(m_errorMsgMap.at(i_errorType), l_severity,
392                         l_additionalData);
393         l_bus.call(l_method);
394     }
395     catch (const std::exception& l_ex)
396     {
397         logging::logMessage(
398             "Sync PEL creation with inventory path failed with error: " +
399             std::string(l_ex.what()));
400     }
401 }
402 
getExceptionData(const std::exception & i_exception)403 types::ExceptionDataMap EventLogger::getExceptionData(
404     const std::exception& i_exception)
405 {
406     types::ExceptionDataMap l_errorInfo{
407         {"ErrorType", types::ErrorType::UndefinedError},
408         {"ErrorMsg", i_exception.what()}};
409 
410     try
411     {
412         if (typeid(i_exception) == typeid(DataException))
413         {
414             const DataException& l_ex =
415                 dynamic_cast<const DataException&>(i_exception);
416             l_errorInfo["ErrorType"] = l_ex.getErrorType();
417             l_errorInfo["ErrorMsg"] =
418                 std::string("Data Exception. Reason: ") + i_exception.what();
419         }
420         else if (typeid(i_exception) == typeid(EccException))
421         {
422             const EccException& l_ex =
423                 dynamic_cast<const EccException&>(i_exception);
424             l_errorInfo["ErrorType"] = l_ex.getErrorType();
425             l_errorInfo["ErrorMsg"] =
426                 std::string("Ecc Exception. Reason: ") + i_exception.what();
427         }
428         else if (typeid(i_exception) == typeid(JsonException))
429         {
430             const JsonException& l_ex =
431                 dynamic_cast<const JsonException&>(i_exception);
432             l_errorInfo["ErrorType"] = l_ex.getErrorType();
433             l_errorInfo["ErrorMsg"] =
434                 std::string("Json Exception. Reason: ") + i_exception.what();
435         }
436         else if (typeid(i_exception) == typeid(GpioException))
437         {
438             const GpioException& l_ex =
439                 dynamic_cast<const GpioException&>(i_exception);
440             l_errorInfo["ErrorType"] = l_ex.getErrorType();
441             l_errorInfo["ErrorMsg"] =
442                 std::string("Gpio Exception. Reason: ") + i_exception.what();
443         }
444         else if (typeid(i_exception) == typeid(DbusException))
445         {
446             const DbusException& l_ex =
447                 dynamic_cast<const DbusException&>(i_exception);
448             l_errorInfo["ErrorType"] = l_ex.getErrorType();
449             l_errorInfo["ErrorMsg"] =
450                 std::string("Dbus Exception. Reason: ") + i_exception.what();
451         }
452         else if (typeid(i_exception) == typeid(FirmwareException))
453         {
454             const FirmwareException& l_ex =
455                 dynamic_cast<const FirmwareException&>(i_exception);
456             l_errorInfo["ErrorType"] = l_ex.getErrorType();
457             l_errorInfo["ErrorMsg"] =
458                 std::string("Firmware Exception. Reason: ") +
459                 i_exception.what();
460         }
461         else if (typeid(i_exception) == typeid(EepromException))
462         {
463             const EepromException& l_ex =
464                 dynamic_cast<const EepromException&>(i_exception);
465             l_errorInfo["ErrorType"] = l_ex.getErrorType();
466             l_errorInfo["ErrorMsg"] =
467                 std::string("Eeprom Exception. Reason: ") + i_exception.what();
468         }
469         else if (typeid(i_exception) == typeid(std::runtime_error))
470         {
471             // Since it is a standard exception no casting is required and error
472             // type is hardcoded.
473             l_errorInfo["ErrorType"] = types::ErrorType::FirmwareError;
474             l_errorInfo["ErrorMsg"] =
475                 std::string("Eeprom Exception. Reason: ") + i_exception.what();
476         }
477     }
478     catch (const std::exception& l_ex)
479     {
480         logging::logMessage(
481             "Failed to get error info, reason: " + std::string(l_ex.what()));
482     }
483     return l_errorInfo;
484 }
485 
getErrorType(const std::exception & i_exception)486 types::ErrorType EventLogger::getErrorType(const std::exception& i_exception)
487 {
488     const auto& l_exceptionDataMap = getExceptionData(i_exception);
489 
490     auto l_itrToErrType = l_exceptionDataMap.find("ErrorType");
491     if (l_itrToErrType == l_exceptionDataMap.end())
492     {
493         return types::ErrorType::UndefinedError;
494     }
495 
496     auto l_ptrToErrType =
497         std::get_if<types::ErrorType>(&l_itrToErrType->second);
498     if (!l_ptrToErrType)
499     {
500         return types::ErrorType::UndefinedError;
501     }
502 
503     return *l_ptrToErrType;
504 }
505 
getErrorMsg(const std::exception & i_exception)506 std::string EventLogger::getErrorMsg(const std::exception& i_exception)
507 {
508     const auto& l_exceptionDataMap = getExceptionData(i_exception);
509 
510     auto l_itrToErrMsg = l_exceptionDataMap.find("ErrorMsg");
511     if (l_itrToErrMsg == l_exceptionDataMap.end())
512     {
513         return i_exception.what();
514     }
515 
516     auto l_ptrToErrMsg = std::get_if<std::string>(&l_itrToErrMsg->second);
517     if (!l_ptrToErrMsg)
518     {
519         return i_exception.what();
520     }
521 
522     return *l_ptrToErrMsg;
523 }
524 
getErrorTypeString(const types::ErrorType & i_errorType)525 std::string EventLogger::getErrorTypeString(
526     const types::ErrorType& i_errorType) noexcept
527 {
528     const auto l_entry = m_errorMsgMap.find(i_errorType);
529     return (l_entry != m_errorMsgMap.end()
530                 ? l_entry->second
531                 : m_errorMsgMap.at(types::ErrorType::UndefinedError));
532 }
533 } // namespace vpd
534