xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision 3433b03a331fca73238e93831422ca8abbab5c7d)
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"
183ccb3adbSEd Tanous #include "dbus_utility.hpp"
193ccb3adbSEd Tanous #include "error_messages.hpp"
20b80ba2e4SAlexander Hansen #include "event_log.hpp"
21d3a48a14SEd Tanous #include "event_matches_filter.hpp"
223ccb3adbSEd Tanous #include "event_service_store.hpp"
232185ddeaSEd Tanous #include "filesystem_log_watcher.hpp"
24c0353249SWludzik, Jozef #include "metric_report.hpp"
252c6ffdb0SEd Tanous #include "ossl_random.hpp"
263ccb3adbSEd Tanous #include "persistent_data.hpp"
2702c1e29fSAlexander Hansen #include "subscription.hpp"
282ac69850SEd Tanous #include "utility.hpp"
292ac69850SEd Tanous #include "utils/dbus_event_log_entry.hpp"
302ac69850SEd Tanous #include "utils/json_utils.hpp"
315b90429aSEd Tanous #include "utils/time_utils.hpp"
327f4eb588SAppaRao 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>
381214b7e7SGunnar Mills 
395e44e3d8SAppaRao Puli #include <algorithm>
40b52664e2SAppaRao Puli #include <cstdlib>
41b52664e2SAppaRao Puli #include <ctime>
42a14c9113SEd Tanous #include <format>
431bf712bcSAyushi Smriti #include <fstream>
44b52664e2SAppaRao Puli #include <memory>
45a14c9113SEd Tanous #include <string>
4656ba386dSMyung Bae #include <string_view>
475fe4ef35SMyung Bae #include <utility>
482ac69850SEd Tanous #include <variant>
49b52664e2SAppaRao Puli 
50b52664e2SAppaRao Puli namespace redfish
51b52664e2SAppaRao Puli {
52156d6b00SAppaRao Puli 
53156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event";
54156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport";
55156d6b00SAppaRao Puli 
561bf712bcSAyushi Smriti static constexpr const char* eventServiceFile =
571bf712bcSAyushi Smriti     "/var/lib/bmcweb/eventservice_config.json";
581bf712bcSAyushi Smriti 
594642bf8fSGeorge Liu static constexpr const char* redfishEventLogFile = "/var/log/redfish";
604642bf8fSGeorge Liu 
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 
682558979cSP Dheeraj Srujan Kumar     std::streampos redfishLogFilePosition{0};
699f616dd1SEd Tanous     size_t noOfEventLogSubscribers{0};
709f616dd1SEd Tanous     size_t noOfMetricReportSubscribers{0};
712ac69850SEd Tanous     std::optional<DbusTelemetryMonitor> matchTelemetryMonitor;
72b52664e2SAppaRao Puli     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
73b52664e2SAppaRao Puli         subscriptionsMap;
74b52664e2SAppaRao Puli 
759f616dd1SEd Tanous     uint64_t eventId{1};
7696330b99SSunitha Harish 
77f80a87f2SEd Tanous     struct Event
78f80a87f2SEd Tanous     {
79f80a87f2SEd Tanous         std::string id;
80f80a87f2SEd Tanous         nlohmann::json message;
81f80a87f2SEd Tanous     };
82f80a87f2SEd Tanous 
83f80a87f2SEd Tanous     constexpr static size_t maxMessages = 200;
84f80a87f2SEd Tanous     boost::circular_buffer<Event> messages{maxMessages};
85f80a87f2SEd Tanous 
86f8ca6d79SEd Tanous     boost::asio::io_context& ioc;
87f8ca6d79SEd Tanous 
88b52664e2SAppaRao Puli   public:
899f616dd1SEd Tanous     EventServiceManager(const EventServiceManager&) = delete;
909f616dd1SEd Tanous     EventServiceManager& operator=(const EventServiceManager&) = delete;
919f616dd1SEd Tanous     EventServiceManager(EventServiceManager&&) = delete;
929f616dd1SEd Tanous     EventServiceManager& operator=(EventServiceManager&&) = delete;
93ecd6a3a2SEd Tanous     ~EventServiceManager() = default;
949f616dd1SEd Tanous 
95f8ca6d79SEd Tanous     explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn)
96b52664e2SAppaRao Puli     {
97f8ca6d79SEd Tanous         // Load config from persist store.
98f8ca6d79SEd Tanous         initConfig();
99f8ca6d79SEd Tanous     }
100f8ca6d79SEd Tanous 
101f8ca6d79SEd Tanous     static EventServiceManager&
102f8ca6d79SEd Tanous         getInstance(boost::asio::io_context* ioc = nullptr)
103f8ca6d79SEd Tanous     {
104f8ca6d79SEd Tanous         static EventServiceManager handler(*ioc);
105b52664e2SAppaRao Puli         return handler;
106b52664e2SAppaRao Puli     }
107b52664e2SAppaRao Puli 
1081bf712bcSAyushi Smriti     void initConfig()
1091bf712bcSAyushi Smriti     {
11028afb49cSJunLin Chen         loadOldBehavior();
1111bf712bcSAyushi Smriti 
11228afb49cSJunLin Chen         persistent_data::EventServiceConfig eventServiceConfig =
11328afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
11428afb49cSJunLin Chen                 .getEventServiceConfig();
1151bf712bcSAyushi Smriti 
11628afb49cSJunLin Chen         serviceEnabled = eventServiceConfig.enabled;
11728afb49cSJunLin Chen         retryAttempts = eventServiceConfig.retryAttempts;
11828afb49cSJunLin Chen         retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval;
1191bf712bcSAyushi Smriti 
12028afb49cSJunLin Chen         for (const auto& it : persistent_data::EventServiceStore::getInstance()
12128afb49cSJunLin Chen                                   .subscriptionsConfigMap)
1221bf712bcSAyushi Smriti         {
1235fe4ef35SMyung Bae             std::shared_ptr<persistent_data::UserSubscription> newSub =
1245fe4ef35SMyung Bae                 it.second;
1254bbf237fSAppaRao Puli 
1266fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
1275fe4ef35SMyung Bae                 boost::urls::parse_absolute_uri(newSub->destinationUrl);
1281bf712bcSAyushi Smriti 
129a716aa74SEd Tanous             if (!url)
1301bf712bcSAyushi Smriti             {
13162598e31SEd Tanous                 BMCWEB_LOG_ERROR(
13262598e31SEd Tanous                     "Failed to validate and split destination url");
1331bf712bcSAyushi Smriti                 continue;
1341bf712bcSAyushi Smriti             }
1351bf712bcSAyushi Smriti             std::shared_ptr<Subscription> subValue =
13621a94d5cSMyung Bae                 std::make_shared<Subscription>(newSub, *url, ioc);
1375fe4ef35SMyung Bae             std::string id = subValue->userSub->id;
138a0969c70SMyung Bae             subValue->deleter = [id]() {
139a0969c70SMyung Bae                 EventServiceManager::getInstance().deleteSubscription(id);
140a0969c70SMyung Bae             };
1411bf712bcSAyushi Smriti 
142a0969c70SMyung Bae             subscriptionsMap.emplace(id, subValue);
14328afb49cSJunLin Chen 
14428afb49cSJunLin Chen             updateNoOfSubscribersCount();
14528afb49cSJunLin Chen 
14683328316SEd Tanous             if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
14783328316SEd Tanous             {
1482558979cSP Dheeraj Srujan Kumar                 cacheRedfishLogFile();
14983328316SEd Tanous             }
1502558979cSP Dheeraj Srujan Kumar 
15128afb49cSJunLin Chen             // Update retry configuration.
15228afb49cSJunLin Chen             subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
1531bf712bcSAyushi Smriti         }
1541bf712bcSAyushi Smriti     }
1551bf712bcSAyushi Smriti 
15656d2396dSEd Tanous     static void loadOldBehavior()
157b52664e2SAppaRao Puli     {
15828afb49cSJunLin Chen         std::ifstream eventConfigFile(eventServiceFile);
15928afb49cSJunLin Chen         if (!eventConfigFile.good())
1601bf712bcSAyushi Smriti         {
16162598e31SEd Tanous             BMCWEB_LOG_DEBUG("Old eventService config not exist");
16228afb49cSJunLin Chen             return;
16328afb49cSJunLin Chen         }
16428afb49cSJunLin Chen         auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false);
16528afb49cSJunLin Chen         if (jsonData.is_discarded())
1664bbf237fSAppaRao Puli         {
16762598e31SEd Tanous             BMCWEB_LOG_ERROR("Old eventService config parse error.");
16828afb49cSJunLin Chen             return;
16928afb49cSJunLin Chen         }
17028afb49cSJunLin Chen 
1710bdda665SEd Tanous         const nlohmann::json::object_t* obj =
1720bdda665SEd Tanous             jsonData.get_ptr<const nlohmann::json::object_t*>();
1730bdda665SEd Tanous         for (const auto& item : *obj)
17428afb49cSJunLin Chen         {
1750bdda665SEd Tanous             if (item.first == "Configuration")
17628afb49cSJunLin Chen             {
17728afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
17828afb49cSJunLin Chen                     .getEventServiceConfig()
1790bdda665SEd Tanous                     .fromJson(item.second);
18028afb49cSJunLin Chen             }
1810bdda665SEd Tanous             else if (item.first == "Subscriptions")
18228afb49cSJunLin Chen             {
1830bdda665SEd Tanous                 for (const auto& elem : item.second)
18428afb49cSJunLin Chen                 {
1854b712a29SEd Tanous                     std::optional<persistent_data::UserSubscription>
18628afb49cSJunLin Chen                         newSubscription =
18728afb49cSJunLin Chen                             persistent_data::UserSubscription::fromJson(elem,
18828afb49cSJunLin Chen                                                                         true);
1894b712a29SEd Tanous                     if (!newSubscription)
19028afb49cSJunLin Chen                     {
19162598e31SEd Tanous                         BMCWEB_LOG_ERROR("Problem reading subscription "
19262598e31SEd Tanous                                          "from old persistent store");
1934bbf237fSAppaRao Puli                         continue;
1944bbf237fSAppaRao Puli                     }
1954b712a29SEd Tanous                     persistent_data::UserSubscription& newSub =
1964b712a29SEd Tanous                         *newSubscription;
1971bf712bcSAyushi Smriti 
19828afb49cSJunLin Chen                     std::uniform_int_distribution<uint32_t> dist(0);
19928afb49cSJunLin Chen                     bmcweb::OpenSSLGenerator gen;
2001bf712bcSAyushi Smriti 
20128afb49cSJunLin Chen                     std::string id;
2021bf712bcSAyushi Smriti 
20328afb49cSJunLin Chen                     int retry = 3;
204e662eae8SEd Tanous                     while (retry != 0)
2051bf712bcSAyushi Smriti                     {
20628afb49cSJunLin Chen                         id = std::to_string(dist(gen));
20728afb49cSJunLin Chen                         if (gen.error())
2087d1cc387SAppaRao Puli                         {
20928afb49cSJunLin Chen                             retry = 0;
21028afb49cSJunLin Chen                             break;
21128afb49cSJunLin Chen                         }
2124b712a29SEd Tanous                         newSub.id = id;
21328afb49cSJunLin Chen                         auto inserted =
21428afb49cSJunLin Chen                             persistent_data::EventServiceStore::getInstance()
2155fe4ef35SMyung Bae                                 .subscriptionsConfigMap.insert(std::pair(
2165fe4ef35SMyung Bae                                     id, std::make_shared<
2175fe4ef35SMyung Bae                                             persistent_data::UserSubscription>(
2185fe4ef35SMyung Bae                                             newSub)));
21928afb49cSJunLin Chen                         if (inserted.second)
22028afb49cSJunLin Chen                         {
22128afb49cSJunLin Chen                             break;
22228afb49cSJunLin Chen                         }
22328afb49cSJunLin Chen                         --retry;
2247d1cc387SAppaRao Puli                     }
2257d1cc387SAppaRao Puli 
22628afb49cSJunLin Chen                     if (retry <= 0)
22728afb49cSJunLin Chen                     {
22862598e31SEd Tanous                         BMCWEB_LOG_ERROR(
22962598e31SEd Tanous                             "Failed to generate random number from old "
23062598e31SEd Tanous                             "persistent store");
23128afb49cSJunLin Chen                         continue;
23228afb49cSJunLin Chen                     }
23328afb49cSJunLin Chen                 }
23428afb49cSJunLin Chen             }
23528afb49cSJunLin Chen 
23628afb49cSJunLin Chen             persistent_data::getConfig().writeData();
2374c521c3cSEd Tanous             std::error_code ec;
2384c521c3cSEd Tanous             std::filesystem::remove(eventServiceFile, ec);
2394c521c3cSEd Tanous             if (ec)
2404c521c3cSEd Tanous             {
2414c521c3cSEd Tanous                 BMCWEB_LOG_DEBUG(
2424c521c3cSEd Tanous                     "Failed to remove old event service file.  Ignoring");
2434c521c3cSEd Tanous             }
2444c521c3cSEd Tanous             else
2454c521c3cSEd Tanous             {
24662598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Remove old eventservice config");
24728afb49cSJunLin Chen             }
24828afb49cSJunLin Chen         }
2494c521c3cSEd Tanous     }
25028afb49cSJunLin Chen 
2519eb808c1SEd Tanous     void updateSubscriptionData() const
25228afb49cSJunLin Chen     {
25328afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25428afb49cSJunLin Chen             .eventServiceConfig.enabled = serviceEnabled;
25528afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25628afb49cSJunLin Chen             .eventServiceConfig.retryAttempts = retryAttempts;
25728afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25828afb49cSJunLin Chen             .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval;
25928afb49cSJunLin Chen 
26028afb49cSJunLin Chen         persistent_data::getConfig().writeData();
26128afb49cSJunLin Chen     }
26228afb49cSJunLin Chen 
26328afb49cSJunLin Chen     void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg)
2647d1cc387SAppaRao Puli     {
2657d1cc387SAppaRao Puli         bool updateConfig = false;
266fe44eb0bSAyushi Smriti         bool updateRetryCfg = false;
2677d1cc387SAppaRao Puli 
2682ac69850SEd Tanous         if (serviceEnabled)
2697d1cc387SAppaRao Puli         {
2702ac69850SEd Tanous             if (noOfMetricReportSubscribers > 0U)
2717d1cc387SAppaRao Puli             {
2722ac69850SEd Tanous                 if (!matchTelemetryMonitor)
2732ac69850SEd Tanous                 {
2742ac69850SEd Tanous                     matchTelemetryMonitor.emplace();
2752ac69850SEd Tanous                 }
2767d1cc387SAppaRao Puli             }
2777d1cc387SAppaRao Puli             else
2787d1cc387SAppaRao Puli             {
2792ac69850SEd Tanous                 matchTelemetryMonitor.reset();
2807d1cc387SAppaRao Puli             }
2812ac69850SEd Tanous         }
2822ac69850SEd Tanous         else
2832ac69850SEd Tanous         {
2842ac69850SEd Tanous             matchTelemetryMonitor.reset();
2852ac69850SEd Tanous         }
2862ac69850SEd Tanous 
2872ac69850SEd Tanous         if (serviceEnabled != cfg.enabled)
2882ac69850SEd Tanous         {
2892ac69850SEd Tanous             serviceEnabled = cfg.enabled;
2907d1cc387SAppaRao Puli             updateConfig = true;
2917d1cc387SAppaRao Puli         }
2927d1cc387SAppaRao Puli 
29328afb49cSJunLin Chen         if (retryAttempts != cfg.retryAttempts)
2947d1cc387SAppaRao Puli         {
29528afb49cSJunLin Chen             retryAttempts = cfg.retryAttempts;
2967d1cc387SAppaRao Puli             updateConfig = true;
297fe44eb0bSAyushi Smriti             updateRetryCfg = true;
2987d1cc387SAppaRao Puli         }
2997d1cc387SAppaRao Puli 
30028afb49cSJunLin Chen         if (retryTimeoutInterval != cfg.retryTimeoutInterval)
3017d1cc387SAppaRao Puli         {
30228afb49cSJunLin Chen             retryTimeoutInterval = cfg.retryTimeoutInterval;
3037d1cc387SAppaRao Puli             updateConfig = true;
304fe44eb0bSAyushi Smriti             updateRetryCfg = true;
3057d1cc387SAppaRao Puli         }
3067d1cc387SAppaRao Puli 
3077d1cc387SAppaRao Puli         if (updateConfig)
3087d1cc387SAppaRao Puli         {
3097d1cc387SAppaRao Puli             updateSubscriptionData();
3107d1cc387SAppaRao Puli         }
311fe44eb0bSAyushi Smriti 
312fe44eb0bSAyushi Smriti         if (updateRetryCfg)
313fe44eb0bSAyushi Smriti         {
314fe44eb0bSAyushi Smriti             // Update the changed retry config to all subscriptions
315fe44eb0bSAyushi Smriti             for (const auto& it :
316fe44eb0bSAyushi Smriti                  EventServiceManager::getInstance().subscriptionsMap)
317fe44eb0bSAyushi Smriti             {
3185e44e3d8SAppaRao Puli                 Subscription& entry = *it.second;
3195e44e3d8SAppaRao Puli                 entry.updateRetryConfig(retryAttempts, retryTimeoutInterval);
320fe44eb0bSAyushi Smriti             }
321fe44eb0bSAyushi Smriti         }
3227d1cc387SAppaRao Puli     }
3237d1cc387SAppaRao Puli 
3247d1cc387SAppaRao Puli     void updateNoOfSubscribersCount()
3257d1cc387SAppaRao Puli     {
3267d1cc387SAppaRao Puli         size_t eventLogSubCount = 0;
3277d1cc387SAppaRao Puli         size_t metricReportSubCount = 0;
3287d1cc387SAppaRao Puli         for (const auto& it : subscriptionsMap)
3297d1cc387SAppaRao Puli         {
3307d1cc387SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
3315fe4ef35SMyung Bae             if (entry->userSub->eventFormatType == eventFormatType)
3327d1cc387SAppaRao Puli             {
3337d1cc387SAppaRao Puli                 eventLogSubCount++;
3347d1cc387SAppaRao Puli             }
3355fe4ef35SMyung Bae             else if (entry->userSub->eventFormatType == metricReportFormatType)
3367d1cc387SAppaRao Puli             {
3377d1cc387SAppaRao Puli                 metricReportSubCount++;
3387d1cc387SAppaRao Puli             }
3397d1cc387SAppaRao Puli         }
3407d1cc387SAppaRao Puli 
3417d1cc387SAppaRao Puli         noOfEventLogSubscribers = eventLogSubCount;
3427d1cc387SAppaRao Puli         if (noOfMetricReportSubscribers != metricReportSubCount)
3437d1cc387SAppaRao Puli         {
3447d1cc387SAppaRao Puli             noOfMetricReportSubscribers = metricReportSubCount;
345e662eae8SEd Tanous             if (noOfMetricReportSubscribers != 0U)
3467d1cc387SAppaRao Puli             {
3472ac69850SEd Tanous                 if (!matchTelemetryMonitor)
3482ac69850SEd Tanous                 {
3492ac69850SEd Tanous                     matchTelemetryMonitor.emplace();
3502ac69850SEd Tanous                 }
3517d1cc387SAppaRao Puli             }
3527d1cc387SAppaRao Puli             else
3537d1cc387SAppaRao Puli             {
3542ac69850SEd Tanous                 matchTelemetryMonitor.reset();
3557d1cc387SAppaRao Puli             }
3567d1cc387SAppaRao Puli         }
3577d1cc387SAppaRao Puli     }
3587d1cc387SAppaRao Puli 
359b52664e2SAppaRao Puli     std::shared_ptr<Subscription> getSubscription(const std::string& id)
360b52664e2SAppaRao Puli     {
361b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
362b52664e2SAppaRao Puli         if (obj == subscriptionsMap.end())
363b52664e2SAppaRao Puli         {
36462598e31SEd Tanous             BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id);
365b52664e2SAppaRao Puli             return nullptr;
366b52664e2SAppaRao Puli         }
367b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue = obj->second;
368b52664e2SAppaRao Puli         return subValue;
369b52664e2SAppaRao Puli     }
370b52664e2SAppaRao Puli 
371f80a87f2SEd Tanous     std::string
372f80a87f2SEd Tanous         addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue)
373b52664e2SAppaRao Puli     {
374fc76b8acSEd Tanous         std::uniform_int_distribution<uint32_t> dist(0);
375fc76b8acSEd Tanous         bmcweb::OpenSSLGenerator gen;
376fc76b8acSEd Tanous 
377b52664e2SAppaRao Puli         std::string id;
378b52664e2SAppaRao Puli 
379b52664e2SAppaRao Puli         int retry = 3;
380e662eae8SEd Tanous         while (retry != 0)
381b52664e2SAppaRao Puli         {
382fc76b8acSEd Tanous             id = std::to_string(dist(gen));
383fc76b8acSEd Tanous             if (gen.error())
384fc76b8acSEd Tanous             {
385fc76b8acSEd Tanous                 retry = 0;
386fc76b8acSEd Tanous                 break;
387fc76b8acSEd Tanous             }
388b52664e2SAppaRao Puli             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
389b52664e2SAppaRao Puli             if (inserted.second)
390b52664e2SAppaRao Puli             {
391b52664e2SAppaRao Puli                 break;
392b52664e2SAppaRao Puli             }
393b52664e2SAppaRao Puli             --retry;
39423a21a1cSEd Tanous         }
395b52664e2SAppaRao Puli 
396b52664e2SAppaRao Puli         if (retry <= 0)
397b52664e2SAppaRao Puli         {
39862598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to generate random number");
399abb93cddSEd Tanous             return "";
400b52664e2SAppaRao Puli         }
401b52664e2SAppaRao Puli 
40256ba386dSMyung Bae         // Set Subscription ID for back trace
4035fe4ef35SMyung Bae         subValue->userSub->id = id;
404a14c9113SEd Tanous 
40528afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
4065fe4ef35SMyung Bae             .subscriptionsConfigMap.emplace(id, subValue->userSub);
40728afb49cSJunLin Chen 
4087d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
4091bf712bcSAyushi Smriti 
41083328316SEd Tanous         if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
41183328316SEd Tanous         {
4122558979cSP Dheeraj Srujan Kumar             if (redfishLogFilePosition != 0)
4137f4eb588SAppaRao Puli             {
4142558979cSP Dheeraj Srujan Kumar                 cacheRedfishLogFile();
4157f4eb588SAppaRao Puli             }
41683328316SEd Tanous         }
4172ac69850SEd Tanous 
418fe44eb0bSAyushi Smriti         // Update retry configuration.
419fe44eb0bSAyushi Smriti         subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
420fe44eb0bSAyushi Smriti 
421f80a87f2SEd Tanous         return id;
422f80a87f2SEd Tanous     }
423f80a87f2SEd Tanous 
424f80a87f2SEd Tanous     std::string
425f80a87f2SEd Tanous         addSSESubscription(const std::shared_ptr<Subscription>& subValue,
426f80a87f2SEd Tanous                            std::string_view lastEventId)
427f80a87f2SEd Tanous     {
428f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
429f80a87f2SEd Tanous 
430f80a87f2SEd Tanous         if (!lastEventId.empty())
431f80a87f2SEd Tanous         {
432f80a87f2SEd Tanous             BMCWEB_LOG_INFO("Attempting to find message for last id {}",
433f80a87f2SEd Tanous                             lastEventId);
434f80a87f2SEd Tanous             boost::circular_buffer<Event>::iterator lastEvent =
435f80a87f2SEd Tanous                 std::find_if(messages.begin(), messages.end(),
436f80a87f2SEd Tanous                              [&lastEventId](const Event& event) {
437f80a87f2SEd Tanous                                  return event.id == lastEventId;
438f80a87f2SEd Tanous                              });
439f80a87f2SEd Tanous             // Can't find a matching ID
440f80a87f2SEd Tanous             if (lastEvent == messages.end())
441f80a87f2SEd Tanous             {
442f80a87f2SEd Tanous                 nlohmann::json msg = messages::eventBufferExceeded();
443f80a87f2SEd Tanous                 // If the buffer overloaded, send all messages.
4446d799e14SEd Tanous                 subValue->sendEventToSubscriber(msg);
445f80a87f2SEd Tanous                 lastEvent = messages.begin();
446f80a87f2SEd Tanous             }
447f80a87f2SEd Tanous             else
448f80a87f2SEd Tanous             {
449f80a87f2SEd Tanous                 // Skip the last event the user already has
450f80a87f2SEd Tanous                 lastEvent++;
451f80a87f2SEd Tanous             }
452f80a87f2SEd Tanous 
453f80a87f2SEd Tanous             for (boost::circular_buffer<Event>::const_iterator event =
454f80a87f2SEd Tanous                      lastEvent;
455f80a87f2SEd Tanous                  lastEvent != messages.end(); lastEvent++)
456f80a87f2SEd Tanous             {
4576d799e14SEd Tanous                 subValue->sendEventToSubscriber(event->message);
458f80a87f2SEd Tanous             }
459f80a87f2SEd Tanous         }
460f80a87f2SEd Tanous         return id;
461f80a87f2SEd Tanous     }
462f80a87f2SEd Tanous 
463f80a87f2SEd Tanous     std::string
464f80a87f2SEd Tanous         addPushSubscription(const std::shared_ptr<Subscription>& subValue)
465f80a87f2SEd Tanous     {
466f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
467a0969c70SMyung Bae         subValue->deleter = [id]() {
468a0969c70SMyung Bae             EventServiceManager::getInstance().deleteSubscription(id);
469a0969c70SMyung Bae         };
470f80a87f2SEd Tanous         updateSubscriptionData();
471b52664e2SAppaRao Puli         return id;
472b52664e2SAppaRao Puli     }
473b52664e2SAppaRao Puli 
474b52664e2SAppaRao Puli     bool isSubscriptionExist(const std::string& id)
475b52664e2SAppaRao Puli     {
476b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
47755f79e6fSEd Tanous         return obj != subscriptionsMap.end();
478b52664e2SAppaRao Puli     }
479b52664e2SAppaRao Puli 
4804b712a29SEd Tanous     bool deleteSubscription(const std::string& id)
481b52664e2SAppaRao Puli     {
482b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
4834b712a29SEd Tanous         if (obj == subscriptionsMap.end())
484b52664e2SAppaRao Puli         {
4854b712a29SEd Tanous             BMCWEB_LOG_WARNING("Could not find subscription with id {}", id);
4864b712a29SEd Tanous             return false;
4874b712a29SEd Tanous         }
488b52664e2SAppaRao Puli         subscriptionsMap.erase(obj);
4894b712a29SEd Tanous         auto& event = persistent_data::EventServiceStore::getInstance();
4904b712a29SEd Tanous         auto persistentObj = event.subscriptionsConfigMap.find(id);
4914b712a29SEd Tanous         if (persistentObj == event.subscriptionsConfigMap.end())
4924b712a29SEd Tanous         {
4934b712a29SEd Tanous             BMCWEB_LOG_ERROR("Subscription wasn't in persistent data");
4944b712a29SEd Tanous             return true;
4954b712a29SEd Tanous         }
49628afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
4974b712a29SEd Tanous             .subscriptionsConfigMap.erase(persistentObj);
4987d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
499b52664e2SAppaRao Puli         updateSubscriptionData();
5004b712a29SEd Tanous 
5014b712a29SEd Tanous         return true;
502b52664e2SAppaRao Puli     }
503b52664e2SAppaRao Puli 
5045e44e3d8SAppaRao Puli     void deleteSseSubscription(const crow::sse_socket::Connection& thisConn)
5055e44e3d8SAppaRao Puli     {
506bdbfae2aSEd Tanous         for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();)
5075e44e3d8SAppaRao Puli         {
508bdbfae2aSEd Tanous             std::shared_ptr<Subscription> entry = it->second;
5095e44e3d8SAppaRao Puli             bool entryIsThisConn = entry->matchSseId(thisConn);
5105e44e3d8SAppaRao Puli             if (entryIsThisConn)
5115e44e3d8SAppaRao Puli             {
5125e44e3d8SAppaRao Puli                 persistent_data::EventServiceStore::getInstance()
5135fe4ef35SMyung Bae                     .subscriptionsConfigMap.erase(entry->userSub->id);
514bdbfae2aSEd Tanous                 it = subscriptionsMap.erase(it);
5155e44e3d8SAppaRao Puli                 return;
5165e44e3d8SAppaRao Puli             }
517bdbfae2aSEd Tanous             it++;
5185e44e3d8SAppaRao Puli         }
5195e44e3d8SAppaRao Puli     }
5205e44e3d8SAppaRao Puli 
5215e44e3d8SAppaRao Puli     size_t getNumberOfSubscriptions() const
522b52664e2SAppaRao Puli     {
523b52664e2SAppaRao Puli         return subscriptionsMap.size();
524b52664e2SAppaRao Puli     }
525b52664e2SAppaRao Puli 
5265e44e3d8SAppaRao Puli     size_t getNumberOfSSESubscriptions() const
5275e44e3d8SAppaRao Puli     {
5283544d2a7SEd Tanous         auto size = std::ranges::count_if(
5293544d2a7SEd Tanous             subscriptionsMap,
5305e44e3d8SAppaRao Puli             [](const std::pair<std::string, std::shared_ptr<Subscription>>&
5315e44e3d8SAppaRao Puli                    entry) {
5325fe4ef35SMyung Bae                 return (entry.second->userSub->subscriptionType ==
5334b712a29SEd Tanous                         subscriptionTypeSSE);
5345e44e3d8SAppaRao Puli             });
5355e44e3d8SAppaRao Puli         return static_cast<size_t>(size);
5365e44e3d8SAppaRao Puli     }
5375e44e3d8SAppaRao Puli 
538b52664e2SAppaRao Puli     std::vector<std::string> getAllIDs()
539b52664e2SAppaRao Puli     {
540b52664e2SAppaRao Puli         std::vector<std::string> idList;
541b52664e2SAppaRao Puli         for (const auto& it : subscriptionsMap)
542b52664e2SAppaRao Puli         {
543b52664e2SAppaRao Puli             idList.emplace_back(it.first);
544b52664e2SAppaRao Puli         }
545b52664e2SAppaRao Puli         return idList;
546b52664e2SAppaRao Puli     }
547b52664e2SAppaRao Puli 
5486ba8c82eSsunharis_in     bool sendTestEventLog()
5490b4bdd93SAppaRao Puli     {
5505e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
5510b4bdd93SAppaRao Puli         {
5520b4bdd93SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
5536ba8c82eSsunharis_in             if (!entry->sendTestEventLog())
5546ba8c82eSsunharis_in             {
5556ba8c82eSsunharis_in                 return false;
5560b4bdd93SAppaRao Puli             }
5570b4bdd93SAppaRao Puli         }
5586ba8c82eSsunharis_in         return true;
5596ba8c82eSsunharis_in     }
560e9a14131SAppaRao Puli 
561*3433b03aSEd Tanous     static void
562*3433b03aSEd Tanous         sendEventsToSubs(const std::vector<EventLogObjectsType>& eventRecords)
563*3433b03aSEd Tanous     {
564*3433b03aSEd Tanous         for (const auto& it :
565*3433b03aSEd Tanous              EventServiceManager::getInstance().subscriptionsMap)
566*3433b03aSEd Tanous         {
567*3433b03aSEd Tanous             Subscription& entry = *it.second;
568*3433b03aSEd Tanous             entry.filterAndSendEventLogs(eventRecords);
569*3433b03aSEd Tanous         }
570*3433b03aSEd Tanous     }
571*3433b03aSEd Tanous 
572b26ff34dSEd Tanous     static void sendTelemetryReportToSubs(
573b26ff34dSEd Tanous         const std::string& reportId, const telemetry::TimestampReadings& var)
574b26ff34dSEd Tanous     {
575b26ff34dSEd Tanous         for (const auto& it :
576b26ff34dSEd Tanous              EventServiceManager::getInstance().subscriptionsMap)
577b26ff34dSEd Tanous         {
578b26ff34dSEd Tanous             Subscription& entry = *it.second;
579b26ff34dSEd Tanous             entry.filterAndSendReports(reportId, var);
580b26ff34dSEd Tanous         }
581b26ff34dSEd Tanous     }
582b26ff34dSEd Tanous 
583f80a87f2SEd Tanous     void sendEvent(nlohmann::json::object_t eventMessage,
584f80a87f2SEd Tanous                    std::string_view origin, std::string_view resourceType)
58596330b99SSunitha Harish     {
586613dabeaSEd Tanous         eventMessage["EventId"] = eventId;
587f80a87f2SEd Tanous 
588613dabeaSEd Tanous         eventMessage["EventTimestamp"] =
589613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
590613dabeaSEd Tanous         eventMessage["OriginOfCondition"] = origin;
591613dabeaSEd Tanous 
592f80a87f2SEd Tanous         // MemberId is 0 : since we are sending one event record.
593788b091bSIgor Kanyuka         eventMessage["MemberId"] = "0";
59496330b99SSunitha Harish 
595f80a87f2SEd Tanous         messages.push_back(Event(std::to_string(eventId), eventMessage));
596f80a87f2SEd Tanous 
597f80a87f2SEd Tanous         for (auto& it : subscriptionsMap)
59896330b99SSunitha Harish         {
599f80a87f2SEd Tanous             std::shared_ptr<Subscription>& entry = it.second;
6005fe4ef35SMyung Bae             if (!eventMatchesFilter(*entry->userSub, eventMessage,
6015fe4ef35SMyung Bae                                     resourceType))
60296330b99SSunitha Harish             {
603f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Filter didn't match");
604f80a87f2SEd Tanous                 continue;
60596330b99SSunitha Harish             }
606f80a87f2SEd Tanous 
607f80a87f2SEd Tanous             nlohmann::json::array_t eventRecord;
608f80a87f2SEd Tanous             eventRecord.emplace_back(eventMessage);
609f80a87f2SEd Tanous 
610613dabeaSEd Tanous             nlohmann::json msgJson;
611613dabeaSEd Tanous 
612613dabeaSEd Tanous             msgJson["@odata.type"] = "#Event.v1_4_0.Event";
613613dabeaSEd Tanous             msgJson["Name"] = "Event Log";
614613dabeaSEd Tanous             msgJson["Id"] = eventId;
615f80a87f2SEd Tanous             msgJson["Events"] = std::move(eventRecord);
616f52c03c1SCarson Labrado 
617f52c03c1SCarson Labrado             std::string strMsg = msgJson.dump(
618f52c03c1SCarson Labrado                 2, ' ', true, nlohmann::json::error_handler_t::replace);
6196d799e14SEd Tanous             entry->sendEventToSubscriber(std::move(strMsg));
6208ece0e45SEd Tanous             eventId++; // increment the eventId
62196330b99SSunitha Harish         }
62296330b99SSunitha Harish     }
62396330b99SSunitha Harish 
6242558979cSP Dheeraj Srujan Kumar     void resetRedfishFilePosition()
6257f4eb588SAppaRao Puli     {
6262558979cSP Dheeraj Srujan Kumar         // Control would be here when Redfish file is created.
6272558979cSP Dheeraj Srujan Kumar         // Reset File Position as new file is created
6282558979cSP Dheeraj Srujan Kumar         redfishLogFilePosition = 0;
6292558979cSP Dheeraj Srujan Kumar     }
6302558979cSP Dheeraj Srujan Kumar 
6312558979cSP Dheeraj Srujan Kumar     void cacheRedfishLogFile()
6322558979cSP Dheeraj Srujan Kumar     {
6332558979cSP Dheeraj Srujan Kumar         // Open the redfish file and read till the last record.
6342558979cSP Dheeraj Srujan Kumar 
6357f4eb588SAppaRao Puli         std::ifstream logStream(redfishEventLogFile);
6367f4eb588SAppaRao Puli         if (!logStream.good())
6377f4eb588SAppaRao Puli         {
63862598e31SEd Tanous             BMCWEB_LOG_ERROR(" Redfish log file open failed ");
6397f4eb588SAppaRao Puli             return;
6407f4eb588SAppaRao Puli         }
6417f4eb588SAppaRao Puli         std::string logEntry;
6427f4eb588SAppaRao Puli         while (std::getline(logStream, logEntry))
6437f4eb588SAppaRao Puli         {
6442558979cSP Dheeraj Srujan Kumar             redfishLogFilePosition = logStream.tellg();
6457f4eb588SAppaRao Puli         }
6467f4eb588SAppaRao Puli     }
6477f4eb588SAppaRao Puli 
6487f4eb588SAppaRao Puli     void readEventLogsFromFile()
6497f4eb588SAppaRao Puli     {
6507f4eb588SAppaRao Puli         std::ifstream logStream(redfishEventLogFile);
6517f4eb588SAppaRao Puli         if (!logStream.good())
6527f4eb588SAppaRao Puli         {
65362598e31SEd Tanous             BMCWEB_LOG_ERROR(" Redfish log file open failed");
6547f4eb588SAppaRao Puli             return;
6557f4eb588SAppaRao Puli         }
6567f4eb588SAppaRao Puli 
6577f4eb588SAppaRao Puli         std::vector<EventLogObjectsType> eventRecords;
6587f4eb588SAppaRao Puli 
6597f4eb588SAppaRao Puli         std::string logEntry;
6602558979cSP Dheeraj Srujan Kumar 
66103d4d37cSAlexander Hansen         BMCWEB_LOG_DEBUG("Redfish log file: seek to {}",
66203d4d37cSAlexander Hansen                          static_cast<int>(redfishLogFilePosition));
66303d4d37cSAlexander Hansen 
6642558979cSP Dheeraj Srujan Kumar         // Get the read pointer to the next log to be read.
6652558979cSP Dheeraj Srujan Kumar         logStream.seekg(redfishLogFilePosition);
6662558979cSP Dheeraj Srujan Kumar 
6677f4eb588SAppaRao Puli         while (std::getline(logStream, logEntry))
6687f4eb588SAppaRao Puli         {
66903d4d37cSAlexander Hansen             BMCWEB_LOG_DEBUG("Redfish log file: found new event log entry");
6702558979cSP Dheeraj Srujan Kumar             // Update Pointer position
6712558979cSP Dheeraj Srujan Kumar             redfishLogFilePosition = logStream.tellg();
6722558979cSP Dheeraj Srujan Kumar 
6732558979cSP Dheeraj Srujan Kumar             std::string idStr;
6742558979cSP Dheeraj Srujan Kumar             if (!event_log::getUniqueEntryID(logEntry, idStr))
6757f4eb588SAppaRao Puli             {
67603d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG(
67703d4d37cSAlexander Hansen                     "Redfish log file: could not get unique entry id for {}",
67803d4d37cSAlexander Hansen                     logEntry);
6797f4eb588SAppaRao Puli                 continue;
6807f4eb588SAppaRao Puli             }
6817f4eb588SAppaRao Puli 
682e662eae8SEd Tanous             if (!serviceEnabled || noOfEventLogSubscribers == 0)
6837f4eb588SAppaRao Puli             {
6842558979cSP Dheeraj Srujan Kumar                 // If Service is not enabled, no need to compute
6852558979cSP Dheeraj Srujan Kumar                 // the remaining items below.
6862558979cSP Dheeraj Srujan Kumar                 // But, Loop must continue to keep track of Timestamp
68703d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG(
68803d4d37cSAlexander Hansen                     "Redfish log file: no subscribers / event service not enabled");
6897f4eb588SAppaRao Puli                 continue;
6907f4eb588SAppaRao Puli             }
6917f4eb588SAppaRao Puli 
6927f4eb588SAppaRao Puli             std::string timestamp;
6937f4eb588SAppaRao Puli             std::string messageID;
6945e715de6SAppaRao Puli             std::vector<std::string> messageArgs;
6957f4eb588SAppaRao Puli             if (event_log::getEventLogParams(logEntry, timestamp, messageID,
6967f4eb588SAppaRao Puli                                              messageArgs) != 0)
6977f4eb588SAppaRao Puli             {
69803d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("Read eventLog entry params failed for {}",
69903d4d37cSAlexander Hansen                                  logEntry);
7007f4eb588SAppaRao Puli                 continue;
7017f4eb588SAppaRao Puli             }
7027f4eb588SAppaRao Puli 
703f80a87f2SEd Tanous             eventRecords.emplace_back(idStr, timestamp, messageID, messageArgs);
7047f4eb588SAppaRao Puli         }
7057f4eb588SAppaRao Puli 
706e662eae8SEd Tanous         if (!serviceEnabled || noOfEventLogSubscribers == 0)
7072558979cSP Dheeraj Srujan Kumar         {
70862598e31SEd Tanous             BMCWEB_LOG_DEBUG("EventService disabled or no Subscriptions.");
7092558979cSP Dheeraj Srujan Kumar             return;
7102558979cSP Dheeraj Srujan Kumar         }
7112558979cSP Dheeraj Srujan Kumar 
7122558979cSP Dheeraj Srujan Kumar         if (eventRecords.empty())
7132558979cSP Dheeraj Srujan Kumar         {
7142558979cSP Dheeraj Srujan Kumar             // No Records to send
71562598e31SEd Tanous             BMCWEB_LOG_DEBUG("No log entries available to be transferred.");
7162558979cSP Dheeraj Srujan Kumar             return;
7172558979cSP Dheeraj Srujan Kumar         }
718*3433b03aSEd Tanous         EventServiceManager::sendEventsToSubs(eventRecords);
7197f4eb588SAppaRao Puli     }
72023a21a1cSEd Tanous };
721b52664e2SAppaRao Puli 
722b52664e2SAppaRao Puli } // namespace redfish
723