xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision fb54610544f97b989b549d8fc94518e2d38c9467)
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
17b26ff34dSEd Tanous #include "dbus_log_watcher.hpp"
18*fb546105SMyung Bae #include "dbus_singleton.hpp"
193ccb3adbSEd Tanous #include "dbus_utility.hpp"
203ccb3adbSEd Tanous #include "error_messages.hpp"
21b80ba2e4SAlexander Hansen #include "event_log.hpp"
22d3a48a14SEd Tanous #include "event_matches_filter.hpp"
233ccb3adbSEd Tanous #include "event_service_store.hpp"
242185ddeaSEd Tanous #include "filesystem_log_watcher.hpp"
25c0353249SWludzik, Jozef #include "metric_report.hpp"
262c6ffdb0SEd Tanous #include "ossl_random.hpp"
273ccb3adbSEd Tanous #include "persistent_data.hpp"
2802c1e29fSAlexander Hansen #include "subscription.hpp"
292ac69850SEd Tanous #include "utility.hpp"
302ac69850SEd Tanous #include "utils/dbus_event_log_entry.hpp"
312ac69850SEd Tanous #include "utils/json_utils.hpp"
325b90429aSEd Tanous #include "utils/time_utils.hpp"
337f4eb588SAppaRao Puli 
34fb4fd5d4SZhenfei Tai #include <boost/asio/io_context.hpp>
35*fb546105SMyung Bae #include <boost/asio/steady_timer.hpp>
36f80a87f2SEd Tanous #include <boost/circular_buffer.hpp>
37b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp>
38ef4c65b7SEd Tanous #include <boost/url/format.hpp>
394a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp>
401214b7e7SGunnar Mills 
415e44e3d8SAppaRao Puli #include <algorithm>
42b52664e2SAppaRao Puli #include <cstdlib>
43b52664e2SAppaRao Puli #include <ctime>
44a14c9113SEd Tanous #include <format>
451bf712bcSAyushi Smriti #include <fstream>
46b52664e2SAppaRao Puli #include <memory>
47a14c9113SEd Tanous #include <string>
4856ba386dSMyung Bae #include <string_view>
495fe4ef35SMyung Bae #include <utility>
502ac69850SEd Tanous #include <variant>
51b52664e2SAppaRao Puli 
52b52664e2SAppaRao Puli namespace redfish
53b52664e2SAppaRao Puli {
54156d6b00SAppaRao Puli 
55156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event";
56156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport";
57156d6b00SAppaRao Puli 
581bf712bcSAyushi Smriti static constexpr const char* eventServiceFile =
591bf712bcSAyushi Smriti     "/var/lib/bmcweb/eventservice_config.json";
601bf712bcSAyushi Smriti 
61b52664e2SAppaRao Puli class EventServiceManager
62b52664e2SAppaRao Puli {
63b52664e2SAppaRao Puli   private:
64d3a9e084SEd Tanous     bool serviceEnabled = false;
65d3a9e084SEd Tanous     uint32_t retryAttempts = 0;
66d3a9e084SEd Tanous     uint32_t retryTimeoutInterval = 0;
677d1cc387SAppaRao Puli 
689f616dd1SEd Tanous     size_t noOfEventLogSubscribers{0};
699f616dd1SEd Tanous     size_t noOfMetricReportSubscribers{0};
706c58a03eSAlexander Hansen     std::optional<DbusEventLogMonitor> dbusEventLogMonitor;
712ac69850SEd Tanous     std::optional<DbusTelemetryMonitor> matchTelemetryMonitor;
727b669723SEd Tanous     std::optional<FilesystemLogWatcher> filesystemLogMonitor;
73b52664e2SAppaRao Puli     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
74b52664e2SAppaRao Puli         subscriptionsMap;
75b52664e2SAppaRao Puli 
769f616dd1SEd Tanous     uint64_t eventId{1};
7796330b99SSunitha Harish 
78f80a87f2SEd Tanous     struct Event
79f80a87f2SEd Tanous     {
80f80a87f2SEd Tanous         std::string id;
81f80a87f2SEd Tanous         nlohmann::json message;
82f80a87f2SEd Tanous     };
83f80a87f2SEd Tanous 
84f80a87f2SEd Tanous     constexpr static size_t maxMessages = 200;
85f80a87f2SEd Tanous     boost::circular_buffer<Event> messages{maxMessages};
86f80a87f2SEd Tanous 
87f8ca6d79SEd Tanous     boost::asio::io_context& ioc;
88f8ca6d79SEd Tanous 
89b52664e2SAppaRao Puli   public:
909f616dd1SEd Tanous     EventServiceManager(const EventServiceManager&) = delete;
919f616dd1SEd Tanous     EventServiceManager& operator=(const EventServiceManager&) = delete;
929f616dd1SEd Tanous     EventServiceManager(EventServiceManager&&) = delete;
939f616dd1SEd Tanous     EventServiceManager& operator=(EventServiceManager&&) = delete;
94ecd6a3a2SEd Tanous     ~EventServiceManager() = default;
959f616dd1SEd Tanous 
96f8ca6d79SEd Tanous     explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn)
97b52664e2SAppaRao Puli     {
98f8ca6d79SEd Tanous         // Load config from persist store.
99f8ca6d79SEd Tanous         initConfig();
100f8ca6d79SEd Tanous     }
101f8ca6d79SEd Tanous 
102f8ca6d79SEd Tanous     static EventServiceManager&
103f8ca6d79SEd Tanous         getInstance(boost::asio::io_context* ioc = nullptr)
104f8ca6d79SEd Tanous     {
105f8ca6d79SEd Tanous         static EventServiceManager handler(*ioc);
106b52664e2SAppaRao Puli         return handler;
107b52664e2SAppaRao Puli     }
108b52664e2SAppaRao Puli 
1091bf712bcSAyushi Smriti     void initConfig()
1101bf712bcSAyushi Smriti     {
11128afb49cSJunLin Chen         loadOldBehavior();
1121bf712bcSAyushi Smriti 
11328afb49cSJunLin Chen         persistent_data::EventServiceConfig eventServiceConfig =
11428afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
11528afb49cSJunLin Chen                 .getEventServiceConfig();
1161bf712bcSAyushi Smriti 
11728afb49cSJunLin Chen         serviceEnabled = eventServiceConfig.enabled;
11828afb49cSJunLin Chen         retryAttempts = eventServiceConfig.retryAttempts;
11928afb49cSJunLin Chen         retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval;
1201bf712bcSAyushi Smriti 
12128afb49cSJunLin Chen         for (const auto& it : persistent_data::EventServiceStore::getInstance()
12228afb49cSJunLin Chen                                   .subscriptionsConfigMap)
1231bf712bcSAyushi Smriti         {
1245fe4ef35SMyung Bae             std::shared_ptr<persistent_data::UserSubscription> newSub =
1255fe4ef35SMyung Bae                 it.second;
1264bbf237fSAppaRao Puli 
1276fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
1285fe4ef35SMyung Bae                 boost::urls::parse_absolute_uri(newSub->destinationUrl);
1291bf712bcSAyushi Smriti 
130a716aa74SEd Tanous             if (!url)
1311bf712bcSAyushi Smriti             {
13262598e31SEd Tanous                 BMCWEB_LOG_ERROR(
13362598e31SEd Tanous                     "Failed to validate and split destination url");
1341bf712bcSAyushi Smriti                 continue;
1351bf712bcSAyushi Smriti             }
1361bf712bcSAyushi Smriti             std::shared_ptr<Subscription> subValue =
13721a94d5cSMyung Bae                 std::make_shared<Subscription>(newSub, *url, ioc);
1385fe4ef35SMyung Bae             std::string id = subValue->userSub->id;
139a0969c70SMyung Bae             subValue->deleter = [id]() {
140a0969c70SMyung Bae                 EventServiceManager::getInstance().deleteSubscription(id);
141a0969c70SMyung Bae             };
1421bf712bcSAyushi Smriti 
143a0969c70SMyung Bae             subscriptionsMap.emplace(id, subValue);
14428afb49cSJunLin Chen 
14528afb49cSJunLin Chen             updateNoOfSubscribersCount();
14628afb49cSJunLin Chen 
14728afb49cSJunLin Chen             // Update retry configuration.
14828afb49cSJunLin Chen             subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
149*fb546105SMyung Bae 
150*fb546105SMyung Bae             // schedule a heartbeat if sendHeartbeat was set to true
151*fb546105SMyung Bae             if (subValue->userSub->sendHeartbeat)
152*fb546105SMyung Bae             {
153*fb546105SMyung Bae                 subValue->scheduleNextHeartbeatEvent();
154*fb546105SMyung Bae             }
1551bf712bcSAyushi Smriti         }
1561bf712bcSAyushi Smriti     }
1571bf712bcSAyushi Smriti 
15856d2396dSEd Tanous     static void loadOldBehavior()
159b52664e2SAppaRao Puli     {
16028afb49cSJunLin Chen         std::ifstream eventConfigFile(eventServiceFile);
16128afb49cSJunLin Chen         if (!eventConfigFile.good())
1621bf712bcSAyushi Smriti         {
16362598e31SEd Tanous             BMCWEB_LOG_DEBUG("Old eventService config not exist");
16428afb49cSJunLin Chen             return;
16528afb49cSJunLin Chen         }
16628afb49cSJunLin Chen         auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false);
16728afb49cSJunLin Chen         if (jsonData.is_discarded())
1684bbf237fSAppaRao Puli         {
16962598e31SEd Tanous             BMCWEB_LOG_ERROR("Old eventService config parse error.");
17028afb49cSJunLin Chen             return;
17128afb49cSJunLin Chen         }
17228afb49cSJunLin Chen 
1730bdda665SEd Tanous         const nlohmann::json::object_t* obj =
1740bdda665SEd Tanous             jsonData.get_ptr<const nlohmann::json::object_t*>();
1750bdda665SEd Tanous         for (const auto& item : *obj)
17628afb49cSJunLin Chen         {
1770bdda665SEd Tanous             if (item.first == "Configuration")
17828afb49cSJunLin Chen             {
17928afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
18028afb49cSJunLin Chen                     .getEventServiceConfig()
1810bdda665SEd Tanous                     .fromJson(item.second);
18228afb49cSJunLin Chen             }
1830bdda665SEd Tanous             else if (item.first == "Subscriptions")
18428afb49cSJunLin Chen             {
1850bdda665SEd Tanous                 for (const auto& elem : item.second)
18628afb49cSJunLin Chen                 {
1874b712a29SEd Tanous                     std::optional<persistent_data::UserSubscription>
18828afb49cSJunLin Chen                         newSubscription =
18928afb49cSJunLin Chen                             persistent_data::UserSubscription::fromJson(elem,
19028afb49cSJunLin Chen                                                                         true);
1914b712a29SEd Tanous                     if (!newSubscription)
19228afb49cSJunLin Chen                     {
19362598e31SEd Tanous                         BMCWEB_LOG_ERROR("Problem reading subscription "
19462598e31SEd Tanous                                          "from old persistent store");
1954bbf237fSAppaRao Puli                         continue;
1964bbf237fSAppaRao Puli                     }
1974b712a29SEd Tanous                     persistent_data::UserSubscription& newSub =
1984b712a29SEd Tanous                         *newSubscription;
1991bf712bcSAyushi Smriti 
20028afb49cSJunLin Chen                     std::uniform_int_distribution<uint32_t> dist(0);
20128afb49cSJunLin Chen                     bmcweb::OpenSSLGenerator gen;
2021bf712bcSAyushi Smriti 
20328afb49cSJunLin Chen                     std::string id;
2041bf712bcSAyushi Smriti 
20528afb49cSJunLin Chen                     int retry = 3;
206e662eae8SEd Tanous                     while (retry != 0)
2071bf712bcSAyushi Smriti                     {
20828afb49cSJunLin Chen                         id = std::to_string(dist(gen));
20928afb49cSJunLin Chen                         if (gen.error())
2107d1cc387SAppaRao Puli                         {
21128afb49cSJunLin Chen                             retry = 0;
21228afb49cSJunLin Chen                             break;
21328afb49cSJunLin Chen                         }
2144b712a29SEd Tanous                         newSub.id = id;
21528afb49cSJunLin Chen                         auto inserted =
21628afb49cSJunLin Chen                             persistent_data::EventServiceStore::getInstance()
2175fe4ef35SMyung Bae                                 .subscriptionsConfigMap.insert(std::pair(
2185fe4ef35SMyung Bae                                     id, std::make_shared<
2195fe4ef35SMyung Bae                                             persistent_data::UserSubscription>(
2205fe4ef35SMyung Bae                                             newSub)));
22128afb49cSJunLin Chen                         if (inserted.second)
22228afb49cSJunLin Chen                         {
22328afb49cSJunLin Chen                             break;
22428afb49cSJunLin Chen                         }
22528afb49cSJunLin Chen                         --retry;
2267d1cc387SAppaRao Puli                     }
2277d1cc387SAppaRao Puli 
22828afb49cSJunLin Chen                     if (retry <= 0)
22928afb49cSJunLin Chen                     {
23062598e31SEd Tanous                         BMCWEB_LOG_ERROR(
23162598e31SEd Tanous                             "Failed to generate random number from old "
23262598e31SEd Tanous                             "persistent store");
23328afb49cSJunLin Chen                         continue;
23428afb49cSJunLin Chen                     }
23528afb49cSJunLin Chen                 }
23628afb49cSJunLin Chen             }
23728afb49cSJunLin Chen 
23828afb49cSJunLin Chen             persistent_data::getConfig().writeData();
2394c521c3cSEd Tanous             std::error_code ec;
2404c521c3cSEd Tanous             std::filesystem::remove(eventServiceFile, ec);
2414c521c3cSEd Tanous             if (ec)
2424c521c3cSEd Tanous             {
2434c521c3cSEd Tanous                 BMCWEB_LOG_DEBUG(
2444c521c3cSEd Tanous                     "Failed to remove old event service file.  Ignoring");
2454c521c3cSEd Tanous             }
2464c521c3cSEd Tanous             else
2474c521c3cSEd Tanous             {
24862598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Remove old eventservice config");
24928afb49cSJunLin Chen             }
25028afb49cSJunLin Chen         }
2514c521c3cSEd Tanous     }
25228afb49cSJunLin Chen 
2539eb808c1SEd Tanous     void updateSubscriptionData() const
25428afb49cSJunLin Chen     {
25528afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25628afb49cSJunLin Chen             .eventServiceConfig.enabled = serviceEnabled;
25728afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25828afb49cSJunLin Chen             .eventServiceConfig.retryAttempts = retryAttempts;
25928afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
26028afb49cSJunLin Chen             .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval;
26128afb49cSJunLin Chen 
26228afb49cSJunLin Chen         persistent_data::getConfig().writeData();
26328afb49cSJunLin Chen     }
26428afb49cSJunLin Chen 
26528afb49cSJunLin Chen     void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg)
2667d1cc387SAppaRao Puli     {
2677d1cc387SAppaRao Puli         bool updateConfig = false;
268fe44eb0bSAyushi Smriti         bool updateRetryCfg = false;
2697d1cc387SAppaRao Puli 
2702ac69850SEd Tanous         if (serviceEnabled)
2717d1cc387SAppaRao Puli         {
2727b669723SEd Tanous             if (noOfEventLogSubscribers > 0U)
2737b669723SEd Tanous             {
2746c58a03eSAlexander Hansen                 if constexpr (BMCWEB_REDFISH_DBUS_LOG)
2756c58a03eSAlexander Hansen                 {
2766c58a03eSAlexander Hansen                     if (!dbusEventLogMonitor)
2776c58a03eSAlexander Hansen                     {
2786c58a03eSAlexander Hansen                         if constexpr (
2796c58a03eSAlexander Hansen                             BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION)
2806c58a03eSAlexander Hansen                         {
2816c58a03eSAlexander Hansen                             dbusEventLogMonitor.emplace();
2826c58a03eSAlexander Hansen                         }
2836c58a03eSAlexander Hansen                     }
2846c58a03eSAlexander Hansen                 }
2856c58a03eSAlexander Hansen                 else
2867b669723SEd Tanous                 {
2877b669723SEd Tanous                     if (!filesystemLogMonitor)
2887b669723SEd Tanous                     {
2897b669723SEd Tanous                         filesystemLogMonitor.emplace(ioc);
2907b669723SEd Tanous                     }
2917b669723SEd Tanous                 }
2927b669723SEd Tanous             }
2937b669723SEd Tanous             else
2947b669723SEd Tanous             {
2956c58a03eSAlexander Hansen                 dbusEventLogMonitor.reset();
2967b669723SEd Tanous                 filesystemLogMonitor.reset();
2977b669723SEd Tanous             }
2987b669723SEd Tanous 
2992ac69850SEd Tanous             if (noOfMetricReportSubscribers > 0U)
3007d1cc387SAppaRao Puli             {
3012ac69850SEd Tanous                 if (!matchTelemetryMonitor)
3022ac69850SEd Tanous                 {
3032ac69850SEd Tanous                     matchTelemetryMonitor.emplace();
3042ac69850SEd Tanous                 }
3057d1cc387SAppaRao Puli             }
3067d1cc387SAppaRao Puli             else
3077d1cc387SAppaRao Puli             {
3082ac69850SEd Tanous                 matchTelemetryMonitor.reset();
3097d1cc387SAppaRao Puli             }
3102ac69850SEd Tanous         }
3112ac69850SEd Tanous         else
3122ac69850SEd Tanous         {
3132ac69850SEd Tanous             matchTelemetryMonitor.reset();
3146c58a03eSAlexander Hansen             dbusEventLogMonitor.reset();
3157b669723SEd Tanous             filesystemLogMonitor.reset();
3162ac69850SEd Tanous         }
3172ac69850SEd Tanous 
3182ac69850SEd Tanous         if (serviceEnabled != cfg.enabled)
3192ac69850SEd Tanous         {
3202ac69850SEd Tanous             serviceEnabled = cfg.enabled;
3217d1cc387SAppaRao Puli             updateConfig = true;
3227d1cc387SAppaRao Puli         }
3237d1cc387SAppaRao Puli 
32428afb49cSJunLin Chen         if (retryAttempts != cfg.retryAttempts)
3257d1cc387SAppaRao Puli         {
32628afb49cSJunLin Chen             retryAttempts = cfg.retryAttempts;
3277d1cc387SAppaRao Puli             updateConfig = true;
328fe44eb0bSAyushi Smriti             updateRetryCfg = true;
3297d1cc387SAppaRao Puli         }
3307d1cc387SAppaRao Puli 
33128afb49cSJunLin Chen         if (retryTimeoutInterval != cfg.retryTimeoutInterval)
3327d1cc387SAppaRao Puli         {
33328afb49cSJunLin Chen             retryTimeoutInterval = cfg.retryTimeoutInterval;
3347d1cc387SAppaRao Puli             updateConfig = true;
335fe44eb0bSAyushi Smriti             updateRetryCfg = true;
3367d1cc387SAppaRao Puli         }
3377d1cc387SAppaRao Puli 
3387d1cc387SAppaRao Puli         if (updateConfig)
3397d1cc387SAppaRao Puli         {
3407d1cc387SAppaRao Puli             updateSubscriptionData();
3417d1cc387SAppaRao Puli         }
342fe44eb0bSAyushi Smriti 
343fe44eb0bSAyushi Smriti         if (updateRetryCfg)
344fe44eb0bSAyushi Smriti         {
345fe44eb0bSAyushi Smriti             // Update the changed retry config to all subscriptions
346fe44eb0bSAyushi Smriti             for (const auto& it :
347fe44eb0bSAyushi Smriti                  EventServiceManager::getInstance().subscriptionsMap)
348fe44eb0bSAyushi Smriti             {
3495e44e3d8SAppaRao Puli                 Subscription& entry = *it.second;
3505e44e3d8SAppaRao Puli                 entry.updateRetryConfig(retryAttempts, retryTimeoutInterval);
351fe44eb0bSAyushi Smriti             }
352fe44eb0bSAyushi Smriti         }
3537d1cc387SAppaRao Puli     }
3547d1cc387SAppaRao Puli 
3557d1cc387SAppaRao Puli     void updateNoOfSubscribersCount()
3567d1cc387SAppaRao Puli     {
3577d1cc387SAppaRao Puli         size_t eventLogSubCount = 0;
3587d1cc387SAppaRao Puli         size_t metricReportSubCount = 0;
3597d1cc387SAppaRao Puli         for (const auto& it : subscriptionsMap)
3607d1cc387SAppaRao Puli         {
3617d1cc387SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
3625fe4ef35SMyung Bae             if (entry->userSub->eventFormatType == eventFormatType)
3637d1cc387SAppaRao Puli             {
3647d1cc387SAppaRao Puli                 eventLogSubCount++;
3657d1cc387SAppaRao Puli             }
3665fe4ef35SMyung Bae             else if (entry->userSub->eventFormatType == metricReportFormatType)
3677d1cc387SAppaRao Puli             {
3687d1cc387SAppaRao Puli                 metricReportSubCount++;
3697d1cc387SAppaRao Puli             }
3707d1cc387SAppaRao Puli         }
3717d1cc387SAppaRao Puli         noOfEventLogSubscribers = eventLogSubCount;
3726c58a03eSAlexander Hansen         if (eventLogSubCount > 0U)
3737d1cc387SAppaRao Puli         {
3746c58a03eSAlexander Hansen             if constexpr (BMCWEB_REDFISH_DBUS_LOG)
3756c58a03eSAlexander Hansen             {
3766c58a03eSAlexander Hansen                 if (!dbusEventLogMonitor &&
3776c58a03eSAlexander Hansen                     BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION)
3786c58a03eSAlexander Hansen                 {
3796c58a03eSAlexander Hansen                     dbusEventLogMonitor.emplace();
3806c58a03eSAlexander Hansen                 }
3816c58a03eSAlexander Hansen             }
3826c58a03eSAlexander Hansen             else
3836c58a03eSAlexander Hansen             {
3846c58a03eSAlexander Hansen                 if (!filesystemLogMonitor)
3856c58a03eSAlexander Hansen                 {
3866c58a03eSAlexander Hansen                     filesystemLogMonitor.emplace(ioc);
3876c58a03eSAlexander Hansen                 }
3886c58a03eSAlexander Hansen             }
3896c58a03eSAlexander Hansen         }
3906c58a03eSAlexander Hansen         else
3916c58a03eSAlexander Hansen         {
3926c58a03eSAlexander Hansen             dbusEventLogMonitor.reset();
3936c58a03eSAlexander Hansen             filesystemLogMonitor.reset();
3946c58a03eSAlexander Hansen         }
3956c58a03eSAlexander Hansen 
3967d1cc387SAppaRao Puli         noOfMetricReportSubscribers = metricReportSubCount;
3976c58a03eSAlexander Hansen         if (metricReportSubCount > 0U)
3987d1cc387SAppaRao Puli         {
3992ac69850SEd Tanous             if (!matchTelemetryMonitor)
4002ac69850SEd Tanous             {
4012ac69850SEd Tanous                 matchTelemetryMonitor.emplace();
4022ac69850SEd Tanous             }
4037d1cc387SAppaRao Puli         }
4047d1cc387SAppaRao Puli         else
4057d1cc387SAppaRao Puli         {
4062ac69850SEd Tanous             matchTelemetryMonitor.reset();
4077d1cc387SAppaRao Puli         }
4087d1cc387SAppaRao Puli     }
4097d1cc387SAppaRao Puli 
410b52664e2SAppaRao Puli     std::shared_ptr<Subscription> getSubscription(const std::string& id)
411b52664e2SAppaRao Puli     {
412b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
413b52664e2SAppaRao Puli         if (obj == subscriptionsMap.end())
414b52664e2SAppaRao Puli         {
41562598e31SEd Tanous             BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id);
416b52664e2SAppaRao Puli             return nullptr;
417b52664e2SAppaRao Puli         }
418b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue = obj->second;
419b52664e2SAppaRao Puli         return subValue;
420b52664e2SAppaRao Puli     }
421b52664e2SAppaRao Puli 
422f80a87f2SEd Tanous     std::string
423f80a87f2SEd Tanous         addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue)
424b52664e2SAppaRao Puli     {
425fc76b8acSEd Tanous         std::uniform_int_distribution<uint32_t> dist(0);
426fc76b8acSEd Tanous         bmcweb::OpenSSLGenerator gen;
427fc76b8acSEd Tanous 
428b52664e2SAppaRao Puli         std::string id;
429b52664e2SAppaRao Puli 
430b52664e2SAppaRao Puli         int retry = 3;
431e662eae8SEd Tanous         while (retry != 0)
432b52664e2SAppaRao Puli         {
433fc76b8acSEd Tanous             id = std::to_string(dist(gen));
434fc76b8acSEd Tanous             if (gen.error())
435fc76b8acSEd Tanous             {
436fc76b8acSEd Tanous                 retry = 0;
437fc76b8acSEd Tanous                 break;
438fc76b8acSEd Tanous             }
439b52664e2SAppaRao Puli             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
440b52664e2SAppaRao Puli             if (inserted.second)
441b52664e2SAppaRao Puli             {
442b52664e2SAppaRao Puli                 break;
443b52664e2SAppaRao Puli             }
444b52664e2SAppaRao Puli             --retry;
44523a21a1cSEd Tanous         }
446b52664e2SAppaRao Puli 
447b52664e2SAppaRao Puli         if (retry <= 0)
448b52664e2SAppaRao Puli         {
44962598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to generate random number");
450abb93cddSEd Tanous             return "";
451b52664e2SAppaRao Puli         }
452b52664e2SAppaRao Puli 
45356ba386dSMyung Bae         // Set Subscription ID for back trace
4545fe4ef35SMyung Bae         subValue->userSub->id = id;
455a14c9113SEd Tanous 
45628afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
4575fe4ef35SMyung Bae             .subscriptionsConfigMap.emplace(id, subValue->userSub);
45828afb49cSJunLin Chen 
4597d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
4601bf712bcSAyushi Smriti 
461fe44eb0bSAyushi Smriti         // Update retry configuration.
462fe44eb0bSAyushi Smriti         subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
463fe44eb0bSAyushi Smriti 
464f80a87f2SEd Tanous         return id;
465f80a87f2SEd Tanous     }
466f80a87f2SEd Tanous 
467f80a87f2SEd Tanous     std::string
468f80a87f2SEd Tanous         addSSESubscription(const std::shared_ptr<Subscription>& subValue,
469f80a87f2SEd Tanous                            std::string_view lastEventId)
470f80a87f2SEd Tanous     {
471f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
472f80a87f2SEd Tanous 
473f80a87f2SEd Tanous         if (!lastEventId.empty())
474f80a87f2SEd Tanous         {
475f80a87f2SEd Tanous             BMCWEB_LOG_INFO("Attempting to find message for last id {}",
476f80a87f2SEd Tanous                             lastEventId);
477f80a87f2SEd Tanous             boost::circular_buffer<Event>::iterator lastEvent =
478f80a87f2SEd Tanous                 std::find_if(messages.begin(), messages.end(),
479f80a87f2SEd Tanous                              [&lastEventId](const Event& event) {
480f80a87f2SEd Tanous                                  return event.id == lastEventId;
481f80a87f2SEd Tanous                              });
482f80a87f2SEd Tanous             // Can't find a matching ID
483f80a87f2SEd Tanous             if (lastEvent == messages.end())
484f80a87f2SEd Tanous             {
485f80a87f2SEd Tanous                 nlohmann::json msg = messages::eventBufferExceeded();
486f80a87f2SEd Tanous                 // If the buffer overloaded, send all messages.
4876d799e14SEd Tanous                 subValue->sendEventToSubscriber(msg);
488f80a87f2SEd Tanous                 lastEvent = messages.begin();
489f80a87f2SEd Tanous             }
490f80a87f2SEd Tanous             else
491f80a87f2SEd Tanous             {
492f80a87f2SEd Tanous                 // Skip the last event the user already has
493f80a87f2SEd Tanous                 lastEvent++;
494f80a87f2SEd Tanous             }
495f80a87f2SEd Tanous 
496f80a87f2SEd Tanous             for (boost::circular_buffer<Event>::const_iterator event =
497f80a87f2SEd Tanous                      lastEvent;
498f80a87f2SEd Tanous                  lastEvent != messages.end(); lastEvent++)
499f80a87f2SEd Tanous             {
5006d799e14SEd Tanous                 subValue->sendEventToSubscriber(event->message);
501f80a87f2SEd Tanous             }
502f80a87f2SEd Tanous         }
503f80a87f2SEd Tanous         return id;
504f80a87f2SEd Tanous     }
505f80a87f2SEd Tanous 
506f80a87f2SEd Tanous     std::string
507f80a87f2SEd Tanous         addPushSubscription(const std::shared_ptr<Subscription>& subValue)
508f80a87f2SEd Tanous     {
509f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
510a0969c70SMyung Bae         subValue->deleter = [id]() {
511a0969c70SMyung Bae             EventServiceManager::getInstance().deleteSubscription(id);
512a0969c70SMyung Bae         };
513f80a87f2SEd Tanous         updateSubscriptionData();
514b52664e2SAppaRao Puli         return id;
515b52664e2SAppaRao Puli     }
516b52664e2SAppaRao Puli 
517b52664e2SAppaRao Puli     bool isSubscriptionExist(const std::string& id)
518b52664e2SAppaRao Puli     {
519b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
52055f79e6fSEd Tanous         return obj != subscriptionsMap.end();
521b52664e2SAppaRao Puli     }
522b52664e2SAppaRao Puli 
5234b712a29SEd Tanous     bool deleteSubscription(const std::string& id)
524b52664e2SAppaRao Puli     {
525b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
5264b712a29SEd Tanous         if (obj == subscriptionsMap.end())
527b52664e2SAppaRao Puli         {
5284b712a29SEd Tanous             BMCWEB_LOG_WARNING("Could not find subscription with id {}", id);
5294b712a29SEd Tanous             return false;
5304b712a29SEd Tanous         }
531b52664e2SAppaRao Puli         subscriptionsMap.erase(obj);
5324b712a29SEd Tanous         auto& event = persistent_data::EventServiceStore::getInstance();
5334b712a29SEd Tanous         auto persistentObj = event.subscriptionsConfigMap.find(id);
5344b712a29SEd Tanous         if (persistentObj == event.subscriptionsConfigMap.end())
5354b712a29SEd Tanous         {
5364b712a29SEd Tanous             BMCWEB_LOG_ERROR("Subscription wasn't in persistent data");
5374b712a29SEd Tanous             return true;
5384b712a29SEd Tanous         }
53928afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
5404b712a29SEd Tanous             .subscriptionsConfigMap.erase(persistentObj);
5417d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
542b52664e2SAppaRao Puli         updateSubscriptionData();
5434b712a29SEd Tanous 
5444b712a29SEd Tanous         return true;
545b52664e2SAppaRao Puli     }
546b52664e2SAppaRao Puli 
5475e44e3d8SAppaRao Puli     void deleteSseSubscription(const crow::sse_socket::Connection& thisConn)
5485e44e3d8SAppaRao Puli     {
549bdbfae2aSEd Tanous         for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();)
5505e44e3d8SAppaRao Puli         {
551bdbfae2aSEd Tanous             std::shared_ptr<Subscription> entry = it->second;
5525e44e3d8SAppaRao Puli             bool entryIsThisConn = entry->matchSseId(thisConn);
5535e44e3d8SAppaRao Puli             if (entryIsThisConn)
5545e44e3d8SAppaRao Puli             {
5555e44e3d8SAppaRao Puli                 persistent_data::EventServiceStore::getInstance()
5565fe4ef35SMyung Bae                     .subscriptionsConfigMap.erase(entry->userSub->id);
557bdbfae2aSEd Tanous                 it = subscriptionsMap.erase(it);
5585e44e3d8SAppaRao Puli                 return;
5595e44e3d8SAppaRao Puli             }
560bdbfae2aSEd Tanous             it++;
5615e44e3d8SAppaRao Puli         }
5625e44e3d8SAppaRao Puli     }
5635e44e3d8SAppaRao Puli 
5645e44e3d8SAppaRao Puli     size_t getNumberOfSubscriptions() const
565b52664e2SAppaRao Puli     {
566b52664e2SAppaRao Puli         return subscriptionsMap.size();
567b52664e2SAppaRao Puli     }
568b52664e2SAppaRao Puli 
5695e44e3d8SAppaRao Puli     size_t getNumberOfSSESubscriptions() const
5705e44e3d8SAppaRao Puli     {
5713544d2a7SEd Tanous         auto size = std::ranges::count_if(
5723544d2a7SEd Tanous             subscriptionsMap,
5735e44e3d8SAppaRao Puli             [](const std::pair<std::string, std::shared_ptr<Subscription>>&
5745e44e3d8SAppaRao Puli                    entry) {
5755fe4ef35SMyung Bae                 return (entry.second->userSub->subscriptionType ==
5764b712a29SEd Tanous                         subscriptionTypeSSE);
5775e44e3d8SAppaRao Puli             });
5785e44e3d8SAppaRao Puli         return static_cast<size_t>(size);
5795e44e3d8SAppaRao Puli     }
5805e44e3d8SAppaRao Puli 
581b52664e2SAppaRao Puli     std::vector<std::string> getAllIDs()
582b52664e2SAppaRao Puli     {
583b52664e2SAppaRao Puli         std::vector<std::string> idList;
584b52664e2SAppaRao Puli         for (const auto& it : subscriptionsMap)
585b52664e2SAppaRao Puli         {
586b52664e2SAppaRao Puli             idList.emplace_back(it.first);
587b52664e2SAppaRao Puli         }
588b52664e2SAppaRao Puli         return idList;
589b52664e2SAppaRao Puli     }
590b52664e2SAppaRao Puli 
5916ba8c82eSsunharis_in     bool sendTestEventLog()
5920b4bdd93SAppaRao Puli     {
5935e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
5940b4bdd93SAppaRao Puli         {
5950b4bdd93SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
5966ba8c82eSsunharis_in             if (!entry->sendTestEventLog())
5976ba8c82eSsunharis_in             {
5986ba8c82eSsunharis_in                 return false;
5990b4bdd93SAppaRao Puli             }
6000b4bdd93SAppaRao Puli         }
6016ba8c82eSsunharis_in         return true;
6026ba8c82eSsunharis_in     }
603e9a14131SAppaRao Puli 
6043433b03aSEd Tanous     static void
6053433b03aSEd Tanous         sendEventsToSubs(const std::vector<EventLogObjectsType>& eventRecords)
6063433b03aSEd Tanous     {
6073433b03aSEd Tanous         for (const auto& it :
6083433b03aSEd Tanous              EventServiceManager::getInstance().subscriptionsMap)
6093433b03aSEd Tanous         {
6103433b03aSEd Tanous             Subscription& entry = *it.second;
6113433b03aSEd Tanous             entry.filterAndSendEventLogs(eventRecords);
6123433b03aSEd Tanous         }
6133433b03aSEd Tanous     }
6143433b03aSEd Tanous 
615b26ff34dSEd Tanous     static void sendTelemetryReportToSubs(
616b26ff34dSEd Tanous         const std::string& reportId, const telemetry::TimestampReadings& var)
617b26ff34dSEd Tanous     {
618b26ff34dSEd Tanous         for (const auto& it :
619b26ff34dSEd Tanous              EventServiceManager::getInstance().subscriptionsMap)
620b26ff34dSEd Tanous         {
621b26ff34dSEd Tanous             Subscription& entry = *it.second;
622b26ff34dSEd Tanous             entry.filterAndSendReports(reportId, var);
623b26ff34dSEd Tanous         }
624b26ff34dSEd Tanous     }
625b26ff34dSEd Tanous 
626f80a87f2SEd Tanous     void sendEvent(nlohmann::json::object_t eventMessage,
627f80a87f2SEd Tanous                    std::string_view origin, std::string_view resourceType)
62896330b99SSunitha Harish     {
629613dabeaSEd Tanous         eventMessage["EventId"] = eventId;
630f80a87f2SEd Tanous 
631613dabeaSEd Tanous         eventMessage["EventTimestamp"] =
632613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
633613dabeaSEd Tanous         eventMessage["OriginOfCondition"] = origin;
634613dabeaSEd Tanous 
635f80a87f2SEd Tanous         // MemberId is 0 : since we are sending one event record.
636788b091bSIgor Kanyuka         eventMessage["MemberId"] = "0";
63796330b99SSunitha Harish 
638f80a87f2SEd Tanous         messages.push_back(Event(std::to_string(eventId), eventMessage));
639f80a87f2SEd Tanous 
640f80a87f2SEd Tanous         for (auto& it : subscriptionsMap)
64196330b99SSunitha Harish         {
642f80a87f2SEd Tanous             std::shared_ptr<Subscription>& entry = it.second;
6435fe4ef35SMyung Bae             if (!eventMatchesFilter(*entry->userSub, eventMessage,
6445fe4ef35SMyung Bae                                     resourceType))
64596330b99SSunitha Harish             {
646f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Filter didn't match");
647f80a87f2SEd Tanous                 continue;
64896330b99SSunitha Harish             }
649f80a87f2SEd Tanous 
650f80a87f2SEd Tanous             nlohmann::json::array_t eventRecord;
651f80a87f2SEd Tanous             eventRecord.emplace_back(eventMessage);
652f80a87f2SEd Tanous 
653613dabeaSEd Tanous             nlohmann::json msgJson;
654613dabeaSEd Tanous 
655613dabeaSEd Tanous             msgJson["@odata.type"] = "#Event.v1_4_0.Event";
656613dabeaSEd Tanous             msgJson["Name"] = "Event Log";
657613dabeaSEd Tanous             msgJson["Id"] = eventId;
658f80a87f2SEd Tanous             msgJson["Events"] = std::move(eventRecord);
659f52c03c1SCarson Labrado 
660f52c03c1SCarson Labrado             std::string strMsg = msgJson.dump(
661f52c03c1SCarson Labrado                 2, ' ', true, nlohmann::json::error_handler_t::replace);
6626d799e14SEd Tanous             entry->sendEventToSubscriber(std::move(strMsg));
6638ece0e45SEd Tanous             eventId++; // increment the eventId
66496330b99SSunitha Harish         }
66596330b99SSunitha Harish     }
66623a21a1cSEd Tanous };
667b52664e2SAppaRao Puli 
668b52664e2SAppaRao Puli } // namespace redfish
669