xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision b80ba2e4b0aad093f27d05fabc1cee1fac650d57)
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"
19*b80ba2e4SAlexander Hansen #include "event_log.hpp"
20d3a48a14SEd Tanous #include "event_matches_filter.hpp"
213ccb3adbSEd Tanous #include "event_service_store.hpp"
22c0353249SWludzik, Jozef #include "metric_report.hpp"
232c6ffdb0SEd Tanous #include "ossl_random.hpp"
243ccb3adbSEd Tanous #include "persistent_data.hpp"
257f4eb588SAppaRao Puli #include "registries.hpp"
268dab0f58SEd Tanous #include "registries_selector.hpp"
2750ebd4afSEd Tanous #include "str_utility.hpp"
2802c1e29fSAlexander Hansen #include "subscription.hpp"
295b90429aSEd Tanous #include "utils/time_utils.hpp"
307f4eb588SAppaRao Puli 
317f4eb588SAppaRao Puli #include <sys/inotify.h>
32b52664e2SAppaRao Puli 
33fb4fd5d4SZhenfei Tai #include <boost/asio/io_context.hpp>
34f80a87f2SEd Tanous #include <boost/circular_buffer.hpp>
35b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp>
36ef4c65b7SEd Tanous #include <boost/url/format.hpp>
374a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp>
38b5b40605Snitroglycerine #include <sdbusplus/bus/match.hpp>
391214b7e7SGunnar Mills 
405e44e3d8SAppaRao Puli #include <algorithm>
41b52664e2SAppaRao Puli #include <cstdlib>
42b52664e2SAppaRao Puli #include <ctime>
43a14c9113SEd Tanous #include <format>
441bf712bcSAyushi Smriti #include <fstream>
45b52664e2SAppaRao Puli #include <memory>
4626702d01SEd Tanous #include <span>
47a14c9113SEd Tanous #include <string>
4856ba386dSMyung Bae #include <string_view>
495fe4ef35SMyung Bae #include <utility>
50b52664e2SAppaRao Puli 
51b52664e2SAppaRao Puli namespace redfish
52b52664e2SAppaRao Puli {
53156d6b00SAppaRao Puli 
54156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event";
55156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport";
56156d6b00SAppaRao Puli 
571bf712bcSAyushi Smriti static constexpr const char* eventServiceFile =
581bf712bcSAyushi Smriti     "/var/lib/bmcweb/eventservice_config.json";
591bf712bcSAyushi Smriti 
60cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
614642bf8fSGeorge Liu static std::optional<boost::asio::posix::stream_descriptor> inotifyConn;
624642bf8fSGeorge Liu static constexpr const char* redfishEventLogDir = "/var/log";
634642bf8fSGeorge Liu static constexpr const char* redfishEventLogFile = "/var/log/redfish";
644642bf8fSGeorge Liu static constexpr const size_t iEventSize = sizeof(inotify_event);
65cf9e417dSEd Tanous 
66cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
674642bf8fSGeorge Liu static int inotifyFd = -1;
68cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
694642bf8fSGeorge Liu static int dirWatchDesc = -1;
70cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
714642bf8fSGeorge Liu static int fileWatchDesc = -1;
724642bf8fSGeorge Liu 
73fffb8c1fSEd Tanous namespace registries
744642bf8fSGeorge Liu {
75*b80ba2e4SAlexander Hansen inline const Message*
767f4eb588SAppaRao Puli     getMsgFromRegistry(const std::string& messageKey,
7726702d01SEd Tanous                        const std::span<const MessageEntry>& registry)
787f4eb588SAppaRao Puli {
793544d2a7SEd Tanous     std::span<const MessageEntry>::iterator messageIt = std::ranges::find_if(
803544d2a7SEd Tanous         registry, [&messageKey](const MessageEntry& messageEntry) {
8155f79e6fSEd Tanous             return messageKey == messageEntry.first;
827f4eb588SAppaRao Puli         });
8326702d01SEd Tanous     if (messageIt != registry.end())
847f4eb588SAppaRao Puli     {
857f4eb588SAppaRao Puli         return &messageIt->second;
867f4eb588SAppaRao Puli     }
877f4eb588SAppaRao Puli 
887f4eb588SAppaRao Puli     return nullptr;
897f4eb588SAppaRao Puli }
907f4eb588SAppaRao Puli 
91*b80ba2e4SAlexander Hansen inline const Message* formatMessage(std::string_view messageID)
927f4eb588SAppaRao Puli {
937f4eb588SAppaRao Puli     // Redfish MessageIds are in the form
947f4eb588SAppaRao Puli     // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find
957f4eb588SAppaRao Puli     // the right Message
967f4eb588SAppaRao Puli     std::vector<std::string> fields;
977f4eb588SAppaRao Puli     fields.reserve(4);
9850ebd4afSEd Tanous 
9950ebd4afSEd Tanous     bmcweb::split(fields, messageID, '.');
1007f4eb588SAppaRao Puli     if (fields.size() != 4)
1017f4eb588SAppaRao Puli     {
1027f4eb588SAppaRao Puli         return nullptr;
1037f4eb588SAppaRao Puli     }
10402cad96eSEd Tanous     const std::string& registryName = fields[0];
10502cad96eSEd Tanous     const std::string& messageKey = fields[3];
1067f4eb588SAppaRao Puli 
1077f4eb588SAppaRao Puli     // Find the right registry and check it for the MessageKey
108b304bd79SP Dheeraj Srujan Kumar     return getMsgFromRegistry(messageKey, getRegistryFromPrefix(registryName));
1097f4eb588SAppaRao Puli }
110fffb8c1fSEd Tanous } // namespace registries
1117f4eb588SAppaRao Puli 
112b52664e2SAppaRao Puli class EventServiceManager
113b52664e2SAppaRao Puli {
114b52664e2SAppaRao Puli   private:
115d3a9e084SEd Tanous     bool serviceEnabled = false;
116d3a9e084SEd Tanous     uint32_t retryAttempts = 0;
117d3a9e084SEd Tanous     uint32_t retryTimeoutInterval = 0;
1187d1cc387SAppaRao Puli 
1192558979cSP Dheeraj Srujan Kumar     std::streampos redfishLogFilePosition{0};
1209f616dd1SEd Tanous     size_t noOfEventLogSubscribers{0};
1219f616dd1SEd Tanous     size_t noOfMetricReportSubscribers{0};
12259d494eeSPatrick Williams     std::shared_ptr<sdbusplus::bus::match_t> matchTelemetryMonitor;
123b52664e2SAppaRao Puli     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
124b52664e2SAppaRao Puli         subscriptionsMap;
125b52664e2SAppaRao Puli 
1269f616dd1SEd Tanous     uint64_t eventId{1};
12796330b99SSunitha Harish 
128f80a87f2SEd Tanous     struct Event
129f80a87f2SEd Tanous     {
130f80a87f2SEd Tanous         std::string id;
131f80a87f2SEd Tanous         nlohmann::json message;
132f80a87f2SEd Tanous     };
133f80a87f2SEd Tanous 
134f80a87f2SEd Tanous     constexpr static size_t maxMessages = 200;
135f80a87f2SEd Tanous     boost::circular_buffer<Event> messages{maxMessages};
136f80a87f2SEd Tanous 
137f8ca6d79SEd Tanous     boost::asio::io_context& ioc;
138f8ca6d79SEd Tanous 
139b52664e2SAppaRao Puli   public:
1409f616dd1SEd Tanous     EventServiceManager(const EventServiceManager&) = delete;
1419f616dd1SEd Tanous     EventServiceManager& operator=(const EventServiceManager&) = delete;
1429f616dd1SEd Tanous     EventServiceManager(EventServiceManager&&) = delete;
1439f616dd1SEd Tanous     EventServiceManager& operator=(EventServiceManager&&) = delete;
144ecd6a3a2SEd Tanous     ~EventServiceManager() = default;
1459f616dd1SEd Tanous 
146f8ca6d79SEd Tanous     explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn)
147b52664e2SAppaRao Puli     {
148f8ca6d79SEd Tanous         // Load config from persist store.
149f8ca6d79SEd Tanous         initConfig();
150f8ca6d79SEd Tanous     }
151f8ca6d79SEd Tanous 
152f8ca6d79SEd Tanous     static EventServiceManager&
153f8ca6d79SEd Tanous         getInstance(boost::asio::io_context* ioc = nullptr)
154f8ca6d79SEd Tanous     {
155f8ca6d79SEd Tanous         static EventServiceManager handler(*ioc);
156b52664e2SAppaRao Puli         return handler;
157b52664e2SAppaRao Puli     }
158b52664e2SAppaRao Puli 
1591bf712bcSAyushi Smriti     void initConfig()
1601bf712bcSAyushi Smriti     {
16128afb49cSJunLin Chen         loadOldBehavior();
1621bf712bcSAyushi Smriti 
16328afb49cSJunLin Chen         persistent_data::EventServiceConfig eventServiceConfig =
16428afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
16528afb49cSJunLin Chen                 .getEventServiceConfig();
1661bf712bcSAyushi Smriti 
16728afb49cSJunLin Chen         serviceEnabled = eventServiceConfig.enabled;
16828afb49cSJunLin Chen         retryAttempts = eventServiceConfig.retryAttempts;
16928afb49cSJunLin Chen         retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval;
1701bf712bcSAyushi Smriti 
17128afb49cSJunLin Chen         for (const auto& it : persistent_data::EventServiceStore::getInstance()
17228afb49cSJunLin Chen                                   .subscriptionsConfigMap)
1731bf712bcSAyushi Smriti         {
1745fe4ef35SMyung Bae             std::shared_ptr<persistent_data::UserSubscription> newSub =
1755fe4ef35SMyung Bae                 it.second;
1764bbf237fSAppaRao Puli 
1776fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
1785fe4ef35SMyung Bae                 boost::urls::parse_absolute_uri(newSub->destinationUrl);
1791bf712bcSAyushi Smriti 
180a716aa74SEd Tanous             if (!url)
1811bf712bcSAyushi Smriti             {
18262598e31SEd Tanous                 BMCWEB_LOG_ERROR(
18362598e31SEd Tanous                     "Failed to validate and split destination url");
1841bf712bcSAyushi Smriti                 continue;
1851bf712bcSAyushi Smriti             }
1861bf712bcSAyushi Smriti             std::shared_ptr<Subscription> subValue =
18721a94d5cSMyung Bae                 std::make_shared<Subscription>(newSub, *url, ioc);
1885fe4ef35SMyung Bae             std::string id = subValue->userSub->id;
189a0969c70SMyung Bae             subValue->deleter = [id]() {
190a0969c70SMyung Bae                 EventServiceManager::getInstance().deleteSubscription(id);
191a0969c70SMyung Bae             };
1921bf712bcSAyushi Smriti 
193a0969c70SMyung Bae             subscriptionsMap.emplace(id, subValue);
19428afb49cSJunLin Chen 
19528afb49cSJunLin Chen             updateNoOfSubscribersCount();
19628afb49cSJunLin Chen 
19783328316SEd Tanous             if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
19883328316SEd Tanous             {
1992558979cSP Dheeraj Srujan Kumar                 cacheRedfishLogFile();
20083328316SEd Tanous             }
2012558979cSP Dheeraj Srujan Kumar 
20228afb49cSJunLin Chen             // Update retry configuration.
20328afb49cSJunLin Chen             subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
2041bf712bcSAyushi Smriti         }
2051bf712bcSAyushi Smriti     }
2061bf712bcSAyushi Smriti 
20756d2396dSEd Tanous     static void loadOldBehavior()
208b52664e2SAppaRao Puli     {
20928afb49cSJunLin Chen         std::ifstream eventConfigFile(eventServiceFile);
21028afb49cSJunLin Chen         if (!eventConfigFile.good())
2111bf712bcSAyushi Smriti         {
21262598e31SEd Tanous             BMCWEB_LOG_DEBUG("Old eventService config not exist");
21328afb49cSJunLin Chen             return;
21428afb49cSJunLin Chen         }
21528afb49cSJunLin Chen         auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false);
21628afb49cSJunLin Chen         if (jsonData.is_discarded())
2174bbf237fSAppaRao Puli         {
21862598e31SEd Tanous             BMCWEB_LOG_ERROR("Old eventService config parse error.");
21928afb49cSJunLin Chen             return;
22028afb49cSJunLin Chen         }
22128afb49cSJunLin Chen 
2220bdda665SEd Tanous         const nlohmann::json::object_t* obj =
2230bdda665SEd Tanous             jsonData.get_ptr<const nlohmann::json::object_t*>();
2240bdda665SEd Tanous         for (const auto& item : *obj)
22528afb49cSJunLin Chen         {
2260bdda665SEd Tanous             if (item.first == "Configuration")
22728afb49cSJunLin Chen             {
22828afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
22928afb49cSJunLin Chen                     .getEventServiceConfig()
2300bdda665SEd Tanous                     .fromJson(item.second);
23128afb49cSJunLin Chen             }
2320bdda665SEd Tanous             else if (item.first == "Subscriptions")
23328afb49cSJunLin Chen             {
2340bdda665SEd Tanous                 for (const auto& elem : item.second)
23528afb49cSJunLin Chen                 {
2364b712a29SEd Tanous                     std::optional<persistent_data::UserSubscription>
23728afb49cSJunLin Chen                         newSubscription =
23828afb49cSJunLin Chen                             persistent_data::UserSubscription::fromJson(elem,
23928afb49cSJunLin Chen                                                                         true);
2404b712a29SEd Tanous                     if (!newSubscription)
24128afb49cSJunLin Chen                     {
24262598e31SEd Tanous                         BMCWEB_LOG_ERROR("Problem reading subscription "
24362598e31SEd Tanous                                          "from old persistent store");
2444bbf237fSAppaRao Puli                         continue;
2454bbf237fSAppaRao Puli                     }
2464b712a29SEd Tanous                     persistent_data::UserSubscription& newSub =
2474b712a29SEd Tanous                         *newSubscription;
2481bf712bcSAyushi Smriti 
24928afb49cSJunLin Chen                     std::uniform_int_distribution<uint32_t> dist(0);
25028afb49cSJunLin Chen                     bmcweb::OpenSSLGenerator gen;
2511bf712bcSAyushi Smriti 
25228afb49cSJunLin Chen                     std::string id;
2531bf712bcSAyushi Smriti 
25428afb49cSJunLin Chen                     int retry = 3;
255e662eae8SEd Tanous                     while (retry != 0)
2561bf712bcSAyushi Smriti                     {
25728afb49cSJunLin Chen                         id = std::to_string(dist(gen));
25828afb49cSJunLin Chen                         if (gen.error())
2597d1cc387SAppaRao Puli                         {
26028afb49cSJunLin Chen                             retry = 0;
26128afb49cSJunLin Chen                             break;
26228afb49cSJunLin Chen                         }
2634b712a29SEd Tanous                         newSub.id = id;
26428afb49cSJunLin Chen                         auto inserted =
26528afb49cSJunLin Chen                             persistent_data::EventServiceStore::getInstance()
2665fe4ef35SMyung Bae                                 .subscriptionsConfigMap.insert(std::pair(
2675fe4ef35SMyung Bae                                     id, std::make_shared<
2685fe4ef35SMyung Bae                                             persistent_data::UserSubscription>(
2695fe4ef35SMyung Bae                                             newSub)));
27028afb49cSJunLin Chen                         if (inserted.second)
27128afb49cSJunLin Chen                         {
27228afb49cSJunLin Chen                             break;
27328afb49cSJunLin Chen                         }
27428afb49cSJunLin Chen                         --retry;
2757d1cc387SAppaRao Puli                     }
2767d1cc387SAppaRao Puli 
27728afb49cSJunLin Chen                     if (retry <= 0)
27828afb49cSJunLin Chen                     {
27962598e31SEd Tanous                         BMCWEB_LOG_ERROR(
28062598e31SEd Tanous                             "Failed to generate random number from old "
28162598e31SEd Tanous                             "persistent store");
28228afb49cSJunLin Chen                         continue;
28328afb49cSJunLin Chen                     }
28428afb49cSJunLin Chen                 }
28528afb49cSJunLin Chen             }
28628afb49cSJunLin Chen 
28728afb49cSJunLin Chen             persistent_data::getConfig().writeData();
2884c521c3cSEd Tanous             std::error_code ec;
2894c521c3cSEd Tanous             std::filesystem::remove(eventServiceFile, ec);
2904c521c3cSEd Tanous             if (ec)
2914c521c3cSEd Tanous             {
2924c521c3cSEd Tanous                 BMCWEB_LOG_DEBUG(
2934c521c3cSEd Tanous                     "Failed to remove old event service file.  Ignoring");
2944c521c3cSEd Tanous             }
2954c521c3cSEd Tanous             else
2964c521c3cSEd Tanous             {
29762598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Remove old eventservice config");
29828afb49cSJunLin Chen             }
29928afb49cSJunLin Chen         }
3004c521c3cSEd Tanous     }
30128afb49cSJunLin Chen 
3029eb808c1SEd Tanous     void updateSubscriptionData() const
30328afb49cSJunLin Chen     {
30428afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
30528afb49cSJunLin Chen             .eventServiceConfig.enabled = serviceEnabled;
30628afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
30728afb49cSJunLin Chen             .eventServiceConfig.retryAttempts = retryAttempts;
30828afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
30928afb49cSJunLin Chen             .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval;
31028afb49cSJunLin Chen 
31128afb49cSJunLin Chen         persistent_data::getConfig().writeData();
31228afb49cSJunLin Chen     }
31328afb49cSJunLin Chen 
31428afb49cSJunLin Chen     void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg)
3157d1cc387SAppaRao Puli     {
3167d1cc387SAppaRao Puli         bool updateConfig = false;
317fe44eb0bSAyushi Smriti         bool updateRetryCfg = false;
3187d1cc387SAppaRao Puli 
31928afb49cSJunLin Chen         if (serviceEnabled != cfg.enabled)
3207d1cc387SAppaRao Puli         {
32128afb49cSJunLin Chen             serviceEnabled = cfg.enabled;
322e662eae8SEd Tanous             if (serviceEnabled && noOfMetricReportSubscribers != 0U)
3237d1cc387SAppaRao Puli             {
3247d1cc387SAppaRao Puli                 registerMetricReportSignal();
3257d1cc387SAppaRao Puli             }
3267d1cc387SAppaRao Puli             else
3277d1cc387SAppaRao Puli             {
3287d1cc387SAppaRao Puli                 unregisterMetricReportSignal();
3297d1cc387SAppaRao Puli             }
3307d1cc387SAppaRao Puli             updateConfig = true;
3317d1cc387SAppaRao Puli         }
3327d1cc387SAppaRao Puli 
33328afb49cSJunLin Chen         if (retryAttempts != cfg.retryAttempts)
3347d1cc387SAppaRao Puli         {
33528afb49cSJunLin Chen             retryAttempts = cfg.retryAttempts;
3367d1cc387SAppaRao Puli             updateConfig = true;
337fe44eb0bSAyushi Smriti             updateRetryCfg = true;
3387d1cc387SAppaRao Puli         }
3397d1cc387SAppaRao Puli 
34028afb49cSJunLin Chen         if (retryTimeoutInterval != cfg.retryTimeoutInterval)
3417d1cc387SAppaRao Puli         {
34228afb49cSJunLin Chen             retryTimeoutInterval = cfg.retryTimeoutInterval;
3437d1cc387SAppaRao Puli             updateConfig = true;
344fe44eb0bSAyushi Smriti             updateRetryCfg = true;
3457d1cc387SAppaRao Puli         }
3467d1cc387SAppaRao Puli 
3477d1cc387SAppaRao Puli         if (updateConfig)
3487d1cc387SAppaRao Puli         {
3497d1cc387SAppaRao Puli             updateSubscriptionData();
3507d1cc387SAppaRao Puli         }
351fe44eb0bSAyushi Smriti 
352fe44eb0bSAyushi Smriti         if (updateRetryCfg)
353fe44eb0bSAyushi Smriti         {
354fe44eb0bSAyushi Smriti             // Update the changed retry config to all subscriptions
355fe44eb0bSAyushi Smriti             for (const auto& it :
356fe44eb0bSAyushi Smriti                  EventServiceManager::getInstance().subscriptionsMap)
357fe44eb0bSAyushi Smriti             {
3585e44e3d8SAppaRao Puli                 Subscription& entry = *it.second;
3595e44e3d8SAppaRao Puli                 entry.updateRetryConfig(retryAttempts, retryTimeoutInterval);
360fe44eb0bSAyushi Smriti             }
361fe44eb0bSAyushi Smriti         }
3627d1cc387SAppaRao Puli     }
3637d1cc387SAppaRao Puli 
3647d1cc387SAppaRao Puli     void updateNoOfSubscribersCount()
3657d1cc387SAppaRao Puli     {
3667d1cc387SAppaRao Puli         size_t eventLogSubCount = 0;
3677d1cc387SAppaRao Puli         size_t metricReportSubCount = 0;
3687d1cc387SAppaRao Puli         for (const auto& it : subscriptionsMap)
3697d1cc387SAppaRao Puli         {
3707d1cc387SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
3715fe4ef35SMyung Bae             if (entry->userSub->eventFormatType == eventFormatType)
3727d1cc387SAppaRao Puli             {
3737d1cc387SAppaRao Puli                 eventLogSubCount++;
3747d1cc387SAppaRao Puli             }
3755fe4ef35SMyung Bae             else if (entry->userSub->eventFormatType == metricReportFormatType)
3767d1cc387SAppaRao Puli             {
3777d1cc387SAppaRao Puli                 metricReportSubCount++;
3787d1cc387SAppaRao Puli             }
3797d1cc387SAppaRao Puli         }
3807d1cc387SAppaRao Puli 
3817d1cc387SAppaRao Puli         noOfEventLogSubscribers = eventLogSubCount;
3827d1cc387SAppaRao Puli         if (noOfMetricReportSubscribers != metricReportSubCount)
3837d1cc387SAppaRao Puli         {
3847d1cc387SAppaRao Puli             noOfMetricReportSubscribers = metricReportSubCount;
385e662eae8SEd Tanous             if (noOfMetricReportSubscribers != 0U)
3867d1cc387SAppaRao Puli             {
3877d1cc387SAppaRao Puli                 registerMetricReportSignal();
3887d1cc387SAppaRao Puli             }
3897d1cc387SAppaRao Puli             else
3907d1cc387SAppaRao Puli             {
3917d1cc387SAppaRao Puli                 unregisterMetricReportSignal();
3927d1cc387SAppaRao Puli             }
3937d1cc387SAppaRao Puli         }
3947d1cc387SAppaRao Puli     }
3957d1cc387SAppaRao Puli 
396b52664e2SAppaRao Puli     std::shared_ptr<Subscription> getSubscription(const std::string& id)
397b52664e2SAppaRao Puli     {
398b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
399b52664e2SAppaRao Puli         if (obj == subscriptionsMap.end())
400b52664e2SAppaRao Puli         {
40162598e31SEd Tanous             BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id);
402b52664e2SAppaRao Puli             return nullptr;
403b52664e2SAppaRao Puli         }
404b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue = obj->second;
405b52664e2SAppaRao Puli         return subValue;
406b52664e2SAppaRao Puli     }
407b52664e2SAppaRao Puli 
408f80a87f2SEd Tanous     std::string
409f80a87f2SEd Tanous         addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue)
410b52664e2SAppaRao Puli     {
411fc76b8acSEd Tanous         std::uniform_int_distribution<uint32_t> dist(0);
412fc76b8acSEd Tanous         bmcweb::OpenSSLGenerator gen;
413fc76b8acSEd Tanous 
414b52664e2SAppaRao Puli         std::string id;
415b52664e2SAppaRao Puli 
416b52664e2SAppaRao Puli         int retry = 3;
417e662eae8SEd Tanous         while (retry != 0)
418b52664e2SAppaRao Puli         {
419fc76b8acSEd Tanous             id = std::to_string(dist(gen));
420fc76b8acSEd Tanous             if (gen.error())
421fc76b8acSEd Tanous             {
422fc76b8acSEd Tanous                 retry = 0;
423fc76b8acSEd Tanous                 break;
424fc76b8acSEd Tanous             }
425b52664e2SAppaRao Puli             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
426b52664e2SAppaRao Puli             if (inserted.second)
427b52664e2SAppaRao Puli             {
428b52664e2SAppaRao Puli                 break;
429b52664e2SAppaRao Puli             }
430b52664e2SAppaRao Puli             --retry;
43123a21a1cSEd Tanous         }
432b52664e2SAppaRao Puli 
433b52664e2SAppaRao Puli         if (retry <= 0)
434b52664e2SAppaRao Puli         {
43562598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to generate random number");
436abb93cddSEd Tanous             return "";
437b52664e2SAppaRao Puli         }
438b52664e2SAppaRao Puli 
43956ba386dSMyung Bae         // Set Subscription ID for back trace
4405fe4ef35SMyung Bae         subValue->userSub->id = id;
441a14c9113SEd Tanous 
44228afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
4435fe4ef35SMyung Bae             .subscriptionsConfigMap.emplace(id, subValue->userSub);
44428afb49cSJunLin Chen 
4457d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
4461bf712bcSAyushi Smriti 
44783328316SEd Tanous         if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
44883328316SEd Tanous         {
4492558979cSP Dheeraj Srujan Kumar             if (redfishLogFilePosition != 0)
4507f4eb588SAppaRao Puli             {
4512558979cSP Dheeraj Srujan Kumar                 cacheRedfishLogFile();
4527f4eb588SAppaRao Puli             }
45383328316SEd Tanous         }
454fe44eb0bSAyushi Smriti         // Update retry configuration.
455fe44eb0bSAyushi Smriti         subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
456fe44eb0bSAyushi Smriti 
457f80a87f2SEd Tanous         return id;
458f80a87f2SEd Tanous     }
459f80a87f2SEd Tanous 
460f80a87f2SEd Tanous     std::string
461f80a87f2SEd Tanous         addSSESubscription(const std::shared_ptr<Subscription>& subValue,
462f80a87f2SEd Tanous                            std::string_view lastEventId)
463f80a87f2SEd Tanous     {
464f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
465f80a87f2SEd Tanous 
466f80a87f2SEd Tanous         if (!lastEventId.empty())
467f80a87f2SEd Tanous         {
468f80a87f2SEd Tanous             BMCWEB_LOG_INFO("Attempting to find message for last id {}",
469f80a87f2SEd Tanous                             lastEventId);
470f80a87f2SEd Tanous             boost::circular_buffer<Event>::iterator lastEvent =
471f80a87f2SEd Tanous                 std::find_if(messages.begin(), messages.end(),
472f80a87f2SEd Tanous                              [&lastEventId](const Event& event) {
473f80a87f2SEd Tanous                                  return event.id == lastEventId;
474f80a87f2SEd Tanous                              });
475f80a87f2SEd Tanous             // Can't find a matching ID
476f80a87f2SEd Tanous             if (lastEvent == messages.end())
477f80a87f2SEd Tanous             {
478f80a87f2SEd Tanous                 nlohmann::json msg = messages::eventBufferExceeded();
479f80a87f2SEd Tanous                 // If the buffer overloaded, send all messages.
4806d799e14SEd Tanous                 subValue->sendEventToSubscriber(msg);
481f80a87f2SEd Tanous                 lastEvent = messages.begin();
482f80a87f2SEd Tanous             }
483f80a87f2SEd Tanous             else
484f80a87f2SEd Tanous             {
485f80a87f2SEd Tanous                 // Skip the last event the user already has
486f80a87f2SEd Tanous                 lastEvent++;
487f80a87f2SEd Tanous             }
488f80a87f2SEd Tanous 
489f80a87f2SEd Tanous             for (boost::circular_buffer<Event>::const_iterator event =
490f80a87f2SEd Tanous                      lastEvent;
491f80a87f2SEd Tanous                  lastEvent != messages.end(); lastEvent++)
492f80a87f2SEd Tanous             {
4936d799e14SEd Tanous                 subValue->sendEventToSubscriber(event->message);
494f80a87f2SEd Tanous             }
495f80a87f2SEd Tanous         }
496f80a87f2SEd Tanous         return id;
497f80a87f2SEd Tanous     }
498f80a87f2SEd Tanous 
499f80a87f2SEd Tanous     std::string
500f80a87f2SEd Tanous         addPushSubscription(const std::shared_ptr<Subscription>& subValue)
501f80a87f2SEd Tanous     {
502f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
503a0969c70SMyung Bae         subValue->deleter = [id]() {
504a0969c70SMyung Bae             EventServiceManager::getInstance().deleteSubscription(id);
505a0969c70SMyung Bae         };
506f80a87f2SEd Tanous         updateSubscriptionData();
507b52664e2SAppaRao Puli         return id;
508b52664e2SAppaRao Puli     }
509b52664e2SAppaRao Puli 
510b52664e2SAppaRao Puli     bool isSubscriptionExist(const std::string& id)
511b52664e2SAppaRao Puli     {
512b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
51355f79e6fSEd Tanous         return obj != subscriptionsMap.end();
514b52664e2SAppaRao Puli     }
515b52664e2SAppaRao Puli 
5164b712a29SEd Tanous     bool deleteSubscription(const std::string& id)
517b52664e2SAppaRao Puli     {
518b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
5194b712a29SEd Tanous         if (obj == subscriptionsMap.end())
520b52664e2SAppaRao Puli         {
5214b712a29SEd Tanous             BMCWEB_LOG_WARNING("Could not find subscription with id {}", id);
5224b712a29SEd Tanous             return false;
5234b712a29SEd Tanous         }
524b52664e2SAppaRao Puli         subscriptionsMap.erase(obj);
5254b712a29SEd Tanous         auto& event = persistent_data::EventServiceStore::getInstance();
5264b712a29SEd Tanous         auto persistentObj = event.subscriptionsConfigMap.find(id);
5274b712a29SEd Tanous         if (persistentObj == event.subscriptionsConfigMap.end())
5284b712a29SEd Tanous         {
5294b712a29SEd Tanous             BMCWEB_LOG_ERROR("Subscription wasn't in persistent data");
5304b712a29SEd Tanous             return true;
5314b712a29SEd Tanous         }
53228afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
5334b712a29SEd Tanous             .subscriptionsConfigMap.erase(persistentObj);
5347d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
535b52664e2SAppaRao Puli         updateSubscriptionData();
5364b712a29SEd Tanous 
5374b712a29SEd Tanous         return true;
538b52664e2SAppaRao Puli     }
539b52664e2SAppaRao Puli 
5405e44e3d8SAppaRao Puli     void deleteSseSubscription(const crow::sse_socket::Connection& thisConn)
5415e44e3d8SAppaRao Puli     {
542bdbfae2aSEd Tanous         for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();)
5435e44e3d8SAppaRao Puli         {
544bdbfae2aSEd Tanous             std::shared_ptr<Subscription> entry = it->second;
5455e44e3d8SAppaRao Puli             bool entryIsThisConn = entry->matchSseId(thisConn);
5465e44e3d8SAppaRao Puli             if (entryIsThisConn)
5475e44e3d8SAppaRao Puli             {
5485e44e3d8SAppaRao Puli                 persistent_data::EventServiceStore::getInstance()
5495fe4ef35SMyung Bae                     .subscriptionsConfigMap.erase(entry->userSub->id);
550bdbfae2aSEd Tanous                 it = subscriptionsMap.erase(it);
5515e44e3d8SAppaRao Puli                 return;
5525e44e3d8SAppaRao Puli             }
553bdbfae2aSEd Tanous             it++;
5545e44e3d8SAppaRao Puli         }
5555e44e3d8SAppaRao Puli     }
5565e44e3d8SAppaRao Puli 
5575e44e3d8SAppaRao Puli     size_t getNumberOfSubscriptions() const
558b52664e2SAppaRao Puli     {
559b52664e2SAppaRao Puli         return subscriptionsMap.size();
560b52664e2SAppaRao Puli     }
561b52664e2SAppaRao Puli 
5625e44e3d8SAppaRao Puli     size_t getNumberOfSSESubscriptions() const
5635e44e3d8SAppaRao Puli     {
5643544d2a7SEd Tanous         auto size = std::ranges::count_if(
5653544d2a7SEd Tanous             subscriptionsMap,
5665e44e3d8SAppaRao Puli             [](const std::pair<std::string, std::shared_ptr<Subscription>>&
5675e44e3d8SAppaRao Puli                    entry) {
5685fe4ef35SMyung Bae                 return (entry.second->userSub->subscriptionType ==
5694b712a29SEd Tanous                         subscriptionTypeSSE);
5705e44e3d8SAppaRao Puli             });
5715e44e3d8SAppaRao Puli         return static_cast<size_t>(size);
5725e44e3d8SAppaRao Puli     }
5735e44e3d8SAppaRao Puli 
574b52664e2SAppaRao Puli     std::vector<std::string> getAllIDs()
575b52664e2SAppaRao Puli     {
576b52664e2SAppaRao Puli         std::vector<std::string> idList;
577b52664e2SAppaRao Puli         for (const auto& it : subscriptionsMap)
578b52664e2SAppaRao Puli         {
579b52664e2SAppaRao Puli             idList.emplace_back(it.first);
580b52664e2SAppaRao Puli         }
581b52664e2SAppaRao Puli         return idList;
582b52664e2SAppaRao Puli     }
583b52664e2SAppaRao Puli 
5846ba8c82eSsunharis_in     bool sendTestEventLog()
5850b4bdd93SAppaRao Puli     {
5865e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
5870b4bdd93SAppaRao Puli         {
5880b4bdd93SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
5896ba8c82eSsunharis_in             if (!entry->sendTestEventLog())
5906ba8c82eSsunharis_in             {
5916ba8c82eSsunharis_in                 return false;
5920b4bdd93SAppaRao Puli             }
5930b4bdd93SAppaRao Puli         }
5946ba8c82eSsunharis_in         return true;
5956ba8c82eSsunharis_in     }
596e9a14131SAppaRao Puli 
597f80a87f2SEd Tanous     void sendEvent(nlohmann::json::object_t eventMessage,
598f80a87f2SEd Tanous                    std::string_view origin, std::string_view resourceType)
59996330b99SSunitha Harish     {
600613dabeaSEd Tanous         eventMessage["EventId"] = eventId;
601f80a87f2SEd Tanous 
602613dabeaSEd Tanous         eventMessage["EventTimestamp"] =
603613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
604613dabeaSEd Tanous         eventMessage["OriginOfCondition"] = origin;
605613dabeaSEd Tanous 
606f80a87f2SEd Tanous         // MemberId is 0 : since we are sending one event record.
607788b091bSIgor Kanyuka         eventMessage["MemberId"] = "0";
60896330b99SSunitha Harish 
609f80a87f2SEd Tanous         messages.push_back(Event(std::to_string(eventId), eventMessage));
610f80a87f2SEd Tanous 
611f80a87f2SEd Tanous         for (auto& it : subscriptionsMap)
61296330b99SSunitha Harish         {
613f80a87f2SEd Tanous             std::shared_ptr<Subscription>& entry = it.second;
6145fe4ef35SMyung Bae             if (!eventMatchesFilter(*entry->userSub, eventMessage,
6155fe4ef35SMyung Bae                                     resourceType))
61696330b99SSunitha Harish             {
617f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Filter didn't match");
618f80a87f2SEd Tanous                 continue;
61996330b99SSunitha Harish             }
620f80a87f2SEd Tanous 
621f80a87f2SEd Tanous             nlohmann::json::array_t eventRecord;
622f80a87f2SEd Tanous             eventRecord.emplace_back(eventMessage);
623f80a87f2SEd Tanous 
624613dabeaSEd Tanous             nlohmann::json msgJson;
625613dabeaSEd Tanous 
626613dabeaSEd Tanous             msgJson["@odata.type"] = "#Event.v1_4_0.Event";
627613dabeaSEd Tanous             msgJson["Name"] = "Event Log";
628613dabeaSEd Tanous             msgJson["Id"] = eventId;
629f80a87f2SEd Tanous             msgJson["Events"] = std::move(eventRecord);
630f52c03c1SCarson Labrado 
631f52c03c1SCarson Labrado             std::string strMsg = msgJson.dump(
632f52c03c1SCarson Labrado                 2, ' ', true, nlohmann::json::error_handler_t::replace);
6336d799e14SEd Tanous             entry->sendEventToSubscriber(std::move(strMsg));
6348ece0e45SEd Tanous             eventId++; // increment the eventId
63596330b99SSunitha Harish         }
63696330b99SSunitha Harish     }
63796330b99SSunitha Harish 
6382558979cSP Dheeraj Srujan Kumar     void resetRedfishFilePosition()
6397f4eb588SAppaRao Puli     {
6402558979cSP Dheeraj Srujan Kumar         // Control would be here when Redfish file is created.
6412558979cSP Dheeraj Srujan Kumar         // Reset File Position as new file is created
6422558979cSP Dheeraj Srujan Kumar         redfishLogFilePosition = 0;
6432558979cSP Dheeraj Srujan Kumar     }
6442558979cSP Dheeraj Srujan Kumar 
6452558979cSP Dheeraj Srujan Kumar     void cacheRedfishLogFile()
6462558979cSP Dheeraj Srujan Kumar     {
6472558979cSP Dheeraj Srujan Kumar         // Open the redfish file and read till the last record.
6482558979cSP Dheeraj Srujan Kumar 
6497f4eb588SAppaRao Puli         std::ifstream logStream(redfishEventLogFile);
6507f4eb588SAppaRao Puli         if (!logStream.good())
6517f4eb588SAppaRao Puli         {
65262598e31SEd Tanous             BMCWEB_LOG_ERROR(" Redfish log file open failed ");
6537f4eb588SAppaRao Puli             return;
6547f4eb588SAppaRao Puli         }
6557f4eb588SAppaRao Puli         std::string logEntry;
6567f4eb588SAppaRao Puli         while (std::getline(logStream, logEntry))
6577f4eb588SAppaRao Puli         {
6582558979cSP Dheeraj Srujan Kumar             redfishLogFilePosition = logStream.tellg();
6597f4eb588SAppaRao Puli         }
6607f4eb588SAppaRao Puli     }
6617f4eb588SAppaRao Puli 
6627f4eb588SAppaRao Puli     void readEventLogsFromFile()
6637f4eb588SAppaRao Puli     {
6647f4eb588SAppaRao Puli         std::ifstream logStream(redfishEventLogFile);
6657f4eb588SAppaRao Puli         if (!logStream.good())
6667f4eb588SAppaRao Puli         {
66762598e31SEd Tanous             BMCWEB_LOG_ERROR(" Redfish log file open failed");
6687f4eb588SAppaRao Puli             return;
6697f4eb588SAppaRao Puli         }
6707f4eb588SAppaRao Puli 
6717f4eb588SAppaRao Puli         std::vector<EventLogObjectsType> eventRecords;
6727f4eb588SAppaRao Puli 
6737f4eb588SAppaRao Puli         std::string logEntry;
6742558979cSP Dheeraj Srujan Kumar 
67503d4d37cSAlexander Hansen         BMCWEB_LOG_DEBUG("Redfish log file: seek to {}",
67603d4d37cSAlexander Hansen                          static_cast<int>(redfishLogFilePosition));
67703d4d37cSAlexander Hansen 
6782558979cSP Dheeraj Srujan Kumar         // Get the read pointer to the next log to be read.
6792558979cSP Dheeraj Srujan Kumar         logStream.seekg(redfishLogFilePosition);
6802558979cSP Dheeraj Srujan Kumar 
6817f4eb588SAppaRao Puli         while (std::getline(logStream, logEntry))
6827f4eb588SAppaRao Puli         {
68303d4d37cSAlexander Hansen             BMCWEB_LOG_DEBUG("Redfish log file: found new event log entry");
6842558979cSP Dheeraj Srujan Kumar             // Update Pointer position
6852558979cSP Dheeraj Srujan Kumar             redfishLogFilePosition = logStream.tellg();
6862558979cSP Dheeraj Srujan Kumar 
6872558979cSP Dheeraj Srujan Kumar             std::string idStr;
6882558979cSP Dheeraj Srujan Kumar             if (!event_log::getUniqueEntryID(logEntry, idStr))
6897f4eb588SAppaRao Puli             {
69003d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG(
69103d4d37cSAlexander Hansen                     "Redfish log file: could not get unique entry id for {}",
69203d4d37cSAlexander Hansen                     logEntry);
6937f4eb588SAppaRao Puli                 continue;
6947f4eb588SAppaRao Puli             }
6957f4eb588SAppaRao Puli 
696e662eae8SEd Tanous             if (!serviceEnabled || noOfEventLogSubscribers == 0)
6977f4eb588SAppaRao Puli             {
6982558979cSP Dheeraj Srujan Kumar                 // If Service is not enabled, no need to compute
6992558979cSP Dheeraj Srujan Kumar                 // the remaining items below.
7002558979cSP Dheeraj Srujan Kumar                 // But, Loop must continue to keep track of Timestamp
70103d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG(
70203d4d37cSAlexander Hansen                     "Redfish log file: no subscribers / event service not enabled");
7037f4eb588SAppaRao Puli                 continue;
7047f4eb588SAppaRao Puli             }
7057f4eb588SAppaRao Puli 
7067f4eb588SAppaRao Puli             std::string timestamp;
7077f4eb588SAppaRao Puli             std::string messageID;
7085e715de6SAppaRao Puli             std::vector<std::string> messageArgs;
7097f4eb588SAppaRao Puli             if (event_log::getEventLogParams(logEntry, timestamp, messageID,
7107f4eb588SAppaRao Puli                                              messageArgs) != 0)
7117f4eb588SAppaRao Puli             {
71203d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("Read eventLog entry params failed for {}",
71303d4d37cSAlexander Hansen                                  logEntry);
7147f4eb588SAppaRao Puli                 continue;
7157f4eb588SAppaRao Puli             }
7167f4eb588SAppaRao Puli 
717f80a87f2SEd Tanous             eventRecords.emplace_back(idStr, timestamp, messageID, messageArgs);
7187f4eb588SAppaRao Puli         }
7197f4eb588SAppaRao Puli 
720e662eae8SEd Tanous         if (!serviceEnabled || noOfEventLogSubscribers == 0)
7212558979cSP Dheeraj Srujan Kumar         {
72262598e31SEd Tanous             BMCWEB_LOG_DEBUG("EventService disabled or no Subscriptions.");
7232558979cSP Dheeraj Srujan Kumar             return;
7242558979cSP Dheeraj Srujan Kumar         }
7252558979cSP Dheeraj Srujan Kumar 
7262558979cSP Dheeraj Srujan Kumar         if (eventRecords.empty())
7272558979cSP Dheeraj Srujan Kumar         {
7282558979cSP Dheeraj Srujan Kumar             // No Records to send
72962598e31SEd Tanous             BMCWEB_LOG_DEBUG("No log entries available to be transferred.");
7302558979cSP Dheeraj Srujan Kumar             return;
7312558979cSP Dheeraj Srujan Kumar         }
7322558979cSP Dheeraj Srujan Kumar 
7335e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
7347f4eb588SAppaRao Puli         {
7357f4eb588SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
7365fe4ef35SMyung Bae             if (entry->userSub->eventFormatType == "Event")
7377f4eb588SAppaRao Puli             {
7387f4eb588SAppaRao Puli                 entry->filterAndSendEventLogs(eventRecords);
7397f4eb588SAppaRao Puli             }
7407f4eb588SAppaRao Puli         }
7417f4eb588SAppaRao Puli     }
7427f4eb588SAppaRao Puli 
7437f4eb588SAppaRao Puli     static void watchRedfishEventLogFile()
7447f4eb588SAppaRao Puli     {
7456a9f85f9SAppaRao Puli         if (!inotifyConn)
7467f4eb588SAppaRao Puli         {
74703d4d37cSAlexander Hansen             BMCWEB_LOG_ERROR("inotify Connection is not present");
7487f4eb588SAppaRao Puli             return;
7497f4eb588SAppaRao Puli         }
7507f4eb588SAppaRao Puli 
7517f4eb588SAppaRao Puli         static std::array<char, 1024> readBuffer;
7527f4eb588SAppaRao Puli 
753bd79bce8SPatrick Williams         inotifyConn->async_read_some(
754bd79bce8SPatrick Williams             boost::asio::buffer(readBuffer),
7557f4eb588SAppaRao Puli             [&](const boost::system::error_code& ec,
7567f4eb588SAppaRao Puli                 const std::size_t& bytesTransferred) {
7579ed3f90aSEd Tanous                 if (ec == boost::asio::error::operation_aborted)
7589ed3f90aSEd Tanous                 {
7599ed3f90aSEd Tanous                     BMCWEB_LOG_DEBUG("Inotify was canceled (shutdown?)");
7609ed3f90aSEd Tanous                     return;
7619ed3f90aSEd Tanous                 }
7627f4eb588SAppaRao Puli                 if (ec)
7637f4eb588SAppaRao Puli                 {
76462598e31SEd Tanous                     BMCWEB_LOG_ERROR("Callback Error: {}", ec.message());
7657f4eb588SAppaRao Puli                     return;
7667f4eb588SAppaRao Puli                 }
76703d4d37cSAlexander Hansen 
76803d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("reading {} via inotify", bytesTransferred);
76903d4d37cSAlexander Hansen 
7707f4eb588SAppaRao Puli                 std::size_t index = 0;
771b792cc56SAppaRao Puli                 while ((index + iEventSize) <= bytesTransferred)
7727f4eb588SAppaRao Puli                 {
773d3a9e084SEd Tanous                     struct inotify_event event
774d3a9e084SEd Tanous                     {};
775b792cc56SAppaRao Puli                     std::memcpy(&event, &readBuffer[index], iEventSize);
776b792cc56SAppaRao Puli                     if (event.wd == dirWatchDesc)
777b792cc56SAppaRao Puli                     {
778b792cc56SAppaRao Puli                         if ((event.len == 0) ||
779b792cc56SAppaRao Puli                             (index + iEventSize + event.len > bytesTransferred))
780b792cc56SAppaRao Puli                         {
781b792cc56SAppaRao Puli                             index += (iEventSize + event.len);
782b792cc56SAppaRao Puli                             continue;
783b792cc56SAppaRao Puli                         }
784b792cc56SAppaRao Puli 
7854f568f74SJiaqing Zhao                         std::string fileName(&readBuffer[index + iEventSize]);
7864f568f74SJiaqing Zhao                         if (fileName != "redfish")
787b792cc56SAppaRao Puli                         {
788b792cc56SAppaRao Puli                             index += (iEventSize + event.len);
789b792cc56SAppaRao Puli                             continue;
790b792cc56SAppaRao Puli                         }
791b792cc56SAppaRao Puli 
79262598e31SEd Tanous                         BMCWEB_LOG_DEBUG(
79362598e31SEd Tanous                             "Redfish log file created/deleted. event.name: {}",
79462598e31SEd Tanous                             fileName);
795b792cc56SAppaRao Puli                         if (event.mask == IN_CREATE)
796b792cc56SAppaRao Puli                         {
797b792cc56SAppaRao Puli                             if (fileWatchDesc != -1)
798b792cc56SAppaRao Puli                             {
79962598e31SEd Tanous                                 BMCWEB_LOG_DEBUG(
80062598e31SEd Tanous                                     "Remove and Add inotify watcher on "
80162598e31SEd Tanous                                     "redfish event log file");
802016761afSAppaRao Puli                                 // Remove existing inotify watcher and add
803016761afSAppaRao Puli                                 // with new redfish event log file.
804016761afSAppaRao Puli                                 inotify_rm_watch(inotifyFd, fileWatchDesc);
805016761afSAppaRao Puli                                 fileWatchDesc = -1;
806b792cc56SAppaRao Puli                             }
807b792cc56SAppaRao Puli 
808b792cc56SAppaRao Puli                             fileWatchDesc = inotify_add_watch(
809b792cc56SAppaRao Puli                                 inotifyFd, redfishEventLogFile, IN_MODIFY);
810b792cc56SAppaRao Puli                             if (fileWatchDesc == -1)
811b792cc56SAppaRao Puli                             {
81262598e31SEd Tanous                                 BMCWEB_LOG_ERROR("inotify_add_watch failed for "
81362598e31SEd Tanous                                                  "redfish log file.");
814b792cc56SAppaRao Puli                                 return;
815b792cc56SAppaRao Puli                             }
816b792cc56SAppaRao Puli 
817b792cc56SAppaRao Puli                             EventServiceManager::getInstance()
8182558979cSP Dheeraj Srujan Kumar                                 .resetRedfishFilePosition();
819b792cc56SAppaRao Puli                             EventServiceManager::getInstance()
820b792cc56SAppaRao Puli                                 .readEventLogsFromFile();
821b792cc56SAppaRao Puli                         }
822b792cc56SAppaRao Puli                         else if ((event.mask == IN_DELETE) ||
823b792cc56SAppaRao Puli                                  (event.mask == IN_MOVED_TO))
824b792cc56SAppaRao Puli                         {
825b792cc56SAppaRao Puli                             if (fileWatchDesc != -1)
826b792cc56SAppaRao Puli                             {
827b792cc56SAppaRao Puli                                 inotify_rm_watch(inotifyFd, fileWatchDesc);
828b792cc56SAppaRao Puli                                 fileWatchDesc = -1;
829b792cc56SAppaRao Puli                             }
830b792cc56SAppaRao Puli                         }
831b792cc56SAppaRao Puli                     }
832b792cc56SAppaRao Puli                     else if (event.wd == fileWatchDesc)
833b792cc56SAppaRao Puli                     {
834b792cc56SAppaRao Puli                         if (event.mask == IN_MODIFY)
8357f4eb588SAppaRao Puli                         {
8367f4eb588SAppaRao Puli                             EventServiceManager::getInstance()
8377f4eb588SAppaRao Puli                                 .readEventLogsFromFile();
8387f4eb588SAppaRao Puli                         }
839b792cc56SAppaRao Puli                     }
840b792cc56SAppaRao Puli                     index += (iEventSize + event.len);
8417f4eb588SAppaRao Puli                 }
8427f4eb588SAppaRao Puli 
8437f4eb588SAppaRao Puli                 watchRedfishEventLogFile();
8447f4eb588SAppaRao Puli             });
8457f4eb588SAppaRao Puli     }
8467f4eb588SAppaRao Puli 
8477f4eb588SAppaRao Puli     static int startEventLogMonitor(boost::asio::io_context& ioc)
8487f4eb588SAppaRao Puli     {
84903d4d37cSAlexander Hansen         BMCWEB_LOG_DEBUG("starting Event Log Monitor");
85003d4d37cSAlexander Hansen 
85123a21a1cSEd Tanous         inotifyConn.emplace(ioc);
852b792cc56SAppaRao Puli         inotifyFd = inotify_init1(IN_NONBLOCK);
853b792cc56SAppaRao Puli         if (inotifyFd == -1)
8547f4eb588SAppaRao Puli         {
85562598e31SEd Tanous             BMCWEB_LOG_ERROR("inotify_init1 failed.");
8567f4eb588SAppaRao Puli             return -1;
8577f4eb588SAppaRao Puli         }
858b792cc56SAppaRao Puli 
859b792cc56SAppaRao Puli         // Add watch on directory to handle redfish event log file
860b792cc56SAppaRao Puli         // create/delete.
861b792cc56SAppaRao Puli         dirWatchDesc = inotify_add_watch(inotifyFd, redfishEventLogDir,
862b792cc56SAppaRao Puli                                          IN_CREATE | IN_MOVED_TO | IN_DELETE);
863b792cc56SAppaRao Puli         if (dirWatchDesc == -1)
8647f4eb588SAppaRao Puli         {
86562598e31SEd Tanous             BMCWEB_LOG_ERROR(
86662598e31SEd Tanous                 "inotify_add_watch failed for event log directory.");
8677f4eb588SAppaRao Puli             return -1;
8687f4eb588SAppaRao Puli         }
8697f4eb588SAppaRao Puli 
870b792cc56SAppaRao Puli         // Watch redfish event log file for modifications.
871bd79bce8SPatrick Williams         fileWatchDesc =
872bd79bce8SPatrick Williams             inotify_add_watch(inotifyFd, redfishEventLogFile, IN_MODIFY);
873b792cc56SAppaRao Puli         if (fileWatchDesc == -1)
874b792cc56SAppaRao Puli         {
87562598e31SEd Tanous             BMCWEB_LOG_ERROR("inotify_add_watch failed for redfish log file.");
876b792cc56SAppaRao Puli             // Don't return error if file not exist.
877b792cc56SAppaRao Puli             // Watch on directory will handle create/delete of file.
878b792cc56SAppaRao Puli         }
879b792cc56SAppaRao Puli 
8807f4eb588SAppaRao Puli         // monitor redfish event log file
881b792cc56SAppaRao Puli         inotifyConn->assign(inotifyFd);
8827f4eb588SAppaRao Puli         watchRedfishEventLogFile();
8837f4eb588SAppaRao Puli 
8847f4eb588SAppaRao Puli         return 0;
8857f4eb588SAppaRao Puli     }
8867f4eb588SAppaRao Puli 
8879ed3f90aSEd Tanous     static void stopEventLogMonitor()
8889ed3f90aSEd Tanous     {
8899ed3f90aSEd Tanous         inotifyConn.reset();
8909ed3f90aSEd Tanous     }
8919ed3f90aSEd Tanous 
89259d494eeSPatrick Williams     static void getReadingsForReport(sdbusplus::message_t& msg)
893156d6b00SAppaRao Puli     {
89456d2396dSEd Tanous         if (msg.is_method_error())
89556d2396dSEd Tanous         {
89662598e31SEd Tanous             BMCWEB_LOG_ERROR("TelemetryMonitor Signal error");
89756d2396dSEd Tanous             return;
89856d2396dSEd Tanous         }
89956d2396dSEd Tanous 
900c0353249SWludzik, Jozef         sdbusplus::message::object_path path(msg.get_path());
901c0353249SWludzik, Jozef         std::string id = path.filename();
902c0353249SWludzik, Jozef         if (id.empty())
903156d6b00SAppaRao Puli         {
90462598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to get Id from path");
905156d6b00SAppaRao Puli             return;
906156d6b00SAppaRao Puli         }
907156d6b00SAppaRao Puli 
908c0353249SWludzik, Jozef         std::string interface;
909b9d36b47SEd Tanous         dbus::utility::DBusPropertiesMap props;
910c0353249SWludzik, Jozef         std::vector<std::string> invalidProps;
911c0353249SWludzik, Jozef         msg.read(interface, props, invalidProps);
912c0353249SWludzik, Jozef 
913bd79bce8SPatrick Williams         auto found = std::ranges::find_if(props, [](const auto& x) {
914bd79bce8SPatrick Williams             return x.first == "Readings";
915bd79bce8SPatrick Williams         });
916c0353249SWludzik, Jozef         if (found == props.end())
917156d6b00SAppaRao Puli         {
91862598e31SEd Tanous             BMCWEB_LOG_INFO("Failed to get Readings from Report properties");
919156d6b00SAppaRao Puli             return;
920156d6b00SAppaRao Puli         }
921156d6b00SAppaRao Puli 
9221e1e598dSJonathan Doman         const telemetry::TimestampReadings* readings =
9231e1e598dSJonathan Doman             std::get_if<telemetry::TimestampReadings>(&found->second);
924e662eae8SEd Tanous         if (readings == nullptr)
9251e1e598dSJonathan Doman         {
92662598e31SEd Tanous             BMCWEB_LOG_INFO("Failed to get Readings from Report properties");
9271e1e598dSJonathan Doman             return;
9281e1e598dSJonathan Doman         }
9291e1e598dSJonathan Doman 
930156d6b00SAppaRao Puli         for (const auto& it :
931156d6b00SAppaRao Puli              EventServiceManager::getInstance().subscriptionsMap)
932156d6b00SAppaRao Puli         {
933e05aec50SEd Tanous             Subscription& entry = *it.second;
9345fe4ef35SMyung Bae             if (entry.userSub->eventFormatType == metricReportFormatType)
935156d6b00SAppaRao Puli             {
9361e1e598dSJonathan Doman                 entry.filterAndSendReports(id, *readings);
937156d6b00SAppaRao Puli             }
938156d6b00SAppaRao Puli         }
939156d6b00SAppaRao Puli     }
940156d6b00SAppaRao Puli 
941156d6b00SAppaRao Puli     void unregisterMetricReportSignal()
942156d6b00SAppaRao Puli     {
9437d1cc387SAppaRao Puli         if (matchTelemetryMonitor)
9447d1cc387SAppaRao Puli         {
94562598e31SEd Tanous             BMCWEB_LOG_DEBUG("Metrics report signal - Unregister");
946156d6b00SAppaRao Puli             matchTelemetryMonitor.reset();
947156d6b00SAppaRao Puli             matchTelemetryMonitor = nullptr;
948156d6b00SAppaRao Puli         }
9497d1cc387SAppaRao Puli     }
950156d6b00SAppaRao Puli 
951156d6b00SAppaRao Puli     void registerMetricReportSignal()
952156d6b00SAppaRao Puli     {
9537d1cc387SAppaRao Puli         if (!serviceEnabled || matchTelemetryMonitor)
954156d6b00SAppaRao Puli         {
95562598e31SEd Tanous             BMCWEB_LOG_DEBUG("Not registering metric report signal.");
956156d6b00SAppaRao Puli             return;
957156d6b00SAppaRao Puli         }
958156d6b00SAppaRao Puli 
95962598e31SEd Tanous         BMCWEB_LOG_DEBUG("Metrics report signal - Register");
960c0353249SWludzik, Jozef         std::string matchStr = "type='signal',member='PropertiesChanged',"
961c0353249SWludzik, Jozef                                "interface='org.freedesktop.DBus.Properties',"
962c0353249SWludzik, Jozef                                "arg0=xyz.openbmc_project.Telemetry.Report";
963156d6b00SAppaRao Puli 
96459d494eeSPatrick Williams         matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match_t>(
96556d2396dSEd Tanous             *crow::connections::systemBus, matchStr, getReadingsForReport);
966156d6b00SAppaRao Puli     }
96723a21a1cSEd Tanous };
968b52664e2SAppaRao Puli 
969b52664e2SAppaRao Puli } // namespace redfish
970