summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Geissler <geissonator@yahoo.com>2018-08-17 17:56:14 +0300
committerAnthony Wilson <wilsonan@us.ibm.com>2019-04-05 00:50:05 +0300
commitcb92c03b1a8798657b9e03602e1ae851b2614e77 (patch)
treee0c4a9939a68cf15d1e508819e09daf7b2d1b9e8
parent61adbda37aa63ae77585797587a7b4b6c3b61b25 (diff)
downloadbmcweb-cb92c03b1a8798657b9e03602e1ae851b2614e77.tar.xz
Initial redfish logging support
This was imported from a fork: https://github.com/ampere-openbmc/bmcweb/commits/ampere-next/redfish-core/lib/logservices.hpp Which had a series of commits from TungVuX and hyche The initial patch is that code verbatim. Follow up patches on top of this make the necessary changes for current bmcweb: - Move to sdbusplus - C++ naming convention changes - Clang format - Some refactoring Tested: Verified new services work correctly when queried e.g. curl -k -H "X-Auth-Token: $bmc_token" -X GET \ https://${bmc}/redfish/v1/Systems/system/LogServices/EventLog/Entries displays the entries properly. RedfishServiceValidator results: /redfish/v1/Systems/system/LogServices pass: 3 passGet: 1 skipOptional: 1 /redfish/v1/Systems/system/LogServices/EventLog pass: 5 passGet: 1 skipOptional: 8 /redfish/v1/Systems/system/LogServices/EventLog/Entries pass: 3 passGet: 1 skipOptional: 1 /redfish/v1/Systems/system/LogServices/EventLog/<str> pass: 6 passGet: 1 skipOptional: 16 Sample Output: curl -k -H "X-Auth-Token: $bmc_token" -X GET https://${bmc}/redfish/v1/Systems/system/LogServices/EventLog/Entries { "@odata.context": "/redfish/v1/$metadata#LogEntryCollection.LogEntryCollection", "@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/Entries", "@odata.type": "#LogEntryCollection.LogEntryCollection", "Description": "Collection of System Event Log Entries", "Members": [ { "@odata.context": "/redfish/v1/$metadata#LogEntry.LogEntry", "@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/Entries/1", "@odata.type": "#LogEntry.v1_4_0.LogEntry", "Created": "2019-02-22T17:11:00+00:00", "EntryType": "Event", "Id": "1", "Message": "example.xyz.openbmc_project.Example.Elog.AutoTestSimple", "Name": "System DBus Event Log Entry", "Severity": "Critical" } ], "Members@odata.count": 1, "Name": "System Event Log Entries" } Change-Id: I422b0d0ec577ea734fecfb6f49101ec5ff45a556 Signed-off-by: Andrew Geissler <geissonator@yahoo.com> Signed-off-by: Anthony Wilson <wilsonan@us.ibm.com>
-rw-r--r--CMakeLists.txt5
-rw-r--r--crow/include/crow/utility.h30
-rw-r--r--redfish-core/include/redfish.hpp3
-rw-r--r--redfish-core/lib/log_services.hpp324
-rw-r--r--redfish-core/lib/managers.hpp19
5 files changed, 352 insertions, 29 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 70e56fd00f..28fbe0ff60 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -35,6 +35,9 @@ option (BMCWEB_ENABLE_REDFISH_CPU_LOG "Enable CPU log service transactions
option (BMCWEB_ENABLE_REDFISH_ONE_CHASSIS "Enable Redfish to assume only one
chassis is present. All sensors will be assumed to be under this
chassis. The chassis path is '/redfish/v1/Chassis/chassis'." OFF)
+option (BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES "Enable DBUS log service
+ transactions through Redfish. Paths are under
+ '/redfish/v1/Systems/system/LogServices/EventLog/Entries'." OFF)
# Insecure options. Every option that starts with a BMCWEB_INSECURE flag should
# not be enabled by default for any platform, unless the author fully
@@ -267,4 +270,6 @@ target_compile_definitions (
$<$<BOOL:${BMCWEB_ENABLE_REDFISH_CPU_LOG}>: -DBMCWEB_ENABLE_REDFISH_CPU_LOG>
$<$<BOOL:${BMCWEB_ENABLE_REDFISH_BMC_JOURNAL}>: -DBMCWEB_ENABLE_REDFISH_BMC_JOURNAL>
$<$<BOOL:${BMCWEB_ENABLE_REDFISH_ONE_CHASSIS}>: -DBMCWEB_ENABLE_REDFISH_ONE_CHASSIS>
+ $<$<BOOL:${BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES}>: -DBMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES>
+
)
diff --git a/crow/include/crow/utility.h b/crow/include/crow/utility.h
index a07c0415af..63d2dece5f 100644
--- a/crow/include/crow/utility.h
+++ b/crow/include/crow/utility.h
@@ -2,7 +2,6 @@
#include "nlohmann/json.hpp"
-#include <boost/utility/string_view.hpp>
#include <cstdint>
#include <cstring>
#include <functional>
@@ -712,5 +711,34 @@ inline void convertToLinks(std::string& s)
s = std::regex_replace(s, nextLink, "$1<a href=\"$5\">$4</a>");
}
+/**
+ * Method returns Date Time information according to requested format
+ *
+ * @param[in] time time in second since the Epoch
+ *
+ * @return Date Time according to requested format
+ */
+inline std::string getDateTime(const std::time_t& time)
+{
+ std::array<char, 128> dateTime;
+ std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
+
+ if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
+ std::localtime(&time)))
+ {
+ // insert the colon required by the ISO 8601 standard
+ redfishDateTime = std::string(dateTime.data());
+ redfishDateTime.insert(redfishDateTime.end() - 2, ':');
+ }
+
+ return redfishDateTime;
+}
+
+inline std::string dateTimeNow()
+{
+ std::time_t time = std::time(nullptr);
+ return getDateTime(time);
+}
+
} // namespace utility
} // namespace crow
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index 36b50e87c7..38832c23d6 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -103,6 +103,9 @@ class RedfishService
nodes.emplace_back(std::make_unique<SystemsCollection>(app));
nodes.emplace_back(std::make_unique<Systems>(app));
nodes.emplace_back(std::make_unique<SystemActionsReset>(app));
+#ifdef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
+ nodes.emplace_back(std::make_unique<DBusLogServiceActionsClear>(app));
+#endif
for (const auto& node : nodes)
{
diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp
index 61cbd9e03d..d515028d6b 100644
--- a/redfish-core/lib/log_services.hpp
+++ b/redfish-core/lib/log_services.hpp
@@ -21,7 +21,7 @@
#include <systemd/sd-journal.h>
#include <boost/container/flat_map.hpp>
-#include <boost/utility/string_view.hpp>
+#include <error_messages.hpp>
#include <variant>
namespace redfish
@@ -38,6 +38,52 @@ constexpr char const *cpuLogRawPECIInterface =
namespace fs = std::filesystem;
+using GetManagedPropertyType = boost::container::flat_map<
+ std::string,
+ sdbusplus::message::variant<std::string, bool, uint8_t, int16_t, uint16_t,
+ int32_t, uint32_t, int64_t, uint64_t, double>>;
+
+using GetManagedObjectsType = boost::container::flat_map<
+ sdbusplus::message::object_path,
+ boost::container::flat_map<std::string, GetManagedPropertyType>>;
+
+inline std::string translateSeverityDbusToRedfish(const std::string &s)
+{
+ if (s == "xyz.openbmc_project.Logging.Entry.Level.Alert")
+ {
+ return "Critical";
+ }
+ else if (s == "xyz.openbmc_project.Logging.Entry.Level.Critical")
+ {
+ return "Critical";
+ }
+ else if (s == "xyz.openbmc_project.Logging.Entry.Level.Debug")
+ {
+ return "OK";
+ }
+ else if (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency")
+ {
+ return "Critical";
+ }
+ else if (s == "xyz.openbmc_project.Logging.Entry.Level.Error")
+ {
+ return "Critical";
+ }
+ else if (s == "xyz.openbmc_project.Logging.Entry.Level.Informational")
+ {
+ return "OK";
+ }
+ else if (s == "xyz.openbmc_project.Logging.Entry.Level.Notice")
+ {
+ return "OK";
+ }
+ else if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning")
+ {
+ return "Warning";
+ }
+ return "";
+}
+
static int getJournalMetadata(sd_journal *journal,
const std::string_view &field,
std::string_view &contents)
@@ -296,7 +342,8 @@ class SystemLogServiceCollection : public Node
{{"@odata.id", "/redfish/v1/Systems/system/LogServices/EventLog"}});
#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
logServiceArray.push_back(
- {{"@odata.id", "/redfish/v1/Systems/system/LogServices/CpuLog"}});
+ {{ "@odata.id",
+ "/redfish/v1/Systems/system/LogServices/CpuLog" }});
#endif
asyncResp->res.jsonValue["Members@odata.count"] =
logServiceArray.size();
@@ -407,7 +454,7 @@ static int fillEventLogEntryJson(const std::string &bmcLogEntryID,
// Fill in the log entry with the gathered data
bmcLogEntryJson = {
- {"@odata.type", "#LogEntry.v1_3_0.LogEntry"},
+ {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
{"@odata.context", "/redfish/v1/$metadata#LogEntry.LogEntry"},
{"@odata.id",
"/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
@@ -467,9 +514,10 @@ class EventLogEntryCollection : public Node
asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
asyncResp->res.jsonValue["Description"] =
"Collection of System Event Log Entries";
+
+#ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
nlohmann::json &logEntryArray = asyncResp->res.jsonValue["Members"];
logEntryArray = nlohmann::json::array();
-
// Go through the journal and create a unique ID for each entry
sd_journal *journalTmp = nullptr;
int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
@@ -525,6 +573,120 @@ class EventLogEntryCollection : public Node
"/redfish/v1/Managers/bmc/LogServices/BmcLog/Entries?$skip=" +
std::to_string(skip + top);
}
+#else
+ // DBus implementation of EventLog/Entries
+ // Make call to Logging Service to find all log entry objects
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec,
+ GetManagedObjectsType &resp) {
+ if (ec)
+ {
+ // TODO Handle for specific error code
+ BMCWEB_LOG_ERROR
+ << "getLogEntriesIfaceData resp_handler got error "
+ << ec;
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ nlohmann::json &entriesArray =
+ asyncResp->res.jsonValue["Members"];
+ entriesArray = nlohmann::json::array();
+ for (auto &objectPath : resp)
+ {
+ for (auto &interfaceMap : objectPath.second)
+ {
+ if (interfaceMap.first !=
+ "xyz.openbmc_project.Logging.Entry")
+ {
+ BMCWEB_LOG_DEBUG << "Bailing early on "
+ << interfaceMap.first;
+ continue;
+ }
+ entriesArray.push_back({});
+ nlohmann::json &thisEntry = entriesArray.back();
+ uint32_t *id;
+ std::time_t timestamp;
+ std::string *severity, *message;
+ bool *resolved;
+ for (auto &propertyMap : interfaceMap.second)
+ {
+ if (propertyMap.first == "Id")
+ {
+ id = sdbusplus::message::variant_ns::get_if<
+ uint32_t>(&propertyMap.second);
+ if (id == nullptr)
+ {
+ messages::propertyMissing(asyncResp->res,
+ "Id");
+ }
+ }
+ else if (propertyMap.first == "Timestamp")
+ {
+ const uint64_t *millisTimeStamp =
+ std::get_if<uint64_t>(&propertyMap.second);
+ if (millisTimeStamp == nullptr)
+ {
+ messages::propertyMissing(asyncResp->res,
+ "Timestamp");
+ }
+ // Retrieve Created property with format:
+ // yyyy-mm-ddThh:mm:ss
+ std::chrono::milliseconds chronoTimeStamp(
+ *millisTimeStamp);
+ timestamp =
+ std::chrono::duration_cast<
+ std::chrono::seconds>(chronoTimeStamp)
+ .count();
+ }
+ else if (propertyMap.first == "Severity")
+ {
+ severity = std::get_if<std::string>(
+ &propertyMap.second);
+ if (severity == nullptr)
+ {
+ messages::propertyMissing(asyncResp->res,
+ "Severity");
+ }
+ }
+ else if (propertyMap.first == "Message")
+ {
+ message = std::get_if<std::string>(
+ &propertyMap.second);
+ if (message == nullptr)
+ {
+ messages::propertyMissing(asyncResp->res,
+ "Message");
+ }
+ }
+ }
+ thisEntry = {
+ {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
+ {"@odata.context", "/redfish/v1/"
+ "$metadata#LogEntry.LogEntry"},
+ {"@odata.id",
+ "/redfish/v1/Systems/system/LogServices/EventLog/"
+ "Entries/" +
+ std::to_string(*id)},
+ {"Name", "System DBus Event Log Entry"},
+ {"Id", std::to_string(*id)},
+ {"Message", *message},
+ {"EntryType", "Event"},
+ {"Severity",
+ translateSeverityDbusToRedfish(*severity)},
+ {"Created", crow::utility::getDateTime(timestamp)}};
+ }
+ }
+ std::sort(entriesArray.begin(), entriesArray.end(),
+ [](const nlohmann::json &left,
+ const nlohmann::json &right) {
+ return (left["Id"] <= right["Id"]);
+ });
+ asyncResp->res.jsonValue["Members@odata.count"] =
+ entriesArray.size();
+ },
+ "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+#endif
}
};
@@ -556,6 +718,8 @@ class EventLogEntry : public Node
return;
}
const std::string &entryID = params[0];
+
+#ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
// Convert the unique ID back to a timestamp to find the entry
uint64_t ts = 0;
uint16_t index = 0;
@@ -605,6 +769,91 @@ class EventLogEntry : public Node
messages::internalError(asyncResp->res);
return;
}
+#else
+ // DBus implementation of EventLog/Entries
+ // Make call to Logging Service to find all log entry objects
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, entryID](const boost::system::error_code ec,
+ GetManagedPropertyType &resp) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "EventLogEntry (DBus) resp_handler got error " << ec;
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ uint32_t *id;
+ std::time_t timestamp;
+ std::string *severity, *message;
+ bool *resolved;
+ for (auto &propertyMap : resp)
+ {
+ if (propertyMap.first == "Id")
+ {
+ id = std::get_if<uint32_t>(&propertyMap.second);
+ if (id == nullptr)
+ {
+ messages::propertyMissing(asyncResp->res, "Id");
+ }
+ }
+ else if (propertyMap.first == "Timestamp")
+ {
+ const uint64_t *millisTimeStamp =
+ std::get_if<uint64_t>(&propertyMap.second);
+ if (millisTimeStamp == nullptr)
+ {
+ messages::propertyMissing(asyncResp->res,
+ "Timestamp");
+ }
+ // Retrieve Created property with format:
+ // yyyy-mm-ddThh:mm:ss
+ std::chrono::milliseconds chronoTimeStamp(
+ *millisTimeStamp);
+ timestamp =
+ std::chrono::duration_cast<std::chrono::seconds>(
+ chronoTimeStamp)
+ .count();
+ }
+ else if (propertyMap.first == "Severity")
+ {
+ severity =
+ std::get_if<std::string>(&propertyMap.second);
+ if (severity == nullptr)
+ {
+ messages::propertyMissing(asyncResp->res,
+ "Severity");
+ }
+ }
+ else if (propertyMap.first == "Message")
+ {
+ message = std::get_if<std::string>(&propertyMap.second);
+ if (message == nullptr)
+ {
+ messages::propertyMissing(asyncResp->res,
+ "Message");
+ }
+ }
+ }
+ asyncResp->res.jsonValue = {
+ {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
+ {"@odata.context", "/redfish/v1/"
+ "$metadata#LogEntry.LogEntry"},
+ {"@odata.id",
+ "/redfish/v1/Systems/system/LogServices/EventLog/"
+ "Entries/" +
+ std::to_string(*id)},
+ {"Name", "System DBus Event Log Entry"},
+ {"Id", std::to_string(*id)},
+ {"Message", *message},
+ {"EntryType", "Event"},
+ {"Severity", translateSeverityDbusToRedfish(*severity)},
+ {"Created", crow::utility::getDateTime(timestamp)}};
+ },
+ "xyz.openbmc_project.Logging",
+ "/xyz/openbmc_project/logging/entry/" + entryID,
+ "org.freedesktop.DBus.Properties", "GetAll",
+ "xyz.openbmc_project.Logging.Entry");
+#endif
}
};
@@ -647,7 +896,8 @@ class BMCLogServiceCollection : public Node
logServiceArray = nlohmann::json::array();
#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
logServiceArray.push_back(
- {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal"}});
+ {{ "@odata.id",
+ "/redfish/v1/Managers/bmc/LogServices/Journal" }});
#endif
asyncResp->res.jsonValue["Members@odata.count"] =
logServiceArray.size();
@@ -724,7 +974,7 @@ static int fillBMCJournalLogEntryJson(const std::string &bmcJournalLogEntryID,
// Fill in the log entry with the gathered data
bmcJournalLogEntryJson = {
- {"@odata.type", "#LogEntry.v1_3_0.LogEntry"},
+ {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
{"@odata.context", "/redfish/v1/$metadata#LogEntry.LogEntry"},
{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
bmcJournalLogEntryID},
@@ -956,8 +1206,9 @@ class CPULogService : public Node
#ifdef BMCWEB_ENABLE_REDFISH_RAW_PECI
asyncResp->res.jsonValue["Actions"]["Oem"].push_back(
{"#CpuLog.SendRawPeci",
- {{"target", "/redfish/v1/Systems/system/LogServices/CpuLog/"
- "Actions/Oem/CpuLog.SendRawPeci"}}});
+ { { "target",
+ "/redfish/v1/Systems/system/LogServices/CpuLog/"
+ "Actions/Oem/CpuLog.SendRawPeci" } }});
#endif
}
};
@@ -1118,7 +1369,7 @@ class CPULogEntry : public Node
}
std::string t = getLogCreatedTime(j);
asyncResp->res.jsonValue = {
- {"@odata.type", "#LogEntry.v1_3_0.LogEntry"},
+ {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
{"@odata.context", "/redfish/v1/$metadata#LogEntry.LogEntry"},
{"@odata.id",
"/redfish/v1/Systems/system/LogServices/CpuLog/Entries/" +
@@ -1231,7 +1482,7 @@ class ImmediateCPULog : public Node
}
std::string t = getLogCreatedTime(j);
asyncResp->res.jsonValue = {
- {"@odata.type", "#LogEntry.v1_3_0.LogEntry"},
+ {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
{"@odata.context", "/redfish/v1/$metadata#LogEntry.LogEntry"},
{"Name", "CPU Debug Log"},
{"EntryType", "Oem"},
@@ -1335,4 +1586,57 @@ class SendRawPECI : public Node
}
};
+/**
+ * DBusLogServiceActionsClear class supports POST method for ClearLog action.
+ */
+class DBusLogServiceActionsClear : public Node
+{
+ public:
+ DBusLogServiceActionsClear(CrowApp &app) :
+ Node(app, "/redfish/v1/Systems/system/LogServices/EventLog/Actions/"
+ "LogService.Reset")
+ {
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
+ }
+
+ private:
+ /**
+ * Function handles POST method request.
+ * The Clear Log actions does not require any parameter.The action deletes
+ * all entries found in the Entries collection for this Log Service.
+ */
+ void doPost(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ BMCWEB_LOG_DEBUG << "Do delete all entries.";
+
+ auto asyncResp = std::make_shared<AsyncResp>(res);
+ // Process response from Logging service.
+ auto resp_handler = [asyncResp](const boost::system::error_code ec) {
+ BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done";
+ if (ec)
+ {
+ // TODO Handle for specific error code
+ BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec;
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
+ return;
+ }
+
+ asyncResp->res.result(boost::beast::http::status::no_content);
+ };
+
+ // Make call to Logging service to request Clear Log
+ crow::connections::systemBus->async_method_call(
+ resp_handler, "xyz.openbmc_project.Logging",
+ "/xyz/openbmc_project/logging",
+ "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
+ }
+};
} // namespace redfish
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
index 3cde0efe62..e6e80a8a78 100644
--- a/redfish-core/lib/managers.hpp
+++ b/redfish-core/lib/managers.hpp
@@ -971,7 +971,7 @@ class Manager : public Node
manager_reset["ResetType@Redfish.AllowableValues"] = {
"GracefulRestart"};
- res.jsonValue["DateTime"] = getDateTime();
+ res.jsonValue["DateTime"] = crow::utility::dateTimeNow();
res.jsonValue["Links"]["ManagerForServers@odata.count"] = 1;
res.jsonValue["Links"]["ManagerForServers"] = {
{{"@odata.id", "/redfish/v1/Systems/system"}}};
@@ -1268,23 +1268,6 @@ class Manager : public Node
}
}
- std::string getDateTime() const
- {
- std::array<char, 128> dateTime;
- std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
- std::time_t time = std::time(nullptr);
-
- if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
- std::localtime(&time)))
- {
- // insert the colon required by the ISO 8601 standard
- redfishDateTime = std::string(dateTime.data());
- redfishDateTime.insert(redfishDateTime.end() - 2, ':');
- }
-
- return redfishDateTime;
- }
-
std::string uuid;
};