Construct Redfish messages using the Message Registry

Instead of using the message and severity from the journal,
this change allows Redfish to search for the MessageId in the
Message Registries to construct the message. This will provide
more accurate Redfish messages and severities since they come
from a single source.

Tested:
Logged Redfish events using new MessageIds and confirmed that
the correct message from the Message Registry is displayed
rather than the message from the journal.

Change-Id: I294593647998c988b36ffccaf95a69cbeab3f92e
Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp
index d2e8e36..90182a1 100644
--- a/redfish-core/lib/log_services.hpp
+++ b/redfish-core/lib/log_services.hpp
@@ -16,9 +16,14 @@
 #pragma once
 
 #include "node.hpp"
+#include "registries.hpp"
+#include "registries/base_message_registry.hpp"
+#include "registries/openbmc_message_registry.hpp"
 
 #include <systemd/sd-journal.h>
 
+#include <boost/algorithm/string/split.hpp>
+#include <boost/beast/core/span.hpp>
 #include <boost/container/flat_map.hpp>
 #include <error_messages.hpp>
 #include <filesystem>
@@ -36,6 +41,53 @@
 constexpr char const *CrashdumpRawPECIInterface =
     "com.intel.crashdump.SendRawPeci";
 
+namespace message_registries
+{
+static const Message *getMessageFromRegistry(
+    const std::string &messageKey,
+    const boost::beast::span<const MessageEntry> registry)
+{
+    boost::beast::span<const MessageEntry>::const_iterator messageIt =
+        std::find_if(registry.cbegin(), registry.cend(),
+                     [&messageKey](const MessageEntry &messageEntry) {
+                         return !std::strcmp(messageEntry.first,
+                                             messageKey.c_str());
+                     });
+    if (messageIt != registry.cend())
+    {
+        return &messageIt->second;
+    }
+
+    return nullptr;
+}
+
+static const Message *getMessage(const std::string_view &messageID)
+{
+    // Redfish MessageIds are in the form
+    // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find
+    // the right Message
+    std::vector<std::string> fields;
+    fields.reserve(4);
+    boost::split(fields, messageID, boost::is_any_of("."));
+    std::string &registryName = fields[0];
+    std::string &messageKey = fields[3];
+
+    // Find the right registry and check it for the MessageKey
+    if (std::string(base::header.registryPrefix) == registryName)
+    {
+        return getMessageFromRegistry(
+            messageKey, boost::beast::span<const MessageEntry>(base::registry));
+    }
+    if (std::string(openbmc::header.registryPrefix) == registryName)
+    {
+        return getMessageFromRegistry(
+            messageKey,
+            boost::beast::span<const MessageEntry>(openbmc::registry));
+    }
+    return nullptr;
+}
+} // namespace message_registries
+
 namespace fs = std::filesystem;
 
 using GetManagedPropertyType = boost::container::flat_map<
@@ -393,24 +445,16 @@
                                  sd_journal *journal,
                                  nlohmann::json &bmcLogEntryJson)
 {
-    // Get the Log Entry contents
-    int ret = 0;
+    // Get the Message from the MessageRegistry
+    const message_registries::Message *message =
+        message_registries::getMessage(messageID);
 
-    std::string_view msg;
-    ret = getJournalMetadata(journal, "MESSAGE", msg);
-    if (ret < 0)
+    std::string msg;
+    std::string severity;
+    if (message != nullptr)
     {
-        BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
-        return 1;
-    }
-
-    // Get the severity from the PRIORITY field
-    int severity = 8; // Default to an invalid priority
-    ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
-    if (ret < 0)
-    {
-        BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
-        return 1;
+        msg = message->message;
+        severity = message->severity;
     }
 
     // Get the MessageArgs from the journal entry by finding all of the
@@ -445,6 +489,17 @@
         }
     }
 
+    // Fill the MessageArgs into the Message
+    for (size_t i = 0; i < messageArgs.size(); i++)
+    {
+        std::string argStr = "%" + std::to_string(i + 1);
+        size_t argPos = msg.find(argStr);
+        if (argPos != std::string::npos)
+        {
+            msg.replace(argPos, argStr.length(), messageArgs[i]);
+        }
+    }
+
     // Get the Created time from the timestamp
     std::string entryTimeStr;
     if (!getEntryTimestamp(journal, entryTimeStr))
@@ -465,9 +520,7 @@
         {"MessageId", messageID},
         {"MessageArgs", std::move(messageArgs)},
         {"EntryType", "Event"},
-        {"Severity",
-         severity <= 2 ? "Critical"
-                       : severity <= 4 ? "Warning" : severity <= 7 ? "OK" : ""},
+        {"Severity", severity},
         {"Created", std::move(entryTimeStr)}};
     return 0;
 }