PEL: Add BMC uptime to PELs in UserData section
A UserData section has been added to each PEL with additional debug
information, now there is a need to add the output of the uptime
command to UserData and display it, but for Hostboot doesn't care
about this property, so skip adding it here it.
Tested: unit test passed
"User Data 0": {
"Section Version": "1",
"Sub-section type": "1",
"Created by": "0x2000",
...
"Uptime": "3y 332d 21h 33m 9s",
"Load": "1.47 0.94 0.61",
},
Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: I3d4c78bb1650da9a91804fc83de60597992ffc8a
diff --git a/extensions/openpower-pels/data_interface.hpp b/extensions/openpower-pels/data_interface.hpp
index 4095cce..c0e8c45 100644
--- a/extensions/openpower-pels/data_interface.hpp
+++ b/extensions/openpower-pels/data_interface.hpp
@@ -4,6 +4,7 @@
#include "dbus_watcher.hpp"
#include <filesystem>
+#include <fstream>
#include <phosphor-logging/log.hpp>
#include <sdbusplus/bus.hpp>
#include <sdbusplus/bus/match.hpp>
@@ -144,6 +145,91 @@
}
/**
+ * @brief Returns the time the system was running.
+ *
+ * @return std::optional<uint64_t> - The System uptime or std::nullopt
+ */
+ std::optional<uint64_t> getUptimeInSeconds() const
+ {
+ std::ifstream versionFile{"/proc/uptime"};
+ std::string line{};
+
+ std::getline(versionFile, line);
+ auto pos = line.find(" ");
+ if (pos == std::string::npos)
+ {
+ return std::nullopt;
+ }
+
+ uint64_t seconds = atol(line.substr(0, pos).c_str());
+ if (seconds == 0)
+ {
+ return std::nullopt;
+ }
+
+ return seconds;
+ }
+
+ /**
+ * @brief Returns the time the system was running.
+ *
+ * @param[in] seconds - The number of seconds the system has been running
+ *
+ * @return std::string - days/hours/minutes/seconds
+ */
+ std::string getBMCUptime(uint64_t seconds) const
+ {
+ time_t t(seconds);
+ tm* p = gmtime(&t);
+
+ std::string uptime = std::to_string(p->tm_year - 70) + "y " +
+ std::to_string(p->tm_yday) + "d " +
+ std::to_string(p->tm_hour) + "h " +
+ std::to_string(p->tm_min) + "m " +
+ std::to_string(p->tm_sec) + "s";
+
+ return uptime;
+ }
+
+ /**
+ * @brief Returns the system load average over the past 1 minute, 5 minutes
+ * and 15 minutes.
+ *
+ * @return std::string - The system load average
+ */
+ std::string getBMCLoadAvg() const
+ {
+ std::string loadavg{};
+
+ std::ifstream loadavgFile{"/proc/loadavg"};
+ std::string line;
+ std::getline(loadavgFile, line);
+
+ size_t count = 3;
+ for (size_t i = 0; i < count; i++)
+ {
+ auto pos = line.find(" ");
+ if (pos == std::string::npos)
+ {
+ return {};
+ }
+
+ if (i != count - 1)
+ {
+ loadavg.append(line.substr(0, pos + 1));
+ }
+ else
+ {
+ loadavg.append(line.substr(0, pos));
+ }
+
+ line = line.substr(pos + 1);
+ }
+
+ return loadavg;
+ }
+
+ /**
* @brief Returns the 'send event logs to host' setting.
*
* @return bool - If sending PELs to the host is enabled.
diff --git a/extensions/openpower-pels/pel.cpp b/extensions/openpower-pels/pel.cpp
index 898dce5..a84b7f8 100644
--- a/extensions/openpower-pels/pel.cpp
+++ b/extensions/openpower-pels/pel.cpp
@@ -574,8 +574,8 @@
static_cast<uint16_t>(ComponentID::phosphorLogging);
// Update system data to ED section
- auto ud =
- util::makeSysInfoUserDataSection(additionalData, dataIface);
+ auto ud = util::makeSysInfoUserDataSection(additionalData,
+ dataIface, false);
extUserData->updateDataSection(subType, componentId,
ud->data());
}
@@ -709,9 +709,24 @@
json["BootState"] = lastSegment('.', dataIface.getBootState());
}
+void addBMCUptime(nlohmann::json& json, const DataInterfaceBase& dataIface)
+{
+ auto seconds = dataIface.getUptimeInSeconds();
+ if (seconds)
+ {
+ json["BMCUptime"] = dataIface.getBMCUptime(*seconds);
+ }
+ else
+ {
+ json["BMCUptime"] = "";
+ }
+ json["BMCLoad"] = dataIface.getBMCLoadAvg();
+}
+
std::unique_ptr<UserData>
makeSysInfoUserDataSection(const AdditionalData& ad,
- const DataInterfaceBase& dataIface)
+ const DataInterfaceBase& dataIface,
+ bool addUptime)
{
nlohmann::json json;
@@ -720,6 +735,11 @@
addIMKeyword(json, dataIface);
addStatesToJSON(json, dataIface);
+ if (addUptime)
+ {
+ addBMCUptime(json, dataIface);
+ }
+
return makeJSONUserDataSection(json);
}
diff --git a/extensions/openpower-pels/pel.hpp b/extensions/openpower-pels/pel.hpp
index 5edcf10..631cbdb 100644
--- a/extensions/openpower-pels/pel.hpp
+++ b/extensions/openpower-pels/pel.hpp
@@ -429,12 +429,15 @@
*
* @param[in] ad - The AdditionalData contents
* @param[in] dataIface - The data interface object
+ * @param[in] addUptime - Whether to add the uptime attribute the default is
+ * true
*
* @return std::unique_ptr<UserData> - The section
*/
std::unique_ptr<UserData>
makeSysInfoUserDataSection(const AdditionalData& ad,
- const DataInterfaceBase& dataIface);
+ const DataInterfaceBase& dataIface,
+ bool addUptime = true);
/**
* @brief Reads data from an opened file descriptor.
diff --git a/test/openpower-pels/data_interface_test.cpp b/test/openpower-pels/data_interface_test.cpp
index 28e455f..3041bc2 100644
--- a/test/openpower-pels/data_interface_test.cpp
+++ b/test/openpower-pels/data_interface_test.cpp
@@ -22,3 +22,15 @@
EXPECT_TRUE(connector.empty());
}
}
+
+TEST(DataInterfaceTest, ExtractUptime)
+{
+ uint64_t seconds = 123456789;
+ std::string retUptime = "3y 332d 21h 33m 9s";
+
+ auto bus = sdbusplus::bus::new_default();
+ DataInterface dataIntf(bus);
+ std::string uptime = dataIntf.getBMCUptime(seconds);
+
+ EXPECT_EQ(uptime, retUptime);
+}
\ No newline at end of file