xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision 1c588de91fcb0c436cb82e9f7c7b05fe6e063066)
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"
18fb546105SMyung 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>
35fb546105SMyung 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);
149fb546105SMyung Bae 
150fb546105SMyung Bae             // schedule a heartbeat if sendHeartbeat was set to true
151fb546105SMyung Bae             if (subValue->userSub->sendHeartbeat)
152fb546105SMyung Bae             {
153fb546105SMyung Bae                 subValue->scheduleNextHeartbeatEvent();
154fb546105SMyung 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*>();
175*1c588de9SAbiola Asojo         if (obj == nullptr)
176*1c588de9SAbiola Asojo         {
177*1c588de9SAbiola Asojo             return;
178*1c588de9SAbiola Asojo         }
1790bdda665SEd Tanous         for (const auto& item : *obj)
18028afb49cSJunLin Chen         {
1810bdda665SEd Tanous             if (item.first == "Configuration")
18228afb49cSJunLin Chen             {
18328afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
18428afb49cSJunLin Chen                     .getEventServiceConfig()
1850bdda665SEd Tanous                     .fromJson(item.second);
18628afb49cSJunLin Chen             }
1870bdda665SEd Tanous             else if (item.first == "Subscriptions")
18828afb49cSJunLin Chen             {
1890bdda665SEd Tanous                 for (const auto& elem : item.second)
19028afb49cSJunLin Chen                 {
1914b712a29SEd Tanous                     std::optional<persistent_data::UserSubscription>
19228afb49cSJunLin Chen                         newSubscription =
19328afb49cSJunLin Chen                             persistent_data::UserSubscription::fromJson(elem,
19428afb49cSJunLin Chen                                                                         true);
1954b712a29SEd Tanous                     if (!newSubscription)
19628afb49cSJunLin Chen                     {
19762598e31SEd Tanous                         BMCWEB_LOG_ERROR("Problem reading subscription "
19862598e31SEd Tanous                                          "from old persistent store");
1994bbf237fSAppaRao Puli                         continue;
2004bbf237fSAppaRao Puli                     }
2014b712a29SEd Tanous                     persistent_data::UserSubscription& newSub =
2024b712a29SEd Tanous                         *newSubscription;
2031bf712bcSAyushi Smriti 
20428afb49cSJunLin Chen                     std::uniform_int_distribution<uint32_t> dist(0);
20528afb49cSJunLin Chen                     bmcweb::OpenSSLGenerator gen;
2061bf712bcSAyushi Smriti 
20728afb49cSJunLin Chen                     std::string id;
2081bf712bcSAyushi Smriti 
20928afb49cSJunLin Chen                     int retry = 3;
210e662eae8SEd Tanous                     while (retry != 0)
2111bf712bcSAyushi Smriti                     {
21228afb49cSJunLin Chen                         id = std::to_string(dist(gen));
21328afb49cSJunLin Chen                         if (gen.error())
2147d1cc387SAppaRao Puli                         {
21528afb49cSJunLin Chen                             retry = 0;
21628afb49cSJunLin Chen                             break;
21728afb49cSJunLin Chen                         }
2184b712a29SEd Tanous                         newSub.id = id;
21928afb49cSJunLin Chen                         auto inserted =
22028afb49cSJunLin Chen                             persistent_data::EventServiceStore::getInstance()
2215fe4ef35SMyung Bae                                 .subscriptionsConfigMap.insert(std::pair(
2225fe4ef35SMyung Bae                                     id, std::make_shared<
2235fe4ef35SMyung Bae                                             persistent_data::UserSubscription>(
2245fe4ef35SMyung Bae                                             newSub)));
22528afb49cSJunLin Chen                         if (inserted.second)
22628afb49cSJunLin Chen                         {
22728afb49cSJunLin Chen                             break;
22828afb49cSJunLin Chen                         }
22928afb49cSJunLin Chen                         --retry;
2307d1cc387SAppaRao Puli                     }
2317d1cc387SAppaRao Puli 
23228afb49cSJunLin Chen                     if (retry <= 0)
23328afb49cSJunLin Chen                     {
23462598e31SEd Tanous                         BMCWEB_LOG_ERROR(
23562598e31SEd Tanous                             "Failed to generate random number from old "
23662598e31SEd Tanous                             "persistent store");
23728afb49cSJunLin Chen                         continue;
23828afb49cSJunLin Chen                     }
23928afb49cSJunLin Chen                 }
24028afb49cSJunLin Chen             }
24128afb49cSJunLin Chen 
24228afb49cSJunLin Chen             persistent_data::getConfig().writeData();
2434c521c3cSEd Tanous             std::error_code ec;
2444c521c3cSEd Tanous             std::filesystem::remove(eventServiceFile, ec);
2454c521c3cSEd Tanous             if (ec)
2464c521c3cSEd Tanous             {
2474c521c3cSEd Tanous                 BMCWEB_LOG_DEBUG(
2484c521c3cSEd Tanous                     "Failed to remove old event service file.  Ignoring");
2494c521c3cSEd Tanous             }
2504c521c3cSEd Tanous             else
2514c521c3cSEd Tanous             {
25262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Remove old eventservice config");
25328afb49cSJunLin Chen             }
25428afb49cSJunLin Chen         }
2554c521c3cSEd Tanous     }
25628afb49cSJunLin Chen 
2579eb808c1SEd Tanous     void updateSubscriptionData() const
25828afb49cSJunLin Chen     {
25928afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
26028afb49cSJunLin Chen             .eventServiceConfig.enabled = serviceEnabled;
26128afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
26228afb49cSJunLin Chen             .eventServiceConfig.retryAttempts = retryAttempts;
26328afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
26428afb49cSJunLin Chen             .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval;
26528afb49cSJunLin Chen 
26628afb49cSJunLin Chen         persistent_data::getConfig().writeData();
26728afb49cSJunLin Chen     }
26828afb49cSJunLin Chen 
26928afb49cSJunLin Chen     void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg)
2707d1cc387SAppaRao Puli     {
2717d1cc387SAppaRao Puli         bool updateConfig = false;
272fe44eb0bSAyushi Smriti         bool updateRetryCfg = false;
2737d1cc387SAppaRao Puli 
2742ac69850SEd Tanous         if (serviceEnabled)
2757d1cc387SAppaRao Puli         {
2767b669723SEd Tanous             if (noOfEventLogSubscribers > 0U)
2777b669723SEd Tanous             {
2786c58a03eSAlexander Hansen                 if constexpr (BMCWEB_REDFISH_DBUS_LOG)
2796c58a03eSAlexander Hansen                 {
2806c58a03eSAlexander Hansen                     if (!dbusEventLogMonitor)
2816c58a03eSAlexander Hansen                     {
2826c58a03eSAlexander Hansen                         if constexpr (
2836c58a03eSAlexander Hansen                             BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION)
2846c58a03eSAlexander Hansen                         {
2856c58a03eSAlexander Hansen                             dbusEventLogMonitor.emplace();
2866c58a03eSAlexander Hansen                         }
2876c58a03eSAlexander Hansen                     }
2886c58a03eSAlexander Hansen                 }
2896c58a03eSAlexander Hansen                 else
2907b669723SEd Tanous                 {
2917b669723SEd Tanous                     if (!filesystemLogMonitor)
2927b669723SEd Tanous                     {
2937b669723SEd Tanous                         filesystemLogMonitor.emplace(ioc);
2947b669723SEd Tanous                     }
2957b669723SEd Tanous                 }
2967b669723SEd Tanous             }
2977b669723SEd Tanous             else
2987b669723SEd Tanous             {
2996c58a03eSAlexander Hansen                 dbusEventLogMonitor.reset();
3007b669723SEd Tanous                 filesystemLogMonitor.reset();
3017b669723SEd Tanous             }
3027b669723SEd Tanous 
3032ac69850SEd Tanous             if (noOfMetricReportSubscribers > 0U)
3047d1cc387SAppaRao Puli             {
3052ac69850SEd Tanous                 if (!matchTelemetryMonitor)
3062ac69850SEd Tanous                 {
3072ac69850SEd Tanous                     matchTelemetryMonitor.emplace();
3082ac69850SEd Tanous                 }
3097d1cc387SAppaRao Puli             }
3107d1cc387SAppaRao Puli             else
3117d1cc387SAppaRao Puli             {
3122ac69850SEd Tanous                 matchTelemetryMonitor.reset();
3137d1cc387SAppaRao Puli             }
3142ac69850SEd Tanous         }
3152ac69850SEd Tanous         else
3162ac69850SEd Tanous         {
3172ac69850SEd Tanous             matchTelemetryMonitor.reset();
3186c58a03eSAlexander Hansen             dbusEventLogMonitor.reset();
3197b669723SEd Tanous             filesystemLogMonitor.reset();
3202ac69850SEd Tanous         }
3212ac69850SEd Tanous 
3222ac69850SEd Tanous         if (serviceEnabled != cfg.enabled)
3232ac69850SEd Tanous         {
3242ac69850SEd Tanous             serviceEnabled = cfg.enabled;
3257d1cc387SAppaRao Puli             updateConfig = true;
3267d1cc387SAppaRao Puli         }
3277d1cc387SAppaRao Puli 
32828afb49cSJunLin Chen         if (retryAttempts != cfg.retryAttempts)
3297d1cc387SAppaRao Puli         {
33028afb49cSJunLin Chen             retryAttempts = cfg.retryAttempts;
3317d1cc387SAppaRao Puli             updateConfig = true;
332fe44eb0bSAyushi Smriti             updateRetryCfg = true;
3337d1cc387SAppaRao Puli         }
3347d1cc387SAppaRao Puli 
33528afb49cSJunLin Chen         if (retryTimeoutInterval != cfg.retryTimeoutInterval)
3367d1cc387SAppaRao Puli         {
33728afb49cSJunLin Chen             retryTimeoutInterval = cfg.retryTimeoutInterval;
3387d1cc387SAppaRao Puli             updateConfig = true;
339fe44eb0bSAyushi Smriti             updateRetryCfg = true;
3407d1cc387SAppaRao Puli         }
3417d1cc387SAppaRao Puli 
3427d1cc387SAppaRao Puli         if (updateConfig)
3437d1cc387SAppaRao Puli         {
3447d1cc387SAppaRao Puli             updateSubscriptionData();
3457d1cc387SAppaRao Puli         }
346fe44eb0bSAyushi Smriti 
347fe44eb0bSAyushi Smriti         if (updateRetryCfg)
348fe44eb0bSAyushi Smriti         {
349fe44eb0bSAyushi Smriti             // Update the changed retry config to all subscriptions
350fe44eb0bSAyushi Smriti             for (const auto& it :
351fe44eb0bSAyushi Smriti                  EventServiceManager::getInstance().subscriptionsMap)
352fe44eb0bSAyushi Smriti             {
3535e44e3d8SAppaRao Puli                 Subscription& entry = *it.second;
3545e44e3d8SAppaRao Puli                 entry.updateRetryConfig(retryAttempts, retryTimeoutInterval);
355fe44eb0bSAyushi Smriti             }
356fe44eb0bSAyushi Smriti         }
3577d1cc387SAppaRao Puli     }
3587d1cc387SAppaRao Puli 
3597d1cc387SAppaRao Puli     void updateNoOfSubscribersCount()
3607d1cc387SAppaRao Puli     {
3617d1cc387SAppaRao Puli         size_t eventLogSubCount = 0;
3627d1cc387SAppaRao Puli         size_t metricReportSubCount = 0;
3637d1cc387SAppaRao Puli         for (const auto& it : subscriptionsMap)
3647d1cc387SAppaRao Puli         {
3657d1cc387SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
3665fe4ef35SMyung Bae             if (entry->userSub->eventFormatType == eventFormatType)
3677d1cc387SAppaRao Puli             {
3687d1cc387SAppaRao Puli                 eventLogSubCount++;
3697d1cc387SAppaRao Puli             }
3705fe4ef35SMyung Bae             else if (entry->userSub->eventFormatType == metricReportFormatType)
3717d1cc387SAppaRao Puli             {
3727d1cc387SAppaRao Puli                 metricReportSubCount++;
3737d1cc387SAppaRao Puli             }
3747d1cc387SAppaRao Puli         }
3757d1cc387SAppaRao Puli         noOfEventLogSubscribers = eventLogSubCount;
3766c58a03eSAlexander Hansen         if (eventLogSubCount > 0U)
3777d1cc387SAppaRao Puli         {
3786c58a03eSAlexander Hansen             if constexpr (BMCWEB_REDFISH_DBUS_LOG)
3796c58a03eSAlexander Hansen             {
3806c58a03eSAlexander Hansen                 if (!dbusEventLogMonitor &&
3816c58a03eSAlexander Hansen                     BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION)
3826c58a03eSAlexander Hansen                 {
3836c58a03eSAlexander Hansen                     dbusEventLogMonitor.emplace();
3846c58a03eSAlexander Hansen                 }
3856c58a03eSAlexander Hansen             }
3866c58a03eSAlexander Hansen             else
3876c58a03eSAlexander Hansen             {
3886c58a03eSAlexander Hansen                 if (!filesystemLogMonitor)
3896c58a03eSAlexander Hansen                 {
3906c58a03eSAlexander Hansen                     filesystemLogMonitor.emplace(ioc);
3916c58a03eSAlexander Hansen                 }
3926c58a03eSAlexander Hansen             }
3936c58a03eSAlexander Hansen         }
3946c58a03eSAlexander Hansen         else
3956c58a03eSAlexander Hansen         {
3966c58a03eSAlexander Hansen             dbusEventLogMonitor.reset();
3976c58a03eSAlexander Hansen             filesystemLogMonitor.reset();
3986c58a03eSAlexander Hansen         }
3996c58a03eSAlexander Hansen 
4007d1cc387SAppaRao Puli         noOfMetricReportSubscribers = metricReportSubCount;
4016c58a03eSAlexander Hansen         if (metricReportSubCount > 0U)
4027d1cc387SAppaRao Puli         {
4032ac69850SEd Tanous             if (!matchTelemetryMonitor)
4042ac69850SEd Tanous             {
4052ac69850SEd Tanous                 matchTelemetryMonitor.emplace();
4062ac69850SEd Tanous             }
4077d1cc387SAppaRao Puli         }
4087d1cc387SAppaRao Puli         else
4097d1cc387SAppaRao Puli         {
4102ac69850SEd Tanous             matchTelemetryMonitor.reset();
4117d1cc387SAppaRao Puli         }
4127d1cc387SAppaRao Puli     }
4137d1cc387SAppaRao Puli 
414b52664e2SAppaRao Puli     std::shared_ptr<Subscription> getSubscription(const std::string& id)
415b52664e2SAppaRao Puli     {
416b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
417b52664e2SAppaRao Puli         if (obj == subscriptionsMap.end())
418b52664e2SAppaRao Puli         {
41962598e31SEd Tanous             BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id);
420b52664e2SAppaRao Puli             return nullptr;
421b52664e2SAppaRao Puli         }
422b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue = obj->second;
423b52664e2SAppaRao Puli         return subValue;
424b52664e2SAppaRao Puli     }
425b52664e2SAppaRao Puli 
426f80a87f2SEd Tanous     std::string
427f80a87f2SEd Tanous         addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue)
428b52664e2SAppaRao Puli     {
429fc76b8acSEd Tanous         std::uniform_int_distribution<uint32_t> dist(0);
430fc76b8acSEd Tanous         bmcweb::OpenSSLGenerator gen;
431fc76b8acSEd Tanous 
432b52664e2SAppaRao Puli         std::string id;
433b52664e2SAppaRao Puli 
434b52664e2SAppaRao Puli         int retry = 3;
435e662eae8SEd Tanous         while (retry != 0)
436b52664e2SAppaRao Puli         {
437fc76b8acSEd Tanous             id = std::to_string(dist(gen));
438fc76b8acSEd Tanous             if (gen.error())
439fc76b8acSEd Tanous             {
440fc76b8acSEd Tanous                 retry = 0;
441fc76b8acSEd Tanous                 break;
442fc76b8acSEd Tanous             }
443b52664e2SAppaRao Puli             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
444b52664e2SAppaRao Puli             if (inserted.second)
445b52664e2SAppaRao Puli             {
446b52664e2SAppaRao Puli                 break;
447b52664e2SAppaRao Puli             }
448b52664e2SAppaRao Puli             --retry;
44923a21a1cSEd Tanous         }
450b52664e2SAppaRao Puli 
451b52664e2SAppaRao Puli         if (retry <= 0)
452b52664e2SAppaRao Puli         {
45362598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to generate random number");
454abb93cddSEd Tanous             return "";
455b52664e2SAppaRao Puli         }
456b52664e2SAppaRao Puli 
45756ba386dSMyung Bae         // Set Subscription ID for back trace
4585fe4ef35SMyung Bae         subValue->userSub->id = id;
459a14c9113SEd Tanous 
46028afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
4615fe4ef35SMyung Bae             .subscriptionsConfigMap.emplace(id, subValue->userSub);
46228afb49cSJunLin Chen 
4637d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
4641bf712bcSAyushi Smriti 
465fe44eb0bSAyushi Smriti         // Update retry configuration.
466fe44eb0bSAyushi Smriti         subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
467fe44eb0bSAyushi Smriti 
468f80a87f2SEd Tanous         return id;
469f80a87f2SEd Tanous     }
470f80a87f2SEd Tanous 
471f80a87f2SEd Tanous     std::string
472f80a87f2SEd Tanous         addSSESubscription(const std::shared_ptr<Subscription>& subValue,
473f80a87f2SEd Tanous                            std::string_view lastEventId)
474f80a87f2SEd Tanous     {
475f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
476f80a87f2SEd Tanous 
477f80a87f2SEd Tanous         if (!lastEventId.empty())
478f80a87f2SEd Tanous         {
479f80a87f2SEd Tanous             BMCWEB_LOG_INFO("Attempting to find message for last id {}",
480f80a87f2SEd Tanous                             lastEventId);
481f80a87f2SEd Tanous             boost::circular_buffer<Event>::iterator lastEvent =
482f80a87f2SEd Tanous                 std::find_if(messages.begin(), messages.end(),
483f80a87f2SEd Tanous                              [&lastEventId](const Event& event) {
484f80a87f2SEd Tanous                                  return event.id == lastEventId;
485f80a87f2SEd Tanous                              });
486f80a87f2SEd Tanous             // Can't find a matching ID
487f80a87f2SEd Tanous             if (lastEvent == messages.end())
488f80a87f2SEd Tanous             {
489f80a87f2SEd Tanous                 nlohmann::json msg = messages::eventBufferExceeded();
490f80a87f2SEd Tanous                 // If the buffer overloaded, send all messages.
4916d799e14SEd Tanous                 subValue->sendEventToSubscriber(msg);
492f80a87f2SEd Tanous                 lastEvent = messages.begin();
493f80a87f2SEd Tanous             }
494f80a87f2SEd Tanous             else
495f80a87f2SEd Tanous             {
496f80a87f2SEd Tanous                 // Skip the last event the user already has
497f80a87f2SEd Tanous                 lastEvent++;
498f80a87f2SEd Tanous             }
499f80a87f2SEd Tanous 
500f80a87f2SEd Tanous             for (boost::circular_buffer<Event>::const_iterator event =
501f80a87f2SEd Tanous                      lastEvent;
502f80a87f2SEd Tanous                  lastEvent != messages.end(); lastEvent++)
503f80a87f2SEd Tanous             {
5046d799e14SEd Tanous                 subValue->sendEventToSubscriber(event->message);
505f80a87f2SEd Tanous             }
506f80a87f2SEd Tanous         }
507f80a87f2SEd Tanous         return id;
508f80a87f2SEd Tanous     }
509f80a87f2SEd Tanous 
510f80a87f2SEd Tanous     std::string
511f80a87f2SEd Tanous         addPushSubscription(const std::shared_ptr<Subscription>& subValue)
512f80a87f2SEd Tanous     {
513f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
514a0969c70SMyung Bae         subValue->deleter = [id]() {
515a0969c70SMyung Bae             EventServiceManager::getInstance().deleteSubscription(id);
516a0969c70SMyung Bae         };
517f80a87f2SEd Tanous         updateSubscriptionData();
518b52664e2SAppaRao Puli         return id;
519b52664e2SAppaRao Puli     }
520b52664e2SAppaRao Puli 
521b52664e2SAppaRao Puli     bool isSubscriptionExist(const std::string& id)
522b52664e2SAppaRao Puli     {
523b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
52455f79e6fSEd Tanous         return obj != subscriptionsMap.end();
525b52664e2SAppaRao Puli     }
526b52664e2SAppaRao Puli 
5274b712a29SEd Tanous     bool deleteSubscription(const std::string& id)
528b52664e2SAppaRao Puli     {
529b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
5304b712a29SEd Tanous         if (obj == subscriptionsMap.end())
531b52664e2SAppaRao Puli         {
5324b712a29SEd Tanous             BMCWEB_LOG_WARNING("Could not find subscription with id {}", id);
5334b712a29SEd Tanous             return false;
5344b712a29SEd Tanous         }
535b52664e2SAppaRao Puli         subscriptionsMap.erase(obj);
5364b712a29SEd Tanous         auto& event = persistent_data::EventServiceStore::getInstance();
5374b712a29SEd Tanous         auto persistentObj = event.subscriptionsConfigMap.find(id);
5384b712a29SEd Tanous         if (persistentObj == event.subscriptionsConfigMap.end())
5394b712a29SEd Tanous         {
5404b712a29SEd Tanous             BMCWEB_LOG_ERROR("Subscription wasn't in persistent data");
5414b712a29SEd Tanous             return true;
5424b712a29SEd Tanous         }
54328afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
5444b712a29SEd Tanous             .subscriptionsConfigMap.erase(persistentObj);
5457d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
546b52664e2SAppaRao Puli         updateSubscriptionData();
5474b712a29SEd Tanous 
5484b712a29SEd Tanous         return true;
549b52664e2SAppaRao Puli     }
550b52664e2SAppaRao Puli 
5515e44e3d8SAppaRao Puli     void deleteSseSubscription(const crow::sse_socket::Connection& thisConn)
5525e44e3d8SAppaRao Puli     {
553bdbfae2aSEd Tanous         for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();)
5545e44e3d8SAppaRao Puli         {
555bdbfae2aSEd Tanous             std::shared_ptr<Subscription> entry = it->second;
5565e44e3d8SAppaRao Puli             bool entryIsThisConn = entry->matchSseId(thisConn);
5575e44e3d8SAppaRao Puli             if (entryIsThisConn)
5585e44e3d8SAppaRao Puli             {
5595e44e3d8SAppaRao Puli                 persistent_data::EventServiceStore::getInstance()
5605fe4ef35SMyung Bae                     .subscriptionsConfigMap.erase(entry->userSub->id);
561bdbfae2aSEd Tanous                 it = subscriptionsMap.erase(it);
5625e44e3d8SAppaRao Puli                 return;
5635e44e3d8SAppaRao Puli             }
564bdbfae2aSEd Tanous             it++;
5655e44e3d8SAppaRao Puli         }
5665e44e3d8SAppaRao Puli     }
5675e44e3d8SAppaRao Puli 
5685e44e3d8SAppaRao Puli     size_t getNumberOfSubscriptions() const
569b52664e2SAppaRao Puli     {
570b52664e2SAppaRao Puli         return subscriptionsMap.size();
571b52664e2SAppaRao Puli     }
572b52664e2SAppaRao Puli 
5735e44e3d8SAppaRao Puli     size_t getNumberOfSSESubscriptions() const
5745e44e3d8SAppaRao Puli     {
5753544d2a7SEd Tanous         auto size = std::ranges::count_if(
5763544d2a7SEd Tanous             subscriptionsMap,
5775e44e3d8SAppaRao Puli             [](const std::pair<std::string, std::shared_ptr<Subscription>>&
5785e44e3d8SAppaRao Puli                    entry) {
5795fe4ef35SMyung Bae                 return (entry.second->userSub->subscriptionType ==
5804b712a29SEd Tanous                         subscriptionTypeSSE);
5815e44e3d8SAppaRao Puli             });
5825e44e3d8SAppaRao Puli         return static_cast<size_t>(size);
5835e44e3d8SAppaRao Puli     }
5845e44e3d8SAppaRao Puli 
585b52664e2SAppaRao Puli     std::vector<std::string> getAllIDs()
586b52664e2SAppaRao Puli     {
587b52664e2SAppaRao Puli         std::vector<std::string> idList;
588b52664e2SAppaRao Puli         for (const auto& it : subscriptionsMap)
589b52664e2SAppaRao Puli         {
590b52664e2SAppaRao Puli             idList.emplace_back(it.first);
591b52664e2SAppaRao Puli         }
592b52664e2SAppaRao Puli         return idList;
593b52664e2SAppaRao Puli     }
594b52664e2SAppaRao Puli 
59581ee0e74SChandramohan Harkude     bool sendTestEventLog(TestEvent& testEvent)
5960b4bdd93SAppaRao Puli     {
5975e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
5980b4bdd93SAppaRao Puli         {
5990b4bdd93SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
60081ee0e74SChandramohan Harkude             if (!entry->sendTestEventLog(testEvent))
6016ba8c82eSsunharis_in             {
6026ba8c82eSsunharis_in                 return false;
6030b4bdd93SAppaRao Puli             }
6040b4bdd93SAppaRao Puli         }
6056ba8c82eSsunharis_in         return true;
6066ba8c82eSsunharis_in     }
607e9a14131SAppaRao Puli 
6083433b03aSEd Tanous     static void
6093433b03aSEd Tanous         sendEventsToSubs(const std::vector<EventLogObjectsType>& eventRecords)
6103433b03aSEd Tanous     {
6113433b03aSEd Tanous         for (const auto& it :
6123433b03aSEd Tanous              EventServiceManager::getInstance().subscriptionsMap)
6133433b03aSEd Tanous         {
6143433b03aSEd Tanous             Subscription& entry = *it.second;
6153433b03aSEd Tanous             entry.filterAndSendEventLogs(eventRecords);
6163433b03aSEd Tanous         }
6173433b03aSEd Tanous     }
6183433b03aSEd Tanous 
619b26ff34dSEd Tanous     static void sendTelemetryReportToSubs(
620b26ff34dSEd Tanous         const std::string& reportId, const telemetry::TimestampReadings& var)
621b26ff34dSEd Tanous     {
622b26ff34dSEd Tanous         for (const auto& it :
623b26ff34dSEd Tanous              EventServiceManager::getInstance().subscriptionsMap)
624b26ff34dSEd Tanous         {
625b26ff34dSEd Tanous             Subscription& entry = *it.second;
626b26ff34dSEd Tanous             entry.filterAndSendReports(reportId, var);
627b26ff34dSEd Tanous         }
628b26ff34dSEd Tanous     }
629b26ff34dSEd Tanous 
630f80a87f2SEd Tanous     void sendEvent(nlohmann::json::object_t eventMessage,
631f80a87f2SEd Tanous                    std::string_view origin, std::string_view resourceType)
63296330b99SSunitha Harish     {
633613dabeaSEd Tanous         eventMessage["EventId"] = eventId;
634f80a87f2SEd Tanous 
635613dabeaSEd Tanous         eventMessage["EventTimestamp"] =
636613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
637613dabeaSEd Tanous         eventMessage["OriginOfCondition"] = origin;
638613dabeaSEd Tanous 
639f80a87f2SEd Tanous         // MemberId is 0 : since we are sending one event record.
640788b091bSIgor Kanyuka         eventMessage["MemberId"] = "0";
64196330b99SSunitha Harish 
642f80a87f2SEd Tanous         messages.push_back(Event(std::to_string(eventId), eventMessage));
643f80a87f2SEd Tanous 
644f80a87f2SEd Tanous         for (auto& it : subscriptionsMap)
64596330b99SSunitha Harish         {
646f80a87f2SEd Tanous             std::shared_ptr<Subscription>& entry = it.second;
6475fe4ef35SMyung Bae             if (!eventMatchesFilter(*entry->userSub, eventMessage,
6485fe4ef35SMyung Bae                                     resourceType))
64996330b99SSunitha Harish             {
650f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Filter didn't match");
651f80a87f2SEd Tanous                 continue;
65296330b99SSunitha Harish             }
653f80a87f2SEd Tanous 
654f80a87f2SEd Tanous             nlohmann::json::array_t eventRecord;
655f80a87f2SEd Tanous             eventRecord.emplace_back(eventMessage);
656f80a87f2SEd Tanous 
657613dabeaSEd Tanous             nlohmann::json msgJson;
658613dabeaSEd Tanous 
659613dabeaSEd Tanous             msgJson["@odata.type"] = "#Event.v1_4_0.Event";
660613dabeaSEd Tanous             msgJson["Name"] = "Event Log";
661613dabeaSEd Tanous             msgJson["Id"] = eventId;
662f80a87f2SEd Tanous             msgJson["Events"] = std::move(eventRecord);
663f52c03c1SCarson Labrado 
664f52c03c1SCarson Labrado             std::string strMsg = msgJson.dump(
665f52c03c1SCarson Labrado                 2, ' ', true, nlohmann::json::error_handler_t::replace);
6666d799e14SEd Tanous             entry->sendEventToSubscriber(std::move(strMsg));
66796330b99SSunitha Harish         }
66821c0ba6eSMyung Bae         eventId++; // increment the eventId
66996330b99SSunitha Harish     }
67023a21a1cSEd Tanous };
671b52664e2SAppaRao Puli 
672b52664e2SAppaRao Puli } // namespace redfish
673