Correct the version of Message Id

Applications are logging Redfish Message ID to journal, but the version
of some message ID are different with the definition of bmcweb. E.g:
- psusensor is defining version of OpenBMC registry is "0.1" as [1].
- The bmcweb defines the version of OpenBMC registry is "0.5" as [2].

It makes the "MessageId" property of Event log's enties has different
version with definition in the /redfish/v1/Registries.

This commit corrects the version of Message ID.

[1]: https://github.com/openbmc/dbus-sensors/blob/6b7123225fc4a5180faf89190e9f64a7e248e697/src/psu/PSUEvent.cpp#L121
[2]: https://github.com/openbmc/bmcweb/blob/master/redfish-core/include/registries/openbmc.json#L1678

Tested:
   Verify the version of Events are the same the version of Registries
   that are defined in the bmcweb.

Change-Id: Ib862c8d0a62cae63082436cb4646a9ca45207872
Signed-off-by: Thang Tran <thuutran@amperecomputing.com>
diff --git a/redfish-core/include/registries.hpp b/redfish-core/include/registries.hpp
index c9313ef..22d594e 100644
--- a/redfish-core/include/registries.hpp
+++ b/redfish-core/include/registries.hpp
@@ -45,6 +45,15 @@
     std::array<const char*, 5> paramTypes;
     const char* resolution;
 };
+
+struct MessageId
+{
+    std::string registryName;
+    std::string majorVersion;
+    std::string minorVersion;
+    std::string messageKey;
+};
+
 using MessageEntry = std::pair<const char*, const Message>;
 using MessageEntries = std::span<const MessageEntry>;
 
@@ -138,4 +147,6 @@
 const Message* getMessageFromRegistry(const std::string& messageKey,
                                       std::span<const MessageEntry> registry);
 
+std::optional<MessageId> getMessageComponents(std::string_view message);
+
 } // namespace redfish::registries
diff --git a/redfish-core/include/utils/eventlog_utils.hpp b/redfish-core/include/utils/eventlog_utils.hpp
index 38cdfec..9456939 100644
--- a/redfish-core/include/utils/eventlog_utils.hpp
+++ b/redfish-core/include/utils/eventlog_utils.hpp
@@ -253,8 +253,24 @@
         return LogParseError::parseFailed;
     }
     std::string& messageID = *logEntryIter;
-    // Get the Message from the MessageRegistry
-    const registries::Message* message = registries::getMessage(messageID);
+
+    std::optional<registries::MessageId> msgComponents =
+        registries::getMessageComponents(messageID);
+    if (!msgComponents)
+    {
+        return LogParseError::parseFailed;
+    }
+
+    std::optional<registries::RegistryEntryRef> registry =
+        registries::getRegistryFromPrefix(msgComponents->registryName);
+    if (!registry)
+    {
+        return LogParseError::messageIdNotInRegistry;
+    }
+
+    // Get the Message from the MessageKey and RegistryEntries
+    const registries::Message* message = registries::getMessageFromRegistry(
+        msgComponents->messageKey, registry->get().entries);
 
     logEntryIter++;
     if (message == nullptr)
@@ -263,6 +279,9 @@
         return LogParseError::messageIdNotInRegistry;
     }
 
+    const unsigned int& versionMajor = registry->get().header.versionMajor;
+    const unsigned int& versionMinor = registry->get().header.versionMinor;
+
     std::vector<std::string_view> messageArgs(logEntryIter,
                                               logEntryFields.end());
     messageArgs.resize(message->numberOfArgs);
@@ -293,7 +312,9 @@
         std::format("{} Event Log Entry", logEntryDescriptor);
     logEntryJson["Id"] = logEntryID;
     logEntryJson["Message"] = std::move(msg);
