summaryrefslogtreecommitdiffstats
path: root/extensions/openpower-pels
diff options
context:
space:
mode:
authorMatt Spinler <spinler@us.ibm.com>2019-09-19 15:33:52 -0500
committerMatt Spinler <spinler@us.ibm.com>2019-10-09 13:11:51 +0000
commit367144cfa0eb857f4cb9ba786f43933469e19e34 (patch)
tree8291c90a44b4ec2b321c3ca2c6e5ed13e21307f9 /extensions/openpower-pels
parent835a86938f3cf59fbdcd25835b48e6cdb1e6552b (diff)
downloadphosphor-logging-367144cfa0eb857f4cb9ba786f43933469e19e34.tar.gz
phosphor-logging-367144cfa0eb857f4cb9ba786f43933469e19e34.zip
PEL: Find an entry in the message registry JSON
The message registry is a JSON file that holds data required to create a PEL out of an OpenBMC event log. It includes fields like 'subsystem', 'event type', 'action flags', 'SRC reason code', etc. Many fields in the message registry are optional, and a very minimal entry make look like: { "Name": "xyz.openbmc_project.Power.Error.Fault", "Subsystem": "power_supply", "ActionFlags": ["service_action", "report"], "SRC": { "ReasonCode": "0x2030" } } This commit adds support to look up a message registry entry based on an OpenBMC event log's 'Message' property (i.e. xyz.openbmc_project.Power.Error.Fault) and then fill in a structure with the fields found. Future commits will fill in the SRC related fields, as well as actually create the PEL. The message registry file can be found on the BMC at: /usr/share/phosphor-logging/pels/message_registry.json. For testing, users can put their own message_registry.json in /etc/phosphor-logging, and that will take precedence. Signed-off-by: Matt Spinler <spinler@us.ibm.com> Change-Id: Ie4195ed7e58ab6a231271f6b295e63b1d0a4cd78
Diffstat (limited to 'extensions/openpower-pels')
-rw-r--r--extensions/openpower-pels/manager.cpp1
-rw-r--r--extensions/openpower-pels/manager.hpp18
-rw-r--r--extensions/openpower-pels/openpower-pels.mk1
-rw-r--r--extensions/openpower-pels/paths.cpp6
-rw-r--r--extensions/openpower-pels/paths.hpp4
-rw-r--r--extensions/openpower-pels/registry.cpp195
-rw-r--r--extensions/openpower-pels/registry.hpp179
7 files changed, 397 insertions, 7 deletions
diff --git a/extensions/openpower-pels/manager.cpp b/extensions/openpower-pels/manager.cpp
index ef071bd..fd3670c 100644
--- a/extensions/openpower-pels/manager.cpp
+++ b/extensions/openpower-pels/manager.cpp
@@ -110,6 +110,7 @@ void Manager::createPEL(const std::string& message, uint32_t obmcLogID,
const std::vector<std::string>& additionalData,
const std::vector<std::string>& associations)
{
+ // TODO: look up the error in _registry and create a PEL
}
} // namespace pels
diff --git a/extensions/openpower-pels/manager.hpp b/extensions/openpower-pels/manager.hpp
index 49ac8bf..5f092f4 100644
--- a/extensions/openpower-pels/manager.hpp
+++ b/extensions/openpower-pels/manager.hpp
@@ -3,6 +3,7 @@
#include "data_interface.hpp"
#include "log_manager.hpp"
#include "paths.hpp"
+#include "registry.hpp"
#include "repository.hpp"
namespace openpower
@@ -10,8 +11,6 @@ namespace openpower
namespace pels
{
-using namespace phosphor::logging;
-
/**
* @brief PEL manager object
*/
@@ -33,7 +32,9 @@ class Manager
explicit Manager(phosphor::logging::internal::Manager& logManager,
std::unique_ptr<DataInterfaceBase>&& dataIface) :
_logManager(logManager),
- _repo(getPELRepoPath()), _dataIface(std::move(dataIface))
+ _repo(getPELRepoPath()),
+ _registry(getMessageRegistryPath() / message::registryFileName),
+ _dataIface(std::move(dataIface))
{
}
@@ -50,7 +51,7 @@ class Manager
* @param[in] associations - the Associations property
*/
void create(const std::string& message, uint32_t obmcLogID,
- uint64_t timestamp, Entry::Level severity,
+ uint64_t timestamp, phosphor::logging::Entry::Level severity,
const std::vector<std::string>& additionalData,
const std::vector<std::string>& associations);
@@ -93,14 +94,14 @@ class Manager
* @param[in] associations - The associations property
*/
void createPEL(const std::string& message, uint32_t obmcLogID,
- uint64_t timestamp, Entry::Level severity,
+ uint64_t timestamp, phosphor::logging::Entry::Level severity,
const std::vector<std::string>& additionalData,
const std::vector<std::string>& associations);
/**
* @brief Reference to phosphor-logging's Manager class
*/
- internal::Manager& _logManager;
+ phosphor::logging::internal::Manager& _logManager;
/**
* @brief The PEL repository object
@@ -108,6 +109,11 @@ class Manager
Repository _repo;
/**
+ * @brief The PEL message registry object
+ */
+ message::Registry _registry;
+
+ /**
* @brief The API the PEL sections use to gather data
*/
std::unique_ptr<DataInterfaceBase> _dataIface;
diff --git a/extensions/openpower-pels/openpower-pels.mk b/extensions/openpower-pels/openpower-pels.mk
index 14e1966..aa69a2e 100644
--- a/extensions/openpower-pels/openpower-pels.mk
+++ b/extensions/openpower-pels/openpower-pels.mk
@@ -10,5 +10,6 @@ phosphor_log_manager_SOURCES += \
extensions/openpower-pels/pel.cpp \
extensions/openpower-pels/pel_values.cpp \
extensions/openpower-pels/private_header.cpp \
+ extensions/openpower-pels/registry.cpp \
extensions/openpower-pels/repository.cpp \
extensions/openpower-pels/user_header.cpp
diff --git a/extensions/openpower-pels/paths.cpp b/extensions/openpower-pels/paths.cpp
index 27e7373..b8ccfe8 100644
--- a/extensions/openpower-pels/paths.cpp
+++ b/extensions/openpower-pels/paths.cpp
@@ -25,6 +25,10 @@ fs::path getPELRepoPath()
return repoPath;
}
-} // namespace pels
+fs::path getMessageRegistryPath()
+{
+ return std::filesystem::path{"/usr/share/phosphor-logging/pels"};
+}
+} // namespace pels
} // namespace openpower
diff --git a/extensions/openpower-pels/paths.hpp b/extensions/openpower-pels/paths.hpp
index 64566d2..91d8c5f 100644
--- a/extensions/openpower-pels/paths.hpp
+++ b/extensions/openpower-pels/paths.hpp
@@ -16,5 +16,9 @@ std::filesystem::path getPELIDFile();
*/
std::filesystem::path getPELRepoPath();
+/**
+ * @brief Returns the path to the message registry JSON file
+ */
+std::filesystem::path getMessageRegistryPath();
} // namespace pels
} // namespace openpower
diff --git a/extensions/openpower-pels/registry.cpp b/extensions/openpower-pels/registry.cpp
new file mode 100644
index 0000000..42ced0c
--- /dev/null
+++ b/extensions/openpower-pels/registry.cpp
@@ -0,0 +1,195 @@
+#include "registry.hpp"
+
+#include "pel_types.hpp"
+#include "pel_values.hpp"
+
+#include <fstream>
+#include <phosphor-logging/log.hpp>
+
+namespace openpower
+{
+namespace pels
+{
+namespace message
+{
+
+namespace pv = pel_values;
+namespace fs = std::filesystem;
+using namespace phosphor::logging;
+
+constexpr auto debugFilePath = "/etc/phosphor-logging/";
+
+namespace helper
+{
+
+uint8_t getSubsystem(const std::string& subsystemName)
+{
+ // Get the actual value to use in the PEL for the string name
+ auto ss = pv::findByName(subsystemName, pv::subsystemValues);
+ if (ss == pv::subsystemValues.end())
+ {
+ // Schema validation should be catching this.
+ log<level::ERR>("Invalid subsystem name used in message registry",
+ entry("SUBSYSTEM=%s", subsystemName.c_str()));
+
+ throw std::runtime_error("Invalid subsystem used in message registry");
+ }
+
+ return std::get<pv::fieldValuePos>(*ss);
+}
+
+uint8_t getSeverity(const std::string& severityName)
+{
+ auto s = pv::findByName(severityName, pv::severityValues);
+ if (s == pv::severityValues.end())
+ {
+ // Schema validation should be catching this.
+ log<level::ERR>("Invalid severity name used in message registry",
+ entry("SEVERITY=%s", severityName.c_str()));
+
+ throw std::runtime_error("Invalid severity used in message registry");
+ }
+
+ return std::get<pv::fieldValuePos>(*s);
+}
+
+uint16_t getActionFlags(const std::vector<std::string>& flags)
+{
+ uint16_t actionFlags = 0;
+
+ // Make the bitmask based on the array of flag names
+ for (const auto& flag : flags)
+ {
+ auto s = pv::findByName(flag, pv::actionFlagsValues);
+ if (s == pv::actionFlagsValues.end())
+ {
+ // Schema validation should be catching this.
+ log<level::ERR>("Invalid action flag name used in message registry",
+ entry("FLAG=%s", flag.c_str()));
+
+ throw std::runtime_error(
+ "Invalid action flag used in message registry");
+ }
+
+ actionFlags |= std::get<pv::fieldValuePos>(*s);
+ }
+
+ return actionFlags;
+}
+
+uint8_t getEventType(const std::string& eventTypeName)
+{
+ auto t = pv::findByName(eventTypeName, pv::eventTypeValues);
+ if (t == pv::eventTypeValues.end())
+ {
+ log<level::ERR>("Invalid event type used in message registry",
+ entry("EVENT_TYPE=%s", eventTypeName.c_str()));
+
+ throw std::runtime_error("Invalid event type used in message registry");
+ }
+ return std::get<pv::fieldValuePos>(*t);
+}
+
+uint8_t getEventScope(const std::string& eventScopeName)
+{
+ auto s = pv::findByName(eventScopeName, pv::eventScopeValues);
+ if (s == pv::eventScopeValues.end())
+ {
+ log<level::ERR>("Invalid event scope used in registry",
+ entry("EVENT_SCOPE=%s", eventScopeName.c_str()));
+
+ throw std::runtime_error(
+ "Invalid event scope used in message registry");
+ }
+ return std::get<pv::fieldValuePos>(*s);
+}
+
+} // namespace helper
+
+std::optional<Entry> Registry::lookup(const std::string& name)
+{
+ // Look in /etc first in case someone put a test file there
+ fs::path debugFile{fs::path{debugFilePath} / registryFileName};
+ nlohmann::json registry;
+ std::ifstream file;
+
+ if (fs::exists(debugFile))
+ {
+ log<level::INFO>("Using debug PEL message registry");
+ file.open(debugFile);
+ }
+ else
+ {
+ file.open(_registryFile);
+ }
+
+ try
+ {
+ registry = nlohmann::json::parse(file);
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>("Error parsing message registry JSON",
+ entry("JSON_ERROR=%s", e.what()));
+ return std::nullopt;
+ }
+
+ // Find an entry with this name in the PEL array.
+ auto e = std::find_if(registry["PELs"].begin(), registry["PELs"].end(),
+ [&name](const auto& j) { return name == j["Name"]; });
+
+ if (e != registry["PELs"].end())
+ {
+ // Fill in the Entry structure from the JSON. Most, but not all, fields
+ // are optional.
+
+ try
+ {
+ Entry entry;
+ entry.name = (*e)["Name"];
+ entry.subsystem = helper::getSubsystem((*e)["Subsystem"]);
+ entry.actionFlags = helper::getActionFlags((*e)["ActionFlags"]);
+
+ if (e->find("MfgActionFlags") != e->end())
+ {
+ entry.mfgActionFlags =
+ helper::getActionFlags((*e)["MfgActionFlags"]);
+ }
+
+ if (e->find("Severity") != e->end())
+ {
+ entry.severity = helper::getSeverity((*e)["Severity"]);
+ }
+
+ if (e->find("MfgSeverity") != e->end())
+ {
+ entry.mfgSeverity = helper::getSeverity((*e)["MfgSeverity"]);
+ }
+
+ if (e->find("EventType") != e->end())
+ {
+ entry.eventType = helper::getEventType((*e)["EventType"]);
+ }
+
+ if (e->find("EventScope") != e->end())
+ {
+ entry.eventScope = helper::getEventScope((*e)["EventScope"]);
+ }
+
+ // TODO: SRC fields
+
+ return entry;
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>("Found invalid message registry field",
+ entry("ERROR=%s", e.what()));
+ }
+ }
+
+ return std::nullopt;
+}
+
+} // namespace message
+} // namespace pels
+} // namespace openpower
diff --git a/extensions/openpower-pels/registry.hpp b/extensions/openpower-pels/registry.hpp
new file mode 100644
index 0000000..e56bd42
--- /dev/null
+++ b/extensions/openpower-pels/registry.hpp
@@ -0,0 +1,179 @@
+#pragma once
+#include <filesystem>
+#include <nlohmann/json.hpp>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace openpower
+{
+namespace pels
+{
+namespace message
+{
+
+constexpr auto registryFileName = "message_registry.json";
+
+/**
+ * @brief Represents a message registry entry, which is used for creating a
+ * PEL from an OpenBMC event log.
+ */
+struct Entry
+{
+ /**
+ * @brief The error name, like "xyz.openbmc_project.Error.Foo".
+ */
+ std::string name;
+
+ /**
+ * @brief The PEL subsystem field.
+ */
+ uint8_t subsystem;
+
+ /**
+ * @brief The optional PEL severity field. If not specified, the PEL
+ * will use the severity of the OpenBMC event log.
+ */
+ std::optional<uint8_t> severity;
+
+ /**
+ * @brief The optional severity field to use when in manufacturing tolerance
+ * mode.
+ */
+ std::optional<uint8_t> mfgSeverity;
+
+ /**
+ * @brief The PEL action flags field.
+ */
+ uint16_t actionFlags;
+
+ /**
+ * @brief The optional action flags to use instead when in manufacturing
+ * tolerance mode.
+ */
+ std::optional<uint16_t> mfgActionFlags;
+
+ /**
+ * @brief The PEL event type field. If not specified, higher level code
+ * will decide the value.
+ */
+ std::optional<uint8_t> eventType;
+
+ /**
+ * @brief The PEL event scope field. If not specified, higher level code
+ * will decide the value.
+ */
+ std::optional<uint8_t> eventScope;
+
+ // TODO: SRC related fields
+};
+
+/**
+ * @class Registry
+ *
+ * This class wraps the message registry JSON data and allows one to find
+ * the message registry entry pertaining to the error name.
+ *
+ * So that new registry files can easily be tested, the code will look for
+ * /etc/phosphor-logging/message_registry.json before looking for the real
+ * path.
+ */
+class Registry
+{
+ public:
+ Registry() = delete;
+ ~Registry() = default;
+ Registry(const Registry&) = default;
+ Registry& operator=(const Registry&) = default;
+ Registry(Registry&&) = default;
+ Registry& operator=(Registry&&) = default;
+
+ /**
+ * @brief Constructor
+ * @param[in] registryFile - The path to the file.
+ */
+ explicit Registry(const std::filesystem::path& registryFile) :
+ _registryFile(registryFile)
+ {
+ }
+
+ /**
+ * @brief Find a registry entry based on its error name.
+ *
+ * This function does do some basic sanity checking on the JSON contents,
+ * but there is also an external program that enforces a schema on the
+ * registry JSON that should catch all of these problems ahead of time.
+ *
+ * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo
+ *
+ * @return optional<Entry> A filled in message registry structure if
+ * found, otherwise an empty optional object.
+ */
+ std::optional<Entry> lookup(const std::string& name);
+
+ private:
+ /**
+ * @brief The path to the registry JSON file.
+ */
+ std::filesystem::path _registryFile;
+};
+
+namespace helper
+{
+
+/**
+ * @brief A helper function to get the PEL subsystem value based on
+ * the registry subsystem name.
+ *
+ * @param[in] subsystemName - The registry name for the subsystem
+ *
+ * @return uint8_t The PEL subsystem value
+ */
+uint8_t getSubsystem(const std::string& subsystemName);
+
+/**
+ * @brief A helper function to get the PEL severity value based on
+ * the registry severity name.
+ *
+ * @param[in] severityName - The registry name for the severity
+ *
+ * @return uint8_t The PEL severity value
+ */
+uint8_t getSeverity(const std::string& severityName);
+
+/**
+ * @brief A helper function to get the action flags value based on
+ * the action flag names used in the registry.
+ *
+ * @param[in] flags - The list of flag names from the registry.
+ *
+ * @return uint16_t - The bitfield of flags used in the PEL.
+ */
+uint16_t getActionFlags(const std::vector<std::string>& flags);
+
+/**
+ * @brief A helper function to get the PEL event type value based on
+ * the registry event type name.
+ *
+ * @param[in] eventTypeName - The registry name for the event type
+ *
+ * @return uint8_t The PEL event type value
+ */
+uint8_t getEventType(const std::string& eventTypeName);
+
+/**
+ * @brief A helper function to get the PEL event scope value based on
+ * the registry event scope name.
+ *
+ * @param[in] eventScopeName - The registry name for the event scope
+ *
+ * @return uint8_t The PEL event scope value
+ */
+uint8_t getEventScope(const std::string& eventScopeName);
+
+} // namespace helper
+
+} // namespace message
+
+} // namespace pels
+} // namespace openpower
OpenPOWER on IntegriCloud