xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision a0969c70c0e5a38c0e65f558e254f1af062b33b4)
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"
19d3a48a14SEd Tanous #include "event_matches_filter.hpp"
203ccb3adbSEd Tanous #include "event_service_store.hpp"
21f80a87f2SEd Tanous #include "filter_expr_executor.hpp"
22539d8c6bSEd Tanous #include "generated/enums/event.hpp"
23539d8c6bSEd Tanous #include "generated/enums/log_entry.hpp"
243ccb3adbSEd Tanous #include "http_client.hpp"
25c0353249SWludzik, Jozef #include "metric_report.hpp"
262c6ffdb0SEd Tanous #include "ossl_random.hpp"
273ccb3adbSEd Tanous #include "persistent_data.hpp"
287f4eb588SAppaRao Puli #include "registries.hpp"
298dab0f58SEd Tanous #include "registries_selector.hpp"
3050ebd4afSEd Tanous #include "str_utility.hpp"
3177665bdaSNan Zhou #include "utility.hpp"
323ccb3adbSEd Tanous #include "utils/json_utils.hpp"
335b90429aSEd Tanous #include "utils/time_utils.hpp"
347f4eb588SAppaRao Puli 
357f4eb588SAppaRao Puli #include <sys/inotify.h>
36b52664e2SAppaRao Puli 
37fb4fd5d4SZhenfei Tai #include <boost/asio/io_context.hpp>
38f80a87f2SEd Tanous #include <boost/circular_buffer.hpp>
39b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp>
40ef4c65b7SEd Tanous #include <boost/url/format.hpp>
414a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp>
42b5b40605Snitroglycerine #include <sdbusplus/bus/match.hpp>
431214b7e7SGunnar Mills 
445e44e3d8SAppaRao Puli #include <algorithm>
45b52664e2SAppaRao Puli #include <cstdlib>
46b52664e2SAppaRao Puli #include <ctime>
47a14c9113SEd Tanous #include <format>
481bf712bcSAyushi Smriti #include <fstream>
49b52664e2SAppaRao Puli #include <memory>
503544d2a7SEd Tanous #include <ranges>
5126702d01SEd Tanous #include <span>
52a14c9113SEd Tanous #include <string>
5356ba386dSMyung Bae #include <string_view>
54b52664e2SAppaRao Puli 
55b52664e2SAppaRao Puli namespace redfish
56b52664e2SAppaRao Puli {
57156d6b00SAppaRao Puli 
58156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event";
59156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport";
60156d6b00SAppaRao Puli 
615e44e3d8SAppaRao Puli static constexpr const char* subscriptionTypeSSE = "SSE";
621bf712bcSAyushi Smriti static constexpr const char* eventServiceFile =
631bf712bcSAyushi Smriti     "/var/lib/bmcweb/eventservice_config.json";
641bf712bcSAyushi Smriti 
655e44e3d8SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20;
665e44e3d8SAppaRao Puli static constexpr const uint8_t maxNoOfSSESubscriptions = 10;
675e44e3d8SAppaRao Puli 
68cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
694642bf8fSGeorge Liu static std::optional<boost::asio::posix::stream_descriptor> inotifyConn;
704642bf8fSGeorge Liu static constexpr const char* redfishEventLogDir = "/var/log";
714642bf8fSGeorge Liu static constexpr const char* redfishEventLogFile = "/var/log/redfish";
724642bf8fSGeorge Liu static constexpr const size_t iEventSize = sizeof(inotify_event);
73cf9e417dSEd Tanous 
74cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
754642bf8fSGeorge Liu static int inotifyFd = -1;
76cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
774642bf8fSGeorge Liu static int dirWatchDesc = -1;
78cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
794642bf8fSGeorge Liu static int fileWatchDesc = -1;
80f80a87f2SEd Tanous struct EventLogObjectsType
81f80a87f2SEd Tanous {
82f80a87f2SEd Tanous     std::string id;
83f80a87f2SEd Tanous     std::string timestamp;
84f80a87f2SEd Tanous     std::string messageId;
85f80a87f2SEd Tanous     std::vector<std::string> messageArgs;
86f80a87f2SEd Tanous };
874642bf8fSGeorge Liu 
88fffb8c1fSEd Tanous namespace registries
894642bf8fSGeorge Liu {
907f4eb588SAppaRao Puli static const Message*
917f4eb588SAppaRao Puli     getMsgFromRegistry(const std::string& messageKey,
9226702d01SEd Tanous                        const std::span<const MessageEntry>& registry)
937f4eb588SAppaRao Puli {
943544d2a7SEd Tanous     std::span<const MessageEntry>::iterator messageIt = std::ranges::find_if(
953544d2a7SEd Tanous         registry, [&messageKey](const MessageEntry& messageEntry) {
9655f79e6fSEd Tanous             return messageKey == messageEntry.first;
977f4eb588SAppaRao Puli         });
9826702d01SEd Tanous     if (messageIt != registry.end())
997f4eb588SAppaRao Puli     {
1007f4eb588SAppaRao Puli         return &messageIt->second;
1017f4eb588SAppaRao Puli     }
1027f4eb588SAppaRao Puli 
1037f4eb588SAppaRao Puli     return nullptr;
1047f4eb588SAppaRao Puli }
1057f4eb588SAppaRao Puli 
10626ccae32SEd Tanous static const Message* formatMessage(std::string_view messageID)
1077f4eb588SAppaRao Puli {
1087f4eb588SAppaRao Puli     // Redfish MessageIds are in the form
1097f4eb588SAppaRao Puli     // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find
1107f4eb588SAppaRao Puli     // the right Message
1117f4eb588SAppaRao Puli     std::vector<std::string> fields;
1127f4eb588SAppaRao Puli     fields.reserve(4);
11350ebd4afSEd Tanous 
11450ebd4afSEd Tanous     bmcweb::split(fields, messageID, '.');
1157f4eb588SAppaRao Puli     if (fields.size() != 4)
1167f4eb588SAppaRao Puli     {
1177f4eb588SAppaRao Puli         return nullptr;
1187f4eb588SAppaRao Puli     }
11902cad96eSEd Tanous     const std::string& registryName = fields[0];
12002cad96eSEd Tanous     const std::string& messageKey = fields[3];
1217f4eb588SAppaRao Puli 
1227f4eb588SAppaRao Puli     // Find the right registry and check it for the MessageKey
123b304bd79SP Dheeraj Srujan Kumar     return getMsgFromRegistry(messageKey, getRegistryFromPrefix(registryName));
1247f4eb588SAppaRao Puli }
125fffb8c1fSEd Tanous } // namespace registries
1267f4eb588SAppaRao Puli 
1277f4eb588SAppaRao Puli namespace event_log
1287f4eb588SAppaRao Puli {
1292558979cSP Dheeraj Srujan Kumar inline bool getUniqueEntryID(const std::string& logEntry, std::string& entryID)
1307f4eb588SAppaRao Puli {
1317f4eb588SAppaRao Puli     static time_t prevTs = 0;
1327f4eb588SAppaRao Puli     static int index = 0;
1337f4eb588SAppaRao Puli 
1347f4eb588SAppaRao Puli     // Get the entry timestamp
1357f4eb588SAppaRao Puli     std::time_t curTs = 0;
1367f4eb588SAppaRao Puli     std::tm timeStruct = {};
1377f4eb588SAppaRao Puli     std::istringstream entryStream(logEntry);
1387f4eb588SAppaRao Puli     if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
1397f4eb588SAppaRao Puli     {
1407f4eb588SAppaRao Puli         curTs = std::mktime(&timeStruct);
1417f4eb588SAppaRao Puli         if (curTs == -1)
1427f4eb588SAppaRao Puli         {
1437f4eb588SAppaRao Puli             return false;
1447f4eb588SAppaRao Puli         }
1457f4eb588SAppaRao Puli     }
1467f4eb588SAppaRao Puli     // If the timestamp isn't unique, increment the index
1477f4eb588SAppaRao Puli     index = (curTs == prevTs) ? index + 1 : 0;
1487f4eb588SAppaRao Puli 
1497f4eb588SAppaRao Puli     // Save the timestamp
1507f4eb588SAppaRao Puli     prevTs = curTs;
1517f4eb588SAppaRao Puli 
1527f4eb588SAppaRao Puli     entryID = std::to_string(curTs);
1537f4eb588SAppaRao Puli     if (index > 0)
1547f4eb588SAppaRao Puli     {
1557f4eb588SAppaRao Puli         entryID += "_" + std::to_string(index);
1567f4eb588SAppaRao Puli     }
1577f4eb588SAppaRao Puli     return true;
1587f4eb588SAppaRao Puli }
1597f4eb588SAppaRao Puli 
16023a21a1cSEd Tanous inline int getEventLogParams(const std::string& logEntry,
16123a21a1cSEd Tanous                              std::string& timestamp, std::string& messageID,
1625e715de6SAppaRao Puli                              std::vector<std::string>& messageArgs)
1637f4eb588SAppaRao Puli {
1647f4eb588SAppaRao Puli     // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
1657f4eb588SAppaRao Puli     // First get the Timestamp
166f23b7296SEd Tanous     size_t space = logEntry.find_first_of(' ');
1677f4eb588SAppaRao Puli     if (space == std::string::npos)
1687f4eb588SAppaRao Puli     {
16903d4d37cSAlexander Hansen         BMCWEB_LOG_ERROR("EventLog Params: could not find first space: {}",
17003d4d37cSAlexander Hansen                          logEntry);
1717f4eb588SAppaRao Puli         return -EINVAL;
1727f4eb588SAppaRao Puli     }
1737f4eb588SAppaRao Puli     timestamp = logEntry.substr(0, space);
1747f4eb588SAppaRao Puli     // Then get the log contents
175f23b7296SEd Tanous     size_t entryStart = logEntry.find_first_not_of(' ', space);
1767f4eb588SAppaRao Puli     if (entryStart == std::string::npos)
1777f4eb588SAppaRao Puli     {
17803d4d37cSAlexander Hansen         BMCWEB_LOG_ERROR("EventLog Params: could not find log contents: {}",
17903d4d37cSAlexander Hansen                          logEntry);
1807f4eb588SAppaRao Puli         return -EINVAL;
1817f4eb588SAppaRao Puli     }
1827f4eb588SAppaRao Puli     std::string_view entry(logEntry);
1837f4eb588SAppaRao Puli     entry.remove_prefix(entryStart);
1847f4eb588SAppaRao Puli     // Use split to separate the entry into its fields
1857f4eb588SAppaRao Puli     std::vector<std::string> logEntryFields;
18650ebd4afSEd Tanous     bmcweb::split(logEntryFields, entry, ',');
1877f4eb588SAppaRao Puli     // We need at least a MessageId to be valid
18826f6976fSEd Tanous     if (logEntryFields.empty())
1897f4eb588SAppaRao Puli     {
19003d4d37cSAlexander Hansen         BMCWEB_LOG_ERROR("EventLog Params: could not find entry fields: {}",
19103d4d37cSAlexander Hansen                          logEntry);
1927f4eb588SAppaRao Puli         return -EINVAL;
1937f4eb588SAppaRao Puli     }
1947f4eb588SAppaRao Puli     messageID = logEntryFields[0];
1957f4eb588SAppaRao Puli 
1967f4eb588SAppaRao Puli     // Get the MessageArgs from the log if there are any
1977f4eb588SAppaRao Puli     if (logEntryFields.size() > 1)
1987f4eb588SAppaRao Puli     {
19902cad96eSEd Tanous         const std::string& messageArgsStart = logEntryFields[1];
2007f4eb588SAppaRao Puli         // If the first string is empty, assume there are no MessageArgs
2017f4eb588SAppaRao Puli         if (!messageArgsStart.empty())
2027f4eb588SAppaRao Puli         {
2035e715de6SAppaRao Puli             messageArgs.assign(logEntryFields.begin() + 1,
2045e715de6SAppaRao Puli                                logEntryFields.end());
2057f4eb588SAppaRao Puli         }
2067f4eb588SAppaRao Puli     }
2077f4eb588SAppaRao Puli 
2087f4eb588SAppaRao Puli     return 0;
2097f4eb588SAppaRao Puli }
2107f4eb588SAppaRao Puli 
211bd79bce8SPatrick Williams inline int formatEventLogEntry(
212bd79bce8SPatrick Williams     const std::string& logEntryID, const std::string& messageID,
213bd79bce8SPatrick Williams     const std::span<std::string_view> messageArgs, std::string timestamp,
214bd79bce8SPatrick Williams     const std::string& customText, nlohmann::json::object_t& logEntryJson)
2157f4eb588SAppaRao Puli {
2167f4eb588SAppaRao Puli     // Get the Message from the MessageRegistry
217fffb8c1fSEd Tanous     const registries::Message* message = registries::formatMessage(messageID);
2187f4eb588SAppaRao Puli 
21980f595e7SEd Tanous     if (message == nullptr)
2207f4eb588SAppaRao Puli     {
22180f595e7SEd Tanous         return -1;
2227f4eb588SAppaRao Puli     }
2237f4eb588SAppaRao Puli 
224bd79bce8SPatrick Williams     std::string msg =
225bd79bce8SPatrick Williams         redfish::registries::fillMessageArgs(messageArgs, message->message);
22680f595e7SEd Tanous     if (msg.empty())
22780f595e7SEd Tanous     {
22880f595e7SEd Tanous         return -1;
22980f595e7SEd Tanous     }
2307f4eb588SAppaRao Puli 
2317f4eb588SAppaRao Puli     // Get the Created time from the timestamp. The log timestamp is in
2327f4eb588SAppaRao Puli     // RFC3339 format which matches the Redfish format except for the
2337f4eb588SAppaRao Puli     // fractional seconds between the '.' and the '+', so just remove them.
234f23b7296SEd Tanous     std::size_t dot = timestamp.find_first_of('.');
235b2f7609bSEd Tanous     std::size_t plus = timestamp.find_first_of('+', dot);
2367f4eb588SAppaRao Puli     if (dot != std::string::npos && plus != std::string::npos)
2377f4eb588SAppaRao Puli     {
2387f4eb588SAppaRao Puli         timestamp.erase(dot, plus - dot);
2397f4eb588SAppaRao Puli     }
2407f4eb588SAppaRao Puli 
2417f4eb588SAppaRao Puli     // Fill in the log entry with the gathered data
2421476687dSEd Tanous     logEntryJson["EventId"] = logEntryID;
243539d8c6bSEd Tanous 
24480f595e7SEd Tanous     logEntryJson["Severity"] = message->messageSeverity;
2451476687dSEd Tanous     logEntryJson["Message"] = std::move(msg);
2461476687dSEd Tanous     logEntryJson["MessageId"] = messageID;
2471476687dSEd Tanous     logEntryJson["MessageArgs"] = messageArgs;
2481476687dSEd Tanous     logEntryJson["EventTimestamp"] = std::move(timestamp);
2491476687dSEd Tanous     logEntryJson["Context"] = customText;
2507f4eb588SAppaRao Puli     return 0;
2517f4eb588SAppaRao Puli }
2527f4eb588SAppaRao Puli 
2537f4eb588SAppaRao Puli } // namespace event_log
2547f4eb588SAppaRao Puli 
255*a0969c70SMyung Bae class Subscription : public std::enable_shared_from_this<Subscription>
256b52664e2SAppaRao Puli {
257b52664e2SAppaRao Puli   public:
258b52664e2SAppaRao Puli     Subscription(const Subscription&) = delete;
259b52664e2SAppaRao Puli     Subscription& operator=(const Subscription&) = delete;
260b52664e2SAppaRao Puli     Subscription(Subscription&&) = delete;
261b52664e2SAppaRao Puli     Subscription& operator=(Subscription&&) = delete;
262b52664e2SAppaRao Puli 
26321a94d5cSMyung Bae     Subscription(const persistent_data::UserSubscription& userSubIn,
26421a94d5cSMyung Bae                  const boost::urls::url_view_base& url,
2654a7fbefdSEd Tanous                  boost::asio::io_context& ioc) :
26621a94d5cSMyung Bae         userSub(userSubIn), policy(std::make_shared<crow::ConnectionPolicy>())
267b52664e2SAppaRao Puli     {
2684b712a29SEd Tanous         userSub.destinationUrl = url;
2695e44e3d8SAppaRao Puli         client.emplace(ioc, policy);
2707adb85acSSunitha Harish         // Subscription constructor
271d14a48ffSCarson Labrado         policy->invalidResp = retryRespHandler;
272b52664e2SAppaRao Puli     }
2734bbf237fSAppaRao Puli 
2745e44e3d8SAppaRao Puli     explicit Subscription(crow::sse_socket::Connection& connIn) :
2755e44e3d8SAppaRao Puli         sseConn(&connIn)
2765e44e3d8SAppaRao Puli     {}
2775e44e3d8SAppaRao Puli 
2789f616dd1SEd Tanous     ~Subscription() = default;
279b52664e2SAppaRao Puli 
280*a0969c70SMyung Bae     // callback for subscription sendData
281*a0969c70SMyung Bae     void resHandler(const std::shared_ptr<Subscription>& /*unused*/,
282*a0969c70SMyung Bae                     const crow::Response& res)
283*a0969c70SMyung Bae     {
284*a0969c70SMyung Bae         BMCWEB_LOG_DEBUG("Response handled with return code: {}",
285*a0969c70SMyung Bae                          res.resultInt());
286*a0969c70SMyung Bae 
287*a0969c70SMyung Bae         if (!client)
288*a0969c70SMyung Bae         {
289*a0969c70SMyung Bae             BMCWEB_LOG_ERROR(
290*a0969c70SMyung Bae                 "Http client wasn't filled but http client callback was called.");
291*a0969c70SMyung Bae             return;
292*a0969c70SMyung Bae         }
293*a0969c70SMyung Bae 
294*a0969c70SMyung Bae         if (userSub.retryPolicy != "TerminateAfterRetries")
295*a0969c70SMyung Bae         {
296*a0969c70SMyung Bae             return;
297*a0969c70SMyung Bae         }
298*a0969c70SMyung Bae         if (client->isTerminated())
299*a0969c70SMyung Bae         {
300*a0969c70SMyung Bae             if (deleter)
301*a0969c70SMyung Bae             {
302*a0969c70SMyung Bae                 BMCWEB_LOG_INFO(
303*a0969c70SMyung Bae                     "Subscription {} is deleted after MaxRetryAttempts",
304*a0969c70SMyung Bae                     userSub.id);
305*a0969c70SMyung Bae                 deleter();
306*a0969c70SMyung Bae             }
307*a0969c70SMyung Bae         }
308*a0969c70SMyung Bae     }
309*a0969c70SMyung Bae 
3106d799e14SEd Tanous     bool sendEventToSubscriber(std::string&& msg)
311b52664e2SAppaRao Puli     {
3126ba8c82eSsunharis_in         persistent_data::EventServiceConfig eventServiceConfig =
3136ba8c82eSsunharis_in             persistent_data::EventServiceStore::getInstance()
3146ba8c82eSsunharis_in                 .getEventServiceConfig();
3156ba8c82eSsunharis_in         if (!eventServiceConfig.enabled)
3166ba8c82eSsunharis_in         {
3176ba8c82eSsunharis_in             return false;
3186ba8c82eSsunharis_in         }
3196ba8c82eSsunharis_in 
3205e44e3d8SAppaRao Puli         if (client)
3215e44e3d8SAppaRao Puli         {
322*a0969c70SMyung Bae             client->sendDataWithCallback(
323*a0969c70SMyung Bae                 std::move(msg), userSub.destinationUrl,
3244b712a29SEd Tanous                 static_cast<ensuressl::VerifyCertificate>(
3254b712a29SEd Tanous                     userSub.verifyCertificate),
326*a0969c70SMyung Bae                 userSub.httpHeaders, boost::beast::http::verb::post,
327*a0969c70SMyung Bae                 std::bind_front(&Subscription::resHandler, this,
328*a0969c70SMyung Bae                                 shared_from_this()));
3295e44e3d8SAppaRao Puli             return true;
3305e44e3d8SAppaRao Puli         }
3317adb85acSSunitha Harish 
3324bbf237fSAppaRao Puli         if (sseConn != nullptr)
3334bbf237fSAppaRao Puli         {
3345e44e3d8SAppaRao Puli             eventSeqNum++;
3356d799e14SEd Tanous             sseConn->sendSseEvent(std::to_string(eventSeqNum), msg);
3364bbf237fSAppaRao Puli         }
3376ba8c82eSsunharis_in         return true;
3384bbf237fSAppaRao Puli     }
3394bbf237fSAppaRao Puli 
3406ba8c82eSsunharis_in     bool sendTestEventLog()
3410b4bdd93SAppaRao Puli     {
342f80a87f2SEd Tanous         nlohmann::json::array_t logEntryArray;
343f80a87f2SEd Tanous         nlohmann::json& logEntryJson = logEntryArray.emplace_back();
3440b4bdd93SAppaRao Puli 
345613dabeaSEd Tanous         logEntryJson["EventId"] = "TestID";
346539d8c6bSEd Tanous         logEntryJson["Severity"] = log_entry::EventSeverity::OK;
347613dabeaSEd Tanous         logEntryJson["Message"] = "Generated test event";
348613dabeaSEd Tanous         logEntryJson["MessageId"] = "OpenBMC.0.2.TestEventLog";
349d2cdd478SChandra Harkude         // MemberId is 0 : since we are sending one event record.
350788b091bSIgor Kanyuka         logEntryJson["MemberId"] = "0";
351613dabeaSEd Tanous         logEntryJson["MessageArgs"] = nlohmann::json::array();
352613dabeaSEd Tanous         logEntryJson["EventTimestamp"] =
353613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
3544b712a29SEd Tanous         logEntryJson["Context"] = userSub.customText;
3550b4bdd93SAppaRao Puli 
3561476687dSEd Tanous         nlohmann::json msg;
3571476687dSEd Tanous         msg["@odata.type"] = "#Event.v1_4_0.Event";
3581476687dSEd Tanous         msg["Id"] = std::to_string(eventSeqNum);
3591476687dSEd Tanous         msg["Name"] = "Event Log";
3601476687dSEd Tanous         msg["Events"] = logEntryArray;
3610b4bdd93SAppaRao Puli 
362bd79bce8SPatrick Williams         std::string strMsg =
363bd79bce8SPatrick Williams             msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
3646d799e14SEd Tanous         return sendEventToSubscriber(std::move(strMsg));
3650b4bdd93SAppaRao Puli     }
3660b4bdd93SAppaRao Puli 
3677f4eb588SAppaRao Puli     void filterAndSendEventLogs(
3687f4eb588SAppaRao Puli         const std::vector<EventLogObjectsType>& eventRecords)
3697f4eb588SAppaRao Puli     {
370f80a87f2SEd Tanous         nlohmann::json::array_t logEntryArray;
3717f4eb588SAppaRao Puli         for (const EventLogObjectsType& logEntry : eventRecords)
3727f4eb588SAppaRao Puli         {
373f80a87f2SEd Tanous             std::vector<std::string_view> messageArgsView(
374f80a87f2SEd Tanous                 logEntry.messageArgs.begin(), logEntry.messageArgs.end());
3757f4eb588SAppaRao Puli 
376f80a87f2SEd Tanous             nlohmann::json::object_t bmcLogEntry;
377f80a87f2SEd Tanous             if (event_log::formatEventLogEntry(
378f80a87f2SEd Tanous                     logEntry.id, logEntry.messageId, messageArgsView,
3794b712a29SEd Tanous                     logEntry.timestamp, userSub.customText, bmcLogEntry) != 0)
3807f4eb588SAppaRao Puli             {
38162598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Read eventLog entry failed");
3827f4eb588SAppaRao Puli                 continue;
3837f4eb588SAppaRao Puli             }
384f80a87f2SEd Tanous 
385d3a48a14SEd Tanous             if (!eventMatchesFilter(userSub, bmcLogEntry, ""))
386f80a87f2SEd Tanous             {
38703d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("Event {} did not match the filter",
38803d4d37cSAlexander Hansen                                  nlohmann::json(bmcLogEntry).dump());
389f80a87f2SEd Tanous                 continue;
390f80a87f2SEd Tanous             }
391f80a87f2SEd Tanous 
392d3a48a14SEd Tanous             if (filter)
393d3a48a14SEd Tanous             {
394d3a48a14SEd Tanous                 if (!memberMatches(bmcLogEntry, *filter))
395d3a48a14SEd Tanous                 {
396d3a48a14SEd Tanous                     BMCWEB_LOG_DEBUG("Filter didn't match");
397d3a48a14SEd Tanous                     continue;
398d3a48a14SEd Tanous                 }
399d3a48a14SEd Tanous             }
400d3a48a14SEd Tanous 
401f80a87f2SEd Tanous             logEntryArray.emplace_back(std::move(bmcLogEntry));
4027f4eb588SAppaRao Puli         }
4037f4eb588SAppaRao Puli 
40426f6976fSEd Tanous         if (logEntryArray.empty())
4057f4eb588SAppaRao Puli         {
40662598e31SEd Tanous             BMCWEB_LOG_DEBUG("No log entries available to be transferred.");
4077f4eb588SAppaRao Puli             return;
4087f4eb588SAppaRao Puli         }
4097f4eb588SAppaRao Puli 
4101476687dSEd Tanous         nlohmann::json msg;
4111476687dSEd Tanous         msg["@odata.type"] = "#Event.v1_4_0.Event";
4121476687dSEd Tanous         msg["Id"] = std::to_string(eventSeqNum);
4131476687dSEd Tanous         msg["Name"] = "Event Log";
414f80a87f2SEd Tanous         msg["Events"] = std::move(logEntryArray);
415bd79bce8SPatrick Williams         std::string strMsg =
416bd79bce8SPatrick Williams             msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
4176d799e14SEd Tanous         sendEventToSubscriber(std::move(strMsg));
4185e44e3d8SAppaRao Puli         eventSeqNum++;
4197f4eb588SAppaRao Puli     }
4207f4eb588SAppaRao Puli 
421248d0230SEd Tanous     void filterAndSendReports(const std::string& reportId,
4221e1e598dSJonathan Doman                               const telemetry::TimestampReadings& var)
423156d6b00SAppaRao Puli     {
424ef4c65b7SEd Tanous         boost::urls::url mrdUri = boost::urls::format(
425ef4c65b7SEd Tanous             "/redfish/v1/TelemetryService/MetricReportDefinitions/{}",
426ef4c65b7SEd Tanous             reportId);
427156d6b00SAppaRao Puli 
428156d6b00SAppaRao Puli         // Empty list means no filter. Send everything.
4294b712a29SEd Tanous         if (!userSub.metricReportDefinitions.empty())
430156d6b00SAppaRao Puli         {
4314b712a29SEd Tanous             if (std::ranges::find(userSub.metricReportDefinitions,
4324b712a29SEd Tanous                                   mrdUri.buffer()) ==
4334b712a29SEd Tanous                 userSub.metricReportDefinitions.end())
434156d6b00SAppaRao Puli             {
435156d6b00SAppaRao Puli                 return;
436156d6b00SAppaRao Puli             }
437156d6b00SAppaRao Puli         }
438156d6b00SAppaRao Puli 
439c0353249SWludzik, Jozef         nlohmann::json msg;
440248d0230SEd Tanous         if (!telemetry::fillReport(msg, reportId, var))
441156d6b00SAppaRao Puli         {
44262598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to fill the MetricReport for DBus "
44362598e31SEd Tanous                              "Report with id {}",
44462598e31SEd Tanous                              reportId);
445c0353249SWludzik, Jozef             return;
446156d6b00SAppaRao Puli         }
447156d6b00SAppaRao Puli 
44822daffd7SAppaRao Puli         // Context is set by user during Event subscription and it must be
44922daffd7SAppaRao Puli         // set for MetricReport response.
4504b712a29SEd Tanous         if (!userSub.customText.empty())
45122daffd7SAppaRao Puli         {
4524b712a29SEd Tanous             msg["Context"] = userSub.customText;
45322daffd7SAppaRao Puli         }
45422daffd7SAppaRao Puli 
455bd79bce8SPatrick Williams         std::string strMsg =
456bd79bce8SPatrick Williams             msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
4576d799e14SEd Tanous         sendEventToSubscriber(std::move(strMsg));
458156d6b00SAppaRao Puli     }
459156d6b00SAppaRao Puli 
460d14a48ffSCarson Labrado     void updateRetryConfig(uint32_t retryAttempts,
461d14a48ffSCarson Labrado                            uint32_t retryTimeoutInterval)
462fe44eb0bSAyushi Smriti     {
46393cf0ac2SEd Tanous         if (policy == nullptr)
46493cf0ac2SEd Tanous         {
46593cf0ac2SEd Tanous             BMCWEB_LOG_DEBUG("Retry policy was nullptr, ignoring set");
46693cf0ac2SEd Tanous             return;
46793cf0ac2SEd Tanous         }
468d14a48ffSCarson Labrado         policy->maxRetryAttempts = retryAttempts;
469d14a48ffSCarson Labrado         policy->retryIntervalSecs = std::chrono::seconds(retryTimeoutInterval);
47062de0c68SAppaRao Puli     }
471fe44eb0bSAyushi Smriti 
4729eb808c1SEd Tanous     uint64_t getEventSeqNum() const
47396330b99SSunitha Harish     {
47496330b99SSunitha Harish         return eventSeqNum;
47596330b99SSunitha Harish     }
47696330b99SSunitha Harish 
47756ba386dSMyung Bae     void setSubscriptionId(const std::string& idIn)
4785e44e3d8SAppaRao Puli     {
47956ba386dSMyung Bae         BMCWEB_LOG_DEBUG("Subscription ID: {}", idIn);
48056ba386dSMyung Bae         userSub.id = idIn;
4815e44e3d8SAppaRao Puli     }
4825e44e3d8SAppaRao Puli 
48356ba386dSMyung Bae     std::string getSubscriptionId() const
4845e44e3d8SAppaRao Puli     {
48556ba386dSMyung Bae         return userSub.id;
4865e44e3d8SAppaRao Puli     }
4875e44e3d8SAppaRao Puli 
4885e44e3d8SAppaRao Puli     bool matchSseId(const crow::sse_socket::Connection& thisConn)
4895e44e3d8SAppaRao Puli     {
4905e44e3d8SAppaRao Puli         return &thisConn == sseConn;
4915e44e3d8SAppaRao Puli     }
4925e44e3d8SAppaRao Puli 
493a7a80296SCarson Labrado     // Check used to indicate what response codes are valid as part of our retry
494a7a80296SCarson Labrado     // policy.  2XX is considered acceptable
495a7a80296SCarson Labrado     static boost::system::error_code retryRespHandler(unsigned int respCode)
496a7a80296SCarson Labrado     {
49762598e31SEd Tanous         BMCWEB_LOG_DEBUG(
49862598e31SEd Tanous             "Checking response code validity for SubscriptionEvent");
499a7a80296SCarson Labrado         if ((respCode < 200) || (respCode >= 300))
500a7a80296SCarson Labrado         {
501a7a80296SCarson Labrado             return boost::system::errc::make_error_code(
502a7a80296SCarson Labrado                 boost::system::errc::result_out_of_range);
503a7a80296SCarson Labrado         }
504a7a80296SCarson Labrado 
505a7a80296SCarson Labrado         // Return 0 if the response code is valid
506a7a80296SCarson Labrado         return boost::system::errc::make_error_code(
507a7a80296SCarson Labrado             boost::system::errc::success);
5089fa6d147SNan Zhou     }
509f80a87f2SEd Tanous 
5104b712a29SEd Tanous     persistent_data::UserSubscription userSub;
511*a0969c70SMyung Bae     std::function<void()> deleter;
5124b712a29SEd Tanous 
513f80a87f2SEd Tanous   private:
514f80a87f2SEd Tanous     uint64_t eventSeqNum = 1;
515f80a87f2SEd Tanous     boost::urls::url host;
516f80a87f2SEd Tanous     std::shared_ptr<crow::ConnectionPolicy> policy;
517f80a87f2SEd Tanous     crow::sse_socket::Connection* sseConn = nullptr;
518f80a87f2SEd Tanous 
519f80a87f2SEd Tanous     std::optional<crow::HttpClient> client;
520f80a87f2SEd Tanous 
521f80a87f2SEd Tanous   public:
522f80a87f2SEd Tanous     std::optional<filter_ast::LogicalAnd> filter;
523b52664e2SAppaRao Puli };
524b52664e2SAppaRao Puli 
525b52664e2SAppaRao Puli class EventServiceManager
526b52664e2SAppaRao Puli {
527b52664e2SAppaRao Puli   private:
528d3a9e084SEd Tanous     bool serviceEnabled = false;
529d3a9e084SEd Tanous     uint32_t retryAttempts = 0;
530d3a9e084SEd Tanous     uint32_t retryTimeoutInterval = 0;
5317d1cc387SAppaRao Puli 
5322558979cSP Dheeraj Srujan Kumar     std::streampos redfishLogFilePosition{0};
5339f616dd1SEd Tanous     size_t noOfEventLogSubscribers{0};
5349f616dd1SEd Tanous     size_t noOfMetricReportSubscribers{0};
53559d494eeSPatrick Williams     std::shared_ptr<sdbusplus::bus::match_t> matchTelemetryMonitor;
536b52664e2SAppaRao Puli     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
537b52664e2SAppaRao Puli         subscriptionsMap;
538b52664e2SAppaRao Puli 
5399f616dd1SEd Tanous     uint64_t eventId{1};
54096330b99SSunitha Harish 
541f80a87f2SEd Tanous     struct Event
542f80a87f2SEd Tanous     {
543f80a87f2SEd Tanous         std::string id;
544f80a87f2SEd Tanous         nlohmann::json message;
545f80a87f2SEd Tanous     };
546f80a87f2SEd Tanous 
547f80a87f2SEd Tanous     constexpr static size_t maxMessages = 200;
548f80a87f2SEd Tanous     boost::circular_buffer<Event> messages{maxMessages};
549f80a87f2SEd Tanous 
550f8ca6d79SEd Tanous     boost::asio::io_context& ioc;
551f8ca6d79SEd Tanous 
552b52664e2SAppaRao Puli   public:
5539f616dd1SEd Tanous     EventServiceManager(const EventServiceManager&) = delete;
5549f616dd1SEd Tanous     EventServiceManager& operator=(const EventServiceManager&) = delete;
5559f616dd1SEd Tanous     EventServiceManager(EventServiceManager&&) = delete;
5569f616dd1SEd Tanous     EventServiceManager& operator=(EventServiceManager&&) = delete;
557ecd6a3a2SEd Tanous     ~EventServiceManager() = default;
5589f616dd1SEd Tanous 
559f8ca6d79SEd Tanous     explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn)
560b52664e2SAppaRao Puli     {
561f8ca6d79SEd Tanous         // Load config from persist store.
562f8ca6d79SEd Tanous         initConfig();
563f8ca6d79SEd Tanous     }
564f8ca6d79SEd Tanous 
565f8ca6d79SEd Tanous     static EventServiceManager&
566f8ca6d79SEd Tanous         getInstance(boost::asio::io_context* ioc = nullptr)
567f8ca6d79SEd Tanous     {
568f8ca6d79SEd Tanous         static EventServiceManager handler(*ioc);
569b52664e2SAppaRao Puli         return handler;
570b52664e2SAppaRao Puli     }
571b52664e2SAppaRao Puli 
5721bf712bcSAyushi Smriti     void initConfig()
5731bf712bcSAyushi Smriti     {
57428afb49cSJunLin Chen         loadOldBehavior();
5751bf712bcSAyushi Smriti 
57628afb49cSJunLin Chen         persistent_data::EventServiceConfig eventServiceConfig =
57728afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
57828afb49cSJunLin Chen                 .getEventServiceConfig();
5791bf712bcSAyushi Smriti 
58028afb49cSJunLin Chen         serviceEnabled = eventServiceConfig.enabled;
58128afb49cSJunLin Chen         retryAttempts = eventServiceConfig.retryAttempts;
58228afb49cSJunLin Chen         retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval;
5831bf712bcSAyushi Smriti 
58428afb49cSJunLin Chen         for (const auto& it : persistent_data::EventServiceStore::getInstance()
58528afb49cSJunLin Chen                                   .subscriptionsConfigMap)
5861bf712bcSAyushi Smriti         {
5874b712a29SEd Tanous             const persistent_data::UserSubscription& newSub = it.second;
5884bbf237fSAppaRao Puli 
5896fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
5904b712a29SEd Tanous                 boost::urls::parse_absolute_uri(newSub.destinationUrl);
5911bf712bcSAyushi Smriti 
592a716aa74SEd Tanous             if (!url)
5931bf712bcSAyushi Smriti             {
59462598e31SEd Tanous                 BMCWEB_LOG_ERROR(
59562598e31SEd Tanous                     "Failed to validate and split destination url");
5961bf712bcSAyushi Smriti                 continue;
5971bf712bcSAyushi Smriti             }
5981bf712bcSAyushi Smriti             std::shared_ptr<Subscription> subValue =
59921a94d5cSMyung Bae                 std::make_shared<Subscription>(newSub, *url, ioc);
600*a0969c70SMyung Bae             std::string id = subValue->userSub.id;
601*a0969c70SMyung Bae             subValue->deleter = [id]() {
602*a0969c70SMyung Bae                 EventServiceManager::getInstance().deleteSubscription(id);
603*a0969c70SMyung Bae             };
6041bf712bcSAyushi Smriti 
605*a0969c70SMyung Bae             subscriptionsMap.emplace(id, subValue);
60628afb49cSJunLin Chen 
60728afb49cSJunLin Chen             updateNoOfSubscribersCount();
60828afb49cSJunLin Chen 
60983328316SEd Tanous             if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
61083328316SEd Tanous             {
6112558979cSP Dheeraj Srujan Kumar                 cacheRedfishLogFile();
61283328316SEd Tanous             }
6132558979cSP Dheeraj Srujan Kumar 
61428afb49cSJunLin Chen             // Update retry configuration.
61528afb49cSJunLin Chen             subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
6161bf712bcSAyushi Smriti         }
6171bf712bcSAyushi Smriti     }
6181bf712bcSAyushi Smriti 
61956d2396dSEd Tanous     static void loadOldBehavior()
620b52664e2SAppaRao Puli     {
62128afb49cSJunLin Chen         std::ifstream eventConfigFile(eventServiceFile);
62228afb49cSJunLin Chen         if (!eventConfigFile.good())
6231bf712bcSAyushi Smriti         {
62462598e31SEd Tanous             BMCWEB_LOG_DEBUG("Old eventService config not exist");
62528afb49cSJunLin Chen             return;
62628afb49cSJunLin Chen         }
62728afb49cSJunLin Chen         auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false);
62828afb49cSJunLin Chen         if (jsonData.is_discarded())
6294bbf237fSAppaRao Puli         {
63062598e31SEd Tanous             BMCWEB_LOG_ERROR("Old eventService config parse error.");
63128afb49cSJunLin Chen             return;
63228afb49cSJunLin Chen         }
63328afb49cSJunLin Chen 
6340bdda665SEd Tanous         const nlohmann::json::object_t* obj =
6350bdda665SEd Tanous             jsonData.get_ptr<const nlohmann::json::object_t*>();
6360bdda665SEd Tanous         for (const auto& item : *obj)
63728afb49cSJunLin Chen         {
6380bdda665SEd Tanous             if (item.first == "Configuration")
63928afb49cSJunLin Chen             {
64028afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
64128afb49cSJunLin Chen                     .getEventServiceConfig()
6420bdda665SEd Tanous                     .fromJson(item.second);
64328afb49cSJunLin Chen             }
6440bdda665SEd Tanous             else if (item.first == "Subscriptions")
64528afb49cSJunLin Chen             {
6460bdda665SEd Tanous                 for (const auto& elem : item.second)
64728afb49cSJunLin Chen                 {
6484b712a29SEd Tanous                     std::optional<persistent_data::UserSubscription>
64928afb49cSJunLin Chen                         newSubscription =
65028afb49cSJunLin Chen                             persistent_data::UserSubscription::fromJson(elem,
65128afb49cSJunLin Chen                                                                         true);
6524b712a29SEd Tanous                     if (!newSubscription)
65328afb49cSJunLin Chen                     {
65462598e31SEd Tanous                         BMCWEB_LOG_ERROR("Problem reading subscription "
65562598e31SEd Tanous                                          "from old persistent store");
6564bbf237fSAppaRao Puli                         continue;
6574bbf237fSAppaRao Puli                     }
6584b712a29SEd Tanous                     persistent_data::UserSubscription& newSub =
6594b712a29SEd Tanous                         *newSubscription;
6601bf712bcSAyushi Smriti 
66128afb49cSJunLin Chen                     std::uniform_int_distribution<uint32_t> dist(0);
66228afb49cSJunLin Chen                     bmcweb::OpenSSLGenerator gen;
6631bf712bcSAyushi Smriti 
66428afb49cSJunLin Chen                     std::string id;
6651bf712bcSAyushi Smriti 
66628afb49cSJunLin Chen                     int retry = 3;
667e662eae8SEd Tanous                     while (retry != 0)
6681bf712bcSAyushi Smriti                     {
66928afb49cSJunLin Chen                         id = std::to_string(dist(gen));
67028afb49cSJunLin Chen                         if (gen.error())
6717d1cc387SAppaRao Puli                         {
67228afb49cSJunLin Chen                             retry = 0;
67328afb49cSJunLin Chen                             break;
67428afb49cSJunLin Chen                         }
6754b712a29SEd Tanous                         newSub.id = id;
67628afb49cSJunLin Chen                         auto inserted =
67728afb49cSJunLin Chen                             persistent_data::EventServiceStore::getInstance()
67828afb49cSJunLin Chen                                 .subscriptionsConfigMap.insert(
6794b712a29SEd Tanous                                     std::pair(id, newSub));
68028afb49cSJunLin Chen                         if (inserted.second)
68128afb49cSJunLin Chen                         {
68228afb49cSJunLin Chen                             break;
68328afb49cSJunLin Chen                         }
68428afb49cSJunLin Chen                         --retry;
6857d1cc387SAppaRao Puli                     }
6867d1cc387SAppaRao Puli 
68728afb49cSJunLin Chen                     if (retry <= 0)
68828afb49cSJunLin Chen                     {
68962598e31SEd Tanous                         BMCWEB_LOG_ERROR(
69062598e31SEd Tanous                             "Failed to generate random number from old "
69162598e31SEd Tanous                             "persistent store");
69228afb49cSJunLin Chen                         continue;
69328afb49cSJunLin Chen                     }
69428afb49cSJunLin Chen                 }
69528afb49cSJunLin Chen             }
69628afb49cSJunLin Chen 
69728afb49cSJunLin Chen             persistent_data::getConfig().writeData();
6984c521c3cSEd Tanous             std::error_code ec;
6994c521c3cSEd Tanous             std::filesystem::remove(eventServiceFile, ec);
7004c521c3cSEd Tanous             if (ec)
7014c521c3cSEd Tanous             {
7024c521c3cSEd Tanous                 BMCWEB_LOG_DEBUG(
7034c521c3cSEd Tanous                     "Failed to remove old event service file.  Ignoring");
7044c521c3cSEd Tanous             }
7054c521c3cSEd Tanous             else
7064c521c3cSEd Tanous             {
70762598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Remove old eventservice config");
70828afb49cSJunLin Chen             }
70928afb49cSJunLin Chen         }
7104c521c3cSEd Tanous     }
71128afb49cSJunLin Chen 
7129eb808c1SEd Tanous     void updateSubscriptionData() const
71328afb49cSJunLin Chen     {
71428afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
71528afb49cSJunLin Chen             .eventServiceConfig.enabled = serviceEnabled;
71628afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
71728afb49cSJunLin Chen             .eventServiceConfig.retryAttempts = retryAttempts;
71828afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
71928afb49cSJunLin Chen             .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval;
72028afb49cSJunLin Chen 
72128afb49cSJunLin Chen         persistent_data::getConfig().writeData();
72228afb49cSJunLin Chen     }
72328afb49cSJunLin Chen 
72428afb49cSJunLin Chen     void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg)
7257d1cc387SAppaRao Puli     {
7267d1cc387SAppaRao Puli         bool updateConfig = false;
727fe44eb0bSAyushi Smriti         bool updateRetryCfg = false;
7287d1cc387SAppaRao Puli 
72928afb49cSJunLin Chen         if (serviceEnabled != cfg.enabled)
7307d1cc387SAppaRao Puli         {
73128afb49cSJunLin Chen             serviceEnabled = cfg.enabled;
732e662eae8SEd Tanous             if (serviceEnabled && noOfMetricReportSubscribers != 0U)
7337d1cc387SAppaRao Puli             {
7347d1cc387SAppaRao Puli                 registerMetricReportSignal();
7357d1cc387SAppaRao Puli             }
7367d1cc387SAppaRao Puli             else
7377d1cc387SAppaRao Puli             {
7387d1cc387SAppaRao Puli                 unregisterMetricReportSignal();
7397d1cc387SAppaRao Puli             }
7407d1cc387SAppaRao Puli             updateConfig = true;
7417d1cc387SAppaRao Puli         }
7427d1cc387SAppaRao Puli 
74328afb49cSJunLin Chen         if (retryAttempts != cfg.retryAttempts)
7447d1cc387SAppaRao Puli         {
74528afb49cSJunLin Chen             retryAttempts = cfg.retryAttempts;
7467d1cc387SAppaRao Puli             updateConfig = true;
747fe44eb0bSAyushi Smriti             updateRetryCfg = true;
7487d1cc387SAppaRao Puli         }
7497d1cc387SAppaRao Puli 
75028afb49cSJunLin Chen         if (retryTimeoutInterval != cfg.retryTimeoutInterval)
7517d1cc387SAppaRao Puli         {
75228afb49cSJunLin Chen             retryTimeoutInterval = cfg.retryTimeoutInterval;
7537d1cc387SAppaRao Puli             updateConfig = true;
754fe44eb0bSAyushi Smriti             updateRetryCfg = true;
7557d1cc387SAppaRao Puli         }
7567d1cc387SAppaRao Puli 
7577d1cc387SAppaRao Puli         if (updateConfig)
7587d1cc387SAppaRao Puli         {
7597d1cc387SAppaRao Puli             updateSubscriptionData();
7607d1cc387SAppaRao Puli         }
761fe44eb0bSAyushi Smriti 
762fe44eb0bSAyushi Smriti         if (updateRetryCfg)
763fe44eb0bSAyushi Smriti         {
764fe44eb0bSAyushi Smriti             // Update the changed retry config to all subscriptions
765fe44eb0bSAyushi Smriti             for (const auto& it :
766fe44eb0bSAyushi Smriti                  EventServiceManager::getInstance().subscriptionsMap)
767fe44eb0bSAyushi Smriti             {
7685e44e3d8SAppaRao Puli                 Subscription& entry = *it.second;
7695e44e3d8SAppaRao Puli                 entry.updateRetryConfig(retryAttempts, retryTimeoutInterval);
770fe44eb0bSAyushi Smriti             }
771fe44eb0bSAyushi Smriti         }
7727d1cc387SAppaRao Puli     }
7737d1cc387SAppaRao Puli 
7747d1cc387SAppaRao Puli     void updateNoOfSubscribersCount()
7757d1cc387SAppaRao Puli     {
7767d1cc387SAppaRao Puli         size_t eventLogSubCount = 0;
7777d1cc387SAppaRao Puli         size_t metricReportSubCount = 0;
7787d1cc387SAppaRao Puli         for (const auto& it : subscriptionsMap)
7797d1cc387SAppaRao Puli         {
7807d1cc387SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
7814b712a29SEd Tanous             if (entry->userSub.eventFormatType == eventFormatType)
7827d1cc387SAppaRao Puli             {
7837d1cc387SAppaRao Puli                 eventLogSubCount++;
7847d1cc387SAppaRao Puli             }
7854b712a29SEd Tanous             else if (entry->userSub.eventFormatType == metricReportFormatType)
7867d1cc387SAppaRao Puli             {
7877d1cc387SAppaRao Puli                 metricReportSubCount++;
7887d1cc387SAppaRao Puli             }
7897d1cc387SAppaRao Puli         }
7907d1cc387SAppaRao Puli 
7917d1cc387SAppaRao Puli         noOfEventLogSubscribers = eventLogSubCount;
7927d1cc387SAppaRao Puli         if (noOfMetricReportSubscribers != metricReportSubCount)
7937d1cc387SAppaRao Puli         {
7947d1cc387SAppaRao Puli             noOfMetricReportSubscribers = metricReportSubCount;
795e662eae8SEd Tanous             if (noOfMetricReportSubscribers != 0U)
7967d1cc387SAppaRao Puli             {
7977d1cc387SAppaRao Puli                 registerMetricReportSignal();
7987d1cc387SAppaRao Puli             }
7997d1cc387SAppaRao Puli             else
8007d1cc387SAppaRao Puli             {
8017d1cc387SAppaRao Puli                 unregisterMetricReportSignal();
8027d1cc387SAppaRao Puli             }
8037d1cc387SAppaRao Puli         }
8047d1cc387SAppaRao Puli     }
8057d1cc387SAppaRao Puli 
806b52664e2SAppaRao Puli     std::shared_ptr<Subscription> getSubscription(const std::string& id)
807b52664e2SAppaRao Puli     {
808b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
809b52664e2SAppaRao Puli         if (obj == subscriptionsMap.end())
810b52664e2SAppaRao Puli         {
81162598e31SEd Tanous             BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id);
812b52664e2SAppaRao Puli             return nullptr;
813b52664e2SAppaRao Puli         }
814b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue = obj->second;
815b52664e2SAppaRao Puli         return subValue;
816b52664e2SAppaRao Puli     }
817b52664e2SAppaRao Puli 
818f80a87f2SEd Tanous     std::string
819f80a87f2SEd Tanous         addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue)
820b52664e2SAppaRao Puli     {
821fc76b8acSEd Tanous         std::uniform_int_distribution<uint32_t> dist(0);
822fc76b8acSEd Tanous         bmcweb::OpenSSLGenerator gen;
823fc76b8acSEd Tanous 
824b52664e2SAppaRao Puli         std::string id;
825b52664e2SAppaRao Puli 
826b52664e2SAppaRao Puli         int retry = 3;
827e662eae8SEd Tanous         while (retry != 0)
828b52664e2SAppaRao Puli         {
829fc76b8acSEd Tanous             id = std::to_string(dist(gen));
830fc76b8acSEd Tanous             if (gen.error())
831fc76b8acSEd Tanous             {
832fc76b8acSEd Tanous                 retry = 0;
833fc76b8acSEd Tanous                 break;
834fc76b8acSEd Tanous             }
835b52664e2SAppaRao Puli             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
836b52664e2SAppaRao Puli             if (inserted.second)
837b52664e2SAppaRao Puli             {
838b52664e2SAppaRao Puli                 break;
839b52664e2SAppaRao Puli             }
840b52664e2SAppaRao Puli             --retry;
84123a21a1cSEd Tanous         }
842b52664e2SAppaRao Puli 
843b52664e2SAppaRao Puli         if (retry <= 0)
844b52664e2SAppaRao Puli         {
84562598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to generate random number");
846abb93cddSEd Tanous             return "";
847b52664e2SAppaRao Puli         }
848b52664e2SAppaRao Puli 
84956ba386dSMyung Bae         // Set Subscription ID for back trace
85056ba386dSMyung Bae         subValue->setSubscriptionId(id);
85156ba386dSMyung Bae 
8524b712a29SEd Tanous         persistent_data::UserSubscription newSub(subValue->userSub);
853a14c9113SEd Tanous 
85428afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
8554b712a29SEd Tanous             .subscriptionsConfigMap.emplace(newSub.id, newSub);
85628afb49cSJunLin Chen 
8577d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
8581bf712bcSAyushi Smriti 
85983328316SEd Tanous         if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
86083328316SEd Tanous         {
8612558979cSP Dheeraj Srujan Kumar             if (redfishLogFilePosition != 0)
8627f4eb588SAppaRao Puli             {
8632558979cSP Dheeraj Srujan Kumar                 cacheRedfishLogFile();
8647f4eb588SAppaRao Puli             }
86583328316SEd Tanous         }
866fe44eb0bSAyushi Smriti         // Update retry configuration.
867fe44eb0bSAyushi Smriti         subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
868fe44eb0bSAyushi Smriti 
869f80a87f2SEd Tanous         return id;
870f80a87f2SEd Tanous     }
871f80a87f2SEd Tanous 
872f80a87f2SEd Tanous     std::string
873f80a87f2SEd Tanous         addSSESubscription(const std::shared_ptr<Subscription>& subValue,
874f80a87f2SEd Tanous                            std::string_view lastEventId)
875f80a87f2SEd Tanous     {
876f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
877f80a87f2SEd Tanous 
878f80a87f2SEd Tanous         if (!lastEventId.empty())
879f80a87f2SEd Tanous         {
880f80a87f2SEd Tanous             BMCWEB_LOG_INFO("Attempting to find message for last id {}",
881f80a87f2SEd Tanous                             lastEventId);
882f80a87f2SEd Tanous             boost::circular_buffer<Event>::iterator lastEvent =
883f80a87f2SEd Tanous                 std::find_if(messages.begin(), messages.end(),
884f80a87f2SEd Tanous                              [&lastEventId](const Event& event) {
885f80a87f2SEd Tanous                                  return event.id == lastEventId;
886f80a87f2SEd Tanous                              });
887f80a87f2SEd Tanous             // Can't find a matching ID
888f80a87f2SEd Tanous             if (lastEvent == messages.end())
889f80a87f2SEd Tanous             {
890f80a87f2SEd Tanous                 nlohmann::json msg = messages::eventBufferExceeded();
891f80a87f2SEd Tanous                 // If the buffer overloaded, send all messages.
8926d799e14SEd Tanous                 subValue->sendEventToSubscriber(msg);
893f80a87f2SEd Tanous                 lastEvent = messages.begin();
894f80a87f2SEd Tanous             }
895f80a87f2SEd Tanous             else
896f80a87f2SEd Tanous             {
897f80a87f2SEd Tanous                 // Skip the last event the user already has
898f80a87f2SEd Tanous                 lastEvent++;
899f80a87f2SEd Tanous             }
900f80a87f2SEd Tanous 
901f80a87f2SEd Tanous             for (boost::circular_buffer<Event>::const_iterator event =
902f80a87f2SEd Tanous                      lastEvent;
903f80a87f2SEd Tanous                  lastEvent != messages.end(); lastEvent++)
904f80a87f2SEd Tanous             {
9056d799e14SEd Tanous                 subValue->sendEventToSubscriber(event->message);
906f80a87f2SEd Tanous             }
907f80a87f2SEd Tanous         }
908f80a87f2SEd Tanous         return id;
909f80a87f2SEd Tanous     }
910f80a87f2SEd Tanous 
911f80a87f2SEd Tanous     std::string
912f80a87f2SEd Tanous         addPushSubscription(const std::shared_ptr<Subscription>& subValue)
913f80a87f2SEd Tanous     {
914f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
915*a0969c70SMyung Bae         subValue->deleter = [id]() {
916*a0969c70SMyung Bae             EventServiceManager::getInstance().deleteSubscription(id);
917*a0969c70SMyung Bae         };
918f80a87f2SEd Tanous         updateSubscriptionData();
919b52664e2SAppaRao Puli         return id;
920b52664e2SAppaRao Puli     }
921b52664e2SAppaRao Puli 
922b52664e2SAppaRao Puli     bool isSubscriptionExist(const std::string& id)
923b52664e2SAppaRao Puli     {
924b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
92555f79e6fSEd Tanous         return obj != subscriptionsMap.end();
926b52664e2SAppaRao Puli     }
927b52664e2SAppaRao Puli 
9284b712a29SEd Tanous     bool deleteSubscription(const std::string& id)
929b52664e2SAppaRao Puli     {
930b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
9314b712a29SEd Tanous         if (obj == subscriptionsMap.end())
932b52664e2SAppaRao Puli         {
9334b712a29SEd Tanous             BMCWEB_LOG_WARNING("Could not find subscription with id {}", id);
9344b712a29SEd Tanous             return false;
9354b712a29SEd Tanous         }
936b52664e2SAppaRao Puli         subscriptionsMap.erase(obj);
9374b712a29SEd Tanous         auto& event = persistent_data::EventServiceStore::getInstance();
9384b712a29SEd Tanous         auto persistentObj = event.subscriptionsConfigMap.find(id);
9394b712a29SEd Tanous         if (persistentObj == event.subscriptionsConfigMap.end())
9404b712a29SEd Tanous         {
9414b712a29SEd Tanous             BMCWEB_LOG_ERROR("Subscription wasn't in persistent data");
9424b712a29SEd Tanous             return true;
9434b712a29SEd Tanous         }
94428afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
9454b712a29SEd Tanous             .subscriptionsConfigMap.erase(persistentObj);
9467d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
947b52664e2SAppaRao Puli         updateSubscriptionData();
9484b712a29SEd Tanous 
9494b712a29SEd Tanous         return true;
950b52664e2SAppaRao Puli     }
951b52664e2SAppaRao Puli 
9525e44e3d8SAppaRao Puli     void deleteSseSubscription(const crow::sse_socket::Connection& thisConn)
9535e44e3d8SAppaRao Puli     {
954bdbfae2aSEd Tanous         for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();)
9555e44e3d8SAppaRao Puli         {
956bdbfae2aSEd Tanous             std::shared_ptr<Subscription> entry = it->second;
9575e44e3d8SAppaRao Puli             bool entryIsThisConn = entry->matchSseId(thisConn);
9585e44e3d8SAppaRao Puli             if (entryIsThisConn)
9595e44e3d8SAppaRao Puli             {
9605e44e3d8SAppaRao Puli                 persistent_data::EventServiceStore::getInstance()
9615e44e3d8SAppaRao Puli                     .subscriptionsConfigMap.erase(
962bdbfae2aSEd Tanous                         it->second->getSubscriptionId());
963bdbfae2aSEd Tanous                 it = subscriptionsMap.erase(it);
9645e44e3d8SAppaRao Puli                 return;
9655e44e3d8SAppaRao Puli             }
966bdbfae2aSEd Tanous             it++;
9675e44e3d8SAppaRao Puli         }
9685e44e3d8SAppaRao Puli     }
9695e44e3d8SAppaRao Puli 
9705e44e3d8SAppaRao Puli     size_t getNumberOfSubscriptions() const
971b52664e2SAppaRao Puli     {
972b52664e2SAppaRao Puli         return subscriptionsMap.size();
973b52664e2SAppaRao Puli     }
974b52664e2SAppaRao Puli 
9755e44e3d8SAppaRao Puli     size_t getNumberOfSSESubscriptions() const
9765e44e3d8SAppaRao Puli     {
9773544d2a7SEd Tanous         auto size = std::ranges::count_if(
9783544d2a7SEd Tanous             subscriptionsMap,
9795e44e3d8SAppaRao Puli             [](const std::pair<std::string, std::shared_ptr<Subscription>>&
9805e44e3d8SAppaRao Puli                    entry) {
9814b712a29SEd Tanous                 return (entry.second->userSub.subscriptionType ==
9824b712a29SEd Tanous                         subscriptionTypeSSE);
9835e44e3d8SAppaRao Puli             });
9845e44e3d8SAppaRao Puli         return static_cast<size_t>(size);
9855e44e3d8SAppaRao Puli     }
9865e44e3d8SAppaRao Puli 
987b52664e2SAppaRao Puli     std::vector<std::string> getAllIDs()
988b52664e2SAppaRao Puli     {
989b52664e2SAppaRao Puli         std::vector<std::string> idList;
990b52664e2SAppaRao Puli         for (const auto& it : subscriptionsMap)
991b52664e2SAppaRao Puli         {
992b52664e2SAppaRao Puli             idList.emplace_back(it.first);
993b52664e2SAppaRao Puli         }
994b52664e2SAppaRao Puli         return idList;
995b52664e2SAppaRao Puli     }
996b52664e2SAppaRao Puli 
9976ba8c82eSsunharis_in     bool sendTestEventLog()
9980b4bdd93SAppaRao Puli     {
9995e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
10000b4bdd93SAppaRao Puli         {
10010b4bdd93SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
10026ba8c82eSsunharis_in             if (!entry->sendTestEventLog())
10036ba8c82eSsunharis_in             {
10046ba8c82eSsunharis_in                 return false;
10050b4bdd93SAppaRao Puli             }
10060b4bdd93SAppaRao Puli         }
10076ba8c82eSsunharis_in         return true;
10086ba8c82eSsunharis_in     }
1009e9a14131SAppaRao Puli 
1010f80a87f2SEd Tanous     void sendEvent(nlohmann::json::object_t eventMessage,
1011f80a87f2SEd Tanous                    std::string_view origin, std::string_view resourceType)
101296330b99SSunitha Harish     {
1013613dabeaSEd Tanous         eventMessage["EventId"] = eventId;
1014f80a87f2SEd Tanous 
1015613dabeaSEd Tanous         eventMessage["EventTimestamp"] =
1016613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
1017613dabeaSEd Tanous         eventMessage["OriginOfCondition"] = origin;
1018613dabeaSEd Tanous 
1019f80a87f2SEd Tanous         // MemberId is 0 : since we are sending one event record.
1020788b091bSIgor Kanyuka         eventMessage["MemberId"] = "0";
102196330b99SSunitha Harish 
1022f80a87f2SEd Tanous         messages.push_back(Event(std::to_string(eventId), eventMessage));
1023f80a87f2SEd Tanous 
1024f80a87f2SEd Tanous         for (auto& it : subscriptionsMap)
102596330b99SSunitha Harish         {
1026f80a87f2SEd Tanous             std::shared_ptr<Subscription>& entry = it.second;
1027d3a48a14SEd Tanous             if (!eventMatchesFilter(entry->userSub, eventMessage, resourceType))
102896330b99SSunitha Harish             {
1029f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Filter didn't match");
1030f80a87f2SEd Tanous                 continue;
103196330b99SSunitha Harish             }
1032f80a87f2SEd Tanous 
1033f80a87f2SEd Tanous             nlohmann::json::array_t eventRecord;
1034f80a87f2SEd Tanous             eventRecord.emplace_back(eventMessage);
1035f80a87f2SEd Tanous 
1036613dabeaSEd Tanous             nlohmann::json msgJson;
1037613dabeaSEd Tanous 
1038613dabeaSEd Tanous             msgJson["@odata.type"] = "#Event.v1_4_0.Event";
1039613dabeaSEd Tanous             msgJson["Name"] = "Event Log";
1040613dabeaSEd Tanous             msgJson["Id"] = eventId;
1041f80a87f2SEd Tanous             msgJson["Events"] = std::move(eventRecord);
1042f52c03c1SCarson Labrado 
1043f52c03c1SCarson Labrado             std::string strMsg = msgJson.dump(
1044f52c03c1SCarson Labrado                 2, ' ', true, nlohmann::json::error_handler_t::replace);
10456d799e14SEd Tanous             entry->sendEventToSubscriber(std::move(strMsg));
10468ece0e45SEd Tanous             eventId++; // increment the eventId
104796330b99SSunitha Harish         }
104896330b99SSunitha Harish     }
104996330b99SSunitha Harish 
10502558979cSP Dheeraj Srujan Kumar     void resetRedfishFilePosition()
10517f4eb588SAppaRao Puli     {
10522558979cSP Dheeraj Srujan Kumar         // Control would be here when Redfish file is created.
10532558979cSP Dheeraj Srujan Kumar         // Reset File Position as new file is created
10542558979cSP Dheeraj Srujan Kumar         redfishLogFilePosition = 0;
10552558979cSP Dheeraj Srujan Kumar     }
10562558979cSP Dheeraj Srujan Kumar 
10572558979cSP Dheeraj Srujan Kumar     void cacheRedfishLogFile()
10582558979cSP Dheeraj Srujan Kumar     {
10592558979cSP Dheeraj Srujan Kumar         // Open the redfish file and read till the last record.
10602558979cSP Dheeraj Srujan Kumar 
10617f4eb588SAppaRao Puli         std::ifstream logStream(redfishEventLogFile);
10627f4eb588SAppaRao Puli         if (!logStream.good())
10637f4eb588SAppaRao Puli         {
106462598e31SEd Tanous             BMCWEB_LOG_ERROR(" Redfish log file open failed ");
10657f4eb588SAppaRao Puli             return;
10667f4eb588SAppaRao Puli         }
10677f4eb588SAppaRao Puli         std::string logEntry;
10687f4eb588SAppaRao Puli         while (std::getline(logStream, logEntry))
10697f4eb588SAppaRao Puli         {
10702558979cSP Dheeraj Srujan Kumar             redfishLogFilePosition = logStream.tellg();
10717f4eb588SAppaRao Puli         }
10727f4eb588SAppaRao Puli     }
10737f4eb588SAppaRao Puli 
10747f4eb588SAppaRao Puli     void readEventLogsFromFile()
10757f4eb588SAppaRao Puli     {
10767f4eb588SAppaRao Puli         std::ifstream logStream(redfishEventLogFile);
10777f4eb588SAppaRao Puli         if (!logStream.good())
10787f4eb588SAppaRao Puli         {
107962598e31SEd Tanous             BMCWEB_LOG_ERROR(" Redfish log file open failed");
10807f4eb588SAppaRao Puli             return;
10817f4eb588SAppaRao Puli         }
10827f4eb588SAppaRao Puli 
10837f4eb588SAppaRao Puli         std::vector<EventLogObjectsType> eventRecords;
10847f4eb588SAppaRao Puli 
10857f4eb588SAppaRao Puli         std::string logEntry;
10862558979cSP Dheeraj Srujan Kumar 
108703d4d37cSAlexander Hansen         BMCWEB_LOG_DEBUG("Redfish log file: seek to {}",
108803d4d37cSAlexander Hansen                          static_cast<int>(redfishLogFilePosition));
108903d4d37cSAlexander Hansen 
10902558979cSP Dheeraj Srujan Kumar         // Get the read pointer to the next log to be read.
10912558979cSP Dheeraj Srujan Kumar         logStream.seekg(redfishLogFilePosition);
10922558979cSP Dheeraj Srujan Kumar 
10937f4eb588SAppaRao Puli         while (std::getline(logStream, logEntry))
10947f4eb588SAppaRao Puli         {
109503d4d37cSAlexander Hansen             BMCWEB_LOG_DEBUG("Redfish log file: found new event log entry");
10962558979cSP Dheeraj Srujan Kumar             // Update Pointer position
10972558979cSP Dheeraj Srujan Kumar             redfishLogFilePosition = logStream.tellg();
10982558979cSP Dheeraj Srujan Kumar 
10992558979cSP Dheeraj Srujan Kumar             std::string idStr;
11002558979cSP Dheeraj Srujan Kumar             if (!event_log::getUniqueEntryID(logEntry, idStr))
11017f4eb588SAppaRao Puli             {
110203d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG(
110303d4d37cSAlexander Hansen                     "Redfish log file: could not get unique entry id for {}",
110403d4d37cSAlexander Hansen                     logEntry);
11057f4eb588SAppaRao Puli                 continue;
11067f4eb588SAppaRao Puli             }
11077f4eb588SAppaRao Puli 
1108e662eae8SEd Tanous             if (!serviceEnabled || noOfEventLogSubscribers == 0)
11097f4eb588SAppaRao Puli             {
11102558979cSP Dheeraj Srujan Kumar                 // If Service is not enabled, no need to compute
11112558979cSP Dheeraj Srujan Kumar                 // the remaining items below.
11122558979cSP Dheeraj Srujan Kumar                 // But, Loop must continue to keep track of Timestamp
111303d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG(
111403d4d37cSAlexander Hansen                     "Redfish log file: no subscribers / event service not enabled");
11157f4eb588SAppaRao Puli                 continue;
11167f4eb588SAppaRao Puli             }
11177f4eb588SAppaRao Puli 
11187f4eb588SAppaRao Puli             std::string timestamp;
11197f4eb588SAppaRao Puli             std::string messageID;
11205e715de6SAppaRao Puli             std::vector<std::string> messageArgs;
11217f4eb588SAppaRao Puli             if (event_log::getEventLogParams(logEntry, timestamp, messageID,
11227f4eb588SAppaRao Puli                                              messageArgs) != 0)
11237f4eb588SAppaRao Puli             {
112403d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("Read eventLog entry params failed for {}",
112503d4d37cSAlexander Hansen                                  logEntry);
11267f4eb588SAppaRao Puli                 continue;
11277f4eb588SAppaRao Puli             }
11287f4eb588SAppaRao Puli 
1129f80a87f2SEd Tanous             eventRecords.emplace_back(idStr, timestamp, messageID, messageArgs);
11307f4eb588SAppaRao Puli         }
11317f4eb588SAppaRao Puli 
1132e662eae8SEd Tanous         if (!serviceEnabled || noOfEventLogSubscribers == 0)
11332558979cSP Dheeraj Srujan Kumar         {
113462598e31SEd Tanous             BMCWEB_LOG_DEBUG("EventService disabled or no Subscriptions.");
11352558979cSP Dheeraj Srujan Kumar             return;
11362558979cSP Dheeraj Srujan Kumar         }
11372558979cSP Dheeraj Srujan Kumar 
11382558979cSP Dheeraj Srujan Kumar         if (eventRecords.empty())
11392558979cSP Dheeraj Srujan Kumar         {
11402558979cSP Dheeraj Srujan Kumar             // No Records to send
114162598e31SEd Tanous             BMCWEB_LOG_DEBUG("No log entries available to be transferred.");
11422558979cSP Dheeraj Srujan Kumar             return;
11432558979cSP Dheeraj Srujan Kumar         }
11442558979cSP Dheeraj Srujan Kumar 
11455e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
11467f4eb588SAppaRao Puli         {
11477f4eb588SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
11484b712a29SEd Tanous             if (entry->userSub.eventFormatType == "Event")
11497f4eb588SAppaRao Puli             {
11507f4eb588SAppaRao Puli                 entry->filterAndSendEventLogs(eventRecords);
11517f4eb588SAppaRao Puli             }
11527f4eb588SAppaRao Puli         }
11537f4eb588SAppaRao Puli     }
11547f4eb588SAppaRao Puli 
11557f4eb588SAppaRao Puli     static void watchRedfishEventLogFile()
11567f4eb588SAppaRao Puli     {
11576a9f85f9SAppaRao Puli         if (!inotifyConn)
11587f4eb588SAppaRao Puli         {
115903d4d37cSAlexander Hansen             BMCWEB_LOG_ERROR("inotify Connection is not present");
11607f4eb588SAppaRao Puli             return;
11617f4eb588SAppaRao Puli         }
11627f4eb588SAppaRao Puli 
11637f4eb588SAppaRao Puli         static std::array<char, 1024> readBuffer;
11647f4eb588SAppaRao Puli 
1165bd79bce8SPatrick Williams         inotifyConn->async_read_some(
1166bd79bce8SPatrick Williams             boost::asio::buffer(readBuffer),
11677f4eb588SAppaRao Puli             [&](const boost::system::error_code& ec,
11687f4eb588SAppaRao Puli                 const std::size_t& bytesTransferred) {
11699ed3f90aSEd Tanous                 if (ec == boost::asio::error::operation_aborted)
11709ed3f90aSEd Tanous                 {
11719ed3f90aSEd Tanous                     BMCWEB_LOG_DEBUG("Inotify was canceled (shutdown?)");
11729ed3f90aSEd Tanous                     return;
11739ed3f90aSEd Tanous                 }
11747f4eb588SAppaRao Puli                 if (ec)
11757f4eb588SAppaRao Puli                 {
117662598e31SEd Tanous                     BMCWEB_LOG_ERROR("Callback Error: {}", ec.message());
11777f4eb588SAppaRao Puli                     return;
11787f4eb588SAppaRao Puli                 }
117903d4d37cSAlexander Hansen 
118003d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("reading {} via inotify", bytesTransferred);
118103d4d37cSAlexander Hansen 
11827f4eb588SAppaRao Puli                 std::size_t index = 0;
1183b792cc56SAppaRao Puli                 while ((index + iEventSize) <= bytesTransferred)
11847f4eb588SAppaRao Puli                 {
1185d3a9e084SEd Tanous                     struct inotify_event event
1186d3a9e084SEd Tanous                     {};
1187b792cc56SAppaRao Puli                     std::memcpy(&event, &readBuffer[index], iEventSize);
1188b792cc56SAppaRao Puli                     if (event.wd == dirWatchDesc)
1189b792cc56SAppaRao Puli                     {
1190b792cc56SAppaRao Puli                         if ((event.len == 0) ||
1191b792cc56SAppaRao Puli                             (index + iEventSize + event.len > bytesTransferred))
1192b792cc56SAppaRao Puli                         {
1193b792cc56SAppaRao Puli                             index += (iEventSize + event.len);
1194b792cc56SAppaRao Puli                             continue;
1195b792cc56SAppaRao Puli                         }
1196b792cc56SAppaRao Puli 
11974f568f74SJiaqing Zhao                         std::string fileName(&readBuffer[index + iEventSize]);
11984f568f74SJiaqing Zhao                         if (fileName != "redfish")
1199b792cc56SAppaRao Puli                         {
1200b792cc56SAppaRao Puli                             index += (iEventSize + event.len);
1201b792cc56SAppaRao Puli                             continue;
1202b792cc56SAppaRao Puli                         }
1203b792cc56SAppaRao Puli 
120462598e31SEd Tanous                         BMCWEB_LOG_DEBUG(
120562598e31SEd Tanous                             "Redfish log file created/deleted. event.name: {}",
120662598e31SEd Tanous                             fileName);
1207b792cc56SAppaRao Puli                         if (event.mask == IN_CREATE)
1208b792cc56SAppaRao Puli                         {
1209b792cc56SAppaRao Puli                             if (fileWatchDesc != -1)
1210b792cc56SAppaRao Puli                             {
121162598e31SEd Tanous                                 BMCWEB_LOG_DEBUG(
121262598e31SEd Tanous                                     "Remove and Add inotify watcher on "
121362598e31SEd Tanous                                     "redfish event log file");
1214016761afSAppaRao Puli                                 // Remove existing inotify watcher and add
1215016761afSAppaRao Puli                                 // with new redfish event log file.
1216016761afSAppaRao Puli                                 inotify_rm_watch(inotifyFd, fileWatchDesc);
1217016761afSAppaRao Puli                                 fileWatchDesc = -1;
1218b792cc56SAppaRao Puli                             }
1219b792cc56SAppaRao Puli 
1220b792cc56SAppaRao Puli                             fileWatchDesc = inotify_add_watch(
1221b792cc56SAppaRao Puli                                 inotifyFd, redfishEventLogFile, IN_MODIFY);
1222b792cc56SAppaRao Puli                             if (fileWatchDesc == -1)
1223b792cc56SAppaRao Puli                             {
122462598e31SEd Tanous                                 BMCWEB_LOG_ERROR("inotify_add_watch failed for "
122562598e31SEd Tanous                                                  "redfish log file.");
1226b792cc56SAppaRao Puli                                 return;
1227b792cc56SAppaRao Puli                             }
1228b792cc56SAppaRao Puli 
1229b792cc56SAppaRao Puli                             EventServiceManager::getInstance()
12302558979cSP Dheeraj Srujan Kumar                                 .resetRedfishFilePosition();
1231b792cc56SAppaRao Puli                             EventServiceManager::getInstance()
1232b792cc56SAppaRao Puli                                 .readEventLogsFromFile();
1233b792cc56SAppaRao Puli                         }
1234b792cc56SAppaRao Puli                         else if ((event.mask == IN_DELETE) ||
1235b792cc56SAppaRao Puli                                  (event.mask == IN_MOVED_TO))
1236b792cc56SAppaRao Puli                         {
1237b792cc56SAppaRao Puli                             if (fileWatchDesc != -1)
1238b792cc56SAppaRao Puli                             {
1239b792cc56SAppaRao Puli                                 inotify_rm_watch(inotifyFd, fileWatchDesc);
1240b792cc56SAppaRao Puli                                 fileWatchDesc = -1;
1241b792cc56SAppaRao Puli                             }
1242b792cc56SAppaRao Puli                         }
1243b792cc56SAppaRao Puli                     }
1244b792cc56SAppaRao Puli                     else if (event.wd == fileWatchDesc)
1245b792cc56SAppaRao Puli                     {
1246b792cc56SAppaRao Puli                         if (event.mask == IN_MODIFY)
12477f4eb588SAppaRao Puli                         {
12487f4eb588SAppaRao Puli                             EventServiceManager::getInstance()
12497f4eb588SAppaRao Puli                                 .readEventLogsFromFile();
12507f4eb588SAppaRao Puli                         }
1251b792cc56SAppaRao Puli                     }
1252b792cc56SAppaRao Puli                     index += (iEventSize + event.len);
12537f4eb588SAppaRao Puli                 }
12547f4eb588SAppaRao Puli 
12557f4eb588SAppaRao Puli                 watchRedfishEventLogFile();
12567f4eb588SAppaRao Puli             });
12577f4eb588SAppaRao Puli     }
12587f4eb588SAppaRao Puli 
12597f4eb588SAppaRao Puli     static int startEventLogMonitor(boost::asio::io_context& ioc)
12607f4eb588SAppaRao Puli     {
126103d4d37cSAlexander Hansen         BMCWEB_LOG_DEBUG("starting Event Log Monitor");
126203d4d37cSAlexander Hansen 
126323a21a1cSEd Tanous         inotifyConn.emplace(ioc);
1264b792cc56SAppaRao Puli         inotifyFd = inotify_init1(IN_NONBLOCK);
1265b792cc56SAppaRao Puli         if (inotifyFd == -1)
12667f4eb588SAppaRao Puli         {
126762598e31SEd Tanous             BMCWEB_LOG_ERROR("inotify_init1 failed.");
12687f4eb588SAppaRao Puli             return -1;
12697f4eb588SAppaRao Puli         }
1270b792cc56SAppaRao Puli 
1271b792cc56SAppaRao Puli         // Add watch on directory to handle redfish event log file
1272b792cc56SAppaRao Puli         // create/delete.
1273b792cc56SAppaRao Puli         dirWatchDesc = inotify_add_watch(inotifyFd, redfishEventLogDir,
1274b792cc56SAppaRao Puli                                          IN_CREATE | IN_MOVED_TO | IN_DELETE);
1275b792cc56SAppaRao Puli         if (dirWatchDesc == -1)
12767f4eb588SAppaRao Puli         {
127762598e31SEd Tanous             BMCWEB_LOG_ERROR(
127862598e31SEd Tanous                 "inotify_add_watch failed for event log directory.");
12797f4eb588SAppaRao Puli             return -1;
12807f4eb588SAppaRao Puli         }
12817f4eb588SAppaRao Puli 
1282b792cc56SAppaRao Puli         // Watch redfish event log file for modifications.
1283bd79bce8SPatrick Williams         fileWatchDesc =
1284bd79bce8SPatrick Williams             inotify_add_watch(inotifyFd, redfishEventLogFile, IN_MODIFY);
1285b792cc56SAppaRao Puli         if (fileWatchDesc == -1)
1286b792cc56SAppaRao Puli         {
128762598e31SEd Tanous             BMCWEB_LOG_ERROR("inotify_add_watch failed for redfish log file.");
1288b792cc56SAppaRao Puli             // Don't return error if file not exist.
1289b792cc56SAppaRao Puli             // Watch on directory will handle create/delete of file.
1290b792cc56SAppaRao Puli         }
1291b792cc56SAppaRao Puli 
12927f4eb588SAppaRao Puli         // monitor redfish event log file
1293b792cc56SAppaRao Puli         inotifyConn->assign(inotifyFd);
12947f4eb588SAppaRao Puli         watchRedfishEventLogFile();
12957f4eb588SAppaRao Puli 
12967f4eb588SAppaRao Puli         return 0;
12977f4eb588SAppaRao Puli     }
12987f4eb588SAppaRao Puli 
12999ed3f90aSEd Tanous     static void stopEventLogMonitor()
13009ed3f90aSEd Tanous     {
13019ed3f90aSEd Tanous         inotifyConn.reset();
13029ed3f90aSEd Tanous     }
13039ed3f90aSEd Tanous 
130459d494eeSPatrick Williams     static void getReadingsForReport(sdbusplus::message_t& msg)
1305156d6b00SAppaRao Puli     {
130656d2396dSEd Tanous         if (msg.is_method_error())
130756d2396dSEd Tanous         {
130862598e31SEd Tanous             BMCWEB_LOG_ERROR("TelemetryMonitor Signal error");
130956d2396dSEd Tanous             return;
131056d2396dSEd Tanous         }
131156d2396dSEd Tanous 
1312c0353249SWludzik, Jozef         sdbusplus::message::object_path path(msg.get_path());
1313c0353249SWludzik, Jozef         std::string id = path.filename();
1314c0353249SWludzik, Jozef         if (id.empty())
1315156d6b00SAppaRao Puli         {
131662598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to get Id from path");
1317156d6b00SAppaRao Puli             return;
1318156d6b00SAppaRao Puli         }
1319156d6b00SAppaRao Puli 
1320c0353249SWludzik, Jozef         std::string interface;
1321b9d36b47SEd Tanous         dbus::utility::DBusPropertiesMap props;
1322c0353249SWludzik, Jozef         std::vector<std::string> invalidProps;
1323c0353249SWludzik, Jozef         msg.read(interface, props, invalidProps);
1324c0353249SWludzik, Jozef 
1325bd79bce8SPatrick Williams         auto found = std::ranges::find_if(props, [](const auto& x) {
1326bd79bce8SPatrick Williams             return x.first == "Readings";
1327bd79bce8SPatrick Williams         });
1328c0353249SWludzik, Jozef         if (found == props.end())
1329156d6b00SAppaRao Puli         {
133062598e31SEd Tanous             BMCWEB_LOG_INFO("Failed to get Readings from Report properties");
1331156d6b00SAppaRao Puli             return;
1332156d6b00SAppaRao Puli         }
1333156d6b00SAppaRao Puli 
13341e1e598dSJonathan Doman         const telemetry::TimestampReadings* readings =
13351e1e598dSJonathan Doman             std::get_if<telemetry::TimestampReadings>(&found->second);
1336e662eae8SEd Tanous         if (readings == nullptr)
13371e1e598dSJonathan Doman         {
133862598e31SEd Tanous             BMCWEB_LOG_INFO("Failed to get Readings from Report properties");
13391e1e598dSJonathan Doman             return;
13401e1e598dSJonathan Doman         }
13411e1e598dSJonathan Doman 
1342156d6b00SAppaRao Puli         for (const auto& it :
1343156d6b00SAppaRao Puli              EventServiceManager::getInstance().subscriptionsMap)
1344156d6b00SAppaRao Puli         {
1345e05aec50SEd Tanous             Subscription& entry = *it.second;
13464b712a29SEd Tanous             if (entry.userSub.eventFormatType == metricReportFormatType)
1347156d6b00SAppaRao Puli             {
13481e1e598dSJonathan Doman                 entry.filterAndSendReports(id, *readings);
1349156d6b00SAppaRao Puli             }
1350156d6b00SAppaRao Puli         }
1351156d6b00SAppaRao Puli     }
1352156d6b00SAppaRao Puli 
1353156d6b00SAppaRao Puli     void unregisterMetricReportSignal()
1354156d6b00SAppaRao Puli     {
13557d1cc387SAppaRao Puli         if (matchTelemetryMonitor)
13567d1cc387SAppaRao Puli         {
135762598e31SEd Tanous             BMCWEB_LOG_DEBUG("Metrics report signal - Unregister");
1358156d6b00SAppaRao Puli             matchTelemetryMonitor.reset();
1359156d6b00SAppaRao Puli             matchTelemetryMonitor = nullptr;
1360156d6b00SAppaRao Puli         }
13617d1cc387SAppaRao Puli     }
1362156d6b00SAppaRao Puli 
1363156d6b00SAppaRao Puli     void registerMetricReportSignal()
1364156d6b00SAppaRao Puli     {
13657d1cc387SAppaRao Puli         if (!serviceEnabled || matchTelemetryMonitor)
1366156d6b00SAppaRao Puli         {
136762598e31SEd Tanous             BMCWEB_LOG_DEBUG("Not registering metric report signal.");
1368156d6b00SAppaRao Puli             return;
1369156d6b00SAppaRao Puli         }
1370156d6b00SAppaRao Puli 
137162598e31SEd Tanous         BMCWEB_LOG_DEBUG("Metrics report signal - Register");
1372c0353249SWludzik, Jozef         std::string matchStr = "type='signal',member='PropertiesChanged',"
1373c0353249SWludzik, Jozef                                "interface='org.freedesktop.DBus.Properties',"
1374c0353249SWludzik, Jozef                                "arg0=xyz.openbmc_project.Telemetry.Report";
1375156d6b00SAppaRao Puli 
137659d494eeSPatrick Williams         matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match_t>(
137756d2396dSEd Tanous             *crow::connections::systemBus, matchStr, getReadingsForReport);
1378156d6b00SAppaRao Puli     }
137923a21a1cSEd Tanous };
1380b52664e2SAppaRao Puli 
1381b52664e2SAppaRao Puli } // namespace redfish
1382