-    logEntryJson["MessageId"] = std::move(messageID);
+    logEntryJson["MessageId"] =
+        std::format("{}.{}.{}.{}", msgComponents->registryName, versionMajor,
+                    versionMinor, msgComponents->messageKey);
     logEntryJson["MessageArgs"] = messageArgs;
     logEntryJson["EntryType"] = "Event";
     logEntryJson["Severity"] = message->messageSeverity;
diff --git a/redfish-core/src/event_log.cpp b/redfish-core/src/event_log.cpp
index 23af3fe..7534bd0 100644
--- a/redfish-core/src/event_log.cpp
+++ b/redfish-core/src/event_log.cpp
@@ -13,7 +13,9 @@
 #include <cstddef>
 #include <cstdint>
 #include <ctime>
+#include <format>
 #include <iomanip>
+#include <optional>
 #include <span>
 #include <sstream>
 #include <string>
@@ -115,14 +117,31 @@
                         std::string timestamp, const std::string& customText,
                         nlohmann::json::object_t& logEntryJson)
 {
-    // Get the Message from the MessageRegistry
-    const registries::Message* message = registries::getMessage(messageID);
+    std::optional<registries::MessageId> msgComponents =
+        registries::getMessageComponents(messageID);
+    if (msgComponents == std::nullopt)
+    {
+        BMCWEB_LOG_DEBUG("Could not get Message components");
+        return -1;
+    }
+
+    std::optional<registries::RegistryEntryRef> registry =
+        registries::getRegistryFromPrefix(msgComponents->registryName);
+    if (!registry)
+    {
+        BMCWEB_LOG_DEBUG("Could not get registry from prefix");
+        return -1;
+    }
+
+    // Get the Message from the MessageKey and RegistryEntries
+    const registries::Message* message = registries::getMessageFromRegistry(
+        msgComponents->messageKey, registry->get().entries);
 
     if (message == nullptr)
     {
         BMCWEB_LOG_DEBUG(
-            "{}: could not find messageID '{}' for log entry {} in registry",
-            __func__, messageID, logEntryID);
+            "Could not find MessageKey '{}' for log entry {} in registry",
+            msgComponents->messageKey, logEntryID);
         return -1;
     }
 
@@ -130,8 +149,7 @@
         redfish::registries::fillMessageArgs(messageArgs, message->message);
     if (msg.empty())
     {
-        BMCWEB_LOG_DEBUG("{}: message is empty after filling fillMessageArgs",
-                         __func__);
+        BMCWEB_LOG_DEBUG("Message is empty after filling fillMessageArgs");
         return -1;
     }
 
@@ -145,12 +163,17 @@
         timestamp.erase(dot, plus - dot);
     }
 
+    const unsigned int& versionMajor = registry->get().header.versionMajor;
+    const unsigned int& versionMinor = registry->get().header.versionMinor;
+
     // Fill in the log entry with the gathered data
     logEntryJson["EventId"] = std::to_string(eventId);
 
     logEntryJson["Severity"] = message->messageSeverity;
     logEntryJson["Message"] = std::move(msg);
-    logEntryJson["MessageId"] = messageID;
+    logEntryJson["MessageId"] =
+        std::format("{}.{}.{}.{}", msgComponents->registryName, versionMajor,
+                    versionMinor, msgComponents->messageKey);
     logEntryJson["MessageArgs"] = messageArgs;
     logEntryJson["EventTimestamp"] = std::move(timestamp);
     logEntryJson["Context"] = customText;
diff --git a/redfish-core/src/registries.cpp b/redfish-core/src/registries.cpp
index 2a426bf..8084a51 100644
--- a/redfish-core/src/registries.cpp
+++ b/redfish-core/src/registries.cpp
@@ -17,6 +17,7 @@
 #include <span>
 #include <string>
 #include <string_view>
+#include <utility>
 #include <vector>
 
 namespace redfish::registries
@@ -67,25 +68,34 @@
     return nullptr;
 }
 
-const Message* getMessage(std::string_view messageID)
+std::optional<MessageId> getMessageComponents(std::string_view message)
 {
-    // Redfish MessageIds are in the form
-    // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find
-    // the right Message
+    // Redfish Message are in the form
+    // RegistryName.MajorVersion.MinorVersion.MessageKey
     std::vector<std::string> fields;
     fields.reserve(4);
-    bmcweb::split(fields, messageID, '.');
+    bmcweb::split(fields, message, '.');
     if (fields.size() != 4)
     {
+        return std::nullopt;
+    }
+
+    return MessageId(std::move(fields[0]), std::move(fields[1]),
+                     std::move(fields[2]), std::move(fields[3]));
+}
+
+const Message* getMessage(std::string_view messageID)
+{
+    std::optional<MessageId> msgComponents = getMessageComponents(messageID);
+    if (!msgComponents)
+    {
         return nullptr;
     }
 
-    const std::string& registryName = fields[0];
-    const std::string& messageKey = fields[3];
-
     // Find the right registry and check it for the MessageKey
-    return getMessageFromRegistry(messageKey,
-                                  getRegistryMessagesFromPrefix(registryName));
+    return getMessageFromRegistry(
+        msgComponents->messageKey,
+        getRegistryMessagesFromPrefix(msgComponents->registryName));
 }
 
 } // namespace redfish::registries
diff --git a/test/redfish-core/include/event_log_test.cpp b/test/redfish-core/include/event_log_test.cpp
index c51eee6..ae77356 100644
--- a/test/redfish-core/include/event_log_test.cpp
+++ b/test/redfish-core/include/event_log_test.cpp
@@ -147,7 +147,7 @@
     ASSERT_EQ(logEntryJson["Message"], "Power supply PSU 1 fan FAN 2 failed.");
 
     ASSERT_TRUE(logEntryJson.contains("MessageId"));
-    ASSERT_EQ(logEntryJson["MessageId"], "OpenBMC.0.1.PowerSupplyFanFailed");
+    ASSERT_EQ(logEntryJson["MessageId"], "OpenBMC.0.5.PowerSupplyFanFailed");
 
     ASSERT_TRUE(logEntryJson.contains("MessageArgs"));
     ASSERT_EQ(logEntryJson["MessageArgs"].size(), 2);
diff --git a/test/redfish-core/include/registries_test.cpp b/test/redfish-core/include/registries_test.cpp
index ab43155..f1f49dd 100644
--- a/test/redfish-core/include/registries_test.cpp
+++ b/test/redfish-core/include/registries_test.cpp
@@ -3,6 +3,8 @@
 #include "registries.hpp"
 #include "registries/openbmc_message_registry.hpp"
 
+#include <optional>
+
 #include <gtest/gtest.h>
 
 namespace redfish::registries
@@ -52,5 +54,30 @@
     ASSERT_NE(msg, nullptr);
 }
 
+TEST(RedfishRegistries, GetMessageComponents)
+{
+    std::optional<registries::MessageId> msgComponents =
+        registries::getMessageComponents("OpenBMC.5.threeComponents");
+    ASSERT_EQ(msgComponents, std::nullopt);
+
+    msgComponents =
+        registries::getMessageComponents("OpenBMC.0.0.5.fiveComponents");
+    ASSERT_EQ(msgComponents, std::nullopt);
+
+    msgComponents =
+        registries::getMessageComponents("OpenBMC.0.5.BIOSAttributesChanged");
+    ASSERT_TRUE(msgComponents);
+
+    if (!msgComponents)
+    {
+        return;
+    }
+
+    EXPECT_EQ(msgComponents->registryName, "OpenBMC");
+    EXPECT_EQ(msgComponents->messageKey, "BIOSAttributesChanged");
+    EXPECT_EQ(msgComponents->majorVersion, "0");
+    EXPECT_EQ(msgComponents->minorVersion, "5");
+}
+
 } // namespace
 } // namespace redfish::registries