Refactor: extract src/event_log.cpp

event_service_manager.hpp contains namespace 'event_log' which is
confusing. Extract it to a separate header and cpp file to have the
filename match the namespace.

No functional changes have been made to the code.

Tested:
- Using Redfish Event Listener, test subscriptions and eventing.
- Redfish Service Validator passes

Change-Id: Ia0bf658b8b46f92aede059d46e8de48f160e073e
Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com>
Signed-off-by: Ed Tanous <ed@tanous.net>
diff --git a/redfish-core/src/event_log.cpp b/redfish-core/src/event_log.cpp
new file mode 100644
index 0000000..5420549
--- /dev/null
+++ b/redfish-core/src/event_log.cpp
@@ -0,0 +1,168 @@
+/*
+Copyright (c) 2020 Intel 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 "event_log.hpp"
+
+#include "event_service_manager.hpp"
+#include "logging.hpp"
+#include "registries.hpp"
+#include "str_utility.hpp"
+
+#include <nlohmann/json.hpp>
+
+#include <cerrno>
+#include <cstddef>
+#include <ctime>
+#include <iomanip>
+#include <span>
+#include <sstream>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+namespace redfish
+{
+
+namespace event_log
+{
+
+bool getUniqueEntryID(const std::string& logEntry, std::string& entryID)
+{
+    static time_t prevTs = 0;
+    static int index = 0;
+
+    // Get the entry timestamp
+    std::time_t curTs = 0;
+    std::tm timeStruct = {};
+    std::istringstream entryStream(logEntry);
+    if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
+    {
+        curTs = std::mktime(&timeStruct);
+        if (curTs == -1)
+        {
+            return false;
+        }
+    }
+    // If the timestamp isn't unique, increment the index
+    index = (curTs == prevTs) ? index + 1 : 0;
+
+    // Save the timestamp
+    prevTs = curTs;
+
+    entryID = std::to_string(curTs);
+    if (index > 0)
+    {
+        entryID += "_" + std::to_string(index);
+    }
+    return true;
+}
+
+int getEventLogParams(const std::string& logEntry, std::string& timestamp,
+                      std::string& messageID,
+                      std::vector<std::string>& messageArgs)
+{
+    // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
+    // First get the Timestamp
+    size_t space = logEntry.find_first_of(' ');
+    if (space == std::string::npos)
+    {
+        BMCWEB_LOG_ERROR("EventLog Params: could not find first space: {}",
+                         logEntry);
+        return -EINVAL;
+    }
+    timestamp = logEntry.substr(0, space);
+    // Then get the log contents
+    size_t entryStart = logEntry.find_first_not_of(' ', space);
+    if (entryStart == std::string::npos)
+    {
+        BMCWEB_LOG_ERROR("EventLog Params: could not find log contents: {}",
+                         logEntry);
+        return -EINVAL;
+    }
+    std::string_view entry(logEntry);
+    entry.remove_prefix(entryStart);
+    // Use split to separate the entry into its fields
+    std::vector<std::string> logEntryFields;
+    bmcweb::split(logEntryFields, entry, ',');
+    // We need at least a MessageId to be valid
+    if (logEntryFields.empty())
+    {
+        BMCWEB_LOG_ERROR("EventLog Params: could not find entry fields: {}",
+                         logEntry);
+        return -EINVAL;
+    }
+    messageID = logEntryFields[0];
+
+    // Get the MessageArgs from the log if there are any
+    if (logEntryFields.size() > 1)
+    {
+        const std::string& messageArgsStart = logEntryFields[1];
+        // If the first string is empty, assume there are no MessageArgs
+        if (!messageArgsStart.empty())
+        {
+            messageArgs.assign(logEntryFields.begin() + 1,
+                               logEntryFields.end());
+        }
+    }
+
+    return 0;
+}
+
+int formatEventLogEntry(
+    const std::string& logEntryID, const std::string& messageID,
+    const std::span<std::string_view> messageArgs, std::string timestamp,
+    const std::string& customText, nlohmann::json::object_t& logEntryJson)
+{
+    // Get the Message from the MessageRegistry
+    const registries::Message* message = registries::formatMessage(messageID);
+
+    if (message == nullptr)
+    {
+        return -1;
+    }
+
+    std::string msg =
+        redfish::registries::fillMessageArgs(messageArgs, message->message);
+    if (msg.empty())
+    {
+        return -1;
+    }
+
+    // Get the Created time from the timestamp. The log timestamp is in
+    // RFC3339 format which matches the Redfish format except for the
+    // fractional seconds between the '.' and the '+', so just remove them.
+    std::size_t dot = timestamp.find_first_of('.');
+    std::size_t plus = timestamp.find_first_of('+', dot);
+    if (dot != std::string::npos && plus != std::string::npos)
+    {
+        timestamp.erase(dot, plus - dot);
+    }
+
+    // Fill in the log entry with the gathered data
+    logEntryJson["EventId"] = logEntryID;
+
+    logEntryJson["Severity"] = message->messageSeverity;
+    logEntryJson["Message"] = std::move(msg);
+    logEntryJson["MessageId"] = messageID;
+    logEntryJson["MessageArgs"] = messageArgs;
+    logEntryJson["EventTimestamp"] = std::move(timestamp);
+    logEntryJson["Context"] = customText;
+    return 0;
+}
+
+} // namespace event_log
+
+} // namespace redfish
diff --git a/redfish-core/src/subscription.cpp b/redfish-core/src/subscription.cpp
index f74435d..0b7a9fd 100644
--- a/redfish-core/src/subscription.cpp
+++ b/redfish-core/src/subscription.cpp
@@ -15,9 +15,9 @@
 */
 #include "subscription.hpp"
 
+#include "event_log.hpp"
 #include "event_logs_object_type.hpp"
 #include "event_matches_filter.hpp"
-#include "event_service_manager.hpp"
 #include "event_service_store.hpp"
 #include "filter_expr_executor.hpp"
 #include "generated/enums/log_entry.hpp"