xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision 21a94d5cd4be74a85c978c0cd63e4c633093c531)
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>
53b52664e2SAppaRao Puli 
54b52664e2SAppaRao Puli namespace redfish
55b52664e2SAppaRao Puli {
56156d6b00SAppaRao Puli 
57156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event";
58156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport";
59156d6b00SAppaRao Puli 
605e44e3d8SAppaRao Puli static constexpr const char* subscriptionTypeSSE = "SSE";
611bf712bcSAyushi Smriti static constexpr const char* eventServiceFile =
621bf712bcSAyushi Smriti     "/var/lib/bmcweb/eventservice_config.json";
631bf712bcSAyushi Smriti 
645e44e3d8SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20;
655e44e3d8SAppaRao Puli static constexpr const uint8_t maxNoOfSSESubscriptions = 10;
665e44e3d8SAppaRao Puli 
67cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
684642bf8fSGeorge Liu static std::optional<boost::asio::posix::stream_descriptor> inotifyConn;
694642bf8fSGeorge Liu static constexpr const char* redfishEventLogDir = "/var/log";
704642bf8fSGeorge Liu static constexpr const char* redfishEventLogFile = "/var/log/redfish";
714642bf8fSGeorge Liu static constexpr const size_t iEventSize = sizeof(inotify_event);
72cf9e417dSEd Tanous 
73cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
744642bf8fSGeorge Liu static int inotifyFd = -1;
75cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
764642bf8fSGeorge Liu static int dirWatchDesc = -1;
77cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
784642bf8fSGeorge Liu static int fileWatchDesc = -1;
79f80a87f2SEd Tanous struct EventLogObjectsType
80f80a87f2SEd Tanous {
81f80a87f2SEd Tanous     std::string id;
82f80a87f2SEd Tanous     std::string timestamp;
83f80a87f2SEd Tanous     std::string messageId;
84f80a87f2SEd Tanous     std::vector<std::string> messageArgs;
85f80a87f2SEd Tanous };
864642bf8fSGeorge Liu 
87fffb8c1fSEd Tanous namespace registries
884642bf8fSGeorge Liu {
897f4eb588SAppaRao Puli static const Message*
907f4eb588SAppaRao Puli     getMsgFromRegistry(const std::string& messageKey,
9126702d01SEd Tanous                        const std::span<const MessageEntry>& registry)
927f4eb588SAppaRao Puli {
933544d2a7SEd Tanous     std::span<const MessageEntry>::iterator messageIt = std::ranges::find_if(
943544d2a7SEd Tanous         registry, [&messageKey](const MessageEntry& messageEntry) {
9555f79e6fSEd Tanous             return messageKey == messageEntry.first;
967f4eb588SAppaRao Puli         });
9726702d01SEd Tanous     if (messageIt != registry.end())
987f4eb588SAppaRao Puli     {
997f4eb588SAppaRao Puli         return &messageIt->second;
1007f4eb588SAppaRao Puli     }
1017f4eb588SAppaRao Puli 
1027f4eb588SAppaRao Puli     return nullptr;
1037f4eb588SAppaRao Puli }
1047f4eb588SAppaRao Puli 
10526ccae32SEd Tanous static const Message* formatMessage(std::string_view messageID)
1067f4eb588SAppaRao Puli {
1077f4eb588SAppaRao Puli     // Redfish MessageIds are in the form
1087f4eb588SAppaRao Puli     // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find
1097f4eb588SAppaRao Puli     // the right Message
1107f4eb588SAppaRao Puli     std::vector<std::string> fields;
1117f4eb588SAppaRao Puli     fields.reserve(4);
11250ebd4afSEd Tanous 
11350ebd4afSEd Tanous     bmcweb::split(fields, messageID, '.');
1147f4eb588SAppaRao Puli     if (fields.size() != 4)
1157f4eb588SAppaRao Puli     {
1167f4eb588SAppaRao Puli         return nullptr;
1177f4eb588SAppaRao Puli     }
11802cad96eSEd Tanous     const std::string& registryName = fields[0];
11902cad96eSEd Tanous     const std::string& messageKey = fields[3];
1207f4eb588SAppaRao Puli 
1217f4eb588SAppaRao Puli     // Find the right registry and check it for the MessageKey
122b304bd79SP Dheeraj Srujan Kumar     return getMsgFromRegistry(messageKey, getRegistryFromPrefix(registryName));
1237f4eb588SAppaRao Puli }
124fffb8c1fSEd Tanous } // namespace registries
1257f4eb588SAppaRao Puli 
1267f4eb588SAppaRao Puli namespace event_log
1277f4eb588SAppaRao Puli {
1282558979cSP Dheeraj Srujan Kumar inline bool getUniqueEntryID(const std::string& logEntry, std::string& entryID)
1297f4eb588SAppaRao Puli {
1307f4eb588SAppaRao Puli     static time_t prevTs = 0;
1317f4eb588SAppaRao Puli     static int index = 0;
1327f4eb588SAppaRao Puli 
1337f4eb588SAppaRao Puli     // Get the entry timestamp
1347f4eb588SAppaRao Puli     std::time_t curTs = 0;
1357f4eb588SAppaRao Puli     std::tm timeStruct = {};
1367f4eb588SAppaRao Puli     std::istringstream entryStream(logEntry);
1377f4eb588SAppaRao Puli     if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
1387f4eb588SAppaRao Puli     {
1397f4eb588SAppaRao Puli         curTs = std::mktime(&timeStruct);
1407f4eb588SAppaRao Puli         if (curTs == -1)
1417f4eb588SAppaRao Puli         {
1427f4eb588SAppaRao Puli             return false;
1437f4eb588SAppaRao Puli         }
1447f4eb588SAppaRao Puli     }
1457f4eb588SAppaRao Puli     // If the timestamp isn't unique, increment the index
1467f4eb588SAppaRao Puli     index = (curTs == prevTs) ? index + 1 : 0;
1477f4eb588SAppaRao Puli 
1487f4eb588SAppaRao Puli     // Save the timestamp
1497f4eb588SAppaRao Puli     prevTs = curTs;
1507f4eb588SAppaRao Puli 
1517f4eb588SAppaRao Puli     entryID = std::to_string(curTs);
1527f4eb588SAppaRao Puli     if (index > 0)
1537f4eb588SAppaRao Puli     {
1547f4eb588SAppaRao Puli         entryID += "_" + std::to_string(index);
1557f4eb588SAppaRao Puli     }
1567f4eb588SAppaRao Puli     return true;
1577f4eb588SAppaRao Puli }
1587f4eb588SAppaRao Puli 
15923a21a1cSEd Tanous inline int getEventLogParams(const std::string& logEntry,
16023a21a1cSEd Tanous                              std::string& timestamp, std::string& messageID,
1615e715de6SAppaRao Puli                              std::vector<std::string>& messageArgs)
1627f4eb588SAppaRao Puli {
1637f4eb588SAppaRao Puli     // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
1647f4eb588SAppaRao Puli     // First get the Timestamp
165f23b7296SEd Tanous     size_t space = logEntry.find_first_of(' ');
1667f4eb588SAppaRao Puli     if (space == std::string::npos)
1677f4eb588SAppaRao Puli     {
16803d4d37cSAlexander Hansen         BMCWEB_LOG_ERROR("EventLog Params: could not find first space: {}",
16903d4d37cSAlexander Hansen                          logEntry);
1707f4eb588SAppaRao Puli         return -EINVAL;
1717f4eb588SAppaRao Puli     }
1727f4eb588SAppaRao Puli     timestamp = logEntry.substr(0, space);
1737f4eb588SAppaRao Puli     // Then get the log contents
174f23b7296SEd Tanous     size_t entryStart = logEntry.find_first_not_of(' ', space);
1757f4eb588SAppaRao Puli     if (entryStart == std::string::npos)
1767f4eb588SAppaRao Puli     {
17703d4d37cSAlexander Hansen         BMCWEB_LOG_ERROR("EventLog Params: could not find log contents: {}",
17803d4d37cSAlexander Hansen                          logEntry);
1797f4eb588SAppaRao Puli         return -EINVAL;
1807f4eb588SAppaRao Puli     }
1817f4eb588SAppaRao Puli     std::string_view entry(logEntry);
1827f4eb588SAppaRao Puli     entry.remove_prefix(entryStart);
1837f4eb588SAppaRao Puli     // Use split to separate the entry into its fields
1847f4eb588SAppaRao Puli     std::vector<std::string> logEntryFields;
18550ebd4afSEd Tanous     bmcweb::split(logEntryFields, entry, ',');
1867f4eb588SAppaRao Puli     // We need at least a MessageId to be valid
18726f6976fSEd Tanous     if (logEntryFields.empty())
1887f4eb588SAppaRao Puli     {
18903d4d37cSAlexander Hansen         BMCWEB_LOG_ERROR("EventLog Params: could not find entry fields: {}",
19003d4d37cSAlexander Hansen                          logEntry);
1917f4eb588SAppaRao Puli         return -EINVAL;
1927f4eb588SAppaRao Puli     }
1937f4eb588SAppaRao Puli     messageID = logEntryFields[0];
1947f4eb588SAppaRao Puli 
1957f4eb588SAppaRao Puli     // Get the MessageArgs from the log if there are any
1967f4eb588SAppaRao Puli     if (logEntryFields.size() > 1)
1977f4eb588SAppaRao Puli     {
19802cad96eSEd Tanous         const std::string& messageArgsStart = logEntryFields[1];
1997f4eb588SAppaRao Puli         // If the first string is empty, assume there are no MessageArgs
2007f4eb588SAppaRao Puli         if (!messageArgsStart.empty())
2017f4eb588SAppaRao Puli         {
2025e715de6SAppaRao Puli             messageArgs.assign(logEntryFields.begin() + 1,
2035e715de6SAppaRao Puli                                logEntryFields.end());
2047f4eb588SAppaRao Puli         }
2057f4eb588SAppaRao Puli     }
2067f4eb588SAppaRao Puli 
2077f4eb588SAppaRao Puli     return 0;
2087f4eb588SAppaRao Puli }
2097f4eb588SAppaRao Puli 
210bd79bce8SPatrick Williams inline int formatEventLogEntry(
211bd79bce8SPatrick Williams     const std::string& logEntryID, const std::string& messageID,
212bd79bce8SPatrick Williams     const std::span<std::string_view> messageArgs, std::string timestamp,
213bd79bce8SPatrick Williams     const std::string& customText, nlohmann::json::object_t& logEntryJson)
2147f4eb588SAppaRao Puli {
2157f4eb588SAppaRao Puli     // Get the Message from the MessageRegistry
216fffb8c1fSEd Tanous     const registries::Message* message = registries::formatMessage(messageID);
2177f4eb588SAppaRao Puli 
21880f595e7SEd Tanous     if (message == nullptr)
2197f4eb588SAppaRao Puli     {
22080f595e7SEd Tanous         return -1;
2217f4eb588SAppaRao Puli     }
2227f4eb588SAppaRao Puli 
223bd79bce8SPatrick Williams     std::string msg =
224bd79bce8SPatrick Williams         redfish::registries::fillMessageArgs(messageArgs, message->message);
22580f595e7SEd Tanous     if (msg.empty())
22680f595e7SEd Tanous     {
22780f595e7SEd Tanous         return -1;
22880f595e7SEd Tanous     }
2297f4eb588SAppaRao Puli 
2307f4eb588SAppaRao Puli     // Get the Created time from the timestamp. The log timestamp is in
2317f4eb588SAppaRao Puli     // RFC3339 format which matches the Redfish format except for the
2327f4eb588SAppaRao Puli     // fractional seconds between the '.' and the '+', so just remove them.
233f23b7296SEd Tanous     std::size_t dot = timestamp.find_first_of('.');
234b2f7609bSEd Tanous     std::size_t plus = timestamp.find_first_of('+', dot);
2357f4eb588SAppaRao Puli     if (dot != std::string::npos && plus != std::string::npos)
2367f4eb588SAppaRao Puli     {
2377f4eb588SAppaRao Puli         timestamp.erase(dot, plus - dot);
2387f4eb588SAppaRao Puli     }
2397f4eb588SAppaRao Puli 
2407f4eb588SAppaRao Puli     // Fill in the log entry with the gathered data
2411476687dSEd Tanous     logEntryJson["EventId"] = logEntryID;
242539d8c6bSEd Tanous 
24380f595e7SEd Tanous     logEntryJson["Severity"] = message->messageSeverity;
2441476687dSEd Tanous     logEntryJson["Message"] = std::move(msg);
2451476687dSEd Tanous     logEntryJson["MessageId"] = messageID;
2461476687dSEd Tanous     logEntryJson["MessageArgs"] = messageArgs;
2471476687dSEd Tanous     logEntryJson["EventTimestamp"] = std::move(timestamp);
2481476687dSEd Tanous     logEntryJson["Context"] = customText;
2497f4eb588SAppaRao Puli     return 0;
2507f4eb588SAppaRao Puli }
2517f4eb588SAppaRao Puli 
2527f4eb588SAppaRao Puli } // namespace event_log
2537f4eb588SAppaRao Puli 
2544b712a29SEd Tanous class Subscription
255b52664e2SAppaRao Puli {
256b52664e2SAppaRao Puli   public:
257b52664e2SAppaRao Puli     Subscription(const Subscription&) = delete;
258b52664e2SAppaRao Puli     Subscription& operator=(const Subscription&) = delete;
259b52664e2SAppaRao Puli     Subscription(Subscription&&) = delete;
260b52664e2SAppaRao Puli     Subscription& operator=(Subscription&&) = delete;
261b52664e2SAppaRao Puli 
262*21a94d5cSMyung Bae     Subscription(const persistent_data::UserSubscription& userSubIn,
263*21a94d5cSMyung Bae                  const boost::urls::url_view_base& url,
2644a7fbefdSEd Tanous                  boost::asio::io_context& ioc) :
265*21a94d5cSMyung Bae         userSub(userSubIn), policy(std::make_shared<crow::ConnectionPolicy>())
266b52664e2SAppaRao Puli     {
2674b712a29SEd Tanous         userSub.destinationUrl = url;
2685e44e3d8SAppaRao Puli         client.emplace(ioc, policy);
2697adb85acSSunitha Harish         // Subscription constructor
270d14a48ffSCarson Labrado         policy->invalidResp = retryRespHandler;
271b52664e2SAppaRao Puli     }
2724bbf237fSAppaRao Puli 
2735e44e3d8SAppaRao Puli     explicit Subscription(crow::sse_socket::Connection& connIn) :
2745e44e3d8SAppaRao Puli         sseConn(&connIn)
2755e44e3d8SAppaRao Puli     {}
2765e44e3d8SAppaRao Puli 
2779f616dd1SEd Tanous     ~Subscription() = default;
278b52664e2SAppaRao Puli 
2796d799e14SEd Tanous     bool sendEventToSubscriber(std::string&& msg)
280b52664e2SAppaRao Puli     {
2816ba8c82eSsunharis_in         persistent_data::EventServiceConfig eventServiceConfig =
2826ba8c82eSsunharis_in             persistent_data::EventServiceStore::getInstance()
2836ba8c82eSsunharis_in                 .getEventServiceConfig();
2846ba8c82eSsunharis_in         if (!eventServiceConfig.enabled)
2856ba8c82eSsunharis_in         {
2866ba8c82eSsunharis_in             return false;
2876ba8c82eSsunharis_in         }
2886ba8c82eSsunharis_in 
2895e44e3d8SAppaRao Puli         if (client)
2905e44e3d8SAppaRao Puli         {
2914b712a29SEd Tanous             client->sendData(std::move(msg), userSub.destinationUrl,
2924b712a29SEd Tanous                              static_cast<ensuressl::VerifyCertificate>(
2934b712a29SEd Tanous                                  userSub.verifyCertificate),
2944b712a29SEd Tanous                              userSub.httpHeaders,
2954b712a29SEd Tanous                              boost::beast::http::verb::post);
2965e44e3d8SAppaRao Puli             return true;
2975e44e3d8SAppaRao Puli         }
2987adb85acSSunitha Harish 
2994bbf237fSAppaRao Puli         if (sseConn != nullptr)
3004bbf237fSAppaRao Puli         {
3015e44e3d8SAppaRao Puli             eventSeqNum++;
3026d799e14SEd Tanous             sseConn->sendSseEvent(std::to_string(eventSeqNum), msg);
3034bbf237fSAppaRao Puli         }
3046ba8c82eSsunharis_in         return true;
3054bbf237fSAppaRao Puli     }
3064bbf237fSAppaRao Puli 
3076ba8c82eSsunharis_in     bool sendTestEventLog()
3080b4bdd93SAppaRao Puli     {
309f80a87f2SEd Tanous         nlohmann::json::array_t logEntryArray;
310f80a87f2SEd Tanous         nlohmann::json& logEntryJson = logEntryArray.emplace_back();
3110b4bdd93SAppaRao Puli 
312613dabeaSEd Tanous         logEntryJson["EventId"] = "TestID";
313539d8c6bSEd Tanous         logEntryJson["Severity"] = log_entry::EventSeverity::OK;
314613dabeaSEd Tanous         logEntryJson["Message"] = "Generated test event";
315613dabeaSEd Tanous         logEntryJson["MessageId"] = "OpenBMC.0.2.TestEventLog";
316d2cdd478SChandra Harkude         // MemberId is 0 : since we are sending one event record.
317d2cdd478SChandra Harkude         logEntryJson["MemberId"] = 0;
318613dabeaSEd Tanous         logEntryJson["MessageArgs"] = nlohmann::json::array();
319613dabeaSEd Tanous         logEntryJson["EventTimestamp"] =
320613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
3214b712a29SEd Tanous         logEntryJson["Context"] = userSub.customText;
3220b4bdd93SAppaRao Puli 
3231476687dSEd Tanous         nlohmann::json msg;
3241476687dSEd Tanous         msg["@odata.type"] = "#Event.v1_4_0.Event";
3251476687dSEd Tanous         msg["Id"] = std::to_string(eventSeqNum);
3261476687dSEd Tanous         msg["Name"] = "Event Log";
3271476687dSEd Tanous         msg["Events"] = logEntryArray;
3280b4bdd93SAppaRao Puli 
329bd79bce8SPatrick Williams         std::string strMsg =
330bd79bce8SPatrick Williams             msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
3316d799e14SEd Tanous         return sendEventToSubscriber(std::move(strMsg));
3320b4bdd93SAppaRao Puli     }
3330b4bdd93SAppaRao Puli 
3347f4eb588SAppaRao Puli     void filterAndSendEventLogs(
3357f4eb588SAppaRao Puli         const std::vector<EventLogObjectsType>& eventRecords)
3367f4eb588SAppaRao Puli     {
337f80a87f2SEd Tanous         nlohmann::json::array_t logEntryArray;
3387f4eb588SAppaRao Puli         for (const EventLogObjectsType& logEntry : eventRecords)
3397f4eb588SAppaRao Puli         {
340f80a87f2SEd Tanous             std::vector<std::string_view> messageArgsView(
341f80a87f2SEd Tanous                 logEntry.messageArgs.begin(), logEntry.messageArgs.end());
3427f4eb588SAppaRao Puli 
343f80a87f2SEd Tanous             nlohmann::json::object_t bmcLogEntry;
344f80a87f2SEd Tanous             if (event_log::formatEventLogEntry(
345f80a87f2SEd Tanous                     logEntry.id, logEntry.messageId, messageArgsView,
3464b712a29SEd Tanous                     logEntry.timestamp, userSub.customText, bmcLogEntry) != 0)
3477f4eb588SAppaRao Puli             {
34862598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Read eventLog entry failed");
3497f4eb588SAppaRao Puli                 continue;
3507f4eb588SAppaRao Puli             }
351f80a87f2SEd Tanous 
352d3a48a14SEd Tanous             if (!eventMatchesFilter(userSub, bmcLogEntry, ""))
353f80a87f2SEd Tanous             {
35403d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("Event {} did not match the filter",
35503d4d37cSAlexander Hansen                                  nlohmann::json(bmcLogEntry).dump());
356f80a87f2SEd Tanous                 continue;
357f80a87f2SEd Tanous             }
358f80a87f2SEd Tanous 
359d3a48a14SEd Tanous             if (filter)
360d3a48a14SEd Tanous             {
361d3a48a14SEd Tanous                 if (!memberMatches(bmcLogEntry, *filter))
362d3a48a14SEd Tanous                 {
363d3a48a14SEd Tanous                     BMCWEB_LOG_DEBUG("Filter didn't match");
364d3a48a14SEd Tanous                     continue;
365d3a48a14SEd Tanous                 }
366d3a48a14SEd Tanous             }
367d3a48a14SEd Tanous 
368f80a87f2SEd Tanous             logEntryArray.emplace_back(std::move(bmcLogEntry));
3697f4eb588SAppaRao Puli         }
3707f4eb588SAppaRao Puli 
37126f6976fSEd Tanous         if (logEntryArray.empty())
3727f4eb588SAppaRao Puli         {
37362598e31SEd Tanous             BMCWEB_LOG_DEBUG("No log entries available to be transferred.");
3747f4eb588SAppaRao Puli             return;
3757f4eb588SAppaRao Puli         }
3767f4eb588SAppaRao Puli 
3771476687dSEd Tanous         nlohmann::json msg;
3781476687dSEd Tanous         msg["@odata.type"] = "#Event.v1_4_0.Event";
3791476687dSEd Tanous         msg["Id"] = std::to_string(eventSeqNum);
3801476687dSEd Tanous         msg["Name"] = "Event Log";
381f80a87f2SEd Tanous         msg["Events"] = std::move(logEntryArray);
382bd79bce8SPatrick Williams         std::string strMsg =
383bd79bce8SPatrick Williams             msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
3846d799e14SEd Tanous         sendEventToSubscriber(std::move(strMsg));
3855e44e3d8SAppaRao Puli         eventSeqNum++;
3867f4eb588SAppaRao Puli     }
3877f4eb588SAppaRao Puli 
388248d0230SEd Tanous     void filterAndSendReports(const std::string& reportId,
3891e1e598dSJonathan Doman                               const telemetry::TimestampReadings& var)
390156d6b00SAppaRao Puli     {
391ef4c65b7SEd Tanous         boost::urls::url mrdUri = boost::urls::format(
392ef4c65b7SEd Tanous             "/redfish/v1/TelemetryService/MetricReportDefinitions/{}",
393ef4c65b7SEd Tanous             reportId);
394156d6b00SAppaRao Puli 
395156d6b00SAppaRao Puli         // Empty list means no filter. Send everything.
3964b712a29SEd Tanous         if (!userSub.metricReportDefinitions.empty())
397156d6b00SAppaRao Puli         {
3984b712a29SEd Tanous             if (std::ranges::find(userSub.metricReportDefinitions,
3994b712a29SEd Tanous                                   mrdUri.buffer()) ==
4004b712a29SEd Tanous                 userSub.metricReportDefinitions.end())
401156d6b00SAppaRao Puli             {
402156d6b00SAppaRao Puli                 return;
403156d6b00SAppaRao Puli             }
404156d6b00SAppaRao Puli         }
405156d6b00SAppaRao Puli 
406c0353249SWludzik, Jozef         nlohmann::json msg;
407248d0230SEd Tanous         if (!telemetry::fillReport(msg, reportId, var))
408156d6b00SAppaRao Puli         {
40962598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to fill the MetricReport for DBus "
41062598e31SEd Tanous                              "Report with id {}",
41162598e31SEd Tanous                              reportId);
412c0353249SWludzik, Jozef             return;
413156d6b00SAppaRao Puli         }
414156d6b00SAppaRao Puli 
41522daffd7SAppaRao Puli         // Context is set by user during Event subscription and it must be
41622daffd7SAppaRao Puli         // set for MetricReport response.
4174b712a29SEd Tanous         if (!userSub.customText.empty())
41822daffd7SAppaRao Puli         {
4194b712a29SEd Tanous             msg["Context"] = userSub.customText;
42022daffd7SAppaRao Puli         }
42122daffd7SAppaRao Puli 
422bd79bce8SPatrick Williams         std::string strMsg =
423bd79bce8SPatrick Williams             msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
4246d799e14SEd Tanous         sendEventToSubscriber(std::move(strMsg));
425156d6b00SAppaRao Puli     }
426156d6b00SAppaRao Puli 
427d14a48ffSCarson Labrado     void updateRetryConfig(uint32_t retryAttempts,
428d14a48ffSCarson Labrado                            uint32_t retryTimeoutInterval)
429fe44eb0bSAyushi Smriti     {
43093cf0ac2SEd Tanous         if (policy == nullptr)
43193cf0ac2SEd Tanous         {
43293cf0ac2SEd Tanous             BMCWEB_LOG_DEBUG("Retry policy was nullptr, ignoring set");
43393cf0ac2SEd Tanous             return;
43493cf0ac2SEd Tanous         }
435d14a48ffSCarson Labrado         policy->maxRetryAttempts = retryAttempts;
436d14a48ffSCarson Labrado         policy->retryIntervalSecs = std::chrono::seconds(retryTimeoutInterval);
43762de0c68SAppaRao Puli     }
438fe44eb0bSAyushi Smriti 
4399eb808c1SEd Tanous     uint64_t getEventSeqNum() const
44096330b99SSunitha Harish     {
44196330b99SSunitha Harish         return eventSeqNum;
44296330b99SSunitha Harish     }
44396330b99SSunitha Harish 
4445e44e3d8SAppaRao Puli     void setSubscriptionId(const std::string& id2)
4455e44e3d8SAppaRao Puli     {
44662598e31SEd Tanous         BMCWEB_LOG_DEBUG("Subscription ID: {}", id2);
4475e44e3d8SAppaRao Puli         subId = id2;
4485e44e3d8SAppaRao Puli     }
4495e44e3d8SAppaRao Puli 
4505e44e3d8SAppaRao Puli     std::string getSubscriptionId()
4515e44e3d8SAppaRao Puli     {
4525e44e3d8SAppaRao Puli         return subId;
4535e44e3d8SAppaRao Puli     }
4545e44e3d8SAppaRao Puli 
4555e44e3d8SAppaRao Puli     bool matchSseId(const crow::sse_socket::Connection& thisConn)
4565e44e3d8SAppaRao Puli     {
4575e44e3d8SAppaRao Puli         return &thisConn == sseConn;
4585e44e3d8SAppaRao Puli     }
4595e44e3d8SAppaRao Puli 
460a7a80296SCarson Labrado     // Check used to indicate what response codes are valid as part of our retry
461a7a80296SCarson Labrado     // policy.  2XX is considered acceptable
462a7a80296SCarson Labrado     static boost::system::error_code retryRespHandler(unsigned int respCode)
463a7a80296SCarson Labrado     {
46462598e31SEd Tanous         BMCWEB_LOG_DEBUG(
46562598e31SEd Tanous             "Checking response code validity for SubscriptionEvent");
466a7a80296SCarson Labrado         if ((respCode < 200) || (respCode >= 300))
467a7a80296SCarson Labrado         {
468a7a80296SCarson Labrado             return boost::system::errc::make_error_code(
469a7a80296SCarson Labrado                 boost::system::errc::result_out_of_range);
470a7a80296SCarson Labrado         }
471a7a80296SCarson Labrado 
472a7a80296SCarson Labrado         // Return 0 if the response code is valid
473a7a80296SCarson Labrado         return boost::system::errc::make_error_code(
474a7a80296SCarson Labrado             boost::system::errc::success);
4759fa6d147SNan Zhou     }
476f80a87f2SEd Tanous 
4774b712a29SEd Tanous     persistent_data::UserSubscription userSub;
4784b712a29SEd Tanous 
479f80a87f2SEd Tanous   private:
480f80a87f2SEd Tanous     std::string subId;
481f80a87f2SEd Tanous     uint64_t eventSeqNum = 1;
482f80a87f2SEd Tanous     boost::urls::url host;
483f80a87f2SEd Tanous     std::shared_ptr<crow::ConnectionPolicy> policy;
484f80a87f2SEd Tanous     crow::sse_socket::Connection* sseConn = nullptr;
485f80a87f2SEd Tanous 
486f80a87f2SEd Tanous     std::optional<crow::HttpClient> client;
487f80a87f2SEd Tanous 
488f80a87f2SEd Tanous   public:
489f80a87f2SEd Tanous     std::optional<filter_ast::LogicalAnd> filter;
490b52664e2SAppaRao Puli };
491b52664e2SAppaRao Puli 
492b52664e2SAppaRao Puli class EventServiceManager
493b52664e2SAppaRao Puli {
494b52664e2SAppaRao Puli   private:
495d3a9e084SEd Tanous     bool serviceEnabled = false;
496d3a9e084SEd Tanous     uint32_t retryAttempts = 0;
497d3a9e084SEd Tanous     uint32_t retryTimeoutInterval = 0;
4987d1cc387SAppaRao Puli 
4992558979cSP Dheeraj Srujan Kumar     std::streampos redfishLogFilePosition{0};
5009f616dd1SEd Tanous     size_t noOfEventLogSubscribers{0};
5019f616dd1SEd Tanous     size_t noOfMetricReportSubscribers{0};
50259d494eeSPatrick Williams     std::shared_ptr<sdbusplus::bus::match_t> matchTelemetryMonitor;
503b52664e2SAppaRao Puli     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
504b52664e2SAppaRao Puli         subscriptionsMap;
505b52664e2SAppaRao Puli 
5069f616dd1SEd Tanous     uint64_t eventId{1};
50796330b99SSunitha Harish 
508f80a87f2SEd Tanous     struct Event
509f80a87f2SEd Tanous     {
510f80a87f2SEd Tanous         std::string id;
511f80a87f2SEd Tanous         nlohmann::json message;
512f80a87f2SEd Tanous     };
513f80a87f2SEd Tanous 
514f80a87f2SEd Tanous     constexpr static size_t maxMessages = 200;
515f80a87f2SEd Tanous     boost::circular_buffer<Event> messages{maxMessages};
516f80a87f2SEd Tanous 
517f8ca6d79SEd Tanous     boost::asio::io_context& ioc;
518f8ca6d79SEd Tanous 
519b52664e2SAppaRao Puli   public:
5209f616dd1SEd Tanous     EventServiceManager(const EventServiceManager&) = delete;
5219f616dd1SEd Tanous     EventServiceManager& operator=(const EventServiceManager&) = delete;
5229f616dd1SEd Tanous     EventServiceManager(EventServiceManager&&) = delete;
5239f616dd1SEd Tanous     EventServiceManager& operator=(EventServiceManager&&) = delete;
524ecd6a3a2SEd Tanous     ~EventServiceManager() = default;
5259f616dd1SEd Tanous 
526f8ca6d79SEd Tanous     explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn)
527b52664e2SAppaRao Puli     {
528f8ca6d79SEd Tanous         // Load config from persist store.
529f8ca6d79SEd Tanous         initConfig();
530f8ca6d79SEd Tanous     }
531f8ca6d79SEd Tanous 
532f8ca6d79SEd Tanous     static EventServiceManager&
533f8ca6d79SEd Tanous         getInstance(boost::asio::io_context* ioc = nullptr)
534f8ca6d79SEd Tanous     {
535f8ca6d79SEd Tanous         static EventServiceManager handler(*ioc);
536b52664e2SAppaRao Puli         return handler;
537b52664e2SAppaRao Puli     }
538b52664e2SAppaRao Puli 
5391bf712bcSAyushi Smriti     void initConfig()
5401bf712bcSAyushi Smriti     {
54128afb49cSJunLin Chen         loadOldBehavior();
5421bf712bcSAyushi Smriti 
54328afb49cSJunLin Chen         persistent_data::EventServiceConfig eventServiceConfig =
54428afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
54528afb49cSJunLin Chen                 .getEventServiceConfig();
5461bf712bcSAyushi Smriti 
54728afb49cSJunLin Chen         serviceEnabled = eventServiceConfig.enabled;
54828afb49cSJunLin Chen         retryAttempts = eventServiceConfig.retryAttempts;
54928afb49cSJunLin Chen         retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval;
5501bf712bcSAyushi Smriti 
55128afb49cSJunLin Chen         for (const auto& it : persistent_data::EventServiceStore::getInstance()
55228afb49cSJunLin Chen                                   .subscriptionsConfigMap)
5531bf712bcSAyushi Smriti         {
5544b712a29SEd Tanous             const persistent_data::UserSubscription& newSub = it.second;
5554bbf237fSAppaRao Puli 
5566fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
5574b712a29SEd Tanous                 boost::urls::parse_absolute_uri(newSub.destinationUrl);
5581bf712bcSAyushi Smriti 
559a716aa74SEd Tanous             if (!url)
5601bf712bcSAyushi Smriti             {
56162598e31SEd Tanous                 BMCWEB_LOG_ERROR(
56262598e31SEd Tanous                     "Failed to validate and split destination url");
5631bf712bcSAyushi Smriti                 continue;
5641bf712bcSAyushi Smriti             }
5651bf712bcSAyushi Smriti             std::shared_ptr<Subscription> subValue =
566*21a94d5cSMyung Bae                 std::make_shared<Subscription>(newSub, *url, ioc);
5671bf712bcSAyushi Smriti 
5684b712a29SEd Tanous             subscriptionsMap.insert(std::pair(subValue->userSub.id, subValue));
56928afb49cSJunLin Chen 
57028afb49cSJunLin Chen             updateNoOfSubscribersCount();
57128afb49cSJunLin Chen 
57283328316SEd Tanous             if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
57383328316SEd Tanous             {
5742558979cSP Dheeraj Srujan Kumar                 cacheRedfishLogFile();
57583328316SEd Tanous             }
5762558979cSP Dheeraj Srujan Kumar 
57728afb49cSJunLin Chen             // Update retry configuration.
57828afb49cSJunLin Chen             subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
5791bf712bcSAyushi Smriti         }
5801bf712bcSAyushi Smriti     }
5811bf712bcSAyushi Smriti 
58256d2396dSEd Tanous     static void loadOldBehavior()
583b52664e2SAppaRao Puli     {
58428afb49cSJunLin Chen         std::ifstream eventConfigFile(eventServiceFile);
58528afb49cSJunLin Chen         if (!eventConfigFile.good())
5861bf712bcSAyushi Smriti         {
58762598e31SEd Tanous             BMCWEB_LOG_DEBUG("Old eventService config not exist");
58828afb49cSJunLin Chen             return;
58928afb49cSJunLin Chen         }
59028afb49cSJunLin Chen         auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false);
59128afb49cSJunLin Chen         if (jsonData.is_discarded())
5924bbf237fSAppaRao Puli         {
59362598e31SEd Tanous             BMCWEB_LOG_ERROR("Old eventService config parse error.");
59428afb49cSJunLin Chen             return;
59528afb49cSJunLin Chen         }
59628afb49cSJunLin Chen 
5970bdda665SEd Tanous         const nlohmann::json::object_t* obj =
5980bdda665SEd Tanous             jsonData.get_ptr<const nlohmann::json::object_t*>();
5990bdda665SEd Tanous         for (const auto& item : *obj)
60028afb49cSJunLin Chen         {
6010bdda665SEd Tanous             if (item.first == "Configuration")
60228afb49cSJunLin Chen             {
60328afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
60428afb49cSJunLin Chen                     .getEventServiceConfig()
6050bdda665SEd Tanous                     .fromJson(item.second);
60628afb49cSJunLin Chen             }
6070bdda665SEd Tanous             else if (item.first == "Subscriptions")
60828afb49cSJunLin Chen             {
6090bdda665SEd Tanous                 for (const auto& elem : item.second)
61028afb49cSJunLin Chen                 {
6114b712a29SEd Tanous                     std::optional<persistent_data::UserSubscription>
61228afb49cSJunLin Chen                         newSubscription =
61328afb49cSJunLin Chen                             persistent_data::UserSubscription::fromJson(elem,
61428afb49cSJunLin Chen                                                                         true);
6154b712a29SEd Tanous                     if (!newSubscription)
61628afb49cSJunLin Chen                     {
61762598e31SEd Tanous                         BMCWEB_LOG_ERROR("Problem reading subscription "
61862598e31SEd Tanous                                          "from old persistent store");
6194bbf237fSAppaRao Puli                         continue;
6204bbf237fSAppaRao Puli                     }
6214b712a29SEd Tanous                     persistent_data::UserSubscription& newSub =
6224b712a29SEd Tanous                         *newSubscription;
6231bf712bcSAyushi Smriti 
62428afb49cSJunLin Chen                     std::uniform_int_distribution<uint32_t> dist(0);
62528afb49cSJunLin Chen                     bmcweb::OpenSSLGenerator gen;
6261bf712bcSAyushi Smriti 
62728afb49cSJunLin Chen                     std::string id;
6281bf712bcSAyushi Smriti 
62928afb49cSJunLin Chen                     int retry = 3;
630e662eae8SEd Tanous                     while (retry != 0)
6311bf712bcSAyushi Smriti                     {
63228afb49cSJunLin Chen                         id = std::to_string(dist(gen));
63328afb49cSJunLin Chen                         if (gen.error())
6347d1cc387SAppaRao Puli                         {
63528afb49cSJunLin Chen                             retry = 0;
63628afb49cSJunLin Chen                             break;
63728afb49cSJunLin Chen                         }
6384b712a29SEd Tanous                         newSub.id = id;
63928afb49cSJunLin Chen                         auto inserted =
64028afb49cSJunLin Chen                             persistent_data::EventServiceStore::getInstance()
64128afb49cSJunLin Chen                                 .subscriptionsConfigMap.insert(
6424b712a29SEd Tanous                                     std::pair(id, newSub));
64328afb49cSJunLin Chen                         if (inserted.second)
64428afb49cSJunLin Chen                         {
64528afb49cSJunLin Chen                             break;
64628afb49cSJunLin Chen                         }
64728afb49cSJunLin Chen                         --retry;
6487d1cc387SAppaRao Puli                     }
6497d1cc387SAppaRao Puli 
65028afb49cSJunLin Chen                     if (retry <= 0)
65128afb49cSJunLin Chen                     {
65262598e31SEd Tanous                         BMCWEB_LOG_ERROR(
65362598e31SEd Tanous                             "Failed to generate random number from old "
65462598e31SEd Tanous                             "persistent store");
65528afb49cSJunLin Chen                         continue;
65628afb49cSJunLin Chen                     }
65728afb49cSJunLin Chen                 }
65828afb49cSJunLin Chen             }
65928afb49cSJunLin Chen 
66028afb49cSJunLin Chen             persistent_data::getConfig().writeData();
6614c521c3cSEd Tanous             std::error_code ec;
6624c521c3cSEd Tanous             std::filesystem::remove(eventServiceFile, ec);
6634c521c3cSEd Tanous             if (ec)
6644c521c3cSEd Tanous             {
6654c521c3cSEd Tanous                 BMCWEB_LOG_DEBUG(
6664c521c3cSEd Tanous                     "Failed to remove old event service file.  Ignoring");
6674c521c3cSEd Tanous             }
6684c521c3cSEd Tanous             else
6694c521c3cSEd Tanous             {
67062598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Remove old eventservice config");
67128afb49cSJunLin Chen             }
67228afb49cSJunLin Chen         }
6734c521c3cSEd Tanous     }
67428afb49cSJunLin Chen 
6759eb808c1SEd Tanous     void updateSubscriptionData() const
67628afb49cSJunLin Chen     {
67728afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
67828afb49cSJunLin Chen             .eventServiceConfig.enabled = serviceEnabled;
67928afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
68028afb49cSJunLin Chen             .eventServiceConfig.retryAttempts = retryAttempts;
68128afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
68228afb49cSJunLin Chen             .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval;
68328afb49cSJunLin Chen 
68428afb49cSJunLin Chen         persistent_data::getConfig().writeData();
68528afb49cSJunLin Chen     }
68628afb49cSJunLin Chen 
68728afb49cSJunLin Chen     void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg)
6887d1cc387SAppaRao Puli     {
6897d1cc387SAppaRao Puli         bool updateConfig = false;
690fe44eb0bSAyushi Smriti         bool updateRetryCfg = false;
6917d1cc387SAppaRao Puli 
69228afb49cSJunLin Chen         if (serviceEnabled != cfg.enabled)
6937d1cc387SAppaRao Puli         {
69428afb49cSJunLin Chen             serviceEnabled = cfg.enabled;
695e662eae8SEd Tanous             if (serviceEnabled && noOfMetricReportSubscribers != 0U)
6967d1cc387SAppaRao Puli             {
6977d1cc387SAppaRao Puli                 registerMetricReportSignal();
6987d1cc387SAppaRao Puli             }
6997d1cc387SAppaRao Puli             else
7007d1cc387SAppaRao Puli             {
7017d1cc387SAppaRao Puli                 unregisterMetricReportSignal();
7027d1cc387SAppaRao Puli             }
7037d1cc387SAppaRao Puli             updateConfig = true;
7047d1cc387SAppaRao Puli         }
7057d1cc387SAppaRao Puli 
70628afb49cSJunLin Chen         if (retryAttempts != cfg.retryAttempts)
7077d1cc387SAppaRao Puli         {
70828afb49cSJunLin Chen             retryAttempts = cfg.retryAttempts;
7097d1cc387SAppaRao Puli             updateConfig = true;
710fe44eb0bSAyushi Smriti             updateRetryCfg = true;
7117d1cc387SAppaRao Puli         }
7127d1cc387SAppaRao Puli 
71328afb49cSJunLin Chen         if (retryTimeoutInterval != cfg.retryTimeoutInterval)
7147d1cc387SAppaRao Puli         {
71528afb49cSJunLin Chen             retryTimeoutInterval = cfg.retryTimeoutInterval;
7167d1cc387SAppaRao Puli             updateConfig = true;
717fe44eb0bSAyushi Smriti             updateRetryCfg = true;
7187d1cc387SAppaRao Puli         }
7197d1cc387SAppaRao Puli 
7207d1cc387SAppaRao Puli         if (updateConfig)
7217d1cc387SAppaRao Puli         {
7227d1cc387SAppaRao Puli             updateSubscriptionData();
7237d1cc387SAppaRao Puli         }
724fe44eb0bSAyushi Smriti 
725fe44eb0bSAyushi Smriti         if (updateRetryCfg)
726fe44eb0bSAyushi Smriti         {
727fe44eb0bSAyushi Smriti             // Update the changed retry config to all subscriptions
728fe44eb0bSAyushi Smriti             for (const auto& it :
729fe44eb0bSAyushi Smriti                  EventServiceManager::getInstance().subscriptionsMap)
730fe44eb0bSAyushi Smriti             {
7315e44e3d8SAppaRao Puli                 Subscription& entry = *it.second;
7325e44e3d8SAppaRao Puli                 entry.updateRetryConfig(retryAttempts, retryTimeoutInterval);
733fe44eb0bSAyushi Smriti             }
734fe44eb0bSAyushi Smriti         }
7357d1cc387SAppaRao Puli     }
7367d1cc387SAppaRao Puli 
7377d1cc387SAppaRao Puli     void updateNoOfSubscribersCount()
7387d1cc387SAppaRao Puli     {
7397d1cc387SAppaRao Puli         size_t eventLogSubCount = 0;
7407d1cc387SAppaRao Puli         size_t metricReportSubCount = 0;
7417d1cc387SAppaRao Puli         for (const auto& it : subscriptionsMap)
7427d1cc387SAppaRao Puli         {
7437d1cc387SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
7444b712a29SEd Tanous             if (entry->userSub.eventFormatType == eventFormatType)
7457d1cc387SAppaRao Puli             {
7467d1cc387SAppaRao Puli                 eventLogSubCount++;
7477d1cc387SAppaRao Puli             }
7484b712a29SEd Tanous             else if (entry->userSub.eventFormatType == metricReportFormatType)
7497d1cc387SAppaRao Puli             {
7507d1cc387SAppaRao Puli                 metricReportSubCount++;
7517d1cc387SAppaRao Puli             }
7527d1cc387SAppaRao Puli         }
7537d1cc387SAppaRao Puli 
7547d1cc387SAppaRao Puli         noOfEventLogSubscribers = eventLogSubCount;
7557d1cc387SAppaRao Puli         if (noOfMetricReportSubscribers != metricReportSubCount)
7567d1cc387SAppaRao Puli         {
7577d1cc387SAppaRao Puli             noOfMetricReportSubscribers = metricReportSubCount;
758e662eae8SEd Tanous             if (noOfMetricReportSubscribers != 0U)
7597d1cc387SAppaRao Puli             {
7607d1cc387SAppaRao Puli                 registerMetricReportSignal();
7617d1cc387SAppaRao Puli             }
7627d1cc387SAppaRao Puli             else
7637d1cc387SAppaRao Puli             {
7647d1cc387SAppaRao Puli                 unregisterMetricReportSignal();
7657d1cc387SAppaRao Puli             }
7667d1cc387SAppaRao Puli         }
7677d1cc387SAppaRao Puli     }
7687d1cc387SAppaRao Puli 
769b52664e2SAppaRao Puli     std::shared_ptr<Subscription> getSubscription(const std::string& id)
770b52664e2SAppaRao Puli     {
771b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
772b52664e2SAppaRao Puli         if (obj == subscriptionsMap.end())
773b52664e2SAppaRao Puli         {
77462598e31SEd Tanous             BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id);
775b52664e2SAppaRao Puli             return nullptr;
776b52664e2SAppaRao Puli         }
777b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue = obj->second;
778b52664e2SAppaRao Puli         return subValue;
779b52664e2SAppaRao Puli     }
780b52664e2SAppaRao Puli 
781f80a87f2SEd Tanous     std::string
782f80a87f2SEd Tanous         addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue)
783b52664e2SAppaRao Puli     {
784fc76b8acSEd Tanous         std::uniform_int_distribution<uint32_t> dist(0);
785fc76b8acSEd Tanous         bmcweb::OpenSSLGenerator gen;
786fc76b8acSEd Tanous 
787b52664e2SAppaRao Puli         std::string id;
788b52664e2SAppaRao Puli 
789b52664e2SAppaRao Puli         int retry = 3;
790e662eae8SEd Tanous         while (retry != 0)
791b52664e2SAppaRao Puli         {
792fc76b8acSEd Tanous             id = std::to_string(dist(gen));
793fc76b8acSEd Tanous             if (gen.error())
794fc76b8acSEd Tanous             {
795fc76b8acSEd Tanous                 retry = 0;
796fc76b8acSEd Tanous                 break;
797fc76b8acSEd Tanous             }
798b52664e2SAppaRao Puli             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
799b52664e2SAppaRao Puli             if (inserted.second)
800b52664e2SAppaRao Puli             {
801b52664e2SAppaRao Puli                 break;
802b52664e2SAppaRao Puli             }
803b52664e2SAppaRao Puli             --retry;
80423a21a1cSEd Tanous         }
805b52664e2SAppaRao Puli 
806b52664e2SAppaRao Puli         if (retry <= 0)
807b52664e2SAppaRao Puli         {
80862598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to generate random number");
809abb93cddSEd Tanous             return "";
810b52664e2SAppaRao Puli         }
811b52664e2SAppaRao Puli 
8124b712a29SEd Tanous         persistent_data::UserSubscription newSub(subValue->userSub);
813a14c9113SEd Tanous 
81428afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
8154b712a29SEd Tanous             .subscriptionsConfigMap.emplace(newSub.id, newSub);
81628afb49cSJunLin Chen 
8177d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
8181bf712bcSAyushi Smriti 
81983328316SEd Tanous         if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
82083328316SEd Tanous         {
8212558979cSP Dheeraj Srujan Kumar             if (redfishLogFilePosition != 0)
8227f4eb588SAppaRao Puli             {
8232558979cSP Dheeraj Srujan Kumar                 cacheRedfishLogFile();
8247f4eb588SAppaRao Puli             }
82583328316SEd Tanous         }
826fe44eb0bSAyushi Smriti         // Update retry configuration.
827fe44eb0bSAyushi Smriti         subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
828fe44eb0bSAyushi Smriti 
8295e44e3d8SAppaRao Puli         // Set Subscription ID for back trace
8305e44e3d8SAppaRao Puli         subValue->setSubscriptionId(id);
831f80a87f2SEd Tanous 
832f80a87f2SEd Tanous         return id;
833f80a87f2SEd Tanous     }
834f80a87f2SEd Tanous 
835f80a87f2SEd Tanous     std::string
836f80a87f2SEd Tanous         addSSESubscription(const std::shared_ptr<Subscription>& subValue,
837f80a87f2SEd Tanous                            std::string_view lastEventId)
838f80a87f2SEd Tanous     {
839f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
840f80a87f2SEd Tanous 
841f80a87f2SEd Tanous         if (!lastEventId.empty())
842f80a87f2SEd Tanous         {
843f80a87f2SEd Tanous             BMCWEB_LOG_INFO("Attempting to find message for last id {}",
844f80a87f2SEd Tanous                             lastEventId);
845f80a87f2SEd Tanous             boost::circular_buffer<Event>::iterator lastEvent =
846f80a87f2SEd Tanous                 std::find_if(messages.begin(), messages.end(),
847f80a87f2SEd Tanous                              [&lastEventId](const Event& event) {
848f80a87f2SEd Tanous                                  return event.id == lastEventId;
849f80a87f2SEd Tanous                              });
850f80a87f2SEd Tanous             // Can't find a matching ID
851f80a87f2SEd Tanous             if (lastEvent == messages.end())
852f80a87f2SEd Tanous             {
853f80a87f2SEd Tanous                 nlohmann::json msg = messages::eventBufferExceeded();
854f80a87f2SEd Tanous                 // If the buffer overloaded, send all messages.
8556d799e14SEd Tanous                 subValue->sendEventToSubscriber(msg);
856f80a87f2SEd Tanous                 lastEvent = messages.begin();
857f80a87f2SEd Tanous             }
858f80a87f2SEd Tanous             else
859f80a87f2SEd Tanous             {
860f80a87f2SEd Tanous                 // Skip the last event the user already has
861f80a87f2SEd Tanous                 lastEvent++;
862f80a87f2SEd Tanous             }
863f80a87f2SEd Tanous 
864f80a87f2SEd Tanous             for (boost::circular_buffer<Event>::const_iterator event =
865f80a87f2SEd Tanous                      lastEvent;
866f80a87f2SEd Tanous                  lastEvent != messages.end(); lastEvent++)
867f80a87f2SEd Tanous             {
8686d799e14SEd Tanous                 subValue->sendEventToSubscriber(event->message);
869f80a87f2SEd Tanous             }
870f80a87f2SEd Tanous         }
871f80a87f2SEd Tanous         return id;
872f80a87f2SEd Tanous     }
873f80a87f2SEd Tanous 
874f80a87f2SEd Tanous     std::string
875f80a87f2SEd Tanous         addPushSubscription(const std::shared_ptr<Subscription>& subValue)
876f80a87f2SEd Tanous     {
877f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
878f80a87f2SEd Tanous 
879f80a87f2SEd Tanous         updateSubscriptionData();
880b52664e2SAppaRao Puli         return id;
881b52664e2SAppaRao Puli     }
882b52664e2SAppaRao Puli 
883b52664e2SAppaRao Puli     bool isSubscriptionExist(const std::string& id)
884b52664e2SAppaRao Puli     {
885b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
88655f79e6fSEd Tanous         return obj != subscriptionsMap.end();
887b52664e2SAppaRao Puli     }
888b52664e2SAppaRao Puli 
8894b712a29SEd Tanous     bool deleteSubscription(const std::string& id)
890b52664e2SAppaRao Puli     {
891b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
8924b712a29SEd Tanous         if (obj == subscriptionsMap.end())
893b52664e2SAppaRao Puli         {
8944b712a29SEd Tanous             BMCWEB_LOG_WARNING("Could not find subscription with id {}", id);
8954b712a29SEd Tanous             return false;
8964b712a29SEd Tanous         }
897b52664e2SAppaRao Puli         subscriptionsMap.erase(obj);
8984b712a29SEd Tanous         auto& event = persistent_data::EventServiceStore::getInstance();
8994b712a29SEd Tanous         auto persistentObj = event.subscriptionsConfigMap.find(id);
9004b712a29SEd Tanous         if (persistentObj == event.subscriptionsConfigMap.end())
9014b712a29SEd Tanous         {
9024b712a29SEd Tanous             BMCWEB_LOG_ERROR("Subscription wasn't in persistent data");
9034b712a29SEd Tanous             return true;
9044b712a29SEd Tanous         }
90528afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
9064b712a29SEd Tanous             .subscriptionsConfigMap.erase(persistentObj);
9077d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
908b52664e2SAppaRao Puli         updateSubscriptionData();
9094b712a29SEd Tanous 
9104b712a29SEd Tanous         return true;
911b52664e2SAppaRao Puli     }
912b52664e2SAppaRao Puli 
9135e44e3d8SAppaRao Puli     void deleteSseSubscription(const crow::sse_socket::Connection& thisConn)
9145e44e3d8SAppaRao Puli     {
915bdbfae2aSEd Tanous         for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();)
9165e44e3d8SAppaRao Puli         {
917bdbfae2aSEd Tanous             std::shared_ptr<Subscription> entry = it->second;
9185e44e3d8SAppaRao Puli             bool entryIsThisConn = entry->matchSseId(thisConn);
9195e44e3d8SAppaRao Puli             if (entryIsThisConn)
9205e44e3d8SAppaRao Puli             {
9215e44e3d8SAppaRao Puli                 persistent_data::EventServiceStore::getInstance()
9225e44e3d8SAppaRao Puli                     .subscriptionsConfigMap.erase(
923bdbfae2aSEd Tanous                         it->second->getSubscriptionId());
924bdbfae2aSEd Tanous                 it = subscriptionsMap.erase(it);
9255e44e3d8SAppaRao Puli                 return;
9265e44e3d8SAppaRao Puli             }
927bdbfae2aSEd Tanous             it++;
9285e44e3d8SAppaRao Puli         }
9295e44e3d8SAppaRao Puli     }
9305e44e3d8SAppaRao Puli 
9315e44e3d8SAppaRao Puli     size_t getNumberOfSubscriptions() const
932b52664e2SAppaRao Puli     {
933b52664e2SAppaRao Puli         return subscriptionsMap.size();
934b52664e2SAppaRao Puli     }
935b52664e2SAppaRao Puli 
9365e44e3d8SAppaRao Puli     size_t getNumberOfSSESubscriptions() const
9375e44e3d8SAppaRao Puli     {
9383544d2a7SEd Tanous         auto size = std::ranges::count_if(
9393544d2a7SEd Tanous             subscriptionsMap,
9405e44e3d8SAppaRao Puli             [](const std::pair<std::string, std::shared_ptr<Subscription>>&
9415e44e3d8SAppaRao Puli                    entry) {
9424b712a29SEd Tanous                 return (entry.second->userSub.subscriptionType ==
9434b712a29SEd Tanous                         subscriptionTypeSSE);
9445e44e3d8SAppaRao Puli             });
9455e44e3d8SAppaRao Puli         return static_cast<size_t>(size);
9465e44e3d8SAppaRao Puli     }
9475e44e3d8SAppaRao Puli 
948b52664e2SAppaRao Puli     std::vector<std::string> getAllIDs()
949b52664e2SAppaRao Puli     {
950b52664e2SAppaRao Puli         std::vector<std::string> idList;
951b52664e2SAppaRao Puli         for (const auto& it : subscriptionsMap)
952b52664e2SAppaRao Puli         {
953b52664e2SAppaRao Puli             idList.emplace_back(it.first);
954b52664e2SAppaRao Puli         }
955b52664e2SAppaRao Puli         return idList;
956b52664e2SAppaRao Puli     }
957b52664e2SAppaRao Puli 
9586ba8c82eSsunharis_in     bool sendTestEventLog()
9590b4bdd93SAppaRao Puli     {
9605e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
9610b4bdd93SAppaRao Puli         {
9620b4bdd93SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
9636ba8c82eSsunharis_in             if (!entry->sendTestEventLog())
9646ba8c82eSsunharis_in             {
9656ba8c82eSsunharis_in                 return false;
9660b4bdd93SAppaRao Puli             }
9670b4bdd93SAppaRao Puli         }
9686ba8c82eSsunharis_in         return true;
9696ba8c82eSsunharis_in     }
970e9a14131SAppaRao Puli 
971f80a87f2SEd Tanous     void sendEvent(nlohmann::json::object_t eventMessage,
972f80a87f2SEd Tanous                    std::string_view origin, std::string_view resourceType)
97396330b99SSunitha Harish     {
974613dabeaSEd Tanous         eventMessage["EventId"] = eventId;
975f80a87f2SEd Tanous 
976613dabeaSEd Tanous         eventMessage["EventTimestamp"] =
977613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
978613dabeaSEd Tanous         eventMessage["OriginOfCondition"] = origin;
979613dabeaSEd Tanous 
980f80a87f2SEd Tanous         // MemberId is 0 : since we are sending one event record.
981f80a87f2SEd Tanous         eventMessage["MemberId"] = 0;
98296330b99SSunitha Harish 
983f80a87f2SEd Tanous         messages.push_back(Event(std::to_string(eventId), eventMessage));
984f80a87f2SEd Tanous 
985f80a87f2SEd Tanous         for (auto& it : subscriptionsMap)
98696330b99SSunitha Harish         {
987f80a87f2SEd Tanous             std::shared_ptr<Subscription>& entry = it.second;
988d3a48a14SEd Tanous             if (!eventMatchesFilter(entry->userSub, eventMessage, resourceType))
98996330b99SSunitha Harish             {
990f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Filter didn't match");
991f80a87f2SEd Tanous                 continue;
99296330b99SSunitha Harish             }
993f80a87f2SEd Tanous 
994f80a87f2SEd Tanous             nlohmann::json::array_t eventRecord;
995f80a87f2SEd Tanous             eventRecord.emplace_back(eventMessage);
996f80a87f2SEd Tanous 
997613dabeaSEd Tanous             nlohmann::json msgJson;
998613dabeaSEd Tanous 
999613dabeaSEd Tanous             msgJson["@odata.type"] = "#Event.v1_4_0.Event";
1000613dabeaSEd Tanous             msgJson["Name"] = "Event Log";
1001613dabeaSEd Tanous             msgJson["Id"] = eventId;
1002f80a87f2SEd Tanous             msgJson["Events"] = std::move(eventRecord);
1003f52c03c1SCarson Labrado 
1004f52c03c1SCarson Labrado             std::string strMsg = msgJson.dump(
1005f52c03c1SCarson Labrado                 2, ' ', true, nlohmann::json::error_handler_t::replace);
10066d799e14SEd Tanous             entry->sendEventToSubscriber(std::move(strMsg));
10078ece0e45SEd Tanous             eventId++; // increment the eventId
100896330b99SSunitha Harish         }
100996330b99SSunitha Harish     }
101096330b99SSunitha Harish 
10112558979cSP Dheeraj Srujan Kumar     void resetRedfishFilePosition()
10127f4eb588SAppaRao Puli     {
10132558979cSP Dheeraj Srujan Kumar         // Control would be here when Redfish file is created.
10142558979cSP Dheeraj Srujan Kumar         // Reset File Position as new file is created
10152558979cSP Dheeraj Srujan Kumar         redfishLogFilePosition = 0;
10162558979cSP Dheeraj Srujan Kumar     }
10172558979cSP Dheeraj Srujan Kumar 
10182558979cSP Dheeraj Srujan Kumar     void cacheRedfishLogFile()
10192558979cSP Dheeraj Srujan Kumar     {
10202558979cSP Dheeraj Srujan Kumar         // Open the redfish file and read till the last record.
10212558979cSP Dheeraj Srujan Kumar 
10227f4eb588SAppaRao Puli         std::ifstream logStream(redfishEventLogFile);
10237f4eb588SAppaRao Puli         if (!logStream.good())
10247f4eb588SAppaRao Puli         {
102562598e31SEd Tanous             BMCWEB_LOG_ERROR(" Redfish log file open failed ");
10267f4eb588SAppaRao Puli             return;
10277f4eb588SAppaRao Puli         }
10287f4eb588SAppaRao Puli         std::string logEntry;
10297f4eb588SAppaRao Puli         while (std::getline(logStream, logEntry))
10307f4eb588SAppaRao Puli         {
10312558979cSP Dheeraj Srujan Kumar             redfishLogFilePosition = logStream.tellg();
10327f4eb588SAppaRao Puli         }
10337f4eb588SAppaRao Puli     }
10347f4eb588SAppaRao Puli 
10357f4eb588SAppaRao Puli     void readEventLogsFromFile()
10367f4eb588SAppaRao Puli     {
10377f4eb588SAppaRao Puli         std::ifstream logStream(redfishEventLogFile);
10387f4eb588SAppaRao Puli         if (!logStream.good())
10397f4eb588SAppaRao Puli         {
104062598e31SEd Tanous             BMCWEB_LOG_ERROR(" Redfish log file open failed");
10417f4eb588SAppaRao Puli             return;
10427f4eb588SAppaRao Puli         }
10437f4eb588SAppaRao Puli 
10447f4eb588SAppaRao Puli         std::vector<EventLogObjectsType> eventRecords;
10457f4eb588SAppaRao Puli 
10467f4eb588SAppaRao Puli         std::string logEntry;
10472558979cSP Dheeraj Srujan Kumar 
104803d4d37cSAlexander Hansen         BMCWEB_LOG_DEBUG("Redfish log file: seek to {}",
104903d4d37cSAlexander Hansen                          static_cast<int>(redfishLogFilePosition));
105003d4d37cSAlexander Hansen 
10512558979cSP Dheeraj Srujan Kumar         // Get the read pointer to the next log to be read.
10522558979cSP Dheeraj Srujan Kumar         logStream.seekg(redfishLogFilePosition);
10532558979cSP Dheeraj Srujan Kumar 
10547f4eb588SAppaRao Puli         while (std::getline(logStream, logEntry))
10557f4eb588SAppaRao Puli         {
105603d4d37cSAlexander Hansen             BMCWEB_LOG_DEBUG("Redfish log file: found new event log entry");
10572558979cSP Dheeraj Srujan Kumar             // Update Pointer position
10582558979cSP Dheeraj Srujan Kumar             redfishLogFilePosition = logStream.tellg();
10592558979cSP Dheeraj Srujan Kumar 
10602558979cSP Dheeraj Srujan Kumar             std::string idStr;
10612558979cSP Dheeraj Srujan Kumar             if (!event_log::getUniqueEntryID(logEntry, idStr))
10627f4eb588SAppaRao Puli             {
106303d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG(
106403d4d37cSAlexander Hansen                     "Redfish log file: could not get unique entry id for {}",
106503d4d37cSAlexander Hansen                     logEntry);
10667f4eb588SAppaRao Puli                 continue;
10677f4eb588SAppaRao Puli             }
10687f4eb588SAppaRao Puli 
1069e662eae8SEd Tanous             if (!serviceEnabled || noOfEventLogSubscribers == 0)
10707f4eb588SAppaRao Puli             {
10712558979cSP Dheeraj Srujan Kumar                 // If Service is not enabled, no need to compute
10722558979cSP Dheeraj Srujan Kumar                 // the remaining items below.
10732558979cSP Dheeraj Srujan Kumar                 // But, Loop must continue to keep track of Timestamp
107403d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG(
107503d4d37cSAlexander Hansen                     "Redfish log file: no subscribers / event service not enabled");
10767f4eb588SAppaRao Puli                 continue;
10777f4eb588SAppaRao Puli             }
10787f4eb588SAppaRao Puli 
10797f4eb588SAppaRao Puli             std::string timestamp;
10807f4eb588SAppaRao Puli             std::string messageID;
10815e715de6SAppaRao Puli             std::vector<std::string> messageArgs;
10827f4eb588SAppaRao Puli             if (event_log::getEventLogParams(logEntry, timestamp, messageID,
10837f4eb588SAppaRao Puli                                              messageArgs) != 0)
10847f4eb588SAppaRao Puli             {
108503d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("Read eventLog entry params failed for {}",
108603d4d37cSAlexander Hansen                                  logEntry);
10877f4eb588SAppaRao Puli                 continue;
10887f4eb588SAppaRao Puli             }
10897f4eb588SAppaRao Puli 
1090f80a87f2SEd Tanous             eventRecords.emplace_back(idStr, timestamp, messageID, messageArgs);
10917f4eb588SAppaRao Puli         }
10927f4eb588SAppaRao Puli 
1093e662eae8SEd Tanous         if (!serviceEnabled || noOfEventLogSubscribers == 0)
10942558979cSP Dheeraj Srujan Kumar         {
109562598e31SEd Tanous             BMCWEB_LOG_DEBUG("EventService disabled or no Subscriptions.");
10962558979cSP Dheeraj Srujan Kumar             return;
10972558979cSP Dheeraj Srujan Kumar         }
10982558979cSP Dheeraj Srujan Kumar 
10992558979cSP Dheeraj Srujan Kumar         if (eventRecords.empty())
11002558979cSP Dheeraj Srujan Kumar         {
11012558979cSP Dheeraj Srujan Kumar             // No Records to send
110262598e31SEd Tanous             BMCWEB_LOG_DEBUG("No log entries available to be transferred.");
11032558979cSP Dheeraj Srujan Kumar             return;
11042558979cSP Dheeraj Srujan Kumar         }
11052558979cSP Dheeraj Srujan Kumar 
11065e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
11077f4eb588SAppaRao Puli         {
11087f4eb588SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
11094b712a29SEd Tanous             if (entry->userSub.eventFormatType == "Event")
11107f4eb588SAppaRao Puli             {
11117f4eb588SAppaRao Puli                 entry->filterAndSendEventLogs(eventRecords);
11127f4eb588SAppaRao Puli             }
11137f4eb588SAppaRao Puli         }
11147f4eb588SAppaRao Puli     }
11157f4eb588SAppaRao Puli 
11167f4eb588SAppaRao Puli     static void watchRedfishEventLogFile()
11177f4eb588SAppaRao Puli     {
11186a9f85f9SAppaRao Puli         if (!inotifyConn)
11197f4eb588SAppaRao Puli         {
112003d4d37cSAlexander Hansen             BMCWEB_LOG_ERROR("inotify Connection is not present");
11217f4eb588SAppaRao Puli             return;
11227f4eb588SAppaRao Puli         }
11237f4eb588SAppaRao Puli 
11247f4eb588SAppaRao Puli         static std::array<char, 1024> readBuffer;
11257f4eb588SAppaRao Puli 
1126bd79bce8SPatrick Williams         inotifyConn->async_read_some(
1127bd79bce8SPatrick Williams             boost::asio::buffer(readBuffer),
11287f4eb588SAppaRao Puli             [&](const boost::system::error_code& ec,
11297f4eb588SAppaRao Puli                 const std::size_t& bytesTransferred) {
11309ed3f90aSEd Tanous                 if (ec == boost::asio::error::operation_aborted)
11319ed3f90aSEd Tanous                 {
11329ed3f90aSEd Tanous                     BMCWEB_LOG_DEBUG("Inotify was canceled (shutdown?)");
11339ed3f90aSEd Tanous                     return;
11349ed3f90aSEd Tanous                 }
11357f4eb588SAppaRao Puli                 if (ec)
11367f4eb588SAppaRao Puli                 {
113762598e31SEd Tanous                     BMCWEB_LOG_ERROR("Callback Error: {}", ec.message());
11387f4eb588SAppaRao Puli                     return;
11397f4eb588SAppaRao Puli                 }
114003d4d37cSAlexander Hansen 
114103d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("reading {} via inotify", bytesTransferred);
114203d4d37cSAlexander Hansen 
11437f4eb588SAppaRao Puli                 std::size_t index = 0;
1144b792cc56SAppaRao Puli                 while ((index + iEventSize) <= bytesTransferred)
11457f4eb588SAppaRao Puli                 {
1146d3a9e084SEd Tanous                     struct inotify_event event
1147d3a9e084SEd Tanous                     {};
1148b792cc56SAppaRao Puli                     std::memcpy(&event, &readBuffer[index], iEventSize);
1149b792cc56SAppaRao Puli                     if (event.wd == dirWatchDesc)
1150b792cc56SAppaRao Puli                     {
1151b792cc56SAppaRao Puli                         if ((event.len == 0) ||
1152b792cc56SAppaRao Puli                             (index + iEventSize + event.len > bytesTransferred))
1153b792cc56SAppaRao Puli                         {
1154b792cc56SAppaRao Puli                             index += (iEventSize + event.len);
1155b792cc56SAppaRao Puli                             continue;
1156b792cc56SAppaRao Puli                         }
1157b792cc56SAppaRao Puli 
11584f568f74SJiaqing Zhao                         std::string fileName(&readBuffer[index + iEventSize]);
11594f568f74SJiaqing Zhao                         if (fileName != "redfish")
1160b792cc56SAppaRao Puli                         {
1161b792cc56SAppaRao Puli                             index += (iEventSize + event.len);
1162b792cc56SAppaRao Puli                             continue;
1163b792cc56SAppaRao Puli                         }
1164b792cc56SAppaRao Puli 
116562598e31SEd Tanous                         BMCWEB_LOG_DEBUG(
116662598e31SEd Tanous                             "Redfish log file created/deleted. event.name: {}",
116762598e31SEd Tanous                             fileName);
1168b792cc56SAppaRao Puli                         if (event.mask == IN_CREATE)
1169b792cc56SAppaRao Puli                         {
1170b792cc56SAppaRao Puli                             if (fileWatchDesc != -1)
1171b792cc56SAppaRao Puli                             {
117262598e31SEd Tanous                                 BMCWEB_LOG_DEBUG(
117362598e31SEd Tanous                                     "Remove and Add inotify watcher on "
117462598e31SEd Tanous                                     "redfish event log file");
1175016761afSAppaRao Puli                                 // Remove existing inotify watcher and add
1176016761afSAppaRao Puli                                 // with new redfish event log file.
1177016761afSAppaRao Puli                                 inotify_rm_watch(inotifyFd, fileWatchDesc);
1178016761afSAppaRao Puli                                 fileWatchDesc = -1;
1179b792cc56SAppaRao Puli                             }
1180b792cc56SAppaRao Puli 
1181b792cc56SAppaRao Puli                             fileWatchDesc = inotify_add_watch(
1182b792cc56SAppaRao Puli                                 inotifyFd, redfishEventLogFile, IN_MODIFY);
1183b792cc56SAppaRao Puli                             if (fileWatchDesc == -1)
1184b792cc56SAppaRao Puli                             {
118562598e31SEd Tanous                                 BMCWEB_LOG_ERROR("inotify_add_watch failed for "
118662598e31SEd Tanous                                                  "redfish log file.");
1187b792cc56SAppaRao Puli                                 return;
1188b792cc56SAppaRao Puli                             }
1189b792cc56SAppaRao Puli 
1190b792cc56SAppaRao Puli                             EventServiceManager::getInstance()
11912558979cSP Dheeraj Srujan Kumar                                 .resetRedfishFilePosition();
1192b792cc56SAppaRao Puli                             EventServiceManager::getInstance()
1193b792cc56SAppaRao Puli                                 .readEventLogsFromFile();
1194b792cc56SAppaRao Puli                         }
1195b792cc56SAppaRao Puli                         else if ((event.mask == IN_DELETE) ||
1196b792cc56SAppaRao Puli                                  (event.mask == IN_MOVED_TO))
1197b792cc56SAppaRao Puli                         {
1198b792cc56SAppaRao Puli                             if (fileWatchDesc != -1)
1199b792cc56SAppaRao Puli                             {
1200b792cc56SAppaRao Puli                                 inotify_rm_watch(inotifyFd, fileWatchDesc);
1201b792cc56SAppaRao Puli                                 fileWatchDesc = -1;
1202b792cc56SAppaRao Puli                             }
1203b792cc56SAppaRao Puli                         }
1204b792cc56SAppaRao Puli                     }
1205b792cc56SAppaRao Puli                     else if (event.wd == fileWatchDesc)
1206b792cc56SAppaRao Puli                     {
1207b792cc56SAppaRao Puli                         if (event.mask == IN_MODIFY)
12087f4eb588SAppaRao Puli                         {
12097f4eb588SAppaRao Puli                             EventServiceManager::getInstance()
12107f4eb588SAppaRao Puli                                 .readEventLogsFromFile();
12117f4eb588SAppaRao Puli                         }
1212b792cc56SAppaRao Puli                     }
1213b792cc56SAppaRao Puli                     index += (iEventSize + event.len);
12147f4eb588SAppaRao Puli                 }
12157f4eb588SAppaRao Puli 
12167f4eb588SAppaRao Puli                 watchRedfishEventLogFile();
12177f4eb588SAppaRao Puli             });
12187f4eb588SAppaRao Puli     }
12197f4eb588SAppaRao Puli 
12207f4eb588SAppaRao Puli     static int startEventLogMonitor(boost::asio::io_context& ioc)
12217f4eb588SAppaRao Puli     {
122203d4d37cSAlexander Hansen         BMCWEB_LOG_DEBUG("starting Event Log Monitor");
122303d4d37cSAlexander Hansen 
122423a21a1cSEd Tanous         inotifyConn.emplace(ioc);
1225b792cc56SAppaRao Puli         inotifyFd = inotify_init1(IN_NONBLOCK);
1226b792cc56SAppaRao Puli         if (inotifyFd == -1)
12277f4eb588SAppaRao Puli         {
122862598e31SEd Tanous             BMCWEB_LOG_ERROR("inotify_init1 failed.");
12297f4eb588SAppaRao Puli             return -1;
12307f4eb588SAppaRao Puli         }
1231b792cc56SAppaRao Puli 
1232b792cc56SAppaRao Puli         // Add watch on directory to handle redfish event log file
1233b792cc56SAppaRao Puli         // create/delete.
1234b792cc56SAppaRao Puli         dirWatchDesc = inotify_add_watch(inotifyFd, redfishEventLogDir,
1235b792cc56SAppaRao Puli                                          IN_CREATE | IN_MOVED_TO | IN_DELETE);
1236b792cc56SAppaRao Puli         if (dirWatchDesc == -1)
12377f4eb588SAppaRao Puli         {
123862598e31SEd Tanous             BMCWEB_LOG_ERROR(
123962598e31SEd Tanous                 "inotify_add_watch failed for event log directory.");
12407f4eb588SAppaRao Puli             return -1;
12417f4eb588SAppaRao Puli         }
12427f4eb588SAppaRao Puli 
1243b792cc56SAppaRao Puli         // Watch redfish event log file for modifications.
1244bd79bce8SPatrick Williams         fileWatchDesc =
1245bd79bce8SPatrick Williams             inotify_add_watch(inotifyFd, redfishEventLogFile, IN_MODIFY);
1246b792cc56SAppaRao Puli         if (fileWatchDesc == -1)
1247b792cc56SAppaRao Puli         {
124862598e31SEd Tanous             BMCWEB_LOG_ERROR("inotify_add_watch failed for redfish log file.");
1249b792cc56SAppaRao Puli             // Don't return error if file not exist.
1250b792cc56SAppaRao Puli             // Watch on directory will handle create/delete of file.
1251b792cc56SAppaRao Puli         }
1252b792cc56SAppaRao Puli 
12537f4eb588SAppaRao Puli         // monitor redfish event log file
1254b792cc56SAppaRao Puli         inotifyConn->assign(inotifyFd);
12557f4eb588SAppaRao Puli         watchRedfishEventLogFile();
12567f4eb588SAppaRao Puli 
12577f4eb588SAppaRao Puli         return 0;
12587f4eb588SAppaRao Puli     }
12597f4eb588SAppaRao Puli 
12609ed3f90aSEd Tanous     static void stopEventLogMonitor()
12619ed3f90aSEd Tanous     {
12629ed3f90aSEd Tanous         inotifyConn.reset();
12639ed3f90aSEd Tanous     }
12649ed3f90aSEd Tanous 
126559d494eeSPatrick Williams     static void getReadingsForReport(sdbusplus::message_t& msg)
1266156d6b00SAppaRao Puli     {
126756d2396dSEd Tanous         if (msg.is_method_error())
126856d2396dSEd Tanous         {
126962598e31SEd Tanous             BMCWEB_LOG_ERROR("TelemetryMonitor Signal error");
127056d2396dSEd Tanous             return;
127156d2396dSEd Tanous         }
127256d2396dSEd Tanous 
1273c0353249SWludzik, Jozef         sdbusplus::message::object_path path(msg.get_path());
1274c0353249SWludzik, Jozef         std::string id = path.filename();
1275c0353249SWludzik, Jozef         if (id.empty())
1276156d6b00SAppaRao Puli         {
127762598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to get Id from path");
1278156d6b00SAppaRao Puli             return;
1279156d6b00SAppaRao Puli         }
1280156d6b00SAppaRao Puli 
1281c0353249SWludzik, Jozef         std::string interface;
1282b9d36b47SEd Tanous         dbus::utility::DBusPropertiesMap props;
1283c0353249SWludzik, Jozef         std::vector<std::string> invalidProps;
1284c0353249SWludzik, Jozef         msg.read(interface, props, invalidProps);
1285c0353249SWludzik, Jozef 
1286bd79bce8SPatrick Williams         auto found = std::ranges::find_if(props, [](const auto& x) {
1287bd79bce8SPatrick Williams             return x.first == "Readings";
1288bd79bce8SPatrick Williams         });
1289c0353249SWludzik, Jozef         if (found == props.end())
1290156d6b00SAppaRao Puli         {
129162598e31SEd Tanous             BMCWEB_LOG_INFO("Failed to get Readings from Report properties");
1292156d6b00SAppaRao Puli             return;
1293156d6b00SAppaRao Puli         }
1294156d6b00SAppaRao Puli 
12951e1e598dSJonathan Doman         const telemetry::TimestampReadings* readings =
12961e1e598dSJonathan Doman             std::get_if<telemetry::TimestampReadings>(&found->second);
1297e662eae8SEd Tanous         if (readings == nullptr)
12981e1e598dSJonathan Doman         {
129962598e31SEd Tanous             BMCWEB_LOG_INFO("Failed to get Readings from Report properties");
13001e1e598dSJonathan Doman             return;
13011e1e598dSJonathan Doman         }
13021e1e598dSJonathan Doman 
1303156d6b00SAppaRao Puli         for (const auto& it :
1304156d6b00SAppaRao Puli              EventServiceManager::getInstance().subscriptionsMap)
1305156d6b00SAppaRao Puli         {
1306e05aec50SEd Tanous             Subscription& entry = *it.second;
13074b712a29SEd Tanous             if (entry.userSub.eventFormatType == metricReportFormatType)
1308156d6b00SAppaRao Puli             {
13091e1e598dSJonathan Doman                 entry.filterAndSendReports(id, *readings);
1310156d6b00SAppaRao Puli             }
1311156d6b00SAppaRao Puli         }
1312156d6b00SAppaRao Puli     }
1313156d6b00SAppaRao Puli 
1314156d6b00SAppaRao Puli     void unregisterMetricReportSignal()
1315156d6b00SAppaRao Puli     {
13167d1cc387SAppaRao Puli         if (matchTelemetryMonitor)
13177d1cc387SAppaRao Puli         {
131862598e31SEd Tanous             BMCWEB_LOG_DEBUG("Metrics report signal - Unregister");
1319156d6b00SAppaRao Puli             matchTelemetryMonitor.reset();
1320156d6b00SAppaRao Puli             matchTelemetryMonitor = nullptr;
1321156d6b00SAppaRao Puli         }
13227d1cc387SAppaRao Puli     }
1323156d6b00SAppaRao Puli 
1324156d6b00SAppaRao Puli     void registerMetricReportSignal()
1325156d6b00SAppaRao Puli     {
13267d1cc387SAppaRao Puli         if (!serviceEnabled || matchTelemetryMonitor)
1327156d6b00SAppaRao Puli         {
132862598e31SEd Tanous             BMCWEB_LOG_DEBUG("Not registering metric report signal.");
1329156d6b00SAppaRao Puli             return;
1330156d6b00SAppaRao Puli         }
1331156d6b00SAppaRao Puli 
133262598e31SEd Tanous         BMCWEB_LOG_DEBUG("Metrics report signal - Register");
1333c0353249SWludzik, Jozef         std::string matchStr = "type='signal',member='PropertiesChanged',"
1334c0353249SWludzik, Jozef                                "interface='org.freedesktop.DBus.Properties',"
1335c0353249SWludzik, Jozef                                "arg0=xyz.openbmc_project.Telemetry.Report";
1336156d6b00SAppaRao Puli 
133759d494eeSPatrick Williams         matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match_t>(
133856d2396dSEd Tanous             *crow::connections::systemBus, matchStr, getReadingsForReport);
1339156d6b00SAppaRao Puli     }
134023a21a1cSEd Tanous };
1341b52664e2SAppaRao Puli 
1342b52664e2SAppaRao Puli } // namespace redfish
1343