Better exception handling in the analyzer
Give the ability to continue creating a PEL with FFDC if there is an
exception in the analysis portion of the analyzer.
Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
Change-Id: I2de281a7c974cfc80779a861a12cb2b9c99e0491
diff --git a/analyzer/analyzer_main.cpp b/analyzer/analyzer_main.cpp
index 25f7005..b89124e 100644
--- a/analyzer/analyzer_main.cpp
+++ b/analyzer/analyzer_main.cpp
@@ -157,13 +157,27 @@
{
if (attnFound)
{
- // Resolve the root cause attention.
- RasDataParser rasData{};
- rasData.getResolution(rootCause)->resolve(servData);
+ try
+ {
+ // Resolve the root cause attention.
+ RasDataParser rasData{};
+ rasData.getResolution(rootCause)->resolve(servData);
+ }
+ catch (const std::exception& e)
+ {
+ trace::err("Exception caught during root cause analysis");
+ trace::err(e.what());
+
+ // We'll still want to create a PEL for the FFDC, but
+ // since the analysis failed, we need to callout Level 2
+ // Support.
+ servData.calloutProcedure(callout::Procedure::NEXTLVL,
+ callout::Priority::HIGH);
+ }
}
else
{
- // Analysis failed so apply the Level 2 Support resolution.
+ // Analysis failed so callout the Level 2 Support.
servData.calloutProcedure(callout::Procedure::NEXTLVL,
callout::Priority::HIGH);
}
diff --git a/analyzer/plugins/plugin.hpp b/analyzer/plugins/plugin.hpp
index c5db3f0..501005c 100644
--- a/analyzer/plugins/plugin.hpp
+++ b/analyzer/plugins/plugin.hpp
@@ -4,6 +4,7 @@
#include <analyzer/service_data.hpp>
#include <hei_chip.hpp>
+#include <util/trace.hpp>
#include <functional>
#include <map>
@@ -107,7 +108,20 @@
PluginFunction get(libhei::ChipType_t i_type,
const std::string& i_name) const
{
- return iv_map.at(i_type).at(i_name);
+ PluginFunction func;
+
+ try
+ {
+ func = iv_map.at(i_type).at(i_name);
+ }
+ catch (const std::out_of_range& e)
+ {
+ trace::err("Plugin not defined: i_type=0x%08x i_name=%s", i_type,
+ i_name.c_str());
+ throw; // caught later downstream
+ }
+
+ return func;
}
};
diff --git a/analyzer/ras-data/ras-data-parser.cpp b/analyzer/ras-data/ras-data-parser.cpp
index 861283b..da8fec0 100644
--- a/analyzer/ras-data/ras-data-parser.cpp
+++ b/analyzer/ras-data/ras-data-parser.cpp
@@ -16,11 +16,34 @@
std::shared_ptr<Resolution>
RasDataParser::getResolution(const libhei::Signature& i_signature)
{
- const auto data = iv_dataFiles.at(i_signature.getChip().getType());
+ nlohmann::json data;
+
+ try
+ {
+ data = iv_dataFiles.at(i_signature.getChip().getType());
+ }
+ catch (const std::out_of_range& e)
+ {
+ trace::err("No RAS data defined for chip type: 0x%08x",
+ i_signature.getChip().getType());
+ throw; // caught later downstream
+ }
const auto action = parseSignature(data, i_signature);
- return parseAction(data, action);
+ std::shared_ptr<Resolution> resolution;
+
+ try
+ {
+ resolution = parseAction(data, action);
+ }
+ catch (...)
+ {
+ trace::err("Unable to get resolution for action: %s", action.c_str());
+ throw; // caught later downstream
+ }
+
+ return resolution;
}
//------------------------------------------------------------------------------
@@ -46,15 +69,23 @@
std::ifstream file{path};
assert(file.good()); // The file must be readable.
- // Parse the JSON.
- auto schema = nlohmann::json::parse(file);
+ try
+ {
+ // Parse the JSON.
+ auto schema = nlohmann::json::parse(file);
- // Get the schema version.
- auto version = schema.at("version").get<unsigned int>();
+ // Get the schema version.
+ auto version = schema.at("version").get<unsigned int>();
- // Keep track of the schemas.
- auto ret = schemaFiles.emplace(version, schema);
- assert(ret.second); // Should not have duplicate entries
+ // Keep track of the schemas.
+ auto ret = schemaFiles.emplace(version, schema);
+ assert(ret.second); // Should not have duplicate entries
+ }
+ catch (...)
+ {
+ trace::err("Failed to parse file: %s", path.string().c_str());
+ throw; // caught later downstream
+ }
}
// Get the RAS data files from the package `data` subdirectory.
@@ -72,27 +103,35 @@
std::ifstream file{path};
assert(file.good()); // The file must be readable.
- // Parse the JSON.
- const auto data = nlohmann::json::parse(file);
+ try
+ {
+ // Parse the JSON.
+ const auto data = nlohmann::json::parse(file);
- // Get the data version.
- auto version = data.at("version").get<unsigned int>();
+ // Get the data version.
+ auto version = data.at("version").get<unsigned int>();
- // Get the schema for this file.
- auto schema = schemaFiles.at(version);
+ // Get the schema for this file.
+ auto schema = schemaFiles.at(version);
- // Validate the data against the schema.
- assert(util::validateJson(schema, data));
+ // Validate the data against the schema.
+ assert(util::validateJson(schema, data));
- // Get the chip model/EC level from the data. The value is currently
- // stored as a string representation of the hex value. So it will have
- // to be converted to an integer.
- libhei::ChipType_t chipType =
- std::stoul(data.at("model_ec").get<std::string>(), 0, 16);
+ // Get the chip model/EC level from the data. The value is currently
+ // stored as a string representation of the hex value. So it will
+ // have to be converted to an integer.
+ libhei::ChipType_t chipType =
+ std::stoul(data.at("model_ec").get<std::string>(), 0, 16);
- // So far, so good. Add the entry.
- auto ret = iv_dataFiles.emplace(chipType, data);
- assert(ret.second); // Should not have duplicate entries
+ // So far, so good. Add the entry.
+ auto ret = iv_dataFiles.emplace(chipType, data);
+ assert(ret.second); // Should not have duplicate entries
+ }
+ catch (...)
+ {
+ trace::err("Failed to parse file: %s", path.string().c_str());
+ throw; // caught later downstream
+ }
}
}
@@ -112,8 +151,22 @@
sprintf(buf, "%02x", i_signature.getInstance());
std::string inst{buf};
+ std::string action;
+
+ try
+ {
+ action =
+ i_data.at("signatures").at(id).at(bit).at(inst).get<std::string>();
+ }
+ catch (const std::out_of_range& e)
+ {
+ trace::err("No action defined for signature: %s %s %s", id.c_str(),
+ bit.c_str(), inst.c_str());
+ throw; // caught later downstream
+ }
+
// Return the action.
- return i_data.at("signatures").at(id).at(bit).at(inst).get<std::string>();
+ return action;
}
//------------------------------------------------------------------------------
diff --git a/analyzer/service_data.cpp b/analyzer/service_data.cpp
index 2a7d5f5..28ef329 100644
--- a/analyzer/service_data.cpp
+++ b/analyzer/service_data.cpp
@@ -166,9 +166,20 @@
// A map to determine the priority order. All of the medium priorities,
// including the medium group priorities, are all the same level.
+ // clang-format off
static const std::map<std::string, unsigned int> m = {
- {"H", 3}, {"M", 2}, {"A", 2}, {"B", 2}, {"C", 2}, {"L", 1},
+ {callout::getString(callout::Priority::HIGH), 3},
+ {callout::getString(callout::Priority::MED), 2},
+ {callout::getString(callout::Priority::MED_A), 2},
+ {callout::getString(callout::Priority::MED_B), 2},
+ {callout::getString(callout::Priority::MED_C), 2},
+ {callout::getString(callout::Priority::LOW), 1},
};
+ // clang-format on
+
+ // The new callout must contain a valid priority.
+ assert(i_callout.contains("Priority") &&
+ m.contains(i_callout.at("Priority")));
bool addCallout = true;