Deduplicate event ids

Redfish specification states:
```
The value of the id field shall be the same as the Id property in the
event payload. The value of the Id property in the event payload should
be the same as the EventId property of the last event record in the
Events array. The value of the EventId property for an event record
should be a positive integer value and should be generated in a
sequential manner.
```

The event service code did not implement that correctly.  So:
1. Add ID fields for all events.
2. Remove the per-sse connection id field and rely solely on
   EventServiceManager.
3. Make sure all paths, (including metric report) are generating an
   event id that's based on the eventservice event id

Tested: Redfish event listener now sees events populated.
LastEventId when sent to the SSE socket now sees a contiguous id.

```
uri=$(curl -s --user "root:0penBmc" -k "https://192.168.7.2/redfish/v1/EventService" | jq -r .ServerSentEventUri)
curl -u root:0penBmc -vvv -k -N -H "Accept: text/event-stream" -H "Last-Event-Id: 0" "https://192.168.7.2$uri"
```

Change-Id: Ic32e036f40a53a9b2715639ae384d7891c768260
Signed-off-by: Ed Tanous <etanous@nvidia.com>
diff --git a/redfish-core/src/event_log.cpp b/redfish-core/src/event_log.cpp
index d7cd2f2..a4e7850 100644
--- a/redfish-core/src/event_log.cpp
+++ b/redfish-core/src/event_log.cpp
@@ -23,6 +23,7 @@
 
 #include <cerrno>
 #include <cstddef>
+#include <cstdint>
 #include <ctime>
 #include <iomanip>
 #include <span>
@@ -120,10 +121,11 @@
     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)
+int formatEventLogEntry(uint64_t eventId, 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::getMessage(messageID);
@@ -156,7 +158,7 @@
     }
 
     // Fill in the log entry with the gathered data
-    logEntryJson["EventId"] = logEntryID;
+    logEntryJson["EventId"] = std::to_string(eventId);
 
     logEntryJson["Severity"] = message->messageSeverity;
     logEntryJson["Message"] = std::move(msg);
diff --git a/redfish-core/src/subscription.cpp b/redfish-core/src/subscription.cpp
index 1ca8a5e..f35a8e9 100644
--- a/redfish-core/src/subscription.cpp
+++ b/redfish-core/src/subscription.cpp
@@ -107,9 +107,6 @@
 {
     // send the heartbeat message
     nlohmann::json eventMessage = messages::redfishServiceFunctional();
-
-    std::string heartEventId = std::to_string(eventSeqNum);
-    eventMessage["EventId"] = heartEventId;
     eventMessage["EventTimestamp"] = time_utils::getDateTimeOffsetNow().first;
     eventMessage["OriginOfCondition"] =
         std::format("/redfish/v1/EventService/Subscriptions/{}", userSub->id);
@@ -121,13 +118,15 @@
     nlohmann::json msgJson;
     msgJson["@odata.type"] = "#Event.v1_4_0.Event";
     msgJson["Name"] = "Heartbeat";
-    msgJson["Id"] = heartEventId;
     msgJson["Events"] = std::move(eventRecord);
 
     std::string strMsg =
         msgJson.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
-    sendEventToSubscriber(std::move(strMsg));
-    eventSeqNum++;
+
+    // Note, eventId here is always zero, because this is a a per subscription
+    // event and doesn't have an "ID"
+    uint64_t eventId = 0;
+    sendEventToSubscriber(eventId, std::move(strMsg));
 }
 
 void Subscription::scheduleNextHeartbeatEvent()
@@ -180,7 +179,7 @@
     scheduleNextHeartbeatEvent();
 }
 
-bool Subscription::sendEventToSubscriber(std::string&& msg)
+bool Subscription::sendEventToSubscriber(uint64_t eventId, std::string&& msg)
 {
     persistent_data::EventServiceConfig eventServiceConfig =
         persistent_data::EventServiceStore::getInstance()
@@ -206,77 +205,13 @@
 
     if (sseConn != nullptr)
     {
-        eventSeqNum++;
-        sseConn->sendSseEvent(std::to_string(eventSeqNum), msg);
+        sseConn->sendSseEvent(std::to_string(eventId), msg);
     }
     return true;
 }
 
-bool Subscription::sendTestEventLog(TestEvent& testEvent)
-{
-    nlohmann::json::array_t logEntryArray;
-    nlohmann::json& logEntryJson = logEntryArray.emplace_back();
-
-    if (testEvent.eventGroupId)
-    {
-        logEntryJson["EventGroupId"] = *testEvent.eventGroupId;
-    }
-
-    if (testEvent.eventId)
-    {
-        logEntryJson["EventId"] = *testEvent.eventId;
-    }
-
-    if (testEvent.eventTimestamp)
-    {
-        logEntryJson["EventTimestamp"] = *testEvent.eventTimestamp;
-    }
-
-    if (testEvent.originOfCondition)
-    {
-        logEntryJson["OriginOfCondition"]["@odata.id"] =
-            *testEvent.originOfCondition;
-    }
-    if (testEvent.severity)
-    {
-        logEntryJson["Severity"] = *testEvent.severity;
-    }
-
-    if (testEvent.message)
-    {
-        logEntryJson["Message"] = *testEvent.message;
-    }
-
-    if (testEvent.resolution)
-    {
-        logEntryJson["Resolution"] = *testEvent.resolution;
-    }
-
-    if (testEvent.messageId)
-    {
-        logEntryJson["MessageId"] = *testEvent.messageId;
-    }
-
-    if (testEvent.messageArgs)
-    {
-        logEntryJson["MessageArgs"] = *testEvent.messageArgs;
-    }
-    // MemberId is 0 : since we are sending one event record.
-    logEntryJson["MemberId"] = "0";
-
-    nlohmann::json msg;
-    msg["@odata.type"] = "#Event.v1_4_0.Event";
-    msg["Id"] = std::to_string(eventSeqNum);
-    msg["Name"] = "Event Log";
-    msg["Events"] = logEntryArray;
-
-    std::string strMsg =
-        msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
-    return sendEventToSubscriber(std::move(strMsg));
-}
-
 void Subscription::filterAndSendEventLogs(
-    const std::vector<EventLogObjectsType>& eventRecords)
+    uint64_t eventId, const std::vector<EventLogObjectsType>& eventRecords)
 {
     nlohmann::json::array_t logEntryArray;
     for (const EventLogObjectsType& logEntry : eventRecords)
@@ -288,7 +223,7 @@
 
         nlohmann::json::object_t bmcLogEntry;
         if (event_log::formatEventLogEntry(
-                logEntry.id, logEntry.messageId, messageArgsView,
+                eventId, logEntry.id, logEntry.messageId, messageArgsView,
                 logEntry.timestamp, userSub->customText, bmcLogEntry) != 0)
         {
             BMCWEB_LOG_WARNING("Read eventLog entry failed");
@@ -312,6 +247,7 @@
         }
 
         logEntryArray.emplace_back(std::move(bmcLogEntry));
+        eventId++;
     }
 
     if (logEntryArray.empty())
@@ -322,16 +258,16 @@
 
     nlohmann::json msg;
     msg["@odata.type"] = "#Event.v1_4_0.Event";
-    msg["Id"] = std::to_string(eventSeqNum);
+    msg["Id"] = std::to_string(eventId);
     msg["Name"] = "Event Log";
     msg["Events"] = std::move(logEntryArray);
     std::string strMsg =
         msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
-    sendEventToSubscriber(std::move(strMsg));
-    eventSeqNum++;
+    sendEventToSubscriber(eventId, std::move(strMsg));
 }
 
-void Subscription::filterAndSendReports(const std::string& reportId,
+void Subscription::filterAndSendReports(uint64_t eventId,
+                                        const std::string& reportId,
                                         const telemetry::TimestampReadings& var)
 {
     boost::urls::url mrdUri = boost::urls::format(
@@ -366,7 +302,7 @@
 
     std::string strMsg =
         msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
-    sendEventToSubscriber(std::move(strMsg));
+    sendEventToSubscriber(eventId, std::move(strMsg));
 }
 
 void Subscription::updateRetryConfig(uint32_t retryAttempts,
@@ -381,11 +317,6 @@
     policy->retryIntervalSecs = std::chrono::seconds(retryTimeoutInterval);
 }
 
-uint64_t Subscription::getEventSeqNum() const
-{
-    return eventSeqNum;
-}
-
 bool Subscription::matchSseId(const crow::sse_socket::Connection& thisConn)
 {
     return &thisConn == sseConn;