xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision a14c9113226dcae33a36eb4e50abbcc28be998ae)
1b52664e2SAppaRao Puli /*
26be832e2SEd Tanous Copyright (c) 2020 Intel Corporation
36be832e2SEd Tanous 
46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License");
56be832e2SEd Tanous you may not use this file except in compliance with the License.
66be832e2SEd Tanous You may obtain a copy of the License at
76be832e2SEd Tanous 
86be832e2SEd Tanous       http://www.apache.org/licenses/LICENSE-2.0
96be832e2SEd Tanous 
106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software
116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS,
126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136be832e2SEd Tanous See the License for the specific language governing permissions and
146be832e2SEd Tanous limitations under the License.
15b52664e2SAppaRao Puli */
16b52664e2SAppaRao Puli #pragma once
173ccb3adbSEd Tanous #include "dbus_utility.hpp"
183ccb3adbSEd Tanous #include "error_messages.hpp"
193ccb3adbSEd Tanous #include "event_service_store.hpp"
20f80a87f2SEd Tanous #include "filter_expr_executor.hpp"
21539d8c6bSEd Tanous #include "generated/enums/event.hpp"
22539d8c6bSEd Tanous #include "generated/enums/log_entry.hpp"
233ccb3adbSEd Tanous #include "http_client.hpp"
24c0353249SWludzik, Jozef #include "metric_report.hpp"
252c6ffdb0SEd Tanous #include "ossl_random.hpp"
263ccb3adbSEd Tanous #include "persistent_data.hpp"
277f4eb588SAppaRao Puli #include "registries.hpp"
288dab0f58SEd Tanous #include "registries_selector.hpp"
2950ebd4afSEd Tanous #include "str_utility.hpp"
3077665bdaSNan Zhou #include "utility.hpp"
313ccb3adbSEd Tanous #include "utils/json_utils.hpp"
325b90429aSEd Tanous #include "utils/time_utils.hpp"
337f4eb588SAppaRao Puli 
347f4eb588SAppaRao Puli #include <sys/inotify.h>
35b52664e2SAppaRao Puli 
36fb4fd5d4SZhenfei Tai #include <boost/asio/io_context.hpp>
37f80a87f2SEd Tanous #include <boost/circular_buffer.hpp>
38b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp>
39ef4c65b7SEd Tanous #include <boost/url/format.hpp>
404a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp>
41b5b40605Snitroglycerine #include <sdbusplus/bus/match.hpp>
421214b7e7SGunnar Mills 
435e44e3d8SAppaRao Puli #include <algorithm>
44b52664e2SAppaRao Puli #include <cstdlib>
45b52664e2SAppaRao Puli #include <ctime>
46*a14c9113SEd Tanous #include <format>
471bf712bcSAyushi Smriti #include <fstream>
48b52664e2SAppaRao Puli #include <memory>
493544d2a7SEd Tanous #include <ranges>
5026702d01SEd Tanous #include <span>
51*a14c9113SEd Tanous #include <string>
52b52664e2SAppaRao Puli 
53b52664e2SAppaRao Puli namespace redfish
54b52664e2SAppaRao Puli {
55156d6b00SAppaRao Puli 
56156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event";
57156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport";
58156d6b00SAppaRao Puli 
595e44e3d8SAppaRao Puli static constexpr const char* subscriptionTypeSSE = "SSE";
601bf712bcSAyushi Smriti static constexpr const char* eventServiceFile =
611bf712bcSAyushi Smriti     "/var/lib/bmcweb/eventservice_config.json";
621bf712bcSAyushi Smriti 
635e44e3d8SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20;
645e44e3d8SAppaRao Puli static constexpr const uint8_t maxNoOfSSESubscriptions = 10;
655e44e3d8SAppaRao Puli 
66cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
674642bf8fSGeorge Liu static std::optional<boost::asio::posix::stream_descriptor> inotifyConn;
684642bf8fSGeorge Liu static constexpr const char* redfishEventLogDir = "/var/log";
694642bf8fSGeorge Liu static constexpr const char* redfishEventLogFile = "/var/log/redfish";
704642bf8fSGeorge Liu static constexpr const size_t iEventSize = sizeof(inotify_event);
71cf9e417dSEd Tanous 
72cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
734642bf8fSGeorge Liu static int inotifyFd = -1;
74cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
754642bf8fSGeorge Liu static int dirWatchDesc = -1;
76cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
774642bf8fSGeorge Liu static int fileWatchDesc = -1;
78f80a87f2SEd Tanous struct EventLogObjectsType
79f80a87f2SEd Tanous {
80f80a87f2SEd Tanous     std::string id;
81f80a87f2SEd Tanous     std::string timestamp;
82f80a87f2SEd Tanous     std::string messageId;
83f80a87f2SEd Tanous     std::vector<std::string> messageArgs;
84f80a87f2SEd Tanous };
854642bf8fSGeorge Liu 
86fffb8c1fSEd Tanous namespace registries
874642bf8fSGeorge Liu {
887f4eb588SAppaRao Puli static const Message*
897f4eb588SAppaRao Puli     getMsgFromRegistry(const std::string& messageKey,
9026702d01SEd Tanous                        const std::span<const MessageEntry>& registry)
917f4eb588SAppaRao Puli {
923544d2a7SEd Tanous     std::span<const MessageEntry>::iterator messageIt = std::ranges::find_if(
933544d2a7SEd Tanous         registry, [&messageKey](const MessageEntry& messageEntry) {
9455f79e6fSEd Tanous             return messageKey == messageEntry.first;
957f4eb588SAppaRao Puli         });
9626702d01SEd Tanous     if (messageIt != registry.end())
977f4eb588SAppaRao Puli     {
987f4eb588SAppaRao Puli         return &messageIt->second;
997f4eb588SAppaRao Puli     }
1007f4eb588SAppaRao Puli 
1017f4eb588SAppaRao Puli     return nullptr;
1027f4eb588SAppaRao Puli }
1037f4eb588SAppaRao Puli 
10426ccae32SEd Tanous static const Message* formatMessage(std::string_view messageID)
1057f4eb588SAppaRao Puli {
1067f4eb588SAppaRao Puli     // Redfish MessageIds are in the form
1077f4eb588SAppaRao Puli     // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find
1087f4eb588SAppaRao Puli     // the right Message
1097f4eb588SAppaRao Puli     std::vector<std::string> fields;
1107f4eb588SAppaRao Puli     fields.reserve(4);
11150ebd4afSEd Tanous 
11250ebd4afSEd Tanous     bmcweb::split(fields, messageID, '.');
1137f4eb588SAppaRao Puli     if (fields.size() != 4)
1147f4eb588SAppaRao Puli     {
1157f4eb588SAppaRao Puli         return nullptr;
1167f4eb588SAppaRao Puli     }
11702cad96eSEd Tanous     const std::string& registryName = fields[0];
11802cad96eSEd Tanous     const std::string& messageKey = fields[3];
1197f4eb588SAppaRao Puli 
1207f4eb588SAppaRao Puli     // Find the right registry and check it for the MessageKey
121b304bd79SP Dheeraj Srujan Kumar     return getMsgFromRegistry(messageKey, getRegistryFromPrefix(registryName));
1227f4eb588SAppaRao Puli }
123fffb8c1fSEd Tanous } // namespace registries
1247f4eb588SAppaRao Puli 
1257f4eb588SAppaRao Puli namespace event_log
1267f4eb588SAppaRao Puli {
1272558979cSP Dheeraj Srujan Kumar inline bool getUniqueEntryID(const std::string& logEntry, std::string& entryID)
1287f4eb588SAppaRao Puli {
1297f4eb588SAppaRao Puli     static time_t prevTs = 0;
1307f4eb588SAppaRao Puli     static int index = 0;
1317f4eb588SAppaRao Puli 
1327f4eb588SAppaRao Puli     // Get the entry timestamp
1337f4eb588SAppaRao Puli     std::time_t curTs = 0;
1347f4eb588SAppaRao Puli     std::tm timeStruct = {};
1357f4eb588SAppaRao Puli     std::istringstream entryStream(logEntry);
1367f4eb588SAppaRao Puli     if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
1377f4eb588SAppaRao Puli     {
1387f4eb588SAppaRao Puli         curTs = std::mktime(&timeStruct);
1397f4eb588SAppaRao Puli         if (curTs == -1)
1407f4eb588SAppaRao Puli         {
1417f4eb588SAppaRao Puli             return false;
1427f4eb588SAppaRao Puli         }
1437f4eb588SAppaRao Puli     }
1447f4eb588SAppaRao Puli     // If the timestamp isn't unique, increment the index
1457f4eb588SAppaRao Puli     index = (curTs == prevTs) ? index + 1 : 0;
1467f4eb588SAppaRao Puli 
1477f4eb588SAppaRao Puli     // Save the timestamp
1487f4eb588SAppaRao Puli     prevTs = curTs;
1497f4eb588SAppaRao Puli 
1507f4eb588SAppaRao Puli     entryID = std::to_string(curTs);
1517f4eb588SAppaRao Puli     if (index > 0)
1527f4eb588SAppaRao Puli     {
1537f4eb588SAppaRao Puli         entryID += "_" + std::to_string(index);
1547f4eb588SAppaRao Puli     }
1557f4eb588SAppaRao Puli     return true;
1567f4eb588SAppaRao Puli }
1577f4eb588SAppaRao Puli 
15823a21a1cSEd Tanous inline int getEventLogParams(const std::string& logEntry,
15923a21a1cSEd Tanous                              std::string& timestamp, std::string& messageID,
1605e715de6SAppaRao Puli                              std::vector<std::string>& messageArgs)
1617f4eb588SAppaRao Puli {
1627f4eb588SAppaRao Puli     // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
1637f4eb588SAppaRao Puli     // First get the Timestamp
164f23b7296SEd Tanous     size_t space = logEntry.find_first_of(' ');
1657f4eb588SAppaRao Puli     if (space == std::string::npos)
1667f4eb588SAppaRao Puli     {
16703d4d37cSAlexander Hansen         BMCWEB_LOG_ERROR("EventLog Params: could not find first space: {}",
16803d4d37cSAlexander Hansen                          logEntry);
1697f4eb588SAppaRao Puli         return -EINVAL;
1707f4eb588SAppaRao Puli     }
1717f4eb588SAppaRao Puli     timestamp = logEntry.substr(0, space);
1727f4eb588SAppaRao Puli     // Then get the log contents
173f23b7296SEd Tanous     size_t entryStart = logEntry.find_first_not_of(' ', space);
1747f4eb588SAppaRao Puli     if (entryStart == std::string::npos)
1757f4eb588SAppaRao Puli     {
17603d4d37cSAlexander Hansen         BMCWEB_LOG_ERROR("EventLog Params: could not find log contents: {}",
17703d4d37cSAlexander Hansen                          logEntry);
1787f4eb588SAppaRao Puli         return -EINVAL;
1797f4eb588SAppaRao Puli     }
1807f4eb588SAppaRao Puli     std::string_view entry(logEntry);
1817f4eb588SAppaRao Puli     entry.remove_prefix(entryStart);
1827f4eb588SAppaRao Puli     // Use split to separate the entry into its fields
1837f4eb588SAppaRao Puli     std::vector<std::string> logEntryFields;
18450ebd4afSEd Tanous     bmcweb::split(logEntryFields, entry, ',');
1857f4eb588SAppaRao Puli     // We need at least a MessageId to be valid
18626f6976fSEd Tanous     if (logEntryFields.empty())
1877f4eb588SAppaRao Puli     {
18803d4d37cSAlexander Hansen         BMCWEB_LOG_ERROR("EventLog Params: could not find entry fields: {}",
18903d4d37cSAlexander Hansen                          logEntry);
1907f4eb588SAppaRao Puli         return -EINVAL;
1917f4eb588SAppaRao Puli     }
1927f4eb588SAppaRao Puli     messageID = logEntryFields[0];
1937f4eb588SAppaRao Puli 
1947f4eb588SAppaRao Puli     // Get the MessageArgs from the log if there are any
1957f4eb588SAppaRao Puli     if (logEntryFields.size() > 1)
1967f4eb588SAppaRao Puli     {
19702cad96eSEd Tanous         const std::string& messageArgsStart = logEntryFields[1];
1987f4eb588SAppaRao Puli         // If the first string is empty, assume there are no MessageArgs
1997f4eb588SAppaRao Puli         if (!messageArgsStart.empty())
2007f4eb588SAppaRao Puli         {
2015e715de6SAppaRao Puli             messageArgs.assign(logEntryFields.begin() + 1,
2025e715de6SAppaRao Puli                                logEntryFields.end());
2037f4eb588SAppaRao Puli         }
2047f4eb588SAppaRao Puli     }
2057f4eb588SAppaRao Puli 
2067f4eb588SAppaRao Puli     return 0;
2077f4eb588SAppaRao Puli }
2087f4eb588SAppaRao Puli 
20923a21a1cSEd Tanous inline void getRegistryAndMessageKey(const std::string& messageID,
2107f4eb588SAppaRao Puli                                      std::string& registryName,
2117f4eb588SAppaRao Puli                                      std::string& messageKey)
2127f4eb588SAppaRao Puli {
2137f4eb588SAppaRao Puli     // Redfish MessageIds are in the form
2147f4eb588SAppaRao Puli     // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find
2157f4eb588SAppaRao Puli     // the right Message
2167f4eb588SAppaRao Puli     std::vector<std::string> fields;
2177f4eb588SAppaRao Puli     fields.reserve(4);
21850ebd4afSEd Tanous     bmcweb::split(fields, messageID, '.');
2197f4eb588SAppaRao Puli     if (fields.size() == 4)
2207f4eb588SAppaRao Puli     {
2217f4eb588SAppaRao Puli         registryName = fields[0];
2227f4eb588SAppaRao Puli         messageKey = fields[3];
2237f4eb588SAppaRao Puli     }
2247f4eb588SAppaRao Puli }
2257f4eb588SAppaRao Puli 
226bd79bce8SPatrick Williams inline int formatEventLogEntry(
227bd79bce8SPatrick Williams     const std::string& logEntryID, const std::string& messageID,
228bd79bce8SPatrick Williams     const std::span<std::string_view> messageArgs, std::string timestamp,
229bd79bce8SPatrick Williams     const std::string& customText, nlohmann::json::object_t& logEntryJson)
2307f4eb588SAppaRao Puli {
2317f4eb588SAppaRao Puli     // Get the Message from the MessageRegistry
232fffb8c1fSEd Tanous     const registries::Message* message = registries::formatMessage(messageID);
2337f4eb588SAppaRao Puli 
23480f595e7SEd Tanous     if (message == nullptr)
2357f4eb588SAppaRao Puli     {
23680f595e7SEd Tanous         return -1;
2377f4eb588SAppaRao Puli     }
2387f4eb588SAppaRao Puli 
239bd79bce8SPatrick Williams     std::string msg =
240bd79bce8SPatrick Williams         redfish::registries::fillMessageArgs(messageArgs, message->message);
24180f595e7SEd Tanous     if (msg.empty())
24280f595e7SEd Tanous     {
24380f595e7SEd Tanous         return -1;
24480f595e7SEd Tanous     }
2457f4eb588SAppaRao Puli 
2467f4eb588SAppaRao Puli     // Get the Created time from the timestamp. The log timestamp is in
2477f4eb588SAppaRao Puli     // RFC3339 format which matches the Redfish format except for the
2487f4eb588SAppaRao Puli     // fractional seconds between the '.' and the '+', so just remove them.
249f23b7296SEd Tanous     std::size_t dot = timestamp.find_first_of('.');
250b2f7609bSEd Tanous     std::size_t plus = timestamp.find_first_of('+', dot);
2517f4eb588SAppaRao Puli     if (dot != std::string::npos && plus != std::string::npos)
2527f4eb588SAppaRao Puli     {
2537f4eb588SAppaRao Puli         timestamp.erase(dot, plus - dot);
2547f4eb588SAppaRao Puli     }
2557f4eb588SAppaRao Puli 
2567f4eb588SAppaRao Puli     // Fill in the log entry with the gathered data
2571476687dSEd Tanous     logEntryJson["EventId"] = logEntryID;
258539d8c6bSEd Tanous 
25980f595e7SEd Tanous     logEntryJson["Severity"] = message->messageSeverity;
2601476687dSEd Tanous     logEntryJson["Message"] = std::move(msg);
2611476687dSEd Tanous     logEntryJson["MessageId"] = messageID;
2621476687dSEd Tanous     logEntryJson["MessageArgs"] = messageArgs;
2631476687dSEd Tanous     logEntryJson["EventTimestamp"] = std::move(timestamp);
2641476687dSEd Tanous     logEntryJson["Context"] = customText;
2657f4eb588SAppaRao Puli     return 0;
2667f4eb588SAppaRao Puli }
2677f4eb588SAppaRao Puli 
2687f4eb588SAppaRao Puli } // namespace event_log
2697f4eb588SAppaRao Puli 
27028afb49cSJunLin Chen class Subscription : public persistent_data::UserSubscription
271b52664e2SAppaRao Puli {
272b52664e2SAppaRao Puli   public:
273b52664e2SAppaRao Puli     Subscription(const Subscription&) = delete;
274b52664e2SAppaRao Puli     Subscription& operator=(const Subscription&) = delete;
275b52664e2SAppaRao Puli     Subscription(Subscription&&) = delete;
276b52664e2SAppaRao Puli     Subscription& operator=(Subscription&&) = delete;
277b52664e2SAppaRao Puli 
2784a7fbefdSEd Tanous     Subscription(const boost::urls::url_view_base& url,
2794a7fbefdSEd Tanous                  boost::asio::io_context& ioc) :
280a716aa74SEd Tanous         policy(std::make_shared<crow::ConnectionPolicy>())
281b52664e2SAppaRao Puli     {
282a716aa74SEd Tanous         destinationUrl = url;
2835e44e3d8SAppaRao Puli         client.emplace(ioc, policy);
2847adb85acSSunitha Harish         // Subscription constructor
285d14a48ffSCarson Labrado         policy->invalidResp = retryRespHandler;
286b52664e2SAppaRao Puli     }
2874bbf237fSAppaRao Puli 
2885e44e3d8SAppaRao Puli     explicit Subscription(crow::sse_socket::Connection& connIn) :
2895e44e3d8SAppaRao Puli         sseConn(&connIn)
2905e44e3d8SAppaRao Puli     {}
2915e44e3d8SAppaRao Puli 
2929f616dd1SEd Tanous     ~Subscription() = default;
293b52664e2SAppaRao Puli 
2946d799e14SEd Tanous     bool sendEventToSubscriber(std::string&& msg)
295b52664e2SAppaRao Puli     {
2966ba8c82eSsunharis_in         persistent_data::EventServiceConfig eventServiceConfig =
2976ba8c82eSsunharis_in             persistent_data::EventServiceStore::getInstance()
2986ba8c82eSsunharis_in                 .getEventServiceConfig();
2996ba8c82eSsunharis_in         if (!eventServiceConfig.enabled)
3006ba8c82eSsunharis_in         {
3016ba8c82eSsunharis_in             return false;
3026ba8c82eSsunharis_in         }
3036ba8c82eSsunharis_in 
3045e44e3d8SAppaRao Puli         if (client)
3055e44e3d8SAppaRao Puli         {
30619bb362bSEd Tanous             client->sendData(
30719bb362bSEd Tanous                 std::move(msg), destinationUrl,
30819bb362bSEd Tanous                 static_cast<ensuressl::VerifyCertificate>(verifyCertificate),
30919bb362bSEd Tanous                 httpHeaders, boost::beast::http::verb::post);
3105e44e3d8SAppaRao Puli             return true;
3115e44e3d8SAppaRao Puli         }
3127adb85acSSunitha Harish 
3134bbf237fSAppaRao Puli         if (sseConn != nullptr)
3144bbf237fSAppaRao Puli         {
3155e44e3d8SAppaRao Puli             eventSeqNum++;
3166d799e14SEd Tanous             sseConn->sendSseEvent(std::to_string(eventSeqNum), msg);
3174bbf237fSAppaRao Puli         }
3186ba8c82eSsunharis_in         return true;
3194bbf237fSAppaRao Puli     }
3204bbf237fSAppaRao Puli 
321f80a87f2SEd Tanous     bool eventMatchesFilter(const nlohmann::json::object_t& eventMessage,
322f80a87f2SEd Tanous                             std::string_view resType)
323f80a87f2SEd Tanous     {
324f80a87f2SEd Tanous         // If resourceTypes list is empty, assume all
325f80a87f2SEd Tanous         if (!resourceTypes.empty())
326f80a87f2SEd Tanous         {
327f80a87f2SEd Tanous             // Search the resourceTypes list for the subscription.
328f80a87f2SEd Tanous             auto resourceTypeIndex = std::ranges::find_if(
329f80a87f2SEd Tanous                 resourceTypes, [resType](const std::string& rtEntry) {
330f80a87f2SEd Tanous                     return rtEntry == resType;
331f80a87f2SEd Tanous                 });
332f80a87f2SEd Tanous             if (resourceTypeIndex == resourceTypes.end())
333f80a87f2SEd Tanous             {
334f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Not subscribed to this resource");
335f80a87f2SEd Tanous                 return false;
336f80a87f2SEd Tanous             }
337f80a87f2SEd Tanous             BMCWEB_LOG_DEBUG("ResourceType {} found in the subscribed list",
338f80a87f2SEd Tanous                              resType);
339f80a87f2SEd Tanous         }
340f80a87f2SEd Tanous 
341*a14c9113SEd Tanous         // If registryPrefixes list is empty, don't filter events
342*a14c9113SEd Tanous         // send everything.
343*a14c9113SEd Tanous         if (!registryPrefixes.empty())
344*a14c9113SEd Tanous         {
345*a14c9113SEd Tanous             auto eventJson = eventMessage.find("MessageId");
346*a14c9113SEd Tanous             if (eventJson == eventMessage.end())
347*a14c9113SEd Tanous             {
348*a14c9113SEd Tanous                 return false;
349*a14c9113SEd Tanous             }
350*a14c9113SEd Tanous 
351*a14c9113SEd Tanous             const std::string* messageId =
352*a14c9113SEd Tanous                 eventJson->second.get_ptr<const std::string*>();
353*a14c9113SEd Tanous             if (messageId == nullptr)
354*a14c9113SEd Tanous             {
355*a14c9113SEd Tanous                 BMCWEB_LOG_ERROR("MessageId wasn't a string???");
356*a14c9113SEd Tanous                 return false;
357*a14c9113SEd Tanous             }
358*a14c9113SEd Tanous 
359*a14c9113SEd Tanous             std::string registry;
360*a14c9113SEd Tanous             std::string messageKey;
361*a14c9113SEd Tanous             event_log::getRegistryAndMessageKey(*messageId, registry,
362*a14c9113SEd Tanous                                                 messageKey);
363*a14c9113SEd Tanous 
364*a14c9113SEd Tanous             auto obj = std::ranges::find(registryPrefixes, registry);
365*a14c9113SEd Tanous             if (obj == registryPrefixes.end())
366*a14c9113SEd Tanous             {
367*a14c9113SEd Tanous                 return false;
368*a14c9113SEd Tanous             }
369*a14c9113SEd Tanous         }
370*a14c9113SEd Tanous 
371*a14c9113SEd Tanous         if (!originResources.empty())
372*a14c9113SEd Tanous         {
373*a14c9113SEd Tanous             auto eventJson = eventMessage.find("OriginOfCondition");
374*a14c9113SEd Tanous             if (eventJson == eventMessage.end())
375*a14c9113SEd Tanous             {
376*a14c9113SEd Tanous                 return false;
377*a14c9113SEd Tanous             }
378*a14c9113SEd Tanous 
379*a14c9113SEd Tanous             const std::string* originOfCondition =
380*a14c9113SEd Tanous                 eventJson->second.get_ptr<const std::string*>();
381*a14c9113SEd Tanous             if (originOfCondition == nullptr)
382*a14c9113SEd Tanous             {
383*a14c9113SEd Tanous                 BMCWEB_LOG_ERROR("OriginOfCondition wasn't a string???");
384*a14c9113SEd Tanous                 return false;
385*a14c9113SEd Tanous             }
386*a14c9113SEd Tanous 
387*a14c9113SEd Tanous             auto obj = std::ranges::find(originResources, *originOfCondition);
388*a14c9113SEd Tanous 
389*a14c9113SEd Tanous             if (obj == originResources.end())
390*a14c9113SEd Tanous             {
391*a14c9113SEd Tanous                 return false;
392*a14c9113SEd Tanous             }
393*a14c9113SEd Tanous         }
394*a14c9113SEd Tanous 
395f80a87f2SEd Tanous         // If registryMsgIds list is empty, assume all
396f80a87f2SEd Tanous         if (!registryMsgIds.empty())
397f80a87f2SEd Tanous         {
398f80a87f2SEd Tanous             auto eventJson = eventMessage.find("MessageId");
399f80a87f2SEd Tanous             if (eventJson == eventMessage.end())
400f80a87f2SEd Tanous             {
40103d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("'MessageId' not present");
402f80a87f2SEd Tanous                 return false;
403f80a87f2SEd Tanous             }
404f80a87f2SEd Tanous 
405f80a87f2SEd Tanous             const std::string* messageId =
406f80a87f2SEd Tanous                 eventJson->second.get_ptr<const std::string*>();
407f80a87f2SEd Tanous             if (messageId == nullptr)
408f80a87f2SEd Tanous             {
409f80a87f2SEd Tanous                 BMCWEB_LOG_ERROR("EventType wasn't a string???");
410f80a87f2SEd Tanous                 return false;
411f80a87f2SEd Tanous             }
412f80a87f2SEd Tanous 
413f80a87f2SEd Tanous             std::string registry;
414f80a87f2SEd Tanous             std::string messageKey;
415f80a87f2SEd Tanous             event_log::getRegistryAndMessageKey(*messageId, registry,
416f80a87f2SEd Tanous                                                 messageKey);
417f80a87f2SEd Tanous 
41803d4d37cSAlexander Hansen             BMCWEB_LOG_DEBUG("extracted registry {}", registry);
41903d4d37cSAlexander Hansen             BMCWEB_LOG_DEBUG("extracted message key {}", messageKey);
42003d4d37cSAlexander Hansen 
421*a14c9113SEd Tanous             auto obj = std::ranges::find(
422*a14c9113SEd Tanous                 registryMsgIds, std::format("{}.{}", registry, messageKey));
423f80a87f2SEd Tanous             if (obj == registryMsgIds.end())
424f80a87f2SEd Tanous             {
42503d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("did not find registry {} in registryMsgIds",
42603d4d37cSAlexander Hansen                                  registry);
42703d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("registryMsgIds has {} entries",
42803d4d37cSAlexander Hansen                                  registryMsgIds.size());
429f80a87f2SEd Tanous                 return false;
430f80a87f2SEd Tanous             }
431f80a87f2SEd Tanous         }
432f80a87f2SEd Tanous 
433f80a87f2SEd Tanous         if (filter)
434f80a87f2SEd Tanous         {
435f80a87f2SEd Tanous             if (!memberMatches(eventMessage, *filter))
436f80a87f2SEd Tanous             {
437f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Filter didn't match");
438f80a87f2SEd Tanous                 return false;
439f80a87f2SEd Tanous             }
440f80a87f2SEd Tanous         }
441f80a87f2SEd Tanous 
442f80a87f2SEd Tanous         return true;
443f80a87f2SEd Tanous     }
444f80a87f2SEd Tanous 
4456ba8c82eSsunharis_in     bool sendTestEventLog()
4460b4bdd93SAppaRao Puli     {
447f80a87f2SEd Tanous         nlohmann::json::array_t logEntryArray;
448f80a87f2SEd Tanous         nlohmann::json& logEntryJson = logEntryArray.emplace_back();
4490b4bdd93SAppaRao Puli 
450613dabeaSEd Tanous         logEntryJson["EventId"] = "TestID";
451539d8c6bSEd Tanous         logEntryJson["Severity"] = log_entry::EventSeverity::OK;
452613dabeaSEd Tanous         logEntryJson["Message"] = "Generated test event";
453613dabeaSEd Tanous         logEntryJson["MessageId"] = "OpenBMC.0.2.TestEventLog";
454d2cdd478SChandra Harkude         // MemberId is 0 : since we are sending one event record.
455d2cdd478SChandra Harkude         logEntryJson["MemberId"] = 0;
456613dabeaSEd Tanous         logEntryJson["MessageArgs"] = nlohmann::json::array();
457613dabeaSEd Tanous         logEntryJson["EventTimestamp"] =
458613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
459613dabeaSEd Tanous         logEntryJson["Context"] = customText;
4600b4bdd93SAppaRao Puli 
4611476687dSEd Tanous         nlohmann::json msg;
4621476687dSEd Tanous         msg["@odata.type"] = "#Event.v1_4_0.Event";
4631476687dSEd Tanous         msg["Id"] = std::to_string(eventSeqNum);
4641476687dSEd Tanous         msg["Name"] = "Event Log";
4651476687dSEd Tanous         msg["Events"] = logEntryArray;
4660b4bdd93SAppaRao Puli 
467bd79bce8SPatrick Williams         std::string strMsg =
468bd79bce8SPatrick Williams             msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
4696d799e14SEd Tanous         return sendEventToSubscriber(std::move(strMsg));
4700b4bdd93SAppaRao Puli     }
4710b4bdd93SAppaRao Puli 
4727f4eb588SAppaRao Puli     void filterAndSendEventLogs(
4737f4eb588SAppaRao Puli         const std::vector<EventLogObjectsType>& eventRecords)
4747f4eb588SAppaRao Puli     {
475f80a87f2SEd Tanous         nlohmann::json::array_t logEntryArray;
4767f4eb588SAppaRao Puli         for (const EventLogObjectsType& logEntry : eventRecords)
4777f4eb588SAppaRao Puli         {
478f80a87f2SEd Tanous             std::vector<std::string_view> messageArgsView(
479f80a87f2SEd Tanous                 logEntry.messageArgs.begin(), logEntry.messageArgs.end());
4807f4eb588SAppaRao Puli 
481f80a87f2SEd Tanous             nlohmann::json::object_t bmcLogEntry;
482f80a87f2SEd Tanous             if (event_log::formatEventLogEntry(
483f80a87f2SEd Tanous                     logEntry.id, logEntry.messageId, messageArgsView,
484f80a87f2SEd Tanous                     logEntry.timestamp, customText, bmcLogEntry) != 0)
4857f4eb588SAppaRao Puli             {
48662598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Read eventLog entry failed");
4877f4eb588SAppaRao Puli                 continue;
4887f4eb588SAppaRao Puli             }
489f80a87f2SEd Tanous 
490f80a87f2SEd Tanous             if (!eventMatchesFilter(bmcLogEntry, ""))
491f80a87f2SEd Tanous             {
49203d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("Event {} did not match the filter",
49303d4d37cSAlexander Hansen                                  nlohmann::json(bmcLogEntry).dump());
494f80a87f2SEd Tanous                 continue;
495f80a87f2SEd Tanous             }
496f80a87f2SEd Tanous 
497f80a87f2SEd Tanous             logEntryArray.emplace_back(std::move(bmcLogEntry));
4987f4eb588SAppaRao Puli         }
4997f4eb588SAppaRao Puli 
50026f6976fSEd Tanous         if (logEntryArray.empty())
5017f4eb588SAppaRao Puli         {
50262598e31SEd Tanous             BMCWEB_LOG_DEBUG("No log entries available to be transferred.");
5037f4eb588SAppaRao Puli             return;
5047f4eb588SAppaRao Puli         }
5057f4eb588SAppaRao Puli 
5061476687dSEd Tanous         nlohmann::json msg;
5071476687dSEd Tanous         msg["@odata.type"] = "#Event.v1_4_0.Event";
5081476687dSEd Tanous         msg["Id"] = std::to_string(eventSeqNum);
5091476687dSEd Tanous         msg["Name"] = "Event Log";
510f80a87f2SEd Tanous         msg["Events"] = std::move(logEntryArray);
511bd79bce8SPatrick Williams         std::string strMsg =
512bd79bce8SPatrick Williams             msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
5136d799e14SEd Tanous         sendEventToSubscriber(std::move(strMsg));
5145e44e3d8SAppaRao Puli         eventSeqNum++;
5157f4eb588SAppaRao Puli     }
5167f4eb588SAppaRao Puli 
517248d0230SEd Tanous     void filterAndSendReports(const std::string& reportId,
5181e1e598dSJonathan Doman                               const telemetry::TimestampReadings& var)
519156d6b00SAppaRao Puli     {
520ef4c65b7SEd Tanous         boost::urls::url mrdUri = boost::urls::format(
521ef4c65b7SEd Tanous             "/redfish/v1/TelemetryService/MetricReportDefinitions/{}",
522ef4c65b7SEd Tanous             reportId);
523156d6b00SAppaRao Puli 
524156d6b00SAppaRao Puli         // Empty list means no filter. Send everything.
52526f6976fSEd Tanous         if (!metricReportDefinitions.empty())
526156d6b00SAppaRao Puli         {
5273544d2a7SEd Tanous             if (std::ranges::find(metricReportDefinitions, mrdUri.buffer()) ==
5283544d2a7SEd Tanous                 metricReportDefinitions.end())
529156d6b00SAppaRao Puli             {
530156d6b00SAppaRao Puli                 return;
531156d6b00SAppaRao Puli             }
532156d6b00SAppaRao Puli         }
533156d6b00SAppaRao Puli 
534c0353249SWludzik, Jozef         nlohmann::json msg;
535248d0230SEd Tanous         if (!telemetry::fillReport(msg, reportId, var))
536156d6b00SAppaRao Puli         {
53762598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to fill the MetricReport for DBus "
53862598e31SEd Tanous                              "Report with id {}",
53962598e31SEd Tanous                              reportId);
540c0353249SWludzik, Jozef             return;
541156d6b00SAppaRao Puli         }
542156d6b00SAppaRao Puli 
54322daffd7SAppaRao Puli         // Context is set by user during Event subscription and it must be
54422daffd7SAppaRao Puli         // set for MetricReport response.
54522daffd7SAppaRao Puli         if (!customText.empty())
54622daffd7SAppaRao Puli         {
54722daffd7SAppaRao Puli             msg["Context"] = customText;
54822daffd7SAppaRao Puli         }
54922daffd7SAppaRao Puli 
550bd79bce8SPatrick Williams         std::string strMsg =
551bd79bce8SPatrick Williams             msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
5526d799e14SEd Tanous         sendEventToSubscriber(std::move(strMsg));
553156d6b00SAppaRao Puli     }
554156d6b00SAppaRao Puli 
555d14a48ffSCarson Labrado     void updateRetryConfig(uint32_t retryAttempts,
556d14a48ffSCarson Labrado                            uint32_t retryTimeoutInterval)
557fe44eb0bSAyushi Smriti     {
55893cf0ac2SEd Tanous         if (policy == nullptr)
55993cf0ac2SEd Tanous         {
56093cf0ac2SEd Tanous             BMCWEB_LOG_DEBUG("Retry policy was nullptr, ignoring set");
56193cf0ac2SEd Tanous             return;
56293cf0ac2SEd Tanous         }
563d14a48ffSCarson Labrado         policy->maxRetryAttempts = retryAttempts;
564d14a48ffSCarson Labrado         policy->retryIntervalSecs = std::chrono::seconds(retryTimeoutInterval);
56562de0c68SAppaRao Puli     }
566fe44eb0bSAyushi Smriti 
5679eb808c1SEd Tanous     uint64_t getEventSeqNum() const
56896330b99SSunitha Harish     {
56996330b99SSunitha Harish         return eventSeqNum;
57096330b99SSunitha Harish     }
57196330b99SSunitha Harish 
5725e44e3d8SAppaRao Puli     void setSubscriptionId(const std::string& id2)
5735e44e3d8SAppaRao Puli     {
57462598e31SEd Tanous         BMCWEB_LOG_DEBUG("Subscription ID: {}", id2);
5755e44e3d8SAppaRao Puli         subId = id2;
5765e44e3d8SAppaRao Puli     }
5775e44e3d8SAppaRao Puli 
5785e44e3d8SAppaRao Puli     std::string getSubscriptionId()
5795e44e3d8SAppaRao Puli     {
5805e44e3d8SAppaRao Puli         return subId;
5815e44e3d8SAppaRao Puli     }
5825e44e3d8SAppaRao Puli 
5835e44e3d8SAppaRao Puli     bool matchSseId(const crow::sse_socket::Connection& thisConn)
5845e44e3d8SAppaRao Puli     {
5855e44e3d8SAppaRao Puli         return &thisConn == sseConn;
5865e44e3d8SAppaRao Puli     }
5875e44e3d8SAppaRao Puli 
588a7a80296SCarson Labrado     // Check used to indicate what response codes are valid as part of our retry
589a7a80296SCarson Labrado     // policy.  2XX is considered acceptable
590a7a80296SCarson Labrado     static boost::system::error_code retryRespHandler(unsigned int respCode)
591a7a80296SCarson Labrado     {
59262598e31SEd Tanous         BMCWEB_LOG_DEBUG(
59362598e31SEd Tanous             "Checking response code validity for SubscriptionEvent");
594a7a80296SCarson Labrado         if ((respCode < 200) || (respCode >= 300))
595a7a80296SCarson Labrado         {
596a7a80296SCarson Labrado             return boost::system::errc::make_error_code(
597a7a80296SCarson Labrado                 boost::system::errc::result_out_of_range);
598a7a80296SCarson Labrado         }
599a7a80296SCarson Labrado 
600a7a80296SCarson Labrado         // Return 0 if the response code is valid
601a7a80296SCarson Labrado         return boost::system::errc::make_error_code(
602a7a80296SCarson Labrado             boost::system::errc::success);
6039fa6d147SNan Zhou     }
604f80a87f2SEd Tanous 
605f80a87f2SEd Tanous   private:
606f80a87f2SEd Tanous     std::string subId;
607f80a87f2SEd Tanous     uint64_t eventSeqNum = 1;
608f80a87f2SEd Tanous     boost::urls::url host;
609f80a87f2SEd Tanous     std::shared_ptr<crow::ConnectionPolicy> policy;
610f80a87f2SEd Tanous     crow::sse_socket::Connection* sseConn = nullptr;
611f80a87f2SEd Tanous 
612f80a87f2SEd Tanous     std::optional<crow::HttpClient> client;
613f80a87f2SEd Tanous 
614f80a87f2SEd Tanous   public:
615f80a87f2SEd Tanous     std::optional<filter_ast::LogicalAnd> filter;
616b52664e2SAppaRao Puli };
617b52664e2SAppaRao Puli 
618b52664e2SAppaRao Puli class EventServiceManager
619b52664e2SAppaRao Puli {
620b52664e2SAppaRao Puli   private:
621d3a9e084SEd Tanous     bool serviceEnabled = false;
622d3a9e084SEd Tanous     uint32_t retryAttempts = 0;
623d3a9e084SEd Tanous     uint32_t retryTimeoutInterval = 0;
6247d1cc387SAppaRao Puli 
6252558979cSP Dheeraj Srujan Kumar     std::streampos redfishLogFilePosition{0};
6269f616dd1SEd Tanous     size_t noOfEventLogSubscribers{0};
6279f616dd1SEd Tanous     size_t noOfMetricReportSubscribers{0};
62859d494eeSPatrick Williams     std::shared_ptr<sdbusplus::bus::match_t> matchTelemetryMonitor;
629b52664e2SAppaRao Puli     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
630b52664e2SAppaRao Puli         subscriptionsMap;
631b52664e2SAppaRao Puli 
6329f616dd1SEd Tanous     uint64_t eventId{1};
63396330b99SSunitha Harish 
634f80a87f2SEd Tanous     struct Event
635f80a87f2SEd Tanous     {
636f80a87f2SEd Tanous         std::string id;
637f80a87f2SEd Tanous         nlohmann::json message;
638f80a87f2SEd Tanous     };
639f80a87f2SEd Tanous 
640f80a87f2SEd Tanous     constexpr static size_t maxMessages = 200;
641f80a87f2SEd Tanous     boost::circular_buffer<Event> messages{maxMessages};
642f80a87f2SEd Tanous 
643f8ca6d79SEd Tanous     boost::asio::io_context& ioc;
644f8ca6d79SEd Tanous 
645b52664e2SAppaRao Puli   public:
6469f616dd1SEd Tanous     EventServiceManager(const EventServiceManager&) = delete;
6479f616dd1SEd Tanous     EventServiceManager& operator=(const EventServiceManager&) = delete;
6489f616dd1SEd Tanous     EventServiceManager(EventServiceManager&&) = delete;
6499f616dd1SEd Tanous     EventServiceManager& operator=(EventServiceManager&&) = delete;
650ecd6a3a2SEd Tanous     ~EventServiceManager() = default;
6519f616dd1SEd Tanous 
652f8ca6d79SEd Tanous     explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn)
653b52664e2SAppaRao Puli     {
654f8ca6d79SEd Tanous         // Load config from persist store.
655f8ca6d79SEd Tanous         initConfig();
656f8ca6d79SEd Tanous     }
657f8ca6d79SEd Tanous 
658f8ca6d79SEd Tanous     static EventServiceManager&
659f8ca6d79SEd Tanous         getInstance(boost::asio::io_context* ioc = nullptr)
660f8ca6d79SEd Tanous     {
661f8ca6d79SEd Tanous         static EventServiceManager handler(*ioc);
662b52664e2SAppaRao Puli         return handler;
663b52664e2SAppaRao Puli     }
664b52664e2SAppaRao Puli 
6651bf712bcSAyushi Smriti     void initConfig()
6661bf712bcSAyushi Smriti     {
66728afb49cSJunLin Chen         loadOldBehavior();
6681bf712bcSAyushi Smriti 
66928afb49cSJunLin Chen         persistent_data::EventServiceConfig eventServiceConfig =
67028afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
67128afb49cSJunLin Chen                 .getEventServiceConfig();
6721bf712bcSAyushi Smriti 
67328afb49cSJunLin Chen         serviceEnabled = eventServiceConfig.enabled;
67428afb49cSJunLin Chen         retryAttempts = eventServiceConfig.retryAttempts;
67528afb49cSJunLin Chen         retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval;
6761bf712bcSAyushi Smriti 
67728afb49cSJunLin Chen         for (const auto& it : persistent_data::EventServiceStore::getInstance()
67828afb49cSJunLin Chen                                   .subscriptionsConfigMap)
6791bf712bcSAyushi Smriti         {
68028afb49cSJunLin Chen             std::shared_ptr<persistent_data::UserSubscription> newSub =
68128afb49cSJunLin Chen                 it.second;
6824bbf237fSAppaRao Puli 
6836fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
684a716aa74SEd Tanous                 boost::urls::parse_absolute_uri(newSub->destinationUrl);
6851bf712bcSAyushi Smriti 
686a716aa74SEd Tanous             if (!url)
6871bf712bcSAyushi Smriti             {
68862598e31SEd Tanous                 BMCWEB_LOG_ERROR(
68962598e31SEd Tanous                     "Failed to validate and split destination url");
6901bf712bcSAyushi Smriti                 continue;
6911bf712bcSAyushi Smriti             }
6921bf712bcSAyushi Smriti             std::shared_ptr<Subscription> subValue =
693a716aa74SEd Tanous                 std::make_shared<Subscription>(*url, ioc);
6941bf712bcSAyushi Smriti 
69528afb49cSJunLin Chen             subValue->id = newSub->id;
69628afb49cSJunLin Chen             subValue->destinationUrl = newSub->destinationUrl;
69728afb49cSJunLin Chen             subValue->protocol = newSub->protocol;
69819bb362bSEd Tanous             subValue->verifyCertificate = newSub->verifyCertificate;
69928afb49cSJunLin Chen             subValue->retryPolicy = newSub->retryPolicy;
70028afb49cSJunLin Chen             subValue->customText = newSub->customText;
70128afb49cSJunLin Chen             subValue->eventFormatType = newSub->eventFormatType;
70228afb49cSJunLin Chen             subValue->subscriptionType = newSub->subscriptionType;
70328afb49cSJunLin Chen             subValue->registryMsgIds = newSub->registryMsgIds;
70428afb49cSJunLin Chen             subValue->registryPrefixes = newSub->registryPrefixes;
70528afb49cSJunLin Chen             subValue->resourceTypes = newSub->resourceTypes;
70628afb49cSJunLin Chen             subValue->httpHeaders = newSub->httpHeaders;
70728afb49cSJunLin Chen             subValue->metricReportDefinitions = newSub->metricReportDefinitions;
708*a14c9113SEd Tanous             subValue->originResources = newSub->originResources;
7091bf712bcSAyushi Smriti 
71028afb49cSJunLin Chen             if (subValue->id.empty())
7111bf712bcSAyushi Smriti             {
71262598e31SEd Tanous                 BMCWEB_LOG_ERROR("Failed to add subscription");
7131bf712bcSAyushi Smriti             }
71428afb49cSJunLin Chen             subscriptionsMap.insert(std::pair(subValue->id, subValue));
71528afb49cSJunLin Chen 
71628afb49cSJunLin Chen             updateNoOfSubscribersCount();
71728afb49cSJunLin Chen 
71883328316SEd Tanous             if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
71983328316SEd Tanous             {
7202558979cSP Dheeraj Srujan Kumar                 cacheRedfishLogFile();
72183328316SEd Tanous             }
7222558979cSP Dheeraj Srujan Kumar 
72328afb49cSJunLin Chen             // Update retry configuration.
72428afb49cSJunLin Chen             subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
7251bf712bcSAyushi Smriti         }
7261bf712bcSAyushi Smriti     }
7271bf712bcSAyushi Smriti 
72856d2396dSEd Tanous     static void loadOldBehavior()
729b52664e2SAppaRao Puli     {
73028afb49cSJunLin Chen         std::ifstream eventConfigFile(eventServiceFile);
73128afb49cSJunLin Chen         if (!eventConfigFile.good())
7321bf712bcSAyushi Smriti         {
73362598e31SEd Tanous             BMCWEB_LOG_DEBUG("Old eventService config not exist");
73428afb49cSJunLin Chen             return;
73528afb49cSJunLin Chen         }
73628afb49cSJunLin Chen         auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false);
73728afb49cSJunLin Chen         if (jsonData.is_discarded())
7384bbf237fSAppaRao Puli         {
73962598e31SEd Tanous             BMCWEB_LOG_ERROR("Old eventService config parse error.");
74028afb49cSJunLin Chen             return;
74128afb49cSJunLin Chen         }
74228afb49cSJunLin Chen 
7430bdda665SEd Tanous         const nlohmann::json::object_t* obj =
7440bdda665SEd Tanous             jsonData.get_ptr<const nlohmann::json::object_t*>();
7450bdda665SEd Tanous         for (const auto& item : *obj)
74628afb49cSJunLin Chen         {
7470bdda665SEd Tanous             if (item.first == "Configuration")
74828afb49cSJunLin Chen             {
74928afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
75028afb49cSJunLin Chen                     .getEventServiceConfig()
7510bdda665SEd Tanous                     .fromJson(item.second);
75228afb49cSJunLin Chen             }
7530bdda665SEd Tanous             else if (item.first == "Subscriptions")
75428afb49cSJunLin Chen             {
7550bdda665SEd Tanous                 for (const auto& elem : item.second)
75628afb49cSJunLin Chen                 {
75728afb49cSJunLin Chen                     std::shared_ptr<persistent_data::UserSubscription>
75828afb49cSJunLin Chen                         newSubscription =
75928afb49cSJunLin Chen                             persistent_data::UserSubscription::fromJson(elem,
76028afb49cSJunLin Chen                                                                         true);
76128afb49cSJunLin Chen                     if (newSubscription == nullptr)
76228afb49cSJunLin Chen                     {
76362598e31SEd Tanous                         BMCWEB_LOG_ERROR("Problem reading subscription "
76462598e31SEd Tanous                                          "from old persistent store");
7654bbf237fSAppaRao Puli                         continue;
7664bbf237fSAppaRao Puli                     }
7671bf712bcSAyushi Smriti 
76828afb49cSJunLin Chen                     std::uniform_int_distribution<uint32_t> dist(0);
76928afb49cSJunLin Chen                     bmcweb::OpenSSLGenerator gen;
7701bf712bcSAyushi Smriti 
77128afb49cSJunLin Chen                     std::string id;
7721bf712bcSAyushi Smriti 
77328afb49cSJunLin Chen                     int retry = 3;
774e662eae8SEd Tanous                     while (retry != 0)
7751bf712bcSAyushi Smriti                     {
77628afb49cSJunLin Chen                         id = std::to_string(dist(gen));
77728afb49cSJunLin Chen                         if (gen.error())
7787d1cc387SAppaRao Puli                         {
77928afb49cSJunLin Chen                             retry = 0;
78028afb49cSJunLin Chen                             break;
78128afb49cSJunLin Chen                         }
78228afb49cSJunLin Chen                         newSubscription->id = id;
78328afb49cSJunLin Chen                         auto inserted =
78428afb49cSJunLin Chen                             persistent_data::EventServiceStore::getInstance()
78528afb49cSJunLin Chen                                 .subscriptionsConfigMap.insert(
78628afb49cSJunLin Chen                                     std::pair(id, newSubscription));
78728afb49cSJunLin Chen                         if (inserted.second)
78828afb49cSJunLin Chen                         {
78928afb49cSJunLin Chen                             break;
79028afb49cSJunLin Chen                         }
79128afb49cSJunLin Chen                         --retry;
7927d1cc387SAppaRao Puli                     }
7937d1cc387SAppaRao Puli 
79428afb49cSJunLin Chen                     if (retry <= 0)
79528afb49cSJunLin Chen                     {
79662598e31SEd Tanous                         BMCWEB_LOG_ERROR(
79762598e31SEd Tanous                             "Failed to generate random number from old "
79862598e31SEd Tanous                             "persistent store");
79928afb49cSJunLin Chen                         continue;
80028afb49cSJunLin Chen                     }
80128afb49cSJunLin Chen                 }
80228afb49cSJunLin Chen             }
80328afb49cSJunLin Chen 
80428afb49cSJunLin Chen             persistent_data::getConfig().writeData();
8054c521c3cSEd Tanous             std::error_code ec;
8064c521c3cSEd Tanous             std::filesystem::remove(eventServiceFile, ec);
8074c521c3cSEd Tanous             if (ec)
8084c521c3cSEd Tanous             {
8094c521c3cSEd Tanous                 BMCWEB_LOG_DEBUG(
8104c521c3cSEd Tanous                     "Failed to remove old event service file.  Ignoring");
8114c521c3cSEd Tanous             }
8124c521c3cSEd Tanous             else
8134c521c3cSEd Tanous             {
81462598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Remove old eventservice config");
81528afb49cSJunLin Chen             }
81628afb49cSJunLin Chen         }
8174c521c3cSEd Tanous     }
81828afb49cSJunLin Chen 
8199eb808c1SEd Tanous     void updateSubscriptionData() const
82028afb49cSJunLin Chen     {
82128afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
82228afb49cSJunLin Chen             .eventServiceConfig.enabled = serviceEnabled;
82328afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
82428afb49cSJunLin Chen             .eventServiceConfig.retryAttempts = retryAttempts;
82528afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
82628afb49cSJunLin Chen             .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval;
82728afb49cSJunLin Chen 
82828afb49cSJunLin Chen         persistent_data::getConfig().writeData();
82928afb49cSJunLin Chen     }
83028afb49cSJunLin Chen 
83128afb49cSJunLin Chen     void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg)
8327d1cc387SAppaRao Puli     {
8337d1cc387SAppaRao Puli         bool updateConfig = false;
834fe44eb0bSAyushi Smriti         bool updateRetryCfg = false;
8357d1cc387SAppaRao Puli 
83628afb49cSJunLin Chen         if (serviceEnabled != cfg.enabled)
8377d1cc387SAppaRao Puli         {
83828afb49cSJunLin Chen             serviceEnabled = cfg.enabled;
839e662eae8SEd Tanous             if (serviceEnabled && noOfMetricReportSubscribers != 0U)
8407d1cc387SAppaRao Puli             {
8417d1cc387SAppaRao Puli                 registerMetricReportSignal();
8427d1cc387SAppaRao Puli             }
8437d1cc387SAppaRao Puli             else
8447d1cc387SAppaRao Puli             {
8457d1cc387SAppaRao Puli                 unregisterMetricReportSignal();
8467d1cc387SAppaRao Puli             }
8477d1cc387SAppaRao Puli             updateConfig = true;
8487d1cc387SAppaRao Puli         }
8497d1cc387SAppaRao Puli 
85028afb49cSJunLin Chen         if (retryAttempts != cfg.retryAttempts)
8517d1cc387SAppaRao Puli         {
85228afb49cSJunLin Chen             retryAttempts = cfg.retryAttempts;
8537d1cc387SAppaRao Puli             updateConfig = true;
854fe44eb0bSAyushi Smriti             updateRetryCfg = true;
8557d1cc387SAppaRao Puli         }
8567d1cc387SAppaRao Puli 
85728afb49cSJunLin Chen         if (retryTimeoutInterval != cfg.retryTimeoutInterval)
8587d1cc387SAppaRao Puli         {
85928afb49cSJunLin Chen             retryTimeoutInterval = cfg.retryTimeoutInterval;
8607d1cc387SAppaRao Puli             updateConfig = true;
861fe44eb0bSAyushi Smriti             updateRetryCfg = true;
8627d1cc387SAppaRao Puli         }
8637d1cc387SAppaRao Puli 
8647d1cc387SAppaRao Puli         if (updateConfig)
8657d1cc387SAppaRao Puli         {
8667d1cc387SAppaRao Puli             updateSubscriptionData();
8677d1cc387SAppaRao Puli         }
868fe44eb0bSAyushi Smriti 
869fe44eb0bSAyushi Smriti         if (updateRetryCfg)
870fe44eb0bSAyushi Smriti         {
871fe44eb0bSAyushi Smriti             // Update the changed retry config to all subscriptions
872fe44eb0bSAyushi Smriti             for (const auto& it :
873fe44eb0bSAyushi Smriti                  EventServiceManager::getInstance().subscriptionsMap)
874fe44eb0bSAyushi Smriti             {
8755e44e3d8SAppaRao Puli                 Subscription& entry = *it.second;
8765e44e3d8SAppaRao Puli                 entry.updateRetryConfig(retryAttempts, retryTimeoutInterval);
877fe44eb0bSAyushi Smriti             }
878fe44eb0bSAyushi Smriti         }
8797d1cc387SAppaRao Puli     }
8807d1cc387SAppaRao Puli 
8817d1cc387SAppaRao Puli     void updateNoOfSubscribersCount()
8827d1cc387SAppaRao Puli     {
8837d1cc387SAppaRao Puli         size_t eventLogSubCount = 0;
8847d1cc387SAppaRao Puli         size_t metricReportSubCount = 0;
8857d1cc387SAppaRao Puli         for (const auto& it : subscriptionsMap)
8867d1cc387SAppaRao Puli         {
8877d1cc387SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
8887d1cc387SAppaRao Puli             if (entry->eventFormatType == eventFormatType)
8897d1cc387SAppaRao Puli             {
8907d1cc387SAppaRao Puli                 eventLogSubCount++;
8917d1cc387SAppaRao Puli             }
8927d1cc387SAppaRao Puli             else if (entry->eventFormatType == metricReportFormatType)
8937d1cc387SAppaRao Puli             {
8947d1cc387SAppaRao Puli                 metricReportSubCount++;
8957d1cc387SAppaRao Puli             }
8967d1cc387SAppaRao Puli         }
8977d1cc387SAppaRao Puli 
8987d1cc387SAppaRao Puli         noOfEventLogSubscribers = eventLogSubCount;
8997d1cc387SAppaRao Puli         if (noOfMetricReportSubscribers != metricReportSubCount)
9007d1cc387SAppaRao Puli         {
9017d1cc387SAppaRao Puli             noOfMetricReportSubscribers = metricReportSubCount;
902e662eae8SEd Tanous             if (noOfMetricReportSubscribers != 0U)
9037d1cc387SAppaRao Puli             {
9047d1cc387SAppaRao Puli                 registerMetricReportSignal();
9057d1cc387SAppaRao Puli             }
9067d1cc387SAppaRao Puli             else
9077d1cc387SAppaRao Puli             {
9087d1cc387SAppaRao Puli                 unregisterMetricReportSignal();
9097d1cc387SAppaRao Puli             }
9107d1cc387SAppaRao Puli         }
9117d1cc387SAppaRao Puli     }
9127d1cc387SAppaRao Puli 
913b52664e2SAppaRao Puli     std::shared_ptr<Subscription> getSubscription(const std::string& id)
914b52664e2SAppaRao Puli     {
915b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
916b52664e2SAppaRao Puli         if (obj == subscriptionsMap.end())
917b52664e2SAppaRao Puli         {
91862598e31SEd Tanous             BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id);
919b52664e2SAppaRao Puli             return nullptr;
920b52664e2SAppaRao Puli         }
921b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue = obj->second;
922b52664e2SAppaRao Puli         return subValue;
923b52664e2SAppaRao Puli     }
924b52664e2SAppaRao Puli 
925f80a87f2SEd Tanous     std::string
926f80a87f2SEd Tanous         addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue)
927b52664e2SAppaRao Puli     {
928fc76b8acSEd Tanous         std::uniform_int_distribution<uint32_t> dist(0);
929fc76b8acSEd Tanous         bmcweb::OpenSSLGenerator gen;
930fc76b8acSEd Tanous 
931b52664e2SAppaRao Puli         std::string id;
932b52664e2SAppaRao Puli 
933b52664e2SAppaRao Puli         int retry = 3;
934e662eae8SEd Tanous         while (retry != 0)
935b52664e2SAppaRao Puli         {
936fc76b8acSEd Tanous             id = std::to_string(dist(gen));
937fc76b8acSEd Tanous             if (gen.error())
938fc76b8acSEd Tanous             {
939fc76b8acSEd Tanous                 retry = 0;
940fc76b8acSEd Tanous                 break;
941fc76b8acSEd Tanous             }
942b52664e2SAppaRao Puli             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
943b52664e2SAppaRao Puli             if (inserted.second)
944b52664e2SAppaRao Puli             {
945b52664e2SAppaRao Puli                 break;
946b52664e2SAppaRao Puli             }
947b52664e2SAppaRao Puli             --retry;
94823a21a1cSEd Tanous         }
949b52664e2SAppaRao Puli 
950b52664e2SAppaRao Puli         if (retry <= 0)
951b52664e2SAppaRao Puli         {
95262598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to generate random number");
953abb93cddSEd Tanous             return "";
954b52664e2SAppaRao Puli         }
955b52664e2SAppaRao Puli 
95628afb49cSJunLin Chen         std::shared_ptr<persistent_data::UserSubscription> newSub =
95728afb49cSJunLin Chen             std::make_shared<persistent_data::UserSubscription>();
95828afb49cSJunLin Chen         newSub->id = id;
95928afb49cSJunLin Chen         newSub->destinationUrl = subValue->destinationUrl;
96028afb49cSJunLin Chen         newSub->protocol = subValue->protocol;
96128afb49cSJunLin Chen         newSub->retryPolicy = subValue->retryPolicy;
96228afb49cSJunLin Chen         newSub->customText = subValue->customText;
96328afb49cSJunLin Chen         newSub->eventFormatType = subValue->eventFormatType;
96428afb49cSJunLin Chen         newSub->subscriptionType = subValue->subscriptionType;
96528afb49cSJunLin Chen         newSub->registryMsgIds = subValue->registryMsgIds;
96628afb49cSJunLin Chen         newSub->registryPrefixes = subValue->registryPrefixes;
96728afb49cSJunLin Chen         newSub->resourceTypes = subValue->resourceTypes;
96828afb49cSJunLin Chen         newSub->httpHeaders = subValue->httpHeaders;
96928afb49cSJunLin Chen         newSub->metricReportDefinitions = subValue->metricReportDefinitions;
970*a14c9113SEd Tanous         newSub->originResources = subValue->originResources;
971*a14c9113SEd Tanous 
97228afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
97328afb49cSJunLin Chen             .subscriptionsConfigMap.emplace(newSub->id, newSub);
97428afb49cSJunLin Chen 
9757d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
9761bf712bcSAyushi Smriti 
97783328316SEd Tanous         if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
97883328316SEd Tanous         {
9792558979cSP Dheeraj Srujan Kumar             if (redfishLogFilePosition != 0)
9807f4eb588SAppaRao Puli             {
9812558979cSP Dheeraj Srujan Kumar                 cacheRedfishLogFile();
9827f4eb588SAppaRao Puli             }
98383328316SEd Tanous         }
984fe44eb0bSAyushi Smriti         // Update retry configuration.
985fe44eb0bSAyushi Smriti         subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
986fe44eb0bSAyushi Smriti 
9875e44e3d8SAppaRao Puli         // Set Subscription ID for back trace
9885e44e3d8SAppaRao Puli         subValue->setSubscriptionId(id);
989f80a87f2SEd Tanous 
990f80a87f2SEd Tanous         return id;
991f80a87f2SEd Tanous     }
992f80a87f2SEd Tanous 
993f80a87f2SEd Tanous     std::string
994f80a87f2SEd Tanous         addSSESubscription(const std::shared_ptr<Subscription>& subValue,
995f80a87f2SEd Tanous                            std::string_view lastEventId)
996f80a87f2SEd Tanous     {
997f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
998f80a87f2SEd Tanous 
999f80a87f2SEd Tanous         if (!lastEventId.empty())
1000f80a87f2SEd Tanous         {
1001f80a87f2SEd Tanous             BMCWEB_LOG_INFO("Attempting to find message for last id {}",
1002f80a87f2SEd Tanous                             lastEventId);
1003f80a87f2SEd Tanous             boost::circular_buffer<Event>::iterator lastEvent =
1004f80a87f2SEd Tanous                 std::find_if(messages.begin(), messages.end(),
1005f80a87f2SEd Tanous                              [&lastEventId](const Event& event) {
1006f80a87f2SEd Tanous                                  return event.id == lastEventId;
1007f80a87f2SEd Tanous                              });
1008f80a87f2SEd Tanous             // Can't find a matching ID
1009f80a87f2SEd Tanous             if (lastEvent == messages.end())
1010f80a87f2SEd Tanous             {
1011f80a87f2SEd Tanous                 nlohmann::json msg = messages::eventBufferExceeded();
1012f80a87f2SEd Tanous                 // If the buffer overloaded, send all messages.
10136d799e14SEd Tanous                 subValue->sendEventToSubscriber(msg);
1014f80a87f2SEd Tanous                 lastEvent = messages.begin();
1015f80a87f2SEd Tanous             }
1016f80a87f2SEd Tanous             else
1017f80a87f2SEd Tanous             {
1018f80a87f2SEd Tanous                 // Skip the last event the user already has
1019f80a87f2SEd Tanous                 lastEvent++;
1020f80a87f2SEd Tanous             }
1021f80a87f2SEd Tanous 
1022f80a87f2SEd Tanous             for (boost::circular_buffer<Event>::const_iterator event =
1023f80a87f2SEd Tanous                      lastEvent;
1024f80a87f2SEd Tanous                  lastEvent != messages.end(); lastEvent++)
1025f80a87f2SEd Tanous             {
10266d799e14SEd Tanous                 subValue->sendEventToSubscriber(event->message);
1027f80a87f2SEd Tanous             }
1028f80a87f2SEd Tanous         }
1029f80a87f2SEd Tanous         return id;
1030f80a87f2SEd Tanous     }
1031f80a87f2SEd Tanous 
1032f80a87f2SEd Tanous     std::string
1033f80a87f2SEd Tanous         addPushSubscription(const std::shared_ptr<Subscription>& subValue)
1034f80a87f2SEd Tanous     {
1035f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
1036f80a87f2SEd Tanous 
1037f80a87f2SEd Tanous         updateSubscriptionData();
1038b52664e2SAppaRao Puli         return id;
1039b52664e2SAppaRao Puli     }
1040b52664e2SAppaRao Puli 
1041b52664e2SAppaRao Puli     bool isSubscriptionExist(const std::string& id)
1042b52664e2SAppaRao Puli     {
1043b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
104455f79e6fSEd Tanous         return obj != subscriptionsMap.end();
1045b52664e2SAppaRao Puli     }
1046b52664e2SAppaRao Puli 
1047b52664e2SAppaRao Puli     void deleteSubscription(const std::string& id)
1048b52664e2SAppaRao Puli     {
1049b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
1050b52664e2SAppaRao Puli         if (obj != subscriptionsMap.end())
1051b52664e2SAppaRao Puli         {
1052b52664e2SAppaRao Puli             subscriptionsMap.erase(obj);
105328afb49cSJunLin Chen             auto obj2 = persistent_data::EventServiceStore::getInstance()
105428afb49cSJunLin Chen                             .subscriptionsConfigMap.find(id);
105528afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
105628afb49cSJunLin Chen                 .subscriptionsConfigMap.erase(obj2);
10577d1cc387SAppaRao Puli             updateNoOfSubscribersCount();
1058b52664e2SAppaRao Puli             updateSubscriptionData();
1059b52664e2SAppaRao Puli         }
1060b52664e2SAppaRao Puli     }
1061b52664e2SAppaRao Puli 
10625e44e3d8SAppaRao Puli     void deleteSseSubscription(const crow::sse_socket::Connection& thisConn)
10635e44e3d8SAppaRao Puli     {
1064bdbfae2aSEd Tanous         for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();)
10655e44e3d8SAppaRao Puli         {
1066bdbfae2aSEd Tanous             std::shared_ptr<Subscription> entry = it->second;
10675e44e3d8SAppaRao Puli             bool entryIsThisConn = entry->matchSseId(thisConn);
10685e44e3d8SAppaRao Puli             if (entryIsThisConn)
10695e44e3d8SAppaRao Puli             {
10705e44e3d8SAppaRao Puli                 persistent_data::EventServiceStore::getInstance()
10715e44e3d8SAppaRao Puli                     .subscriptionsConfigMap.erase(
1072bdbfae2aSEd Tanous                         it->second->getSubscriptionId());
1073bdbfae2aSEd Tanous                 it = subscriptionsMap.erase(it);
10745e44e3d8SAppaRao Puli                 return;
10755e44e3d8SAppaRao Puli             }
1076bdbfae2aSEd Tanous             it++;
10775e44e3d8SAppaRao Puli         }
10785e44e3d8SAppaRao Puli     }
10795e44e3d8SAppaRao Puli 
10805e44e3d8SAppaRao Puli     size_t getNumberOfSubscriptions() const
1081b52664e2SAppaRao Puli     {
1082b52664e2SAppaRao Puli         return subscriptionsMap.size();
1083b52664e2SAppaRao Puli     }
1084b52664e2SAppaRao Puli 
10855e44e3d8SAppaRao Puli     size_t getNumberOfSSESubscriptions() const
10865e44e3d8SAppaRao Puli     {
10873544d2a7SEd Tanous         auto size = std::ranges::count_if(
10883544d2a7SEd Tanous             subscriptionsMap,
10895e44e3d8SAppaRao Puli             [](const std::pair<std::string, std::shared_ptr<Subscription>>&
10905e44e3d8SAppaRao Puli                    entry) {
10915e44e3d8SAppaRao Puli                 return (entry.second->subscriptionType == subscriptionTypeSSE);
10925e44e3d8SAppaRao Puli             });
10935e44e3d8SAppaRao Puli         return static_cast<size_t>(size);
10945e44e3d8SAppaRao Puli     }
10955e44e3d8SAppaRao Puli 
1096b52664e2SAppaRao Puli     std::vector<std::string> getAllIDs()
1097b52664e2SAppaRao Puli     {
1098b52664e2SAppaRao Puli         std::vector<std::string> idList;
1099b52664e2SAppaRao Puli         for (const auto& it : subscriptionsMap)
1100b52664e2SAppaRao Puli         {
1101b52664e2SAppaRao Puli             idList.emplace_back(it.first);
1102b52664e2SAppaRao Puli         }
1103b52664e2SAppaRao Puli         return idList;
1104b52664e2SAppaRao Puli     }
1105b52664e2SAppaRao Puli 
11066ba8c82eSsunharis_in     bool sendTestEventLog()
11070b4bdd93SAppaRao Puli     {
11085e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
11090b4bdd93SAppaRao Puli         {
11100b4bdd93SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
11116ba8c82eSsunharis_in             if (!entry->sendTestEventLog())
11126ba8c82eSsunharis_in             {
11136ba8c82eSsunharis_in                 return false;
11140b4bdd93SAppaRao Puli             }
11150b4bdd93SAppaRao Puli         }
11166ba8c82eSsunharis_in         return true;
11176ba8c82eSsunharis_in     }
1118e9a14131SAppaRao Puli 
1119f80a87f2SEd Tanous     void sendEvent(nlohmann::json::object_t eventMessage,
1120f80a87f2SEd Tanous                    std::string_view origin, std::string_view resourceType)
112196330b99SSunitha Harish     {
1122613dabeaSEd Tanous         eventMessage["EventId"] = eventId;
1123f80a87f2SEd Tanous 
1124613dabeaSEd Tanous         eventMessage["EventTimestamp"] =
1125613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
1126613dabeaSEd Tanous         eventMessage["OriginOfCondition"] = origin;
1127613dabeaSEd Tanous 
1128f80a87f2SEd Tanous         // MemberId is 0 : since we are sending one event record.
1129f80a87f2SEd Tanous         eventMessage["MemberId"] = 0;
113096330b99SSunitha Harish 
1131f80a87f2SEd Tanous         messages.push_back(Event(std::to_string(eventId), eventMessage));
1132f80a87f2SEd Tanous 
1133f80a87f2SEd Tanous         for (auto& it : subscriptionsMap)
113496330b99SSunitha Harish         {
1135f80a87f2SEd Tanous             std::shared_ptr<Subscription>& entry = it.second;
1136f80a87f2SEd Tanous             if (!entry->eventMatchesFilter(eventMessage, resourceType))
113796330b99SSunitha Harish             {
1138f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Filter didn't match");
1139f80a87f2SEd Tanous                 continue;
114096330b99SSunitha Harish             }
1141f80a87f2SEd Tanous 
1142f80a87f2SEd Tanous             nlohmann::json::array_t eventRecord;
1143f80a87f2SEd Tanous             eventRecord.emplace_back(eventMessage);
1144f80a87f2SEd Tanous 
1145613dabeaSEd Tanous             nlohmann::json msgJson;
1146613dabeaSEd Tanous 
1147613dabeaSEd Tanous             msgJson["@odata.type"] = "#Event.v1_4_0.Event";
1148613dabeaSEd Tanous             msgJson["Name"] = "Event Log";
1149613dabeaSEd Tanous             msgJson["Id"] = eventId;
1150f80a87f2SEd Tanous             msgJson["Events"] = std::move(eventRecord);
1151f52c03c1SCarson Labrado 
1152f52c03c1SCarson Labrado             std::string strMsg = msgJson.dump(
1153f52c03c1SCarson Labrado                 2, ' ', true, nlohmann::json::error_handler_t::replace);
11546d799e14SEd Tanous             entry->sendEventToSubscriber(std::move(strMsg));
11558ece0e45SEd Tanous             eventId++; // increment the eventId
115696330b99SSunitha Harish         }
115796330b99SSunitha Harish     }
115896330b99SSunitha Harish 
11592558979cSP Dheeraj Srujan Kumar     void resetRedfishFilePosition()
11607f4eb588SAppaRao Puli     {
11612558979cSP Dheeraj Srujan Kumar         // Control would be here when Redfish file is created.
11622558979cSP Dheeraj Srujan Kumar         // Reset File Position as new file is created
11632558979cSP Dheeraj Srujan Kumar         redfishLogFilePosition = 0;
11642558979cSP Dheeraj Srujan Kumar     }
11652558979cSP Dheeraj Srujan Kumar 
11662558979cSP Dheeraj Srujan Kumar     void cacheRedfishLogFile()
11672558979cSP Dheeraj Srujan Kumar     {
11682558979cSP Dheeraj Srujan Kumar         // Open the redfish file and read till the last record.
11692558979cSP Dheeraj Srujan Kumar 
11707f4eb588SAppaRao Puli         std::ifstream logStream(redfishEventLogFile);
11717f4eb588SAppaRao Puli         if (!logStream.good())
11727f4eb588SAppaRao Puli         {
117362598e31SEd Tanous             BMCWEB_LOG_ERROR(" Redfish log file open failed ");
11747f4eb588SAppaRao Puli             return;
11757f4eb588SAppaRao Puli         }
11767f4eb588SAppaRao Puli         std::string logEntry;
11777f4eb588SAppaRao Puli         while (std::getline(logStream, logEntry))
11787f4eb588SAppaRao Puli         {
11792558979cSP Dheeraj Srujan Kumar             redfishLogFilePosition = logStream.tellg();
11807f4eb588SAppaRao Puli         }
11817f4eb588SAppaRao Puli     }
11827f4eb588SAppaRao Puli 
11837f4eb588SAppaRao Puli     void readEventLogsFromFile()
11847f4eb588SAppaRao Puli     {
11857f4eb588SAppaRao Puli         std::ifstream logStream(redfishEventLogFile);
11867f4eb588SAppaRao Puli         if (!logStream.good())
11877f4eb588SAppaRao Puli         {
118862598e31SEd Tanous             BMCWEB_LOG_ERROR(" Redfish log file open failed");
11897f4eb588SAppaRao Puli             return;
11907f4eb588SAppaRao Puli         }
11917f4eb588SAppaRao Puli 
11927f4eb588SAppaRao Puli         std::vector<EventLogObjectsType> eventRecords;
11937f4eb588SAppaRao Puli 
11947f4eb588SAppaRao Puli         std::string logEntry;
11952558979cSP Dheeraj Srujan Kumar 
119603d4d37cSAlexander Hansen         BMCWEB_LOG_DEBUG("Redfish log file: seek to {}",
119703d4d37cSAlexander Hansen                          static_cast<int>(redfishLogFilePosition));
119803d4d37cSAlexander Hansen 
11992558979cSP Dheeraj Srujan Kumar         // Get the read pointer to the next log to be read.
12002558979cSP Dheeraj Srujan Kumar         logStream.seekg(redfishLogFilePosition);
12012558979cSP Dheeraj Srujan Kumar 
12027f4eb588SAppaRao Puli         while (std::getline(logStream, logEntry))
12037f4eb588SAppaRao Puli         {
120403d4d37cSAlexander Hansen             BMCWEB_LOG_DEBUG("Redfish log file: found new event log entry");
12052558979cSP Dheeraj Srujan Kumar             // Update Pointer position
12062558979cSP Dheeraj Srujan Kumar             redfishLogFilePosition = logStream.tellg();
12072558979cSP Dheeraj Srujan Kumar 
12082558979cSP Dheeraj Srujan Kumar             std::string idStr;
12092558979cSP Dheeraj Srujan Kumar             if (!event_log::getUniqueEntryID(logEntry, idStr))
12107f4eb588SAppaRao Puli             {
121103d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG(
121203d4d37cSAlexander Hansen                     "Redfish log file: could not get unique entry id for {}",
121303d4d37cSAlexander Hansen                     logEntry);
12147f4eb588SAppaRao Puli                 continue;
12157f4eb588SAppaRao Puli             }
12167f4eb588SAppaRao Puli 
1217e662eae8SEd Tanous             if (!serviceEnabled || noOfEventLogSubscribers == 0)
12187f4eb588SAppaRao Puli             {
12192558979cSP Dheeraj Srujan Kumar                 // If Service is not enabled, no need to compute
12202558979cSP Dheeraj Srujan Kumar                 // the remaining items below.
12212558979cSP Dheeraj Srujan Kumar                 // But, Loop must continue to keep track of Timestamp
122203d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG(
122303d4d37cSAlexander Hansen                     "Redfish log file: no subscribers / event service not enabled");
12247f4eb588SAppaRao Puli                 continue;
12257f4eb588SAppaRao Puli             }
12267f4eb588SAppaRao Puli 
12277f4eb588SAppaRao Puli             std::string timestamp;
12287f4eb588SAppaRao Puli             std::string messageID;
12295e715de6SAppaRao Puli             std::vector<std::string> messageArgs;
12307f4eb588SAppaRao Puli             if (event_log::getEventLogParams(logEntry, timestamp, messageID,
12317f4eb588SAppaRao Puli                                              messageArgs) != 0)
12327f4eb588SAppaRao Puli             {
123303d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("Read eventLog entry params failed for {}",
123403d4d37cSAlexander Hansen                                  logEntry);
12357f4eb588SAppaRao Puli                 continue;
12367f4eb588SAppaRao Puli             }
12377f4eb588SAppaRao Puli 
1238f80a87f2SEd Tanous             eventRecords.emplace_back(idStr, timestamp, messageID, messageArgs);
12397f4eb588SAppaRao Puli         }
12407f4eb588SAppaRao Puli 
1241e662eae8SEd Tanous         if (!serviceEnabled || noOfEventLogSubscribers == 0)
12422558979cSP Dheeraj Srujan Kumar         {
124362598e31SEd Tanous             BMCWEB_LOG_DEBUG("EventService disabled or no Subscriptions.");
12442558979cSP Dheeraj Srujan Kumar             return;
12452558979cSP Dheeraj Srujan Kumar         }
12462558979cSP Dheeraj Srujan Kumar 
12472558979cSP Dheeraj Srujan Kumar         if (eventRecords.empty())
12482558979cSP Dheeraj Srujan Kumar         {
12492558979cSP Dheeraj Srujan Kumar             // No Records to send
125062598e31SEd Tanous             BMCWEB_LOG_DEBUG("No log entries available to be transferred.");
12512558979cSP Dheeraj Srujan Kumar             return;
12522558979cSP Dheeraj Srujan Kumar         }
12532558979cSP Dheeraj Srujan Kumar 
12545e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
12557f4eb588SAppaRao Puli         {
12567f4eb588SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
12577f4eb588SAppaRao Puli             if (entry->eventFormatType == "Event")
12587f4eb588SAppaRao Puli             {
12597f4eb588SAppaRao Puli                 entry->filterAndSendEventLogs(eventRecords);
12607f4eb588SAppaRao Puli             }
12617f4eb588SAppaRao Puli         }
12627f4eb588SAppaRao Puli     }
12637f4eb588SAppaRao Puli 
12647f4eb588SAppaRao Puli     static void watchRedfishEventLogFile()
12657f4eb588SAppaRao Puli     {
12666a9f85f9SAppaRao Puli         if (!inotifyConn)
12677f4eb588SAppaRao Puli         {
126803d4d37cSAlexander Hansen             BMCWEB_LOG_ERROR("inotify Connection is not present");
12697f4eb588SAppaRao Puli             return;
12707f4eb588SAppaRao Puli         }
12717f4eb588SAppaRao Puli 
12727f4eb588SAppaRao Puli         static std::array<char, 1024> readBuffer;
12737f4eb588SAppaRao Puli 
1274bd79bce8SPatrick Williams         inotifyConn->async_read_some(
1275bd79bce8SPatrick Williams             boost::asio::buffer(readBuffer),
12767f4eb588SAppaRao Puli             [&](const boost::system::error_code& ec,
12777f4eb588SAppaRao Puli                 const std::size_t& bytesTransferred) {
12789ed3f90aSEd Tanous                 if (ec == boost::asio::error::operation_aborted)
12799ed3f90aSEd Tanous                 {
12809ed3f90aSEd Tanous                     BMCWEB_LOG_DEBUG("Inotify was canceled (shutdown?)");
12819ed3f90aSEd Tanous                     return;
12829ed3f90aSEd Tanous                 }
12837f4eb588SAppaRao Puli                 if (ec)
12847f4eb588SAppaRao Puli                 {
128562598e31SEd Tanous                     BMCWEB_LOG_ERROR("Callback Error: {}", ec.message());
12867f4eb588SAppaRao Puli                     return;
12877f4eb588SAppaRao Puli                 }
128803d4d37cSAlexander Hansen 
128903d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("reading {} via inotify", bytesTransferred);
129003d4d37cSAlexander Hansen 
12917f4eb588SAppaRao Puli                 std::size_t index = 0;
1292b792cc56SAppaRao Puli                 while ((index + iEventSize) <= bytesTransferred)
12937f4eb588SAppaRao Puli                 {
1294d3a9e084SEd Tanous                     struct inotify_event event
1295d3a9e084SEd Tanous                     {};
1296b792cc56SAppaRao Puli                     std::memcpy(&event, &readBuffer[index], iEventSize);
1297b792cc56SAppaRao Puli                     if (event.wd == dirWatchDesc)
1298b792cc56SAppaRao Puli                     {
1299b792cc56SAppaRao Puli                         if ((event.len == 0) ||
1300b792cc56SAppaRao Puli                             (index + iEventSize + event.len > bytesTransferred))
1301b792cc56SAppaRao Puli                         {
1302b792cc56SAppaRao Puli                             index += (iEventSize + event.len);
1303b792cc56SAppaRao Puli                             continue;
1304b792cc56SAppaRao Puli                         }
1305b792cc56SAppaRao Puli 
13064f568f74SJiaqing Zhao                         std::string fileName(&readBuffer[index + iEventSize]);
13074f568f74SJiaqing Zhao                         if (fileName != "redfish")
1308b792cc56SAppaRao Puli                         {
1309b792cc56SAppaRao Puli                             index += (iEventSize + event.len);
1310b792cc56SAppaRao Puli                             continue;
1311b792cc56SAppaRao Puli                         }
1312b792cc56SAppaRao Puli 
131362598e31SEd Tanous                         BMCWEB_LOG_DEBUG(
131462598e31SEd Tanous                             "Redfish log file created/deleted. event.name: {}",
131562598e31SEd Tanous                             fileName);
1316b792cc56SAppaRao Puli                         if (event.mask == IN_CREATE)
1317b792cc56SAppaRao Puli                         {
1318b792cc56SAppaRao Puli                             if (fileWatchDesc != -1)
1319b792cc56SAppaRao Puli                             {
132062598e31SEd Tanous                                 BMCWEB_LOG_DEBUG(
132162598e31SEd Tanous                                     "Remove and Add inotify watcher on "
132262598e31SEd Tanous                                     "redfish event log file");
1323016761afSAppaRao Puli                                 // Remove existing inotify watcher and add
1324016761afSAppaRao Puli                                 // with new redfish event log file.
1325016761afSAppaRao Puli                                 inotify_rm_watch(inotifyFd, fileWatchDesc);
1326016761afSAppaRao Puli                                 fileWatchDesc = -1;
1327b792cc56SAppaRao Puli                             }
1328b792cc56SAppaRao Puli 
1329b792cc56SAppaRao Puli                             fileWatchDesc = inotify_add_watch(
1330b792cc56SAppaRao Puli                                 inotifyFd, redfishEventLogFile, IN_MODIFY);
1331b792cc56SAppaRao Puli                             if (fileWatchDesc == -1)
1332b792cc56SAppaRao Puli                             {
133362598e31SEd Tanous                                 BMCWEB_LOG_ERROR("inotify_add_watch failed for "
133462598e31SEd Tanous                                                  "redfish log file.");
1335b792cc56SAppaRao Puli                                 return;
1336b792cc56SAppaRao Puli                             }
1337b792cc56SAppaRao Puli 
1338b792cc56SAppaRao Puli                             EventServiceManager::getInstance()
13392558979cSP Dheeraj Srujan Kumar                                 .resetRedfishFilePosition();
1340b792cc56SAppaRao Puli                             EventServiceManager::getInstance()
1341b792cc56SAppaRao Puli                                 .readEventLogsFromFile();
1342b792cc56SAppaRao Puli                         }
1343b792cc56SAppaRao Puli                         else if ((event.mask == IN_DELETE) ||
1344b792cc56SAppaRao Puli                                  (event.mask == IN_MOVED_TO))
1345b792cc56SAppaRao Puli                         {
1346b792cc56SAppaRao Puli                             if (fileWatchDesc != -1)
1347b792cc56SAppaRao Puli                             {
1348b792cc56SAppaRao Puli                                 inotify_rm_watch(inotifyFd, fileWatchDesc);
1349b792cc56SAppaRao Puli                                 fileWatchDesc = -1;
1350b792cc56SAppaRao Puli                             }
1351b792cc56SAppaRao Puli                         }
1352b792cc56SAppaRao Puli                     }
1353b792cc56SAppaRao Puli                     else if (event.wd == fileWatchDesc)
1354b792cc56SAppaRao Puli                     {
1355b792cc56SAppaRao Puli                         if (event.mask == IN_MODIFY)
13567f4eb588SAppaRao Puli                         {
13577f4eb588SAppaRao Puli                             EventServiceManager::getInstance()
13587f4eb588SAppaRao Puli                                 .readEventLogsFromFile();
13597f4eb588SAppaRao Puli                         }
1360b792cc56SAppaRao Puli                     }
1361b792cc56SAppaRao Puli                     index += (iEventSize + event.len);
13627f4eb588SAppaRao Puli                 }
13637f4eb588SAppaRao Puli 
13647f4eb588SAppaRao Puli                 watchRedfishEventLogFile();
13657f4eb588SAppaRao Puli             });
13667f4eb588SAppaRao Puli     }
13677f4eb588SAppaRao Puli 
13687f4eb588SAppaRao Puli     static int startEventLogMonitor(boost::asio::io_context& ioc)
13697f4eb588SAppaRao Puli     {
137003d4d37cSAlexander Hansen         BMCWEB_LOG_DEBUG("starting Event Log Monitor");
137103d4d37cSAlexander Hansen 
137223a21a1cSEd Tanous         inotifyConn.emplace(ioc);
1373b792cc56SAppaRao Puli         inotifyFd = inotify_init1(IN_NONBLOCK);
1374b792cc56SAppaRao Puli         if (inotifyFd == -1)
13757f4eb588SAppaRao Puli         {
137662598e31SEd Tanous             BMCWEB_LOG_ERROR("inotify_init1 failed.");
13777f4eb588SAppaRao Puli             return -1;
13787f4eb588SAppaRao Puli         }
1379b792cc56SAppaRao Puli 
1380b792cc56SAppaRao Puli         // Add watch on directory to handle redfish event log file
1381b792cc56SAppaRao Puli         // create/delete.
1382b792cc56SAppaRao Puli         dirWatchDesc = inotify_add_watch(inotifyFd, redfishEventLogDir,
1383b792cc56SAppaRao Puli                                          IN_CREATE | IN_MOVED_TO | IN_DELETE);
1384b792cc56SAppaRao Puli         if (dirWatchDesc == -1)
13857f4eb588SAppaRao Puli         {
138662598e31SEd Tanous             BMCWEB_LOG_ERROR(
138762598e31SEd Tanous                 "inotify_add_watch failed for event log directory.");
13887f4eb588SAppaRao Puli             return -1;
13897f4eb588SAppaRao Puli         }
13907f4eb588SAppaRao Puli 
1391b792cc56SAppaRao Puli         // Watch redfish event log file for modifications.
1392bd79bce8SPatrick Williams         fileWatchDesc =
1393bd79bce8SPatrick Williams             inotify_add_watch(inotifyFd, redfishEventLogFile, IN_MODIFY);
1394b792cc56SAppaRao Puli         if (fileWatchDesc == -1)
1395b792cc56SAppaRao Puli         {
139662598e31SEd Tanous             BMCWEB_LOG_ERROR("inotify_add_watch failed for redfish log file.");
1397b792cc56SAppaRao Puli             // Don't return error if file not exist.
1398b792cc56SAppaRao Puli             // Watch on directory will handle create/delete of file.
1399b792cc56SAppaRao Puli         }
1400b792cc56SAppaRao Puli 
14017f4eb588SAppaRao Puli         // monitor redfish event log file
1402b792cc56SAppaRao Puli         inotifyConn->assign(inotifyFd);
14037f4eb588SAppaRao Puli         watchRedfishEventLogFile();
14047f4eb588SAppaRao Puli 
14057f4eb588SAppaRao Puli         return 0;
14067f4eb588SAppaRao Puli     }
14077f4eb588SAppaRao Puli 
14089ed3f90aSEd Tanous     static void stopEventLogMonitor()
14099ed3f90aSEd Tanous     {
14109ed3f90aSEd Tanous         inotifyConn.reset();
14119ed3f90aSEd Tanous     }
14129ed3f90aSEd Tanous 
141359d494eeSPatrick Williams     static void getReadingsForReport(sdbusplus::message_t& msg)
1414156d6b00SAppaRao Puli     {
141556d2396dSEd Tanous         if (msg.is_method_error())
141656d2396dSEd Tanous         {
141762598e31SEd Tanous             BMCWEB_LOG_ERROR("TelemetryMonitor Signal error");
141856d2396dSEd Tanous             return;
141956d2396dSEd Tanous         }
142056d2396dSEd Tanous 
1421c0353249SWludzik, Jozef         sdbusplus::message::object_path path(msg.get_path());
1422c0353249SWludzik, Jozef         std::string id = path.filename();
1423c0353249SWludzik, Jozef         if (id.empty())
1424156d6b00SAppaRao Puli         {
142562598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to get Id from path");
1426156d6b00SAppaRao Puli             return;
1427156d6b00SAppaRao Puli         }
1428156d6b00SAppaRao Puli 
1429c0353249SWludzik, Jozef         std::string interface;
1430b9d36b47SEd Tanous         dbus::utility::DBusPropertiesMap props;
1431c0353249SWludzik, Jozef         std::vector<std::string> invalidProps;
1432c0353249SWludzik, Jozef         msg.read(interface, props, invalidProps);
1433c0353249SWludzik, Jozef 
1434bd79bce8SPatrick Williams         auto found = std::ranges::find_if(props, [](const auto& x) {
1435bd79bce8SPatrick Williams             return x.first == "Readings";
1436bd79bce8SPatrick Williams         });
1437c0353249SWludzik, Jozef         if (found == props.end())
1438156d6b00SAppaRao Puli         {
143962598e31SEd Tanous             BMCWEB_LOG_INFO("Failed to get Readings from Report properties");
1440156d6b00SAppaRao Puli             return;
1441156d6b00SAppaRao Puli         }
1442156d6b00SAppaRao Puli 
14431e1e598dSJonathan Doman         const telemetry::TimestampReadings* readings =
14441e1e598dSJonathan Doman             std::get_if<telemetry::TimestampReadings>(&found->second);
1445e662eae8SEd Tanous         if (readings == nullptr)
14461e1e598dSJonathan Doman         {
144762598e31SEd Tanous             BMCWEB_LOG_INFO("Failed to get Readings from Report properties");
14481e1e598dSJonathan Doman             return;
14491e1e598dSJonathan Doman         }
14501e1e598dSJonathan Doman 
1451156d6b00SAppaRao Puli         for (const auto& it :
1452156d6b00SAppaRao Puli              EventServiceManager::getInstance().subscriptionsMap)
1453156d6b00SAppaRao Puli         {
1454e05aec50SEd Tanous             Subscription& entry = *it.second;
1455c0353249SWludzik, Jozef             if (entry.eventFormatType == metricReportFormatType)
1456156d6b00SAppaRao Puli             {
14571e1e598dSJonathan Doman                 entry.filterAndSendReports(id, *readings);
1458156d6b00SAppaRao Puli             }
1459156d6b00SAppaRao Puli         }
1460156d6b00SAppaRao Puli     }
1461156d6b00SAppaRao Puli 
1462156d6b00SAppaRao Puli     void unregisterMetricReportSignal()
1463156d6b00SAppaRao Puli     {
14647d1cc387SAppaRao Puli         if (matchTelemetryMonitor)
14657d1cc387SAppaRao Puli         {
146662598e31SEd Tanous             BMCWEB_LOG_DEBUG("Metrics report signal - Unregister");
1467156d6b00SAppaRao Puli             matchTelemetryMonitor.reset();
1468156d6b00SAppaRao Puli             matchTelemetryMonitor = nullptr;
1469156d6b00SAppaRao Puli         }
14707d1cc387SAppaRao Puli     }
1471156d6b00SAppaRao Puli 
1472156d6b00SAppaRao Puli     void registerMetricReportSignal()
1473156d6b00SAppaRao Puli     {
14747d1cc387SAppaRao Puli         if (!serviceEnabled || matchTelemetryMonitor)
1475156d6b00SAppaRao Puli         {
147662598e31SEd Tanous             BMCWEB_LOG_DEBUG("Not registering metric report signal.");
1477156d6b00SAppaRao Puli             return;
1478156d6b00SAppaRao Puli         }
1479156d6b00SAppaRao Puli 
148062598e31SEd Tanous         BMCWEB_LOG_DEBUG("Metrics report signal - Register");
1481c0353249SWludzik, Jozef         std::string matchStr = "type='signal',member='PropertiesChanged',"
1482c0353249SWludzik, Jozef                                "interface='org.freedesktop.DBus.Properties',"
1483c0353249SWludzik, Jozef                                "arg0=xyz.openbmc_project.Telemetry.Report";
1484156d6b00SAppaRao Puli 
148559d494eeSPatrick Williams         matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match_t>(
148656d2396dSEd Tanous             *crow::connections::systemBus, matchStr, getReadingsForReport);
1487156d6b00SAppaRao Puli     }
148823a21a1cSEd Tanous };
1489b52664e2SAppaRao Puli 
1490b52664e2SAppaRao Puli } // namespace redfish
1491