diff options
Diffstat (limited to 'extensions/openpower-pels/user_data_json.cpp')
| -rw-r--r-- | extensions/openpower-pels/user_data_json.cpp | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/extensions/openpower-pels/user_data_json.cpp b/extensions/openpower-pels/user_data_json.cpp new file mode 100644 index 0000000..a86ccb3 --- /dev/null +++ b/extensions/openpower-pels/user_data_json.cpp @@ -0,0 +1,153 @@ +/** + * Copyright © 2020 IBM Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "user_data_json.hpp" + +#include "pel_types.hpp" +#include "user_data_formats.hpp" + +#include <fifo_map.hpp> +#include <iomanip> +#include <nlohmann/json.hpp> +#include <phosphor-logging/log.hpp> +#include <sstream> + +namespace openpower::pels::user_data +{ + +using namespace phosphor::logging; + +// Use fifo_map as nlohmann::json's map. We are just ignoring the 'less' +// compare. With this map the keys are kept in FIFO order. +template <class K, class V, class dummy_compare, class A> +using fifoMap = nlohmann::fifo_map<K, V, nlohmann::fifo_map_compare<K>, A>; +using fifoJSON = nlohmann::basic_json<fifoMap>; + +/** + * @brief Returns a JSON string for use by PEL::printSectionInJSON(). + * + * The returning string will contain a JSON object, but without + * the outer {}. If the input JSON isn't a JSON object (dict), then + * one will be created with the input added to a 'Data' key. + * + * @param[in] json - The JSON to convert to a string + * + * @return std::string - The JSON string + */ +std::string prettyJSON(uint16_t componentID, uint8_t subType, uint8_t version, + const fifoJSON& json) +{ + fifoJSON output; + output["Section Version"] = std::to_string(version); + output["Sub-section type"] = std::to_string(subType); + + char value[10]; + sprintf(value, "0x%04X", componentID); + output["Created by"] = std::string{value}; + + if (!json.is_object()) + { + output["Data"] = json; + } + else + { + for (const auto& [key, value] : json.items()) + { + output[key] = value; + } + } + + // Let nlohmann do the pretty printing. + std::stringstream stream; + stream << std::setw(4) << output; + + auto jsonString = stream.str(); + + // Now it looks like: + // { + // "Section Version": ... + // ... + // } + + // Since PEL::printSectionInJSON() will supply the outer { }s, + // remove the existing ones. + + // Replace the { and the following newline, and the } and its + // preceeding newline. + jsonString.erase(0, 2); + + auto pos = jsonString.find_last_of('}'); + jsonString.erase(pos - 1); + + return jsonString; +} + +/** + * @brief Convert to an appropriate JSON string as the data is one of + * the formats that we natively support. + * + * @param[in] componentID - The comp ID from the UserData section header + * @param[in] subType - The subtype from the UserData section header + * @param[in] version - The version from the UserData section header + * @param[in] data - The data itself + * + * @return std::optional<std::string> - The JSON string if it could be created, + * else std::nullopt. + */ +std::optional<std::string> + getBuiltinFormatJSON(uint16_t componentID, uint8_t subType, uint8_t version, + const std::vector<uint8_t>& data) +{ + switch (subType) + { + case static_cast<uint8_t>(UserDataFormat::json): + { + std::string jsonString{data.begin(), data.begin() + data.size()}; + + fifoJSON json = nlohmann::json::parse(jsonString); + + return prettyJSON(componentID, subType, version, json); + } + default: + break; + } + return std::nullopt; +} + +std::optional<std::string> getJSON(uint16_t componentID, uint8_t subType, + uint8_t version, + const std::vector<uint8_t>& data) +{ + try + { + switch (componentID) + { + case static_cast<uint16_t>(ComponentID::phosphorLogging): + return getBuiltinFormatJSON(componentID, subType, version, + data); + default: + break; + } + } + catch (std::exception& e) + { + log<level::ERR>("Failed parsing UserData", entry("ERROR=%s", e.what())); + } + + return std::nullopt; +} + +} // namespace openpower::pels::user_data |

