diff options
-rw-r--r-- | extensions/openpower-pels/additional_data.hpp | 34 | ||||
-rw-r--r-- | extensions/openpower-pels/pel.cpp | 37 | ||||
-rw-r--r-- | extensions/openpower-pels/pel.hpp | 16 | ||||
-rw-r--r-- | extensions/openpower-pels/user_data_formats.hpp | 19 | ||||
-rw-r--r-- | test/openpower-pels/additional_data_test.cpp | 7 | ||||
-rw-r--r-- | test/openpower-pels/pel_test.cpp | 29 |
6 files changed, 142 insertions, 0 deletions
diff --git a/extensions/openpower-pels/additional_data.hpp b/extensions/openpower-pels/additional_data.hpp index b855054..f133e0f 100644 --- a/extensions/openpower-pels/additional_data.hpp +++ b/extensions/openpower-pels/additional_data.hpp @@ -1,5 +1,6 @@ #pragma once #include <map> +#include <nlohmann/json.hpp> #include <optional> #include <string> #include <vector> @@ -67,6 +68,39 @@ class AdditionalData return std::nullopt; } + /** + * @brief Remove a key/value pair from the contained data + * + * @param[in] key - The key of the entry to remove + */ + void remove(const std::string& key) + { + _data.erase(key); + } + + /** + * @brief Says if the object has no data + * + * @return bool true if the object is empty + */ + inline bool empty() const + { + return _data.empty(); + } + + /** + * @brief Returns the contained data as a JSON object + * + * Looks like: {"key1":"value1","key2":"value2"} + * + * @return json - The JSON object + */ + nlohmann::json toJSON() const + { + nlohmann::json j = _data; + return j; + } + private: /** * @brief a map of keys to values diff --git a/extensions/openpower-pels/pel.cpp b/extensions/openpower-pels/pel.cpp index ffd4974..af904ff 100644 --- a/extensions/openpower-pels/pel.cpp +++ b/extensions/openpower-pels/pel.cpp @@ -6,6 +6,7 @@ #include "section_factory.hpp" #include "src.hpp" #include "stream.hpp" +#include "user_data_formats.hpp" #include <phosphor-logging/log.hpp> @@ -30,6 +31,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)); + if (!additionalData.empty()) + { + auto ud = util::makeADUserDataSection(additionalData); + _optionalSections.push_back(std::move(ud)); + } + _ph->sectionCount() = 2 + _optionalSections.size(); } @@ -134,5 +141,35 @@ std::optional<SRC*> PEL::primarySRC() const return std::nullopt; } +namespace util +{ + +std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad) +{ + assert(!ad.empty()); + nlohmann::json json; + + // Remove the 'ESEL' entry, as it contains a full PEL in the value. + if (ad.getValue("ESEL")) + { + auto newAD = ad; + newAD.remove("ESEL"); + json = newAD.toJSON(); + } + else + { + json = ad.toJSON(); + } + + auto jsonString = json.dump(); + std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end()); + + return std::make_unique<UserData>( + static_cast<uint16_t>(ComponentID::phosphorLogging), + static_cast<uint8_t>(UserDataFormat::json), + static_cast<uint8_t>(UserDataFormatVersion::json), jsonData); +} + +} // namespace util } // namespace pels } // namespace openpower diff --git a/extensions/openpower-pels/pel.hpp b/extensions/openpower-pels/pel.hpp index bc857e2..f63cfdd 100644 --- a/extensions/openpower-pels/pel.hpp +++ b/extensions/openpower-pels/pel.hpp @@ -5,6 +5,7 @@ #include "private_header.hpp" #include "registry.hpp" #include "src.hpp" +#include "user_data.hpp" #include "user_header.hpp" #include <memory> @@ -249,5 +250,20 @@ class PEL std::vector<std::unique_ptr<Section>> _optionalSections; }; +namespace util +{ + +/** + * @brief Create a UserData section containing the AdditionalData + * contents as a JSON string. + * + * @param[in] ad - The AdditionalData contents + * + * @return std::unique_ptr<UserData> - The section + */ +std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad); + +} // namespace util + } // namespace pels } // namespace openpower diff --git a/extensions/openpower-pels/user_data_formats.hpp b/extensions/openpower-pels/user_data_formats.hpp new file mode 100644 index 0000000..53cb5ee --- /dev/null +++ b/extensions/openpower-pels/user_data_formats.hpp @@ -0,0 +1,19 @@ +#pragma once + +namespace openpower +{ +namespace pels +{ + +enum class UserDataFormat +{ + json = 1 +}; + +enum class UserDataFormatVersion +{ + json = 1 +}; + +} // namespace pels +} // namespace openpower diff --git a/test/openpower-pels/additional_data_test.cpp b/test/openpower-pels/additional_data_test.cpp index 2be06c4..1bf4af7 100644 --- a/test/openpower-pels/additional_data_test.cpp +++ b/test/openpower-pels/additional_data_test.cpp @@ -24,4 +24,11 @@ TEST(AdditionalDataTest, GetKeywords) EXPECT_FALSE(ad.getValue("HELLOWORLD")); EXPECT_FALSE(ad.getValue("VALUE5")); + + auto json = ad.toJSON(); + std::string expected = R"({"KEY1":"VALUE1","KEY2":"VALUE2","KEY3":""})"; + EXPECT_EQ(json.dump(), expected); + + ad.remove("KEY1"); + EXPECT_FALSE(ad.getValue("KEY1")); } diff --git a/test/openpower-pels/pel_test.cpp b/test/openpower-pels/pel_test.cpp index b0c6528..6494c52 100644 --- a/test/openpower-pels/pel_test.cpp +++ b/test/openpower-pels/pel_test.cpp @@ -231,3 +231,32 @@ TEST_F(PELTest, InvalidGenericTest) EXPECT_TRUE(foundGeneric); } + +// Create a UserData section out of AdditionalData +TEST_F(PELTest, MakeUDSectionTest) +{ + std::vector<std::string> ad{"KEY1=VALUE1", "KEY2=VALUE2", "KEY3=VALUE3", + "ESEL=TEST"}; + AdditionalData additionalData{ad}; + + auto ud = util::makeADUserDataSection(additionalData); + + 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); + + const auto& d = ud->data(); + + std::string jsonString{d.begin(), d.end()}; + std::string expected = + R"({"KEY1":"VALUE1","KEY2":"VALUE2","KEY3":"VALUE3"})"; + EXPECT_EQ(jsonString, expected); + + // Ensure we can read this as JSON + auto newJSON = nlohmann::json::parse(jsonString); + EXPECT_EQ(newJSON["KEY1"], "VALUE1"); + EXPECT_EQ(newJSON["KEY2"], "VALUE2"); + EXPECT_EQ(newJSON["KEY3"], "VALUE3"); +}
\ No newline at end of file |