summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Spinler <spinler@us.ibm.com>2020-01-22 14:55:07 -0600
committerMatt Spinler <spinler@us.ibm.com>2020-01-31 15:00:11 +0000
commit4dcd3f46599a8c702fca4b13e4370a0ec7f66ffd (patch)
tree618aebb1ccb9b5231f9c1e8d6c74658005ec6b68
parentc7c3e40249fcba41b4c6b15676fc1054e6ce1049 (diff)
downloadphosphor-logging-4dcd3f46599a8c702fca4b13e4370a0ec7f66ffd.tar.gz
phosphor-logging-4dcd3f46599a8c702fca4b13e4370a0ec7f66ffd.zip
PEL: Save process name in a UserData section
When creating a new PEL, add a UserData section that contains various pieces of system information that will be saved in every error log. In this first commit, just save the process name of the creator, provided they passed in the '_PID' AdditionalData item containing their PID. Future commits will add other items like certain D-Bus properties. Signed-off-by: Matt Spinler <spinler@us.ibm.com> Change-Id: I7139b4056e494277ff3388bfa8a00002c9c89dc1
-rw-r--r--extensions/openpower-pels/data_interface.hpp23
-rw-r--r--extensions/openpower-pels/pel.cpp63
-rw-r--r--extensions/openpower-pels/pel.hpp12
-rw-r--r--test/openpower-pels/pel_test.cpp58
4 files changed, 145 insertions, 11 deletions
diff --git a/extensions/openpower-pels/data_interface.hpp b/extensions/openpower-pels/data_interface.hpp
index 88c590a..e690542 100644
--- a/extensions/openpower-pels/data_interface.hpp
+++ b/extensions/openpower-pels/data_interface.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include <filesystem>
#include <phosphor-logging/log.hpp>
#include <sdbusplus/bus.hpp>
#include <sdbusplus/bus/match.hpp>
@@ -135,6 +136,28 @@ class DataInterfaceBase
return _serverFWVersion;
}
+ /**
+ * @brief Returns the process name given its PID.
+ *
+ * @param[in] pid - The PID value as a string
+ *
+ * @return std::optional<std::string> - The name, or std::nullopt
+ */
+ std::optional<std::string> getProcessName(const std::string& pid) const
+ {
+ namespace fs = std::filesystem;
+
+ fs::path path{"/proc"};
+ path /= fs::path{pid} / "exe";
+
+ if (fs::exists(path))
+ {
+ return fs::read_symlink(path);
+ }
+
+ return std::nullopt;
+ }
+
protected:
/**
* @brief Sets the host on/off state and runs any
diff --git a/extensions/openpower-pels/pel.cpp b/extensions/openpower-pels/pel.cpp
index 625d177..0c05ac1 100644
--- a/extensions/openpower-pels/pel.cpp
+++ b/extensions/openpower-pels/pel.cpp
@@ -56,9 +56,12 @@ PEL::PEL(const message::Entry& entry, uint32_t obmcLogID, uint64_t timestamp,
auto mtms = std::make_unique<FailingMTMS>(dataIface);
_optionalSections.push_back(std::move(mtms));
+ auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
+ _optionalSections.push_back(std::move(ud));
+
if (!additionalData.empty())
{
- auto ud = util::makeADUserDataSection(additionalData);
+ ud = util::makeADUserDataSection(additionalData);
// To be safe, check there isn't too much data
if (size() + ud->header().size <= _maxPELSize)
@@ -299,6 +302,23 @@ void PEL::toJSON() const
namespace util
{
+std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json)
+{
+ auto jsonString = json.dump();
+ std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
+
+ // Pad to a 4 byte boundary
+ while ((jsonData.size() % 4) != 0)
+ {
+ jsonData.push_back(0);
+ }
+
+ return std::make_unique<UserData>(
+ static_cast<uint16_t>(ComponentID::phosphorLogging),
+ static_cast<uint8_t>(UserDataFormat::json),
+ static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
+}
+
std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
{
assert(!ad.empty());
@@ -316,19 +336,42 @@ std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
json = ad.toJSON();
}
- auto jsonString = json.dump();
- std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
+ return makeJSONUserDataSection(json);
+}
- // Pad to a 4 byte boundary
- while ((jsonData.size() % 4) != 0)
+void addProcessNameToJSON(nlohmann::json& json,
+ const std::optional<std::string>& pid,
+ const DataInterfaceBase& dataIface)
+{
+ std::string name = "Unknown";
+
+ try
+ {
+ if (pid)
+ {
+ auto n = dataIface.getProcessName(*pid);
+ if (n)
+ {
+ name = *n;
+ }
+ }
+ }
+ catch (std::exception& e)
{
- jsonData.push_back(0);
}
- return std::make_unique<UserData>(
- static_cast<uint16_t>(ComponentID::phosphorLogging),
- static_cast<uint8_t>(UserDataFormat::json),
- static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
+ json["Process Name"] = std::move(name);
+}
+
+std::unique_ptr<UserData>
+ makeSysInfoUserDataSection(const AdditionalData& ad,
+ const DataInterfaceBase& dataIface)
+{
+ nlohmann::json json;
+
+ addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
+
+ return makeJSONUserDataSection(json);
}
} // namespace util
diff --git a/extensions/openpower-pels/pel.hpp b/extensions/openpower-pels/pel.hpp
index 24e5e56..5f14354 100644
--- a/extensions/openpower-pels/pel.hpp
+++ b/extensions/openpower-pels/pel.hpp
@@ -344,6 +344,18 @@ namespace util
*/
std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad);
+/**
+ * @brief Create a UserData section containing various useful pieces
+ * of system information as a JSON string.
+ *
+ * @param[in] ad - The AdditionalData contents
+ * @param[in] dataIface - The data interface object
+ *
+ * @return std::unique_ptr<UserData> - The section
+ */
+std::unique_ptr<UserData>
+ makeSysInfoUserDataSection(const AdditionalData& ad,
+ const DataInterfaceBase& dataIface);
} // namespace util
} // namespace pels
diff --git a/test/openpower-pels/pel_test.cpp b/test/openpower-pels/pel_test.cpp
index 995f780..1a5f81f 100644
--- a/test/openpower-pels/pel_test.cpp
+++ b/test/openpower-pels/pel_test.cpp
@@ -136,7 +136,8 @@ TEST_F(PELTest, CreateFromRegistryTest)
regEntry.src.type = 0xBD;
regEntry.src.reasonCode = 0x1234;
- AdditionalData ad;
+ std::vector<std::string> data{"KEY1=VALUE1"};
+ AdditionalData ad{data};
MockDataInterface dataIface;
PEL pel{regEntry, 42, timestamp, phosphor::logging::Entry::Level::Error, ad,
@@ -148,6 +149,34 @@ TEST_F(PELTest, CreateFromRegistryTest)
EXPECT_EQ(pel.primarySRC().value()->asciiString(),
"BD051234 ");
+
+ // Check that certain optional sections have been created
+ size_t mtmsCount = 0;
+ size_t euhCount = 0;
+ size_t udCount = 0;
+
+ for (const auto& section : pel.optionalSections())
+ {
+ if (section->header().id ==
+ static_cast<uint16_t>(SectionID::failingMTMS))
+ {
+ mtmsCount++;
+ }
+ else if (section->header().id ==
+ static_cast<uint16_t>(SectionID::extendedUserHeader))
+ {
+ euhCount++;
+ }
+ else if (section->header().id ==
+ static_cast<uint16_t>(SectionID::userData))
+ {
+ udCount++;
+ }
+ }
+
+ EXPECT_EQ(mtmsCount, 1);
+ EXPECT_EQ(euhCount, 1);
+ EXPECT_EQ(udCount, 2); // AD section and sysInfo section
}
// Test that we'll create Generic optional sections for sections that
@@ -282,3 +311,30 @@ TEST_F(PELTest, MakeUDSectionTest)
EXPECT_EQ(newJSON["KEY2"], "VALUE2");
EXPECT_EQ(newJSON["KEY3"], "VALUE3");
}
+
+// Create the UserData section that contains system info
+TEST_F(PELTest, MakeSysInfoSectionTest)
+{
+ MockDataInterface dataIface;
+
+ std::string pid = "_PID=" + std::to_string(getpid());
+ std::vector<std::string> ad{pid};
+ AdditionalData additionalData{ad};
+
+ auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
+
+ EXPECT_TRUE(ud->valid());
+ EXPECT_EQ(ud->header().id, 0x5544);
+ EXPECT_EQ(ud->header().version, 0x01);
+ EXPECT_EQ(ud->header().subType, 0x01);
+ EXPECT_EQ(ud->header().componentID, 0x2000);
+
+ // Pull out the JSON data and check it.
+ const auto& d = ud->data();
+ std::string jsonString{d.begin(), d.end()};
+ auto json = nlohmann::json::parse(jsonString);
+
+ // Ensure the 'Process Name' entry contains 'pel_test'
+ auto name = json["Process Name"].get<std::string>();
+ EXPECT_NE(name.find("pel_test"), std::string::npos);
+}
OpenPOWER on IntegriCloud