xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision 4b712a29debc1a0860cc04850b262203cad402a5)
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>
46a14c9113SEd Tanous #include <format>
471bf712bcSAyushi Smriti #include <fstream>
48b52664e2SAppaRao Puli #include <memory>
493544d2a7SEd Tanous #include <ranges>
5026702d01SEd Tanous #include <span>
51a14c9113SEd 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 
270*4b712a29SEd Tanous class Subscription
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     {
282*4b712a29SEd Tanous         userSub.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         {
306*4b712a29SEd Tanous             client->sendData(std::move(msg), userSub.destinationUrl,
307*4b712a29SEd Tanous                              static_cast<ensuressl::VerifyCertificate>(
308*4b712a29SEd Tanous                                  userSub.verifyCertificate),
309*4b712a29SEd Tanous                              userSub.httpHeaders,
310*4b712a29SEd Tanous                              boost::beast::http::verb::post);
3115e44e3d8SAppaRao Puli             return true;
3125e44e3d8SAppaRao Puli         }
3137adb85acSSunitha Harish 
3144bbf237fSAppaRao Puli         if (sseConn != nullptr)
3154bbf237fSAppaRao Puli         {
3165e44e3d8SAppaRao Puli             eventSeqNum++;
3176d799e14SEd Tanous             sseConn->sendSseEvent(std::to_string(eventSeqNum), msg);
3184bbf237fSAppaRao Puli         }
3196ba8c82eSsunharis_in         return true;
3204bbf237fSAppaRao Puli     }
3214bbf237fSAppaRao Puli 
322f80a87f2SEd Tanous     bool eventMatchesFilter(const nlohmann::json::object_t& eventMessage,
323f80a87f2SEd Tanous                             std::string_view resType)
324f80a87f2SEd Tanous     {
325f80a87f2SEd Tanous         // If resourceTypes list is empty, assume all
326*4b712a29SEd Tanous         if (!userSub.resourceTypes.empty())
327f80a87f2SEd Tanous         {
328f80a87f2SEd Tanous             // Search the resourceTypes list for the subscription.
329f80a87f2SEd Tanous             auto resourceTypeIndex = std::ranges::find_if(
330*4b712a29SEd Tanous                 userSub.resourceTypes, [resType](const std::string& rtEntry) {
331f80a87f2SEd Tanous                     return rtEntry == resType;
332f80a87f2SEd Tanous                 });
333*4b712a29SEd Tanous             if (resourceTypeIndex == userSub.resourceTypes.end())
334f80a87f2SEd Tanous             {
335f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Not subscribed to this resource");
336f80a87f2SEd Tanous                 return false;
337f80a87f2SEd Tanous             }
338f80a87f2SEd Tanous             BMCWEB_LOG_DEBUG("ResourceType {} found in the subscribed list",
339f80a87f2SEd Tanous                              resType);
340f80a87f2SEd Tanous         }
341f80a87f2SEd Tanous 
342a14c9113SEd Tanous         // If registryPrefixes list is empty, don't filter events
343a14c9113SEd Tanous         // send everything.
344*4b712a29SEd Tanous         if (!userSub.registryPrefixes.empty())
345a14c9113SEd Tanous         {
346a14c9113SEd Tanous             auto eventJson = eventMessage.find("MessageId");
347a14c9113SEd Tanous             if (eventJson == eventMessage.end())
348a14c9113SEd Tanous             {
349a14c9113SEd Tanous                 return false;
350a14c9113SEd Tanous             }
351a14c9113SEd Tanous 
352a14c9113SEd Tanous             const std::string* messageId =
353a14c9113SEd Tanous                 eventJson->second.get_ptr<const std::string*>();
354a14c9113SEd Tanous             if (messageId == nullptr)
355a14c9113SEd Tanous             {
356a14c9113SEd Tanous                 BMCWEB_LOG_ERROR("MessageId wasn't a string???");
357a14c9113SEd Tanous                 return false;
358a14c9113SEd Tanous             }
359a14c9113SEd Tanous 
360a14c9113SEd Tanous             std::string registry;
361a14c9113SEd Tanous             std::string messageKey;
362a14c9113SEd Tanous             event_log::getRegistryAndMessageKey(*messageId, registry,
363a14c9113SEd Tanous                                                 messageKey);
364a14c9113SEd Tanous 
365*4b712a29SEd Tanous             auto obj = std::ranges::find(userSub.registryPrefixes, registry);
366*4b712a29SEd Tanous             if (obj == userSub.registryPrefixes.end())
367a14c9113SEd Tanous             {
368a14c9113SEd Tanous                 return false;
369a14c9113SEd Tanous             }
370a14c9113SEd Tanous         }
371a14c9113SEd Tanous 
372*4b712a29SEd Tanous         if (!userSub.originResources.empty())
373a14c9113SEd Tanous         {
374a14c9113SEd Tanous             auto eventJson = eventMessage.find("OriginOfCondition");
375a14c9113SEd Tanous             if (eventJson == eventMessage.end())
376a14c9113SEd Tanous             {
377a14c9113SEd Tanous                 return false;
378a14c9113SEd Tanous             }
379a14c9113SEd Tanous 
380a14c9113SEd Tanous             const std::string* originOfCondition =
381a14c9113SEd Tanous                 eventJson->second.get_ptr<const std::string*>();
382a14c9113SEd Tanous             if (originOfCondition == nullptr)
383a14c9113SEd Tanous             {
384a14c9113SEd Tanous                 BMCWEB_LOG_ERROR("OriginOfCondition wasn't a string???");
385a14c9113SEd Tanous                 return false;
386a14c9113SEd Tanous             }
387a14c9113SEd Tanous 
388*4b712a29SEd Tanous             auto obj =
389*4b712a29SEd Tanous                 std::ranges::find(userSub.originResources, *originOfCondition);
390a14c9113SEd Tanous 
391*4b712a29SEd Tanous             if (obj == userSub.originResources.end())
392a14c9113SEd Tanous             {
393a14c9113SEd Tanous                 return false;
394a14c9113SEd Tanous             }
395a14c9113SEd Tanous         }
396a14c9113SEd Tanous 
397f80a87f2SEd Tanous         // If registryMsgIds list is empty, assume all
398*4b712a29SEd Tanous         if (!userSub.registryMsgIds.empty())
399f80a87f2SEd Tanous         {
400f80a87f2SEd Tanous             auto eventJson = eventMessage.find("MessageId");
401f80a87f2SEd Tanous             if (eventJson == eventMessage.end())
402f80a87f2SEd Tanous             {
40303d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("'MessageId' not present");
404f80a87f2SEd Tanous                 return false;
405f80a87f2SEd Tanous             }
406f80a87f2SEd Tanous 
407f80a87f2SEd Tanous             const std::string* messageId =
408f80a87f2SEd Tanous                 eventJson->second.get_ptr<const std::string*>();
409f80a87f2SEd Tanous             if (messageId == nullptr)
410f80a87f2SEd Tanous             {
411f80a87f2SEd Tanous                 BMCWEB_LOG_ERROR("EventType wasn't a string???");
412f80a87f2SEd Tanous                 return false;
413f80a87f2SEd Tanous             }
414f80a87f2SEd Tanous 
415f80a87f2SEd Tanous             std::string registry;
416f80a87f2SEd Tanous             std::string messageKey;
417f80a87f2SEd Tanous             event_log::getRegistryAndMessageKey(*messageId, registry,
418f80a87f2SEd Tanous                                                 messageKey);
419f80a87f2SEd Tanous 
42003d4d37cSAlexander Hansen             BMCWEB_LOG_DEBUG("extracted registry {}", registry);
42103d4d37cSAlexander Hansen             BMCWEB_LOG_DEBUG("extracted message key {}", messageKey);
42203d4d37cSAlexander Hansen 
423*4b712a29SEd Tanous             auto obj =
424*4b712a29SEd Tanous                 std::ranges::find(userSub.registryMsgIds,
425*4b712a29SEd Tanous                                   std::format("{}.{}", registry, messageKey));
426*4b712a29SEd Tanous             if (obj == userSub.registryMsgIds.end())
427f80a87f2SEd Tanous             {
42803d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("did not find registry {} in registryMsgIds",
42903d4d37cSAlexander Hansen                                  registry);
43003d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("registryMsgIds has {} entries",
431*4b712a29SEd Tanous                                  userSub.registryMsgIds.size());
432f80a87f2SEd Tanous                 return false;
433f80a87f2SEd Tanous             }
434f80a87f2SEd Tanous         }
435f80a87f2SEd Tanous 
436f80a87f2SEd Tanous         if (filter)
437f80a87f2SEd Tanous         {
438f80a87f2SEd Tanous             if (!memberMatches(eventMessage, *filter))
439f80a87f2SEd Tanous             {
440f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Filter didn't match");
441f80a87f2SEd Tanous                 return false;
442f80a87f2SEd Tanous             }
443f80a87f2SEd Tanous         }
444f80a87f2SEd Tanous 
445f80a87f2SEd Tanous         return true;
446f80a87f2SEd Tanous     }
447f80a87f2SEd Tanous 
4486ba8c82eSsunharis_in     bool sendTestEventLog()
4490b4bdd93SAppaRao Puli     {
450f80a87f2SEd Tanous         nlohmann::json::array_t logEntryArray;
451f80a87f2SEd Tanous         nlohmann::json& logEntryJson = logEntryArray.emplace_back();
4520b4bdd93SAppaRao Puli 
453613dabeaSEd Tanous         logEntryJson["EventId"] = "TestID";
454539d8c6bSEd Tanous         logEntryJson["Severity"] = log_entry::EventSeverity::OK;
455613dabeaSEd Tanous         logEntryJson["Message"] = "Generated test event";
456613dabeaSEd Tanous         logEntryJson["MessageId"] = "OpenBMC.0.2.TestEventLog";
457d2cdd478SChandra Harkude         // MemberId is 0 : since we are sending one event record.
458d2cdd478SChandra Harkude         logEntryJson["MemberId"] = 0;
459613dabeaSEd Tanous         logEntryJson["MessageArgs"] = nlohmann::json::array();
460613dabeaSEd Tanous         logEntryJson["EventTimestamp"] =
461613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
462*4b712a29SEd Tanous         logEntryJson["Context"] = userSub.customText;
4630b4bdd93SAppaRao Puli 
4641476687dSEd Tanous         nlohmann::json msg;
4651476687dSEd Tanous         msg["@odata.type"] = "#Event.v1_4_0.Event";
4661476687dSEd Tanous         msg["Id"] = std::to_string(eventSeqNum);
4671476687dSEd Tanous         msg["Name"] = "Event Log";
4681476687dSEd Tanous         msg["Events"] = logEntryArray;
4690b4bdd93SAppaRao Puli 
470bd79bce8SPatrick Williams         std::string strMsg =
471bd79bce8SPatrick Williams             msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
4726d799e14SEd Tanous         return sendEventToSubscriber(std::move(strMsg));
4730b4bdd93SAppaRao Puli     }
4740b4bdd93SAppaRao Puli 
4757f4eb588SAppaRao Puli     void filterAndSendEventLogs(
4767f4eb588SAppaRao Puli         const std::vector<EventLogObjectsType>& eventRecords)
4777f4eb588SAppaRao Puli     {
478f80a87f2SEd Tanous         nlohmann::json::array_t logEntryArray;
4797f4eb588SAppaRao Puli         for (const EventLogObjectsType& logEntry : eventRecords)
4807f4eb588SAppaRao Puli         {
481f80a87f2SEd Tanous             std::vector<std::string_view> messageArgsView(
482f80a87f2SEd Tanous                 logEntry.messageArgs.begin(), logEntry.messageArgs.end());
4837f4eb588SAppaRao Puli 
484f80a87f2SEd Tanous             nlohmann::json::object_t bmcLogEntry;
485f80a87f2SEd Tanous             if (event_log::formatEventLogEntry(
486f80a87f2SEd Tanous                     logEntry.id, logEntry.messageId, messageArgsView,
487*4b712a29SEd Tanous                     logEntry.timestamp, userSub.customText, bmcLogEntry) != 0)
4887f4eb588SAppaRao Puli             {
48962598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Read eventLog entry failed");
4907f4eb588SAppaRao Puli                 continue;
4917f4eb588SAppaRao Puli             }
492f80a87f2SEd Tanous 
493f80a87f2SEd Tanous             if (!eventMatchesFilter(bmcLogEntry, ""))
494f80a87f2SEd Tanous             {
49503d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("Event {} did not match the filter",
49603d4d37cSAlexander Hansen                                  nlohmann::json(bmcLogEntry).dump());
497f80a87f2SEd Tanous                 continue;
498f80a87f2SEd Tanous             }
499f80a87f2SEd Tanous 
500f80a87f2SEd Tanous             logEntryArray.emplace_back(std::move(bmcLogEntry));
5017f4eb588SAppaRao Puli         }
5027f4eb588SAppaRao Puli 
50326f6976fSEd Tanous         if (logEntryArray.empty())
5047f4eb588SAppaRao Puli         {
50562598e31SEd Tanous             BMCWEB_LOG_DEBUG("No log entries available to be transferred.");
5067f4eb588SAppaRao Puli             return;
5077f4eb588SAppaRao Puli         }
5087f4eb588SAppaRao Puli 
5091476687dSEd Tanous         nlohmann::json msg;
5101476687dSEd Tanous         msg["@odata.type"] = "#Event.v1_4_0.Event";
5111476687dSEd Tanous         msg["Id"] = std::to_string(eventSeqNum);
5121476687dSEd Tanous         msg["Name"] = "Event Log";
513f80a87f2SEd Tanous         msg["Events"] = std::move(logEntryArray);
514bd79bce8SPatrick Williams         std::string strMsg =
515bd79bce8SPatrick Williams             msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
5166d799e14SEd Tanous         sendEventToSubscriber(std::move(strMsg));
5175e44e3d8SAppaRao Puli         eventSeqNum++;
5187f4eb588SAppaRao Puli     }
5197f4eb588SAppaRao Puli 
520248d0230SEd Tanous     void filterAndSendReports(const std::string& reportId,
5211e1e598dSJonathan Doman                               const telemetry::TimestampReadings& var)
522156d6b00SAppaRao Puli     {
523ef4c65b7SEd Tanous         boost::urls::url mrdUri = boost::urls::format(
524ef4c65b7SEd Tanous             "/redfish/v1/TelemetryService/MetricReportDefinitions/{}",
525ef4c65b7SEd Tanous             reportId);
526156d6b00SAppaRao Puli 
527156d6b00SAppaRao Puli         // Empty list means no filter. Send everything.
528*4b712a29SEd Tanous         if (!userSub.metricReportDefinitions.empty())
529156d6b00SAppaRao Puli         {
530*4b712a29SEd Tanous             if (std::ranges::find(userSub.metricReportDefinitions,
531*4b712a29SEd Tanous                                   mrdUri.buffer()) ==
532*4b712a29SEd Tanous                 userSub.metricReportDefinitions.end())
533156d6b00SAppaRao Puli             {
534156d6b00SAppaRao Puli                 return;
535156d6b00SAppaRao Puli             }
536156d6b00SAppaRao Puli         }
537156d6b00SAppaRao Puli 
538c0353249SWludzik, Jozef         nlohmann::json msg;
539248d0230SEd Tanous         if (!telemetry::fillReport(msg, reportId, var))
540156d6b00SAppaRao Puli         {
54162598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to fill the MetricReport for DBus "
54262598e31SEd Tanous                              "Report with id {}",
54362598e31SEd Tanous                              reportId);
544c0353249SWludzik, Jozef             return;
545156d6b00SAppaRao Puli         }
546156d6b00SAppaRao Puli 
54722daffd7SAppaRao Puli         // Context is set by user during Event subscription and it must be
54822daffd7SAppaRao Puli         // set for MetricReport response.
549*4b712a29SEd Tanous         if (!userSub.customText.empty())
55022daffd7SAppaRao Puli         {
551*4b712a29SEd Tanous             msg["Context"] = userSub.customText;
55222daffd7SAppaRao Puli         }
55322daffd7SAppaRao Puli 
554bd79bce8SPatrick Williams         std::string strMsg =
555bd79bce8SPatrick Williams             msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
5566d799e14SEd Tanous         sendEventToSubscriber(std::move(strMsg));
557156d6b00SAppaRao Puli     }
558156d6b00SAppaRao Puli 
559d14a48ffSCarson Labrado     void updateRetryConfig(uint32_t retryAttempts,
560d14a48ffSCarson Labrado                            uint32_t retryTimeoutInterval)
561fe44eb0bSAyushi Smriti     {
56293cf0ac2SEd Tanous         if (policy == nullptr)
56393cf0ac2SEd Tanous         {
56493cf0ac2SEd Tanous             BMCWEB_LOG_DEBUG("Retry policy was nullptr, ignoring set");
56593cf0ac2SEd Tanous             return;
56693cf0ac2SEd Tanous         }
567d14a48ffSCarson Labrado         policy->maxRetryAttempts = retryAttempts;
568d14a48ffSCarson Labrado         policy->retryIntervalSecs = std::chrono::seconds(retryTimeoutInterval);
56962de0c68SAppaRao Puli     }
570fe44eb0bSAyushi Smriti 
5719eb808c1SEd Tanous     uint64_t getEventSeqNum() const
57296330b99SSunitha Harish     {
57396330b99SSunitha Harish         return eventSeqNum;
57496330b99SSunitha Harish     }
57596330b99SSunitha Harish 
5765e44e3d8SAppaRao Puli     void setSubscriptionId(const std::string& id2)
5775e44e3d8SAppaRao Puli     {
57862598e31SEd Tanous         BMCWEB_LOG_DEBUG("Subscription ID: {}", id2);
5795e44e3d8SAppaRao Puli         subId = id2;
5805e44e3d8SAppaRao Puli     }
5815e44e3d8SAppaRao Puli 
5825e44e3d8SAppaRao Puli     std::string getSubscriptionId()
5835e44e3d8SAppaRao Puli     {
5845e44e3d8SAppaRao Puli         return subId;
5855e44e3d8SAppaRao Puli     }
5865e44e3d8SAppaRao Puli 
5875e44e3d8SAppaRao Puli     bool matchSseId(const crow::sse_socket::Connection& thisConn)
5885e44e3d8SAppaRao Puli     {
5895e44e3d8SAppaRao Puli         return &thisConn == sseConn;
5905e44e3d8SAppaRao Puli     }
5915e44e3d8SAppaRao Puli 
592a7a80296SCarson Labrado     // Check used to indicate what response codes are valid as part of our retry
593a7a80296SCarson Labrado     // policy.  2XX is considered acceptable
594a7a80296SCarson Labrado     static boost::system::error_code retryRespHandler(unsigned int respCode)
595a7a80296SCarson Labrado     {
59662598e31SEd Tanous         BMCWEB_LOG_DEBUG(
59762598e31SEd Tanous             "Checking response code validity for SubscriptionEvent");
598a7a80296SCarson Labrado         if ((respCode < 200) || (respCode >= 300))
599a7a80296SCarson Labrado         {
600a7a80296SCarson Labrado             return boost::system::errc::make_error_code(
601a7a80296SCarson Labrado                 boost::system::errc::result_out_of_range);
602a7a80296SCarson Labrado         }
603a7a80296SCarson Labrado 
604a7a80296SCarson Labrado         // Return 0 if the response code is valid
605a7a80296SCarson Labrado         return boost::system::errc::make_error_code(
606a7a80296SCarson Labrado             boost::system::errc::success);
6079fa6d147SNan Zhou     }
608f80a87f2SEd Tanous 
609*4b712a29SEd Tanous     persistent_data::UserSubscription userSub;
610*4b712a29SEd Tanous 
611f80a87f2SEd Tanous   private:
612f80a87f2SEd Tanous     std::string subId;
613f80a87f2SEd Tanous     uint64_t eventSeqNum = 1;
614f80a87f2SEd Tanous     boost::urls::url host;
615f80a87f2SEd Tanous     std::shared_ptr<crow::ConnectionPolicy> policy;
616f80a87f2SEd Tanous     crow::sse_socket::Connection* sseConn = nullptr;
617f80a87f2SEd Tanous 
618f80a87f2SEd Tanous     std::optional<crow::HttpClient> client;
619f80a87f2SEd Tanous 
620f80a87f2SEd Tanous   public:
621f80a87f2SEd Tanous     std::optional<filter_ast::LogicalAnd> filter;
622b52664e2SAppaRao Puli };
623b52664e2SAppaRao Puli 
624b52664e2SAppaRao Puli class EventServiceManager
625b52664e2SAppaRao Puli {
626b52664e2SAppaRao Puli   private:
627d3a9e084SEd Tanous     bool serviceEnabled = false;
628d3a9e084SEd Tanous     uint32_t retryAttempts = 0;
629d3a9e084SEd Tanous     uint32_t retryTimeoutInterval = 0;
6307d1cc387SAppaRao Puli 
6312558979cSP Dheeraj Srujan Kumar     std::streampos redfishLogFilePosition{0};
6329f616dd1SEd Tanous     size_t noOfEventLogSubscribers{0};
6339f616dd1SEd Tanous     size_t noOfMetricReportSubscribers{0};
63459d494eeSPatrick Williams     std::shared_ptr<sdbusplus::bus::match_t> matchTelemetryMonitor;
635b52664e2SAppaRao Puli     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
636b52664e2SAppaRao Puli         subscriptionsMap;
637b52664e2SAppaRao Puli 
6389f616dd1SEd Tanous     uint64_t eventId{1};
63996330b99SSunitha Harish 
640f80a87f2SEd Tanous     struct Event
641f80a87f2SEd Tanous     {
642f80a87f2SEd Tanous         std::string id;
643f80a87f2SEd Tanous         nlohmann::json message;
644f80a87f2SEd Tanous     };
645f80a87f2SEd Tanous 
646f80a87f2SEd Tanous     constexpr static size_t maxMessages = 200;
647f80a87f2SEd Tanous     boost::circular_buffer<Event> messages{maxMessages};
648f80a87f2SEd Tanous 
649f8ca6d79SEd Tanous     boost::asio::io_context& ioc;
650f8ca6d79SEd Tanous 
651b52664e2SAppaRao Puli   public:
6529f616dd1SEd Tanous     EventServiceManager(const EventServiceManager&) = delete;
6539f616dd1SEd Tanous     EventServiceManager& operator=(const EventServiceManager&) = delete;
6549f616dd1SEd Tanous     EventServiceManager(EventServiceManager&&) = delete;
6559f616dd1SEd Tanous     EventServiceManager& operator=(EventServiceManager&&) = delete;
656ecd6a3a2SEd Tanous     ~EventServiceManager() = default;
6579f616dd1SEd Tanous 
658f8ca6d79SEd Tanous     explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn)
659b52664e2SAppaRao Puli     {
660f8ca6d79SEd Tanous         // Load config from persist store.
661f8ca6d79SEd Tanous         initConfig();
662f8ca6d79SEd Tanous     }
663f8ca6d79SEd Tanous 
664f8ca6d79SEd Tanous     static EventServiceManager&
665f8ca6d79SEd Tanous         getInstance(boost::asio::io_context* ioc = nullptr)
666f8ca6d79SEd Tanous     {
667f8ca6d79SEd Tanous         static EventServiceManager handler(*ioc);
668b52664e2SAppaRao Puli         return handler;
669b52664e2SAppaRao Puli     }
670b52664e2SAppaRao Puli 
6711bf712bcSAyushi Smriti     void initConfig()
6721bf712bcSAyushi Smriti     {
67328afb49cSJunLin Chen         loadOldBehavior();
6741bf712bcSAyushi Smriti 
67528afb49cSJunLin Chen         persistent_data::EventServiceConfig eventServiceConfig =
67628afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
67728afb49cSJunLin Chen                 .getEventServiceConfig();
6781bf712bcSAyushi Smriti 
67928afb49cSJunLin Chen         serviceEnabled = eventServiceConfig.enabled;
68028afb49cSJunLin Chen         retryAttempts = eventServiceConfig.retryAttempts;
68128afb49cSJunLin Chen         retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval;
6821bf712bcSAyushi Smriti 
68328afb49cSJunLin Chen         for (const auto& it : persistent_data::EventServiceStore::getInstance()
68428afb49cSJunLin Chen                                   .subscriptionsConfigMap)
6851bf712bcSAyushi Smriti         {
686*4b712a29SEd Tanous             const persistent_data::UserSubscription& newSub = it.second;
6874bbf237fSAppaRao Puli 
6886fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
689*4b712a29SEd Tanous                 boost::urls::parse_absolute_uri(newSub.destinationUrl);
6901bf712bcSAyushi Smriti 
691a716aa74SEd Tanous             if (!url)
6921bf712bcSAyushi Smriti             {
69362598e31SEd Tanous                 BMCWEB_LOG_ERROR(
69462598e31SEd Tanous                     "Failed to validate and split destination url");
6951bf712bcSAyushi Smriti                 continue;
6961bf712bcSAyushi Smriti             }
6971bf712bcSAyushi Smriti             std::shared_ptr<Subscription> subValue =
698a716aa74SEd Tanous                 std::make_shared<Subscription>(*url, ioc);
699*4b712a29SEd Tanous             subValue->userSub = newSub;
7001bf712bcSAyushi Smriti 
701*4b712a29SEd Tanous             subscriptionsMap.insert(std::pair(subValue->userSub.id, subValue));
70228afb49cSJunLin Chen 
70328afb49cSJunLin Chen             updateNoOfSubscribersCount();
70428afb49cSJunLin Chen 
70583328316SEd Tanous             if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
70683328316SEd Tanous             {
7072558979cSP Dheeraj Srujan Kumar                 cacheRedfishLogFile();
70883328316SEd Tanous             }
7092558979cSP Dheeraj Srujan Kumar 
71028afb49cSJunLin Chen             // Update retry configuration.
71128afb49cSJunLin Chen             subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
7121bf712bcSAyushi Smriti         }
7131bf712bcSAyushi Smriti     }
7141bf712bcSAyushi Smriti 
71556d2396dSEd Tanous     static void loadOldBehavior()
716b52664e2SAppaRao Puli     {
71728afb49cSJunLin Chen         std::ifstream eventConfigFile(eventServiceFile);
71828afb49cSJunLin Chen         if (!eventConfigFile.good())
7191bf712bcSAyushi Smriti         {
72062598e31SEd Tanous             BMCWEB_LOG_DEBUG("Old eventService config not exist");
72128afb49cSJunLin Chen             return;
72228afb49cSJunLin Chen         }
72328afb49cSJunLin Chen         auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false);
72428afb49cSJunLin Chen         if (jsonData.is_discarded())
7254bbf237fSAppaRao Puli         {
72662598e31SEd Tanous             BMCWEB_LOG_ERROR("Old eventService config parse error.");
72728afb49cSJunLin Chen             return;
72828afb49cSJunLin Chen         }
72928afb49cSJunLin Chen 
7300bdda665SEd Tanous         const nlohmann::json::object_t* obj =
7310bdda665SEd Tanous             jsonData.get_ptr<const nlohmann::json::object_t*>();
7320bdda665SEd Tanous         for (const auto& item : *obj)
73328afb49cSJunLin Chen         {
7340bdda665SEd Tanous             if (item.first == "Configuration")
73528afb49cSJunLin Chen             {
73628afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
73728afb49cSJunLin Chen                     .getEventServiceConfig()
7380bdda665SEd Tanous                     .fromJson(item.second);
73928afb49cSJunLin Chen             }
7400bdda665SEd Tanous             else if (item.first == "Subscriptions")
74128afb49cSJunLin Chen             {
7420bdda665SEd Tanous                 for (const auto& elem : item.second)
74328afb49cSJunLin Chen                 {
744*4b712a29SEd Tanous                     std::optional<persistent_data::UserSubscription>
74528afb49cSJunLin Chen                         newSubscription =
74628afb49cSJunLin Chen                             persistent_data::UserSubscription::fromJson(elem,
74728afb49cSJunLin Chen                                                                         true);
748*4b712a29SEd Tanous                     if (!newSubscription)
74928afb49cSJunLin Chen                     {
75062598e31SEd Tanous                         BMCWEB_LOG_ERROR("Problem reading subscription "
75162598e31SEd Tanous                                          "from old persistent store");
7524bbf237fSAppaRao Puli                         continue;
7534bbf237fSAppaRao Puli                     }
754*4b712a29SEd Tanous                     persistent_data::UserSubscription& newSub =
755*4b712a29SEd Tanous                         *newSubscription;
7561bf712bcSAyushi Smriti 
75728afb49cSJunLin Chen                     std::uniform_int_distribution<uint32_t> dist(0);
75828afb49cSJunLin Chen                     bmcweb::OpenSSLGenerator gen;
7591bf712bcSAyushi Smriti 
76028afb49cSJunLin Chen                     std::string id;
7611bf712bcSAyushi Smriti 
76228afb49cSJunLin Chen                     int retry = 3;
763e662eae8SEd Tanous                     while (retry != 0)
7641bf712bcSAyushi Smriti                     {
76528afb49cSJunLin Chen                         id = std::to_string(dist(gen));
76628afb49cSJunLin Chen                         if (gen.error())
7677d1cc387SAppaRao Puli                         {
76828afb49cSJunLin Chen                             retry = 0;
76928afb49cSJunLin Chen                             break;
77028afb49cSJunLin Chen                         }
771*4b712a29SEd Tanous                         newSub.id = id;
77228afb49cSJunLin Chen                         auto inserted =
77328afb49cSJunLin Chen                             persistent_data::EventServiceStore::getInstance()
77428afb49cSJunLin Chen                                 .subscriptionsConfigMap.insert(
775*4b712a29SEd Tanous                                     std::pair(id, newSub));
77628afb49cSJunLin Chen                         if (inserted.second)
77728afb49cSJunLin Chen                         {
77828afb49cSJunLin Chen                             break;
77928afb49cSJunLin Chen                         }
78028afb49cSJunLin Chen                         --retry;
7817d1cc387SAppaRao Puli                     }
7827d1cc387SAppaRao Puli 
78328afb49cSJunLin Chen                     if (retry <= 0)
78428afb49cSJunLin Chen                     {
78562598e31SEd Tanous                         BMCWEB_LOG_ERROR(
78662598e31SEd Tanous                             "Failed to generate random number from old "
78762598e31SEd Tanous                             "persistent store");
78828afb49cSJunLin Chen                         continue;
78928afb49cSJunLin Chen                     }
79028afb49cSJunLin Chen                 }
79128afb49cSJunLin Chen             }
79228afb49cSJunLin Chen 
79328afb49cSJunLin Chen             persistent_data::getConfig().writeData();
7944c521c3cSEd Tanous             std::error_code ec;
7954c521c3cSEd Tanous             std::filesystem::remove(eventServiceFile, ec);
7964c521c3cSEd Tanous             if (ec)
7974c521c3cSEd Tanous             {
7984c521c3cSEd Tanous                 BMCWEB_LOG_DEBUG(
7994c521c3cSEd Tanous                     "Failed to remove old event service file.  Ignoring");
8004c521c3cSEd Tanous             }
8014c521c3cSEd Tanous             else
8024c521c3cSEd Tanous             {
80362598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Remove old eventservice config");
80428afb49cSJunLin Chen             }
80528afb49cSJunLin Chen         }
8064c521c3cSEd Tanous     }
80728afb49cSJunLin Chen 
8089eb808c1SEd Tanous     void updateSubscriptionData() const
80928afb49cSJunLin Chen     {
81028afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
81128afb49cSJunLin Chen             .eventServiceConfig.enabled = serviceEnabled;
81228afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
81328afb49cSJunLin Chen             .eventServiceConfig.retryAttempts = retryAttempts;
81428afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
81528afb49cSJunLin Chen             .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval;
81628afb49cSJunLin Chen 
81728afb49cSJunLin Chen         persistent_data::getConfig().writeData();
81828afb49cSJunLin Chen     }
81928afb49cSJunLin Chen 
82028afb49cSJunLin Chen     void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg)
8217d1cc387SAppaRao Puli     {
8227d1cc387SAppaRao Puli         bool updateConfig = false;
823fe44eb0bSAyushi Smriti         bool updateRetryCfg = false;
8247d1cc387SAppaRao Puli 
82528afb49cSJunLin Chen         if (serviceEnabled != cfg.enabled)
8267d1cc387SAppaRao Puli         {
82728afb49cSJunLin Chen             serviceEnabled = cfg.enabled;
828e662eae8SEd Tanous             if (serviceEnabled && noOfMetricReportSubscribers != 0U)
8297d1cc387SAppaRao Puli             {
8307d1cc387SAppaRao Puli                 registerMetricReportSignal();
8317d1cc387SAppaRao Puli             }
8327d1cc387SAppaRao Puli             else
8337d1cc387SAppaRao Puli             {
8347d1cc387SAppaRao Puli                 unregisterMetricReportSignal();
8357d1cc387SAppaRao Puli             }
8367d1cc387SAppaRao Puli             updateConfig = true;
8377d1cc387SAppaRao Puli         }
8387d1cc387SAppaRao Puli 
83928afb49cSJunLin Chen         if (retryAttempts != cfg.retryAttempts)
8407d1cc387SAppaRao Puli         {
84128afb49cSJunLin Chen             retryAttempts = cfg.retryAttempts;
8427d1cc387SAppaRao Puli             updateConfig = true;
843fe44eb0bSAyushi Smriti             updateRetryCfg = true;
8447d1cc387SAppaRao Puli         }
8457d1cc387SAppaRao Puli 
84628afb49cSJunLin Chen         if (retryTimeoutInterval != cfg.retryTimeoutInterval)
8477d1cc387SAppaRao Puli         {
84828afb49cSJunLin Chen             retryTimeoutInterval = cfg.retryTimeoutInterval;
8497d1cc387SAppaRao Puli             updateConfig = true;
850fe44eb0bSAyushi Smriti             updateRetryCfg = true;
8517d1cc387SAppaRao Puli         }
8527d1cc387SAppaRao Puli 
8537d1cc387SAppaRao Puli         if (updateConfig)
8547d1cc387SAppaRao Puli         {
8557d1cc387SAppaRao Puli             updateSubscriptionData();
8567d1cc387SAppaRao Puli         }
857fe44eb0bSAyushi Smriti 
858fe44eb0bSAyushi Smriti         if (updateRetryCfg)
859fe44eb0bSAyushi Smriti         {
860fe44eb0bSAyushi Smriti             // Update the changed retry config to all subscriptions
861fe44eb0bSAyushi Smriti             for (const auto& it :
862fe44eb0bSAyushi Smriti                  EventServiceManager::getInstance().subscriptionsMap)
863fe44eb0bSAyushi Smriti             {
8645e44e3d8SAppaRao Puli                 Subscription& entry = *it.second;
8655e44e3d8SAppaRao Puli                 entry.updateRetryConfig(retryAttempts, retryTimeoutInterval);
866fe44eb0bSAyushi Smriti             }
867fe44eb0bSAyushi Smriti         }
8687d1cc387SAppaRao Puli     }
8697d1cc387SAppaRao Puli 
8707d1cc387SAppaRao Puli     void updateNoOfSubscribersCount()
8717d1cc387SAppaRao Puli     {
8727d1cc387SAppaRao Puli         size_t eventLogSubCount = 0;
8737d1cc387SAppaRao Puli         size_t metricReportSubCount = 0;
8747d1cc387SAppaRao Puli         for (const auto& it : subscriptionsMap)
8757d1cc387SAppaRao Puli         {
8767d1cc387SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
877*4b712a29SEd Tanous             if (entry->userSub.eventFormatType == eventFormatType)
8787d1cc387SAppaRao Puli             {
8797d1cc387SAppaRao Puli                 eventLogSubCount++;
8807d1cc387SAppaRao Puli             }
881*4b712a29SEd Tanous             else if (entry->userSub.eventFormatType == metricReportFormatType)
8827d1cc387SAppaRao Puli             {
8837d1cc387SAppaRao Puli                 metricReportSubCount++;
8847d1cc387SAppaRao Puli             }
8857d1cc387SAppaRao Puli         }
8867d1cc387SAppaRao Puli 
8877d1cc387SAppaRao Puli         noOfEventLogSubscribers = eventLogSubCount;
8887d1cc387SAppaRao Puli         if (noOfMetricReportSubscribers != metricReportSubCount)
8897d1cc387SAppaRao Puli         {
8907d1cc387SAppaRao Puli             noOfMetricReportSubscribers = metricReportSubCount;
891e662eae8SEd Tanous             if (noOfMetricReportSubscribers != 0U)
8927d1cc387SAppaRao Puli             {
8937d1cc387SAppaRao Puli                 registerMetricReportSignal();
8947d1cc387SAppaRao Puli             }
8957d1cc387SAppaRao Puli             else
8967d1cc387SAppaRao Puli             {
8977d1cc387SAppaRao Puli                 unregisterMetricReportSignal();
8987d1cc387SAppaRao Puli             }
8997d1cc387SAppaRao Puli         }
9007d1cc387SAppaRao Puli     }
9017d1cc387SAppaRao Puli 
902b52664e2SAppaRao Puli     std::shared_ptr<Subscription> getSubscription(const std::string& id)
903b52664e2SAppaRao Puli     {
904b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
905b52664e2SAppaRao Puli         if (obj == subscriptionsMap.end())
906b52664e2SAppaRao Puli         {
90762598e31SEd Tanous             BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id);
908b52664e2SAppaRao Puli             return nullptr;
909b52664e2SAppaRao Puli         }
910b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue = obj->second;
911b52664e2SAppaRao Puli         return subValue;
912b52664e2SAppaRao Puli     }
913b52664e2SAppaRao Puli 
914f80a87f2SEd Tanous     std::string
915f80a87f2SEd Tanous         addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue)
916b52664e2SAppaRao Puli     {
917fc76b8acSEd Tanous         std::uniform_int_distribution<uint32_t> dist(0);
918fc76b8acSEd Tanous         bmcweb::OpenSSLGenerator gen;
919fc76b8acSEd Tanous 
920b52664e2SAppaRao Puli         std::string id;
921b52664e2SAppaRao Puli 
922b52664e2SAppaRao Puli         int retry = 3;
923e662eae8SEd Tanous         while (retry != 0)
924b52664e2SAppaRao Puli         {
925fc76b8acSEd Tanous             id = std::to_string(dist(gen));
926fc76b8acSEd Tanous             if (gen.error())
927fc76b8acSEd Tanous             {
928fc76b8acSEd Tanous                 retry = 0;
929fc76b8acSEd Tanous                 break;
930fc76b8acSEd Tanous             }
931b52664e2SAppaRao Puli             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
932b52664e2SAppaRao Puli             if (inserted.second)
933b52664e2SAppaRao Puli             {
934b52664e2SAppaRao Puli                 break;
935b52664e2SAppaRao Puli             }
936b52664e2SAppaRao Puli             --retry;
93723a21a1cSEd Tanous         }
938b52664e2SAppaRao Puli 
939b52664e2SAppaRao Puli         if (retry <= 0)
940b52664e2SAppaRao Puli         {
94162598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to generate random number");
942abb93cddSEd Tanous             return "";
943b52664e2SAppaRao Puli         }
944b52664e2SAppaRao Puli 
945*4b712a29SEd Tanous         persistent_data::UserSubscription newSub(subValue->userSub);
946a14c9113SEd Tanous 
94728afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
948*4b712a29SEd Tanous             .subscriptionsConfigMap.emplace(newSub.id, newSub);
94928afb49cSJunLin Chen 
9507d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
9511bf712bcSAyushi Smriti 
95283328316SEd Tanous         if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
95383328316SEd Tanous         {
9542558979cSP Dheeraj Srujan Kumar             if (redfishLogFilePosition != 0)
9557f4eb588SAppaRao Puli             {
9562558979cSP Dheeraj Srujan Kumar                 cacheRedfishLogFile();
9577f4eb588SAppaRao Puli             }
95883328316SEd Tanous         }
959fe44eb0bSAyushi Smriti         // Update retry configuration.
960fe44eb0bSAyushi Smriti         subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
961fe44eb0bSAyushi Smriti 
9625e44e3d8SAppaRao Puli         // Set Subscription ID for back trace
9635e44e3d8SAppaRao Puli         subValue->setSubscriptionId(id);
964f80a87f2SEd Tanous 
965f80a87f2SEd Tanous         return id;
966f80a87f2SEd Tanous     }
967f80a87f2SEd Tanous 
968f80a87f2SEd Tanous     std::string
969f80a87f2SEd Tanous         addSSESubscription(const std::shared_ptr<Subscription>& subValue,
970f80a87f2SEd Tanous                            std::string_view lastEventId)
971f80a87f2SEd Tanous     {
972f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
973f80a87f2SEd Tanous 
974f80a87f2SEd Tanous         if (!lastEventId.empty())
975f80a87f2SEd Tanous         {
976f80a87f2SEd Tanous             BMCWEB_LOG_INFO("Attempting to find message for last id {}",
977f80a87f2SEd Tanous                             lastEventId);
978f80a87f2SEd Tanous             boost::circular_buffer<Event>::iterator lastEvent =
979f80a87f2SEd Tanous                 std::find_if(messages.begin(), messages.end(),
980f80a87f2SEd Tanous                              [&lastEventId](const Event& event) {
981f80a87f2SEd Tanous                                  return event.id == lastEventId;
982f80a87f2SEd Tanous                              });
983f80a87f2SEd Tanous             // Can't find a matching ID
984f80a87f2SEd Tanous             if (lastEvent == messages.end())
985f80a87f2SEd Tanous             {
986f80a87f2SEd Tanous                 nlohmann::json msg = messages::eventBufferExceeded();
987f80a87f2SEd Tanous                 // If the buffer overloaded, send all messages.
9886d799e14SEd Tanous                 subValue->sendEventToSubscriber(msg);
989f80a87f2SEd Tanous                 lastEvent = messages.begin();
990f80a87f2SEd Tanous             }
991f80a87f2SEd Tanous             else
992f80a87f2SEd Tanous             {
993f80a87f2SEd Tanous                 // Skip the last event the user already has
994f80a87f2SEd Tanous                 lastEvent++;
995f80a87f2SEd Tanous             }
996f80a87f2SEd Tanous 
997f80a87f2SEd Tanous             for (boost::circular_buffer<Event>::const_iterator event =
998f80a87f2SEd Tanous                      lastEvent;
999f80a87f2SEd Tanous                  lastEvent != messages.end(); lastEvent++)
1000f80a87f2SEd Tanous             {
10016d799e14SEd Tanous                 subValue->sendEventToSubscriber(event->message);
1002f80a87f2SEd Tanous             }
1003f80a87f2SEd Tanous         }
1004f80a87f2SEd Tanous         return id;
1005f80a87f2SEd Tanous     }
1006f80a87f2SEd Tanous 
1007f80a87f2SEd Tanous     std::string
1008f80a87f2SEd Tanous         addPushSubscription(const std::shared_ptr<Subscription>& subValue)
1009f80a87f2SEd Tanous     {
1010f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
1011f80a87f2SEd Tanous 
1012f80a87f2SEd Tanous         updateSubscriptionData();
1013b52664e2SAppaRao Puli         return id;
1014b52664e2SAppaRao Puli     }
1015b52664e2SAppaRao Puli 
1016b52664e2SAppaRao Puli     bool isSubscriptionExist(const std::string& id)
1017b52664e2SAppaRao Puli     {
1018b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
101955f79e6fSEd Tanous         return obj != subscriptionsMap.end();
1020b52664e2SAppaRao Puli     }
1021b52664e2SAppaRao Puli 
1022*4b712a29SEd Tanous     bool deleteSubscription(const std::string& id)
1023b52664e2SAppaRao Puli     {
1024b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
1025*4b712a29SEd Tanous         if (obj == subscriptionsMap.end())
1026b52664e2SAppaRao Puli         {
1027*4b712a29SEd Tanous             BMCWEB_LOG_WARNING("Could not find subscription with id {}", id);
1028*4b712a29SEd Tanous             return false;
1029*4b712a29SEd Tanous         }
1030b52664e2SAppaRao Puli         subscriptionsMap.erase(obj);
1031*4b712a29SEd Tanous         auto& event = persistent_data::EventServiceStore::getInstance();
1032*4b712a29SEd Tanous         auto persistentObj = event.subscriptionsConfigMap.find(id);
1033*4b712a29SEd Tanous         if (persistentObj == event.subscriptionsConfigMap.end())
1034*4b712a29SEd Tanous         {
1035*4b712a29SEd Tanous             BMCWEB_LOG_ERROR("Subscription wasn't in persistent data");
1036*4b712a29SEd Tanous             return true;
1037*4b712a29SEd Tanous         }
103828afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
1039*4b712a29SEd Tanous             .subscriptionsConfigMap.erase(persistentObj);
10407d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
1041b52664e2SAppaRao Puli         updateSubscriptionData();
1042*4b712a29SEd Tanous 
1043*4b712a29SEd Tanous         return true;
1044b52664e2SAppaRao Puli     }
1045b52664e2SAppaRao Puli 
10465e44e3d8SAppaRao Puli     void deleteSseSubscription(const crow::sse_socket::Connection& thisConn)
10475e44e3d8SAppaRao Puli     {
1048bdbfae2aSEd Tanous         for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();)
10495e44e3d8SAppaRao Puli         {
1050bdbfae2aSEd Tanous             std::shared_ptr<Subscription> entry = it->second;
10515e44e3d8SAppaRao Puli             bool entryIsThisConn = entry->matchSseId(thisConn);
10525e44e3d8SAppaRao Puli             if (entryIsThisConn)
10535e44e3d8SAppaRao Puli             {
10545e44e3d8SAppaRao Puli                 persistent_data::EventServiceStore::getInstance()
10555e44e3d8SAppaRao Puli                     .subscriptionsConfigMap.erase(
1056bdbfae2aSEd Tanous                         it->second->getSubscriptionId());
1057bdbfae2aSEd Tanous                 it = subscriptionsMap.erase(it);
10585e44e3d8SAppaRao Puli                 return;
10595e44e3d8SAppaRao Puli             }
1060bdbfae2aSEd Tanous             it++;
10615e44e3d8SAppaRao Puli         }
10625e44e3d8SAppaRao Puli     }
10635e44e3d8SAppaRao Puli 
10645e44e3d8SAppaRao Puli     size_t getNumberOfSubscriptions() const
1065b52664e2SAppaRao Puli     {
1066b52664e2SAppaRao Puli         return subscriptionsMap.size();
1067b52664e2SAppaRao Puli     }
1068b52664e2SAppaRao Puli 
10695e44e3d8SAppaRao Puli     size_t getNumberOfSSESubscriptions() const
10705e44e3d8SAppaRao Puli     {
10713544d2a7SEd Tanous         auto size = std::ranges::count_if(
10723544d2a7SEd Tanous             subscriptionsMap,
10735e44e3d8SAppaRao Puli             [](const std::pair<std::string, std::shared_ptr<Subscription>>&
10745e44e3d8SAppaRao Puli                    entry) {
1075*4b712a29SEd Tanous                 return (entry.second->userSub.subscriptionType ==
1076*4b712a29SEd Tanous                         subscriptionTypeSSE);
10775e44e3d8SAppaRao Puli             });
10785e44e3d8SAppaRao Puli         return static_cast<size_t>(size);
10795e44e3d8SAppaRao Puli     }
10805e44e3d8SAppaRao Puli 
1081b52664e2SAppaRao Puli     std::vector<std::string> getAllIDs()
1082b52664e2SAppaRao Puli     {
1083b52664e2SAppaRao Puli         std::vector<std::string> idList;
1084b52664e2SAppaRao Puli         for (const auto& it : subscriptionsMap)
1085b52664e2SAppaRao Puli         {
1086b52664e2SAppaRao Puli             idList.emplace_back(it.first);
1087b52664e2SAppaRao Puli         }
1088b52664e2SAppaRao Puli         return idList;
1089b52664e2SAppaRao Puli     }
1090b52664e2SAppaRao Puli 
10916ba8c82eSsunharis_in     bool sendTestEventLog()
10920b4bdd93SAppaRao Puli     {
10935e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
10940b4bdd93SAppaRao Puli         {
10950b4bdd93SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
10966ba8c82eSsunharis_in             if (!entry->sendTestEventLog())
10976ba8c82eSsunharis_in             {
10986ba8c82eSsunharis_in                 return false;
10990b4bdd93SAppaRao Puli             }
11000b4bdd93SAppaRao Puli         }
11016ba8c82eSsunharis_in         return true;
11026ba8c82eSsunharis_in     }
1103e9a14131SAppaRao Puli 
1104f80a87f2SEd Tanous     void sendEvent(nlohmann::json::object_t eventMessage,
1105f80a87f2SEd Tanous                    std::string_view origin, std::string_view resourceType)
110696330b99SSunitha Harish     {
1107613dabeaSEd Tanous         eventMessage["EventId"] = eventId;
1108f80a87f2SEd Tanous 
1109613dabeaSEd Tanous         eventMessage["EventTimestamp"] =
1110613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
1111613dabeaSEd Tanous         eventMessage["OriginOfCondition"] = origin;
1112613dabeaSEd Tanous 
1113f80a87f2SEd Tanous         // MemberId is 0 : since we are sending one event record.
1114f80a87f2SEd Tanous         eventMessage["MemberId"] = 0;
111596330b99SSunitha Harish 
1116f80a87f2SEd Tanous         messages.push_back(Event(std::to_string(eventId), eventMessage));
1117f80a87f2SEd Tanous 
1118f80a87f2SEd Tanous         for (auto& it : subscriptionsMap)
111996330b99SSunitha Harish         {
1120f80a87f2SEd Tanous             std::shared_ptr<Subscription>& entry = it.second;
1121f80a87f2SEd Tanous             if (!entry->eventMatchesFilter(eventMessage, resourceType))
112296330b99SSunitha Harish             {
1123f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Filter didn't match");
1124f80a87f2SEd Tanous                 continue;
112596330b99SSunitha Harish             }
1126f80a87f2SEd Tanous 
1127f80a87f2SEd Tanous             nlohmann::json::array_t eventRecord;
1128f80a87f2SEd Tanous             eventRecord.emplace_back(eventMessage);
1129f80a87f2SEd Tanous 
1130613dabeaSEd Tanous             nlohmann::json msgJson;
1131613dabeaSEd Tanous 
1132613dabeaSEd Tanous             msgJson["@odata.type"] = "#Event.v1_4_0.Event";
1133613dabeaSEd Tanous             msgJson["Name"] = "Event Log";
1134613dabeaSEd Tanous             msgJson["Id"] = eventId;
1135f80a87f2SEd Tanous             msgJson["Events"] = std::move(eventRecord);
1136f52c03c1SCarson Labrado 
1137f52c03c1SCarson Labrado             std::string strMsg = msgJson.dump(
1138f52c03c1SCarson Labrado                 2, ' ', true, nlohmann::json::error_handler_t::replace);
11396d799e14SEd Tanous             entry->sendEventToSubscriber(std::move(strMsg));
11408ece0e45SEd Tanous             eventId++; // increment the eventId
114196330b99SSunitha Harish         }
114296330b99SSunitha Harish     }
114396330b99SSunitha Harish 
11442558979cSP Dheeraj Srujan Kumar     void resetRedfishFilePosition()
11457f4eb588SAppaRao Puli     {
11462558979cSP Dheeraj Srujan Kumar         // Control would be here when Redfish file is created.
11472558979cSP Dheeraj Srujan Kumar         // Reset File Position as new file is created
11482558979cSP Dheeraj Srujan Kumar         redfishLogFilePosition = 0;
11492558979cSP Dheeraj Srujan Kumar     }
11502558979cSP Dheeraj Srujan Kumar 
11512558979cSP Dheeraj Srujan Kumar     void cacheRedfishLogFile()
11522558979cSP Dheeraj Srujan Kumar     {
11532558979cSP Dheeraj Srujan Kumar         // Open the redfish file and read till the last record.
11542558979cSP Dheeraj Srujan Kumar 
11557f4eb588SAppaRao Puli         std::ifstream logStream(redfishEventLogFile);
11567f4eb588SAppaRao Puli         if (!logStream.good())
11577f4eb588SAppaRao Puli         {
115862598e31SEd Tanous             BMCWEB_LOG_ERROR(" Redfish log file open failed ");
11597f4eb588SAppaRao Puli             return;
11607f4eb588SAppaRao Puli         }
11617f4eb588SAppaRao Puli         std::string logEntry;
11627f4eb588SAppaRao Puli         while (std::getline(logStream, logEntry))
11637f4eb588SAppaRao Puli         {
11642558979cSP Dheeraj Srujan Kumar             redfishLogFilePosition = logStream.tellg();
11657f4eb588SAppaRao Puli         }
11667f4eb588SAppaRao Puli     }
11677f4eb588SAppaRao Puli 
11687f4eb588SAppaRao Puli     void readEventLogsFromFile()
11697f4eb588SAppaRao Puli     {
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 
11777f4eb588SAppaRao Puli         std::vector<EventLogObjectsType> eventRecords;
11787f4eb588SAppaRao Puli 
11797f4eb588SAppaRao Puli         std::string logEntry;
11802558979cSP Dheeraj Srujan Kumar 
118103d4d37cSAlexander Hansen         BMCWEB_LOG_DEBUG("Redfish log file: seek to {}",
118203d4d37cSAlexander Hansen                          static_cast<int>(redfishLogFilePosition));
118303d4d37cSAlexander Hansen 
11842558979cSP Dheeraj Srujan Kumar         // Get the read pointer to the next log to be read.
11852558979cSP Dheeraj Srujan Kumar         logStream.seekg(redfishLogFilePosition);
11862558979cSP Dheeraj Srujan Kumar 
11877f4eb588SAppaRao Puli         while (std::getline(logStream, logEntry))
11887f4eb588SAppaRao Puli         {
118903d4d37cSAlexander Hansen             BMCWEB_LOG_DEBUG("Redfish log file: found new event log entry");
11902558979cSP Dheeraj Srujan Kumar             // Update Pointer position
11912558979cSP Dheeraj Srujan Kumar             redfishLogFilePosition = logStream.tellg();
11922558979cSP Dheeraj Srujan Kumar 
11932558979cSP Dheeraj Srujan Kumar             std::string idStr;
11942558979cSP Dheeraj Srujan Kumar             if (!event_log::getUniqueEntryID(logEntry, idStr))
11957f4eb588SAppaRao Puli             {
119603d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG(
119703d4d37cSAlexander Hansen                     "Redfish log file: could not get unique entry id for {}",
119803d4d37cSAlexander Hansen                     logEntry);
11997f4eb588SAppaRao Puli                 continue;
12007f4eb588SAppaRao Puli             }
12017f4eb588SAppaRao Puli 
1202e662eae8SEd Tanous             if (!serviceEnabled || noOfEventLogSubscribers == 0)
12037f4eb588SAppaRao Puli             {
12042558979cSP Dheeraj Srujan Kumar                 // If Service is not enabled, no need to compute
12052558979cSP Dheeraj Srujan Kumar                 // the remaining items below.
12062558979cSP Dheeraj Srujan Kumar                 // But, Loop must continue to keep track of Timestamp
120703d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG(
120803d4d37cSAlexander Hansen                     "Redfish log file: no subscribers / event service not enabled");
12097f4eb588SAppaRao Puli                 continue;
12107f4eb588SAppaRao Puli             }
12117f4eb588SAppaRao Puli 
12127f4eb588SAppaRao Puli             std::string timestamp;
12137f4eb588SAppaRao Puli             std::string messageID;
12145e715de6SAppaRao Puli             std::vector<std::string> messageArgs;
12157f4eb588SAppaRao Puli             if (event_log::getEventLogParams(logEntry, timestamp, messageID,
12167f4eb588SAppaRao Puli                                              messageArgs) != 0)
12177f4eb588SAppaRao Puli             {
121803d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("Read eventLog entry params failed for {}",
121903d4d37cSAlexander Hansen                                  logEntry);
12207f4eb588SAppaRao Puli                 continue;
12217f4eb588SAppaRao Puli             }
12227f4eb588SAppaRao Puli 
1223f80a87f2SEd Tanous             eventRecords.emplace_back(idStr, timestamp, messageID, messageArgs);
12247f4eb588SAppaRao Puli         }
12257f4eb588SAppaRao Puli 
1226e662eae8SEd Tanous         if (!serviceEnabled || noOfEventLogSubscribers == 0)
12272558979cSP Dheeraj Srujan Kumar         {
122862598e31SEd Tanous             BMCWEB_LOG_DEBUG("EventService disabled or no Subscriptions.");
12292558979cSP Dheeraj Srujan Kumar             return;
12302558979cSP Dheeraj Srujan Kumar         }
12312558979cSP Dheeraj Srujan Kumar 
12322558979cSP Dheeraj Srujan Kumar         if (eventRecords.empty())
12332558979cSP Dheeraj Srujan Kumar         {
12342558979cSP Dheeraj Srujan Kumar             // No Records to send
123562598e31SEd Tanous             BMCWEB_LOG_DEBUG("No log entries available to be transferred.");
12362558979cSP Dheeraj Srujan Kumar             return;
12372558979cSP Dheeraj Srujan Kumar         }
12382558979cSP Dheeraj Srujan Kumar 
12395e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
12407f4eb588SAppaRao Puli         {
12417f4eb588SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
1242*4b712a29SEd Tanous             if (entry->userSub.eventFormatType == "Event")
12437f4eb588SAppaRao Puli             {
12447f4eb588SAppaRao Puli                 entry->filterAndSendEventLogs(eventRecords);
12457f4eb588SAppaRao Puli             }
12467f4eb588SAppaRao Puli         }
12477f4eb588SAppaRao Puli     }
12487f4eb588SAppaRao Puli 
12497f4eb588SAppaRao Puli     static void watchRedfishEventLogFile()
12507f4eb588SAppaRao Puli     {
12516a9f85f9SAppaRao Puli         if (!inotifyConn)
12527f4eb588SAppaRao Puli         {
125303d4d37cSAlexander Hansen             BMCWEB_LOG_ERROR("inotify Connection is not present");
12547f4eb588SAppaRao Puli             return;
12557f4eb588SAppaRao Puli         }
12567f4eb588SAppaRao Puli 
12577f4eb588SAppaRao Puli         static std::array<char, 1024> readBuffer;
12587f4eb588SAppaRao Puli 
1259bd79bce8SPatrick Williams         inotifyConn->async_read_some(
1260bd79bce8SPatrick Williams             boost::asio::buffer(readBuffer),
12617f4eb588SAppaRao Puli             [&](const boost::system::error_code& ec,
12627f4eb588SAppaRao Puli                 const std::size_t& bytesTransferred) {
12639ed3f90aSEd Tanous                 if (ec == boost::asio::error::operation_aborted)
12649ed3f90aSEd Tanous                 {
12659ed3f90aSEd Tanous                     BMCWEB_LOG_DEBUG("Inotify was canceled (shutdown?)");
12669ed3f90aSEd Tanous                     return;
12679ed3f90aSEd Tanous                 }
12687f4eb588SAppaRao Puli                 if (ec)
12697f4eb588SAppaRao Puli                 {
127062598e31SEd Tanous                     BMCWEB_LOG_ERROR("Callback Error: {}", ec.message());
12717f4eb588SAppaRao Puli                     return;
12727f4eb588SAppaRao Puli                 }
127303d4d37cSAlexander Hansen 
127403d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("reading {} via inotify", bytesTransferred);
127503d4d37cSAlexander Hansen 
12767f4eb588SAppaRao Puli                 std::size_t index = 0;
1277b792cc56SAppaRao Puli                 while ((index + iEventSize) <= bytesTransferred)
12787f4eb588SAppaRao Puli                 {
1279d3a9e084SEd Tanous                     struct inotify_event event
1280d3a9e084SEd Tanous                     {};
1281b792cc56SAppaRao Puli                     std::memcpy(&event, &readBuffer[index], iEventSize);
1282b792cc56SAppaRao Puli                     if (event.wd == dirWatchDesc)
1283b792cc56SAppaRao Puli                     {
1284b792cc56SAppaRao Puli                         if ((event.len == 0) ||
1285b792cc56SAppaRao Puli                             (index + iEventSize + event.len > bytesTransferred))
1286b792cc56SAppaRao Puli                         {
1287b792cc56SAppaRao Puli                             index += (iEventSize + event.len);
1288b792cc56SAppaRao Puli                             continue;
1289b792cc56SAppaRao Puli                         }
1290b792cc56SAppaRao Puli 
12914f568f74SJiaqing Zhao                         std::string fileName(&readBuffer[index + iEventSize]);
12924f568f74SJiaqing Zhao                         if (fileName != "redfish")
1293b792cc56SAppaRao Puli                         {
1294b792cc56SAppaRao Puli                             index += (iEventSize + event.len);
1295b792cc56SAppaRao Puli                             continue;
1296b792cc56SAppaRao Puli                         }
1297b792cc56SAppaRao Puli 
129862598e31SEd Tanous                         BMCWEB_LOG_DEBUG(
129962598e31SEd Tanous                             "Redfish log file created/deleted. event.name: {}",
130062598e31SEd Tanous                             fileName);
1301b792cc56SAppaRao Puli                         if (event.mask == IN_CREATE)
1302b792cc56SAppaRao Puli                         {
1303b792cc56SAppaRao Puli                             if (fileWatchDesc != -1)
1304b792cc56SAppaRao Puli                             {
130562598e31SEd Tanous                                 BMCWEB_LOG_DEBUG(
130662598e31SEd Tanous                                     "Remove and Add inotify watcher on "
130762598e31SEd Tanous                                     "redfish event log file");
1308016761afSAppaRao Puli                                 // Remove existing inotify watcher and add
1309016761afSAppaRao Puli                                 // with new redfish event log file.
1310016761afSAppaRao Puli                                 inotify_rm_watch(inotifyFd, fileWatchDesc);
1311016761afSAppaRao Puli                                 fileWatchDesc = -1;
1312b792cc56SAppaRao Puli                             }
1313b792cc56SAppaRao Puli 
1314b792cc56SAppaRao Puli                             fileWatchDesc = inotify_add_watch(
1315b792cc56SAppaRao Puli                                 inotifyFd, redfishEventLogFile, IN_MODIFY);
1316b792cc56SAppaRao Puli                             if (fileWatchDesc == -1)
1317b792cc56SAppaRao Puli                             {
131862598e31SEd Tanous                                 BMCWEB_LOG_ERROR("inotify_add_watch failed for "
131962598e31SEd Tanous                                                  "redfish log file.");
1320b792cc56SAppaRao Puli                                 return;
1321b792cc56SAppaRao Puli                             }
1322b792cc56SAppaRao Puli 
1323b792cc56SAppaRao Puli                             EventServiceManager::getInstance()
13242558979cSP Dheeraj Srujan Kumar                                 .resetRedfishFilePosition();
1325b792cc56SAppaRao Puli                             EventServiceManager::getInstance()
1326b792cc56SAppaRao Puli                                 .readEventLogsFromFile();
1327b792cc56SAppaRao Puli                         }
1328b792cc56SAppaRao Puli                         else if ((event.mask == IN_DELETE) ||
1329b792cc56SAppaRao Puli                                  (event.mask == IN_MOVED_TO))
1330b792cc56SAppaRao Puli                         {
1331b792cc56SAppaRao Puli                             if (fileWatchDesc != -1)
1332b792cc56SAppaRao Puli                             {
1333b792cc56SAppaRao Puli                                 inotify_rm_watch(inotifyFd, fileWatchDesc);
1334b792cc56SAppaRao Puli                                 fileWatchDesc = -1;
1335b792cc56SAppaRao Puli                             }
1336b792cc56SAppaRao Puli                         }
1337b792cc56SAppaRao Puli                     }
1338b792cc56SAppaRao Puli                     else if (event.wd == fileWatchDesc)
1339b792cc56SAppaRao Puli                     {
1340b792cc56SAppaRao Puli                         if (event.mask == IN_MODIFY)
13417f4eb588SAppaRao Puli                         {
13427f4eb588SAppaRao Puli                             EventServiceManager::getInstance()
13437f4eb588SAppaRao Puli                                 .readEventLogsFromFile();
13447f4eb588SAppaRao Puli                         }
1345b792cc56SAppaRao Puli                     }
1346b792cc56SAppaRao Puli                     index += (iEventSize + event.len);
13477f4eb588SAppaRao Puli                 }
13487f4eb588SAppaRao Puli 
13497f4eb588SAppaRao Puli                 watchRedfishEventLogFile();
13507f4eb588SAppaRao Puli             });
13517f4eb588SAppaRao Puli     }
13527f4eb588SAppaRao Puli 
13537f4eb588SAppaRao Puli     static int startEventLogMonitor(boost::asio::io_context& ioc)
13547f4eb588SAppaRao Puli     {
135503d4d37cSAlexander Hansen         BMCWEB_LOG_DEBUG("starting Event Log Monitor");
135603d4d37cSAlexander Hansen 
135723a21a1cSEd Tanous         inotifyConn.emplace(ioc);
1358b792cc56SAppaRao Puli         inotifyFd = inotify_init1(IN_NONBLOCK);
1359b792cc56SAppaRao Puli         if (inotifyFd == -1)
13607f4eb588SAppaRao Puli         {
136162598e31SEd Tanous             BMCWEB_LOG_ERROR("inotify_init1 failed.");
13627f4eb588SAppaRao Puli             return -1;
13637f4eb588SAppaRao Puli         }
1364b792cc56SAppaRao Puli 
1365b792cc56SAppaRao Puli         // Add watch on directory to handle redfish event log file
1366b792cc56SAppaRao Puli         // create/delete.
1367b792cc56SAppaRao Puli         dirWatchDesc = inotify_add_watch(inotifyFd, redfishEventLogDir,
1368b792cc56SAppaRao Puli                                          IN_CREATE | IN_MOVED_TO | IN_DELETE);
1369b792cc56SAppaRao Puli         if (dirWatchDesc == -1)
13707f4eb588SAppaRao Puli         {
137162598e31SEd Tanous             BMCWEB_LOG_ERROR(
137262598e31SEd Tanous                 "inotify_add_watch failed for event log directory.");
13737f4eb588SAppaRao Puli             return -1;
13747f4eb588SAppaRao Puli         }
13757f4eb588SAppaRao Puli 
1376b792cc56SAppaRao Puli         // Watch redfish event log file for modifications.
1377bd79bce8SPatrick Williams         fileWatchDesc =
1378bd79bce8SPatrick Williams             inotify_add_watch(inotifyFd, redfishEventLogFile, IN_MODIFY);
1379b792cc56SAppaRao Puli         if (fileWatchDesc == -1)
1380b792cc56SAppaRao Puli         {
138162598e31SEd Tanous             BMCWEB_LOG_ERROR("inotify_add_watch failed for redfish log file.");
1382b792cc56SAppaRao Puli             // Don't return error if file not exist.
1383b792cc56SAppaRao Puli             // Watch on directory will handle create/delete of file.
1384b792cc56SAppaRao Puli         }
1385b792cc56SAppaRao Puli 
13867f4eb588SAppaRao Puli         // monitor redfish event log file
1387b792cc56SAppaRao Puli         inotifyConn->assign(inotifyFd);
13887f4eb588SAppaRao Puli         watchRedfishEventLogFile();
13897f4eb588SAppaRao Puli 
13907f4eb588SAppaRao Puli         return 0;
13917f4eb588SAppaRao Puli     }
13927f4eb588SAppaRao Puli 
13939ed3f90aSEd Tanous     static void stopEventLogMonitor()
13949ed3f90aSEd Tanous     {
13959ed3f90aSEd Tanous         inotifyConn.reset();
13969ed3f90aSEd Tanous     }
13979ed3f90aSEd Tanous 
139859d494eeSPatrick Williams     static void getReadingsForReport(sdbusplus::message_t& msg)
1399156d6b00SAppaRao Puli     {
140056d2396dSEd Tanous         if (msg.is_method_error())
140156d2396dSEd Tanous         {
140262598e31SEd Tanous             BMCWEB_LOG_ERROR("TelemetryMonitor Signal error");
140356d2396dSEd Tanous             return;
140456d2396dSEd Tanous         }
140556d2396dSEd Tanous 
1406c0353249SWludzik, Jozef         sdbusplus::message::object_path path(msg.get_path());
1407c0353249SWludzik, Jozef         std::string id = path.filename();
1408c0353249SWludzik, Jozef         if (id.empty())
1409156d6b00SAppaRao Puli         {
141062598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to get Id from path");
1411156d6b00SAppaRao Puli             return;
1412156d6b00SAppaRao Puli         }
1413156d6b00SAppaRao Puli 
1414c0353249SWludzik, Jozef         std::string interface;
1415b9d36b47SEd Tanous         dbus::utility::DBusPropertiesMap props;
1416c0353249SWludzik, Jozef         std::vector<std::string> invalidProps;
1417c0353249SWludzik, Jozef         msg.read(interface, props, invalidProps);
1418c0353249SWludzik, Jozef 
1419bd79bce8SPatrick Williams         auto found = std::ranges::find_if(props, [](const auto& x) {
1420bd79bce8SPatrick Williams             return x.first == "Readings";
1421bd79bce8SPatrick Williams         });
1422c0353249SWludzik, Jozef         if (found == props.end())
1423156d6b00SAppaRao Puli         {
142462598e31SEd Tanous             BMCWEB_LOG_INFO("Failed to get Readings from Report properties");
1425156d6b00SAppaRao Puli             return;
1426156d6b00SAppaRao Puli         }
1427156d6b00SAppaRao Puli 
14281e1e598dSJonathan Doman         const telemetry::TimestampReadings* readings =
14291e1e598dSJonathan Doman             std::get_if<telemetry::TimestampReadings>(&found->second);
1430e662eae8SEd Tanous         if (readings == nullptr)
14311e1e598dSJonathan Doman         {
143262598e31SEd Tanous             BMCWEB_LOG_INFO("Failed to get Readings from Report properties");
14331e1e598dSJonathan Doman             return;
14341e1e598dSJonathan Doman         }
14351e1e598dSJonathan Doman 
1436156d6b00SAppaRao Puli         for (const auto& it :
1437156d6b00SAppaRao Puli              EventServiceManager::getInstance().subscriptionsMap)
1438156d6b00SAppaRao Puli         {
1439e05aec50SEd Tanous             Subscription& entry = *it.second;
1440*4b712a29SEd Tanous             if (entry.userSub.eventFormatType == metricReportFormatType)
1441156d6b00SAppaRao Puli             {
14421e1e598dSJonathan Doman                 entry.filterAndSendReports(id, *readings);
1443156d6b00SAppaRao Puli             }
1444156d6b00SAppaRao Puli         }
1445156d6b00SAppaRao Puli     }
1446156d6b00SAppaRao Puli 
1447156d6b00SAppaRao Puli     void unregisterMetricReportSignal()
1448156d6b00SAppaRao Puli     {
14497d1cc387SAppaRao Puli         if (matchTelemetryMonitor)
14507d1cc387SAppaRao Puli         {
145162598e31SEd Tanous             BMCWEB_LOG_DEBUG("Metrics report signal - Unregister");
1452156d6b00SAppaRao Puli             matchTelemetryMonitor.reset();
1453156d6b00SAppaRao Puli             matchTelemetryMonitor = nullptr;
1454156d6b00SAppaRao Puli         }
14557d1cc387SAppaRao Puli     }
1456156d6b00SAppaRao Puli 
1457156d6b00SAppaRao Puli     void registerMetricReportSignal()
1458156d6b00SAppaRao Puli     {
14597d1cc387SAppaRao Puli         if (!serviceEnabled || matchTelemetryMonitor)
1460156d6b00SAppaRao Puli         {
146162598e31SEd Tanous             BMCWEB_LOG_DEBUG("Not registering metric report signal.");
1462156d6b00SAppaRao Puli             return;
1463156d6b00SAppaRao Puli         }
1464156d6b00SAppaRao Puli 
146562598e31SEd Tanous         BMCWEB_LOG_DEBUG("Metrics report signal - Register");
1466c0353249SWludzik, Jozef         std::string matchStr = "type='signal',member='PropertiesChanged',"
1467c0353249SWludzik, Jozef                                "interface='org.freedesktop.DBus.Properties',"
1468c0353249SWludzik, Jozef                                "arg0=xyz.openbmc_project.Telemetry.Report";
1469156d6b00SAppaRao Puli 
147059d494eeSPatrick Williams         matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match_t>(
147156d2396dSEd Tanous             *crow::connections::systemBus, matchStr, getReadingsForReport);
1472156d6b00SAppaRao Puli     }
147323a21a1cSEd Tanous };
1474b52664e2SAppaRao Puli 
1475b52664e2SAppaRao Puli } // namespace redfish
1476