xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision b26ff34d5c35b623b0eb7de24f952d4c5d2459bf)
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
17*b26ff34dSEd 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"
285b90429aSEd Tanous #include "utils/time_utils.hpp"
297f4eb588SAppaRao Puli 
307f4eb588SAppaRao Puli #include <sys/inotify.h>
31b52664e2SAppaRao Puli 
32fb4fd5d4SZhenfei Tai #include <boost/asio/io_context.hpp>
33f80a87f2SEd Tanous #include <boost/circular_buffer.hpp>
34b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp>
35ef4c65b7SEd Tanous #include <boost/url/format.hpp>
364a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp>
37b5b40605Snitroglycerine #include <sdbusplus/bus/match.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>
48b52664e2SAppaRao Puli 
49b52664e2SAppaRao Puli namespace redfish
50b52664e2SAppaRao Puli {
51156d6b00SAppaRao Puli 
52156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event";
53156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport";
54156d6b00SAppaRao Puli 
551bf712bcSAyushi Smriti static constexpr const char* eventServiceFile =
561bf712bcSAyushi Smriti     "/var/lib/bmcweb/eventservice_config.json";
571bf712bcSAyushi Smriti 
584642bf8fSGeorge Liu static constexpr const char* redfishEventLogFile = "/var/log/redfish";
594642bf8fSGeorge Liu 
60b52664e2SAppaRao Puli class EventServiceManager
61b52664e2SAppaRao Puli {
62b52664e2SAppaRao Puli   private:
63d3a9e084SEd Tanous     bool serviceEnabled = false;
64d3a9e084SEd Tanous     uint32_t retryAttempts = 0;
65d3a9e084SEd Tanous     uint32_t retryTimeoutInterval = 0;
667d1cc387SAppaRao Puli 
672558979cSP Dheeraj Srujan Kumar     std::streampos redfishLogFilePosition{0};
689f616dd1SEd Tanous     size_t noOfEventLogSubscribers{0};
699f616dd1SEd Tanous     size_t noOfMetricReportSubscribers{0};
7059d494eeSPatrick Williams     std::shared_ptr<sdbusplus::bus::match_t> matchTelemetryMonitor;
71b52664e2SAppaRao Puli     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
72b52664e2SAppaRao Puli         subscriptionsMap;
73b52664e2SAppaRao Puli 
749f616dd1SEd Tanous     uint64_t eventId{1};
7596330b99SSunitha Harish 
76f80a87f2SEd Tanous     struct Event
77f80a87f2SEd Tanous     {
78f80a87f2SEd Tanous         std::string id;
79f80a87f2SEd Tanous         nlohmann::json message;
80f80a87f2SEd Tanous     };
81f80a87f2SEd Tanous 
82f80a87f2SEd Tanous     constexpr static size_t maxMessages = 200;
83f80a87f2SEd Tanous     boost::circular_buffer<Event> messages{maxMessages};
84f80a87f2SEd Tanous 
85f8ca6d79SEd Tanous     boost::asio::io_context& ioc;
86f8ca6d79SEd Tanous 
87b52664e2SAppaRao Puli   public:
889f616dd1SEd Tanous     EventServiceManager(const EventServiceManager&) = delete;
899f616dd1SEd Tanous     EventServiceManager& operator=(const EventServiceManager&) = delete;
909f616dd1SEd Tanous     EventServiceManager(EventServiceManager&&) = delete;
919f616dd1SEd Tanous     EventServiceManager& operator=(EventServiceManager&&) = delete;
92ecd6a3a2SEd Tanous     ~EventServiceManager() = default;
939f616dd1SEd Tanous 
94f8ca6d79SEd Tanous     explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn)
95b52664e2SAppaRao Puli     {
96f8ca6d79SEd Tanous         // Load config from persist store.
97f8ca6d79SEd Tanous         initConfig();
98f8ca6d79SEd Tanous     }
99f8ca6d79SEd Tanous 
100f8ca6d79SEd Tanous     static EventServiceManager&
101f8ca6d79SEd Tanous         getInstance(boost::asio::io_context* ioc = nullptr)
102f8ca6d79SEd Tanous     {
103f8ca6d79SEd Tanous         static EventServiceManager handler(*ioc);
104b52664e2SAppaRao Puli         return handler;
105b52664e2SAppaRao Puli     }
106b52664e2SAppaRao Puli 
1071bf712bcSAyushi Smriti     void initConfig()
1081bf712bcSAyushi Smriti     {
10928afb49cSJunLin Chen         loadOldBehavior();
1101bf712bcSAyushi Smriti 
11128afb49cSJunLin Chen         persistent_data::EventServiceConfig eventServiceConfig =
11228afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
11328afb49cSJunLin Chen                 .getEventServiceConfig();
1141bf712bcSAyushi Smriti 
11528afb49cSJunLin Chen         serviceEnabled = eventServiceConfig.enabled;
11628afb49cSJunLin Chen         retryAttempts = eventServiceConfig.retryAttempts;
11728afb49cSJunLin Chen         retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval;
1181bf712bcSAyushi Smriti 
11928afb49cSJunLin Chen         for (const auto& it : persistent_data::EventServiceStore::getInstance()
12028afb49cSJunLin Chen                                   .subscriptionsConfigMap)
1211bf712bcSAyushi Smriti         {
1225fe4ef35SMyung Bae             std::shared_ptr<persistent_data::UserSubscription> newSub =
1235fe4ef35SMyung Bae                 it.second;
1244bbf237fSAppaRao Puli 
1256fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
1265fe4ef35SMyung Bae                 boost::urls::parse_absolute_uri(newSub->destinationUrl);
1271bf712bcSAyushi Smriti 
128a716aa74SEd Tanous             if (!url)
1291bf712bcSAyushi Smriti             {
13062598e31SEd Tanous                 BMCWEB_LOG_ERROR(
13162598e31SEd Tanous                     "Failed to validate and split destination url");
1321bf712bcSAyushi Smriti                 continue;
1331bf712bcSAyushi Smriti             }
1341bf712bcSAyushi Smriti             std::shared_ptr<Subscription> subValue =
13521a94d5cSMyung Bae                 std::make_shared<Subscription>(newSub, *url, ioc);
1365fe4ef35SMyung Bae             std::string id = subValue->userSub->id;
137a0969c70SMyung Bae             subValue->deleter = [id]() {
138a0969c70SMyung Bae                 EventServiceManager::getInstance().deleteSubscription(id);
139a0969c70SMyung Bae             };
1401bf712bcSAyushi Smriti 
141a0969c70SMyung Bae             subscriptionsMap.emplace(id, subValue);
14228afb49cSJunLin Chen 
14328afb49cSJunLin Chen             updateNoOfSubscribersCount();
14428afb49cSJunLin Chen 
14583328316SEd Tanous             if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
14683328316SEd Tanous             {
1472558979cSP Dheeraj Srujan Kumar                 cacheRedfishLogFile();
14883328316SEd Tanous             }
1492558979cSP Dheeraj Srujan Kumar 
15028afb49cSJunLin Chen             // Update retry configuration.
15128afb49cSJunLin Chen             subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
1521bf712bcSAyushi Smriti         }
1531bf712bcSAyushi Smriti     }
1541bf712bcSAyushi Smriti 
15556d2396dSEd Tanous     static void loadOldBehavior()
156b52664e2SAppaRao Puli     {
15728afb49cSJunLin Chen         std::ifstream eventConfigFile(eventServiceFile);
15828afb49cSJunLin Chen         if (!eventConfigFile.good())
1591bf712bcSAyushi Smriti         {
16062598e31SEd Tanous             BMCWEB_LOG_DEBUG("Old eventService config not exist");
16128afb49cSJunLin Chen             return;
16228afb49cSJunLin Chen         }
16328afb49cSJunLin Chen         auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false);
16428afb49cSJunLin Chen         if (jsonData.is_discarded())
1654bbf237fSAppaRao Puli         {
16662598e31SEd Tanous             BMCWEB_LOG_ERROR("Old eventService config parse error.");
16728afb49cSJunLin Chen             return;
16828afb49cSJunLin Chen         }
16928afb49cSJunLin Chen 
1700bdda665SEd Tanous         const nlohmann::json::object_t* obj =
1710bdda665SEd Tanous             jsonData.get_ptr<const nlohmann::json::object_t*>();
1720bdda665SEd Tanous         for (const auto& item : *obj)
17328afb49cSJunLin Chen         {
1740bdda665SEd Tanous             if (item.first == "Configuration")
17528afb49cSJunLin Chen             {
17628afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
17728afb49cSJunLin Chen                     .getEventServiceConfig()
1780bdda665SEd Tanous                     .fromJson(item.second);
17928afb49cSJunLin Chen             }
1800bdda665SEd Tanous             else if (item.first == "Subscriptions")
18128afb49cSJunLin Chen             {
1820bdda665SEd Tanous                 for (const auto& elem : item.second)
18328afb49cSJunLin Chen                 {
1844b712a29SEd Tanous                     std::optional<persistent_data::UserSubscription>
18528afb49cSJunLin Chen                         newSubscription =
18628afb49cSJunLin Chen                             persistent_data::UserSubscription::fromJson(elem,
18728afb49cSJunLin Chen                                                                         true);
1884b712a29SEd Tanous                     if (!newSubscription)
18928afb49cSJunLin Chen                     {
19062598e31SEd Tanous                         BMCWEB_LOG_ERROR("Problem reading subscription "
19162598e31SEd Tanous                                          "from old persistent store");
1924bbf237fSAppaRao Puli                         continue;
1934bbf237fSAppaRao Puli                     }
1944b712a29SEd Tanous                     persistent_data::UserSubscription& newSub =
1954b712a29SEd Tanous                         *newSubscription;
1961bf712bcSAyushi Smriti 
19728afb49cSJunLin Chen                     std::uniform_int_distribution<uint32_t> dist(0);
19828afb49cSJunLin Chen                     bmcweb::OpenSSLGenerator gen;
1991bf712bcSAyushi Smriti 
20028afb49cSJunLin Chen                     std::string id;
2011bf712bcSAyushi Smriti 
20228afb49cSJunLin Chen                     int retry = 3;
203e662eae8SEd Tanous                     while (retry != 0)
2041bf712bcSAyushi Smriti                     {
20528afb49cSJunLin Chen                         id = std::to_string(dist(gen));
20628afb49cSJunLin Chen                         if (gen.error())
2077d1cc387SAppaRao Puli                         {
20828afb49cSJunLin Chen                             retry = 0;
20928afb49cSJunLin Chen                             break;
21028afb49cSJunLin Chen                         }
2114b712a29SEd Tanous                         newSub.id = id;
21228afb49cSJunLin Chen                         auto inserted =
21328afb49cSJunLin Chen                             persistent_data::EventServiceStore::getInstance()
2145fe4ef35SMyung Bae                                 .subscriptionsConfigMap.insert(std::pair(
2155fe4ef35SMyung Bae                                     id, std::make_shared<
2165fe4ef35SMyung Bae                                             persistent_data::UserSubscription>(
2175fe4ef35SMyung Bae                                             newSub)));
21828afb49cSJunLin Chen                         if (inserted.second)
21928afb49cSJunLin Chen                         {
22028afb49cSJunLin Chen                             break;
22128afb49cSJunLin Chen                         }
22228afb49cSJunLin Chen                         --retry;
2237d1cc387SAppaRao Puli                     }
2247d1cc387SAppaRao Puli 
22528afb49cSJunLin Chen                     if (retry <= 0)
22628afb49cSJunLin Chen                     {
22762598e31SEd Tanous                         BMCWEB_LOG_ERROR(
22862598e31SEd Tanous                             "Failed to generate random number from old "
22962598e31SEd Tanous                             "persistent store");
23028afb49cSJunLin Chen                         continue;
23128afb49cSJunLin Chen                     }
23228afb49cSJunLin Chen                 }
23328afb49cSJunLin Chen             }
23428afb49cSJunLin Chen 
23528afb49cSJunLin Chen             persistent_data::getConfig().writeData();
2364c521c3cSEd Tanous             std::error_code ec;
2374c521c3cSEd Tanous             std::filesystem::remove(eventServiceFile, ec);
2384c521c3cSEd Tanous             if (ec)
2394c521c3cSEd Tanous             {
2404c521c3cSEd Tanous                 BMCWEB_LOG_DEBUG(
2414c521c3cSEd Tanous                     "Failed to remove old event service file.  Ignoring");
2424c521c3cSEd Tanous             }
2434c521c3cSEd Tanous             else
2444c521c3cSEd Tanous             {
24562598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Remove old eventservice config");
24628afb49cSJunLin Chen             }
24728afb49cSJunLin Chen         }
2484c521c3cSEd Tanous     }
24928afb49cSJunLin Chen 
2509eb808c1SEd Tanous     void updateSubscriptionData() const
25128afb49cSJunLin Chen     {
25228afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25328afb49cSJunLin Chen             .eventServiceConfig.enabled = serviceEnabled;
25428afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25528afb49cSJunLin Chen             .eventServiceConfig.retryAttempts = retryAttempts;
25628afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25728afb49cSJunLin Chen             .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval;
25828afb49cSJunLin Chen 
25928afb49cSJunLin Chen         persistent_data::getConfig().writeData();
26028afb49cSJunLin Chen     }
26128afb49cSJunLin Chen 
26228afb49cSJunLin Chen     void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg)
2637d1cc387SAppaRao Puli     {
2647d1cc387SAppaRao Puli         bool updateConfig = false;
265fe44eb0bSAyushi Smriti         bool updateRetryCfg = false;
2667d1cc387SAppaRao Puli 
26728afb49cSJunLin Chen         if (serviceEnabled != cfg.enabled)
2687d1cc387SAppaRao Puli         {
26928afb49cSJunLin Chen             serviceEnabled = cfg.enabled;
270e662eae8SEd Tanous             if (serviceEnabled && noOfMetricReportSubscribers != 0U)
2717d1cc387SAppaRao Puli             {
2727d1cc387SAppaRao Puli                 registerMetricReportSignal();
2737d1cc387SAppaRao Puli             }
2747d1cc387SAppaRao Puli             else
2757d1cc387SAppaRao Puli             {
2767d1cc387SAppaRao Puli                 unregisterMetricReportSignal();
2777d1cc387SAppaRao Puli             }
2787d1cc387SAppaRao Puli             updateConfig = true;
2797d1cc387SAppaRao Puli         }
2807d1cc387SAppaRao Puli 
28128afb49cSJunLin Chen         if (retryAttempts != cfg.retryAttempts)
2827d1cc387SAppaRao Puli         {
28328afb49cSJunLin Chen             retryAttempts = cfg.retryAttempts;
2847d1cc387SAppaRao Puli             updateConfig = true;
285fe44eb0bSAyushi Smriti             updateRetryCfg = true;
2867d1cc387SAppaRao Puli         }
2877d1cc387SAppaRao Puli 
28828afb49cSJunLin Chen         if (retryTimeoutInterval != cfg.retryTimeoutInterval)
2897d1cc387SAppaRao Puli         {
29028afb49cSJunLin Chen             retryTimeoutInterval = cfg.retryTimeoutInterval;
2917d1cc387SAppaRao Puli             updateConfig = true;
292fe44eb0bSAyushi Smriti             updateRetryCfg = true;
2937d1cc387SAppaRao Puli         }
2947d1cc387SAppaRao Puli 
2957d1cc387SAppaRao Puli         if (updateConfig)
2967d1cc387SAppaRao Puli         {
2977d1cc387SAppaRao Puli             updateSubscriptionData();
2987d1cc387SAppaRao Puli         }
299fe44eb0bSAyushi Smriti 
300fe44eb0bSAyushi Smriti         if (updateRetryCfg)
301fe44eb0bSAyushi Smriti         {
302fe44eb0bSAyushi Smriti             // Update the changed retry config to all subscriptions
303fe44eb0bSAyushi Smriti             for (const auto& it :
304fe44eb0bSAyushi Smriti                  EventServiceManager::getInstance().subscriptionsMap)
305fe44eb0bSAyushi Smriti             {
3065e44e3d8SAppaRao Puli                 Subscription& entry = *it.second;
3075e44e3d8SAppaRao Puli                 entry.updateRetryConfig(retryAttempts, retryTimeoutInterval);
308fe44eb0bSAyushi Smriti             }
309fe44eb0bSAyushi Smriti         }
3107d1cc387SAppaRao Puli     }
3117d1cc387SAppaRao Puli 
3127d1cc387SAppaRao Puli     void updateNoOfSubscribersCount()
3137d1cc387SAppaRao Puli     {
3147d1cc387SAppaRao Puli         size_t eventLogSubCount = 0;
3157d1cc387SAppaRao Puli         size_t metricReportSubCount = 0;
3167d1cc387SAppaRao Puli         for (const auto& it : subscriptionsMap)
3177d1cc387SAppaRao Puli         {
3187d1cc387SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
3195fe4ef35SMyung Bae             if (entry->userSub->eventFormatType == eventFormatType)
3207d1cc387SAppaRao Puli             {
3217d1cc387SAppaRao Puli                 eventLogSubCount++;
3227d1cc387SAppaRao Puli             }
3235fe4ef35SMyung Bae             else if (entry->userSub->eventFormatType == metricReportFormatType)
3247d1cc387SAppaRao Puli             {
3257d1cc387SAppaRao Puli                 metricReportSubCount++;
3267d1cc387SAppaRao Puli             }
3277d1cc387SAppaRao Puli         }
3287d1cc387SAppaRao Puli 
3297d1cc387SAppaRao Puli         noOfEventLogSubscribers = eventLogSubCount;
3307d1cc387SAppaRao Puli         if (noOfMetricReportSubscribers != metricReportSubCount)
3317d1cc387SAppaRao Puli         {
3327d1cc387SAppaRao Puli             noOfMetricReportSubscribers = metricReportSubCount;
333e662eae8SEd Tanous             if (noOfMetricReportSubscribers != 0U)
3347d1cc387SAppaRao Puli             {
3357d1cc387SAppaRao Puli                 registerMetricReportSignal();
3367d1cc387SAppaRao Puli             }
3377d1cc387SAppaRao Puli             else
3387d1cc387SAppaRao Puli             {
3397d1cc387SAppaRao Puli                 unregisterMetricReportSignal();
3407d1cc387SAppaRao Puli             }
3417d1cc387SAppaRao Puli         }
3427d1cc387SAppaRao Puli     }
3437d1cc387SAppaRao Puli 
344b52664e2SAppaRao Puli     std::shared_ptr<Subscription> getSubscription(const std::string& id)
345b52664e2SAppaRao Puli     {
346b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
347b52664e2SAppaRao Puli         if (obj == subscriptionsMap.end())
348b52664e2SAppaRao Puli         {
34962598e31SEd Tanous             BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id);
350b52664e2SAppaRao Puli             return nullptr;
351b52664e2SAppaRao Puli         }
352b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue = obj->second;
353b52664e2SAppaRao Puli         return subValue;
354b52664e2SAppaRao Puli     }
355b52664e2SAppaRao Puli 
356f80a87f2SEd Tanous     std::string
357f80a87f2SEd Tanous         addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue)
358b52664e2SAppaRao Puli     {
359fc76b8acSEd Tanous         std::uniform_int_distribution<uint32_t> dist(0);
360fc76b8acSEd Tanous         bmcweb::OpenSSLGenerator gen;
361fc76b8acSEd Tanous 
362b52664e2SAppaRao Puli         std::string id;
363b52664e2SAppaRao Puli 
364b52664e2SAppaRao Puli         int retry = 3;
365e662eae8SEd Tanous         while (retry != 0)
366b52664e2SAppaRao Puli         {
367fc76b8acSEd Tanous             id = std::to_string(dist(gen));
368fc76b8acSEd Tanous             if (gen.error())
369fc76b8acSEd Tanous             {
370fc76b8acSEd Tanous                 retry = 0;
371fc76b8acSEd Tanous                 break;
372fc76b8acSEd Tanous             }
373b52664e2SAppaRao Puli             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
374b52664e2SAppaRao Puli             if (inserted.second)
375b52664e2SAppaRao Puli             {
376b52664e2SAppaRao Puli                 break;
377b52664e2SAppaRao Puli             }
378b52664e2SAppaRao Puli             --retry;
37923a21a1cSEd Tanous         }
380b52664e2SAppaRao Puli 
381b52664e2SAppaRao Puli         if (retry <= 0)
382b52664e2SAppaRao Puli         {
38362598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to generate random number");
384abb93cddSEd Tanous             return "";
385b52664e2SAppaRao Puli         }
386b52664e2SAppaRao Puli 
38756ba386dSMyung Bae         // Set Subscription ID for back trace
3885fe4ef35SMyung Bae         subValue->userSub->id = id;
389a14c9113SEd Tanous 
39028afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
3915fe4ef35SMyung Bae             .subscriptionsConfigMap.emplace(id, subValue->userSub);
39228afb49cSJunLin Chen 
3937d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
3941bf712bcSAyushi Smriti 
39583328316SEd Tanous         if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
39683328316SEd Tanous         {
3972558979cSP Dheeraj Srujan Kumar             if (redfishLogFilePosition != 0)
3987f4eb588SAppaRao Puli             {
3992558979cSP Dheeraj Srujan Kumar                 cacheRedfishLogFile();
4007f4eb588SAppaRao Puli             }
40183328316SEd Tanous         }
402fe44eb0bSAyushi Smriti         // Update retry configuration.
403fe44eb0bSAyushi Smriti         subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
404fe44eb0bSAyushi Smriti 
405f80a87f2SEd Tanous         return id;
406f80a87f2SEd Tanous     }
407f80a87f2SEd Tanous 
408f80a87f2SEd Tanous     std::string
409f80a87f2SEd Tanous         addSSESubscription(const std::shared_ptr<Subscription>& subValue,
410f80a87f2SEd Tanous                            std::string_view lastEventId)
411f80a87f2SEd Tanous     {
412f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
413f80a87f2SEd Tanous 
414f80a87f2SEd Tanous         if (!lastEventId.empty())
415f80a87f2SEd Tanous         {
416f80a87f2SEd Tanous             BMCWEB_LOG_INFO("Attempting to find message for last id {}",
417f80a87f2SEd Tanous                             lastEventId);
418f80a87f2SEd Tanous             boost::circular_buffer<Event>::iterator lastEvent =
419f80a87f2SEd Tanous                 std::find_if(messages.begin(), messages.end(),
420f80a87f2SEd Tanous                              [&lastEventId](const Event& event) {
421f80a87f2SEd Tanous                                  return event.id == lastEventId;
422f80a87f2SEd Tanous                              });
423f80a87f2SEd Tanous             // Can't find a matching ID
424f80a87f2SEd Tanous             if (lastEvent == messages.end())
425f80a87f2SEd Tanous             {
426f80a87f2SEd Tanous                 nlohmann::json msg = messages::eventBufferExceeded();
427f80a87f2SEd Tanous                 // If the buffer overloaded, send all messages.
4286d799e14SEd Tanous                 subValue->sendEventToSubscriber(msg);
429f80a87f2SEd Tanous                 lastEvent = messages.begin();
430f80a87f2SEd Tanous             }
431f80a87f2SEd Tanous             else
432f80a87f2SEd Tanous             {
433f80a87f2SEd Tanous                 // Skip the last event the user already has
434f80a87f2SEd Tanous                 lastEvent++;
435f80a87f2SEd Tanous             }
436f80a87f2SEd Tanous 
437f80a87f2SEd Tanous             for (boost::circular_buffer<Event>::const_iterator event =
438f80a87f2SEd Tanous                      lastEvent;
439f80a87f2SEd Tanous                  lastEvent != messages.end(); lastEvent++)
440f80a87f2SEd Tanous             {
4416d799e14SEd Tanous                 subValue->sendEventToSubscriber(event->message);
442f80a87f2SEd Tanous             }
443f80a87f2SEd Tanous         }
444f80a87f2SEd Tanous         return id;
445f80a87f2SEd Tanous     }
446f80a87f2SEd Tanous 
447f80a87f2SEd Tanous     std::string
448f80a87f2SEd Tanous         addPushSubscription(const std::shared_ptr<Subscription>& subValue)
449f80a87f2SEd Tanous     {
450f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
451a0969c70SMyung Bae         subValue->deleter = [id]() {
452a0969c70SMyung Bae             EventServiceManager::getInstance().deleteSubscription(id);
453a0969c70SMyung Bae         };
454f80a87f2SEd Tanous         updateSubscriptionData();
455b52664e2SAppaRao Puli         return id;
456b52664e2SAppaRao Puli     }
457b52664e2SAppaRao Puli 
458b52664e2SAppaRao Puli     bool isSubscriptionExist(const std::string& id)
459b52664e2SAppaRao Puli     {
460b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
46155f79e6fSEd Tanous         return obj != subscriptionsMap.end();
462b52664e2SAppaRao Puli     }
463b52664e2SAppaRao Puli 
4644b712a29SEd Tanous     bool deleteSubscription(const std::string& id)
465b52664e2SAppaRao Puli     {
466b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
4674b712a29SEd Tanous         if (obj == subscriptionsMap.end())
468b52664e2SAppaRao Puli         {
4694b712a29SEd Tanous             BMCWEB_LOG_WARNING("Could not find subscription with id {}", id);
4704b712a29SEd Tanous             return false;
4714b712a29SEd Tanous         }
472b52664e2SAppaRao Puli         subscriptionsMap.erase(obj);
4734b712a29SEd Tanous         auto& event = persistent_data::EventServiceStore::getInstance();
4744b712a29SEd Tanous         auto persistentObj = event.subscriptionsConfigMap.find(id);
4754b712a29SEd Tanous         if (persistentObj == event.subscriptionsConfigMap.end())
4764b712a29SEd Tanous         {
4774b712a29SEd Tanous             BMCWEB_LOG_ERROR("Subscription wasn't in persistent data");
4784b712a29SEd Tanous             return true;
4794b712a29SEd Tanous         }
48028afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
4814b712a29SEd Tanous             .subscriptionsConfigMap.erase(persistentObj);
4827d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
483b52664e2SAppaRao Puli         updateSubscriptionData();
4844b712a29SEd Tanous 
4854b712a29SEd Tanous         return true;
486b52664e2SAppaRao Puli     }
487b52664e2SAppaRao Puli 
4885e44e3d8SAppaRao Puli     void deleteSseSubscription(const crow::sse_socket::Connection& thisConn)
4895e44e3d8SAppaRao Puli     {
490bdbfae2aSEd Tanous         for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();)
4915e44e3d8SAppaRao Puli         {
492bdbfae2aSEd Tanous             std::shared_ptr<Subscription> entry = it->second;
4935e44e3d8SAppaRao Puli             bool entryIsThisConn = entry->matchSseId(thisConn);
4945e44e3d8SAppaRao Puli             if (entryIsThisConn)
4955e44e3d8SAppaRao Puli             {
4965e44e3d8SAppaRao Puli                 persistent_data::EventServiceStore::getInstance()
4975fe4ef35SMyung Bae                     .subscriptionsConfigMap.erase(entry->userSub->id);
498bdbfae2aSEd Tanous                 it = subscriptionsMap.erase(it);
4995e44e3d8SAppaRao Puli                 return;
5005e44e3d8SAppaRao Puli             }
501bdbfae2aSEd Tanous             it++;
5025e44e3d8SAppaRao Puli         }
5035e44e3d8SAppaRao Puli     }
5045e44e3d8SAppaRao Puli 
5055e44e3d8SAppaRao Puli     size_t getNumberOfSubscriptions() const
506b52664e2SAppaRao Puli     {
507b52664e2SAppaRao Puli         return subscriptionsMap.size();
508b52664e2SAppaRao Puli     }
509b52664e2SAppaRao Puli 
5105e44e3d8SAppaRao Puli     size_t getNumberOfSSESubscriptions() const
5115e44e3d8SAppaRao Puli     {
5123544d2a7SEd Tanous         auto size = std::ranges::count_if(
5133544d2a7SEd Tanous             subscriptionsMap,
5145e44e3d8SAppaRao Puli             [](const std::pair<std::string, std::shared_ptr<Subscription>>&
5155e44e3d8SAppaRao Puli                    entry) {
5165fe4ef35SMyung Bae                 return (entry.second->userSub->subscriptionType ==
5174b712a29SEd Tanous                         subscriptionTypeSSE);
5185e44e3d8SAppaRao Puli             });
5195e44e3d8SAppaRao Puli         return static_cast<size_t>(size);
5205e44e3d8SAppaRao Puli     }
5215e44e3d8SAppaRao Puli 
522b52664e2SAppaRao Puli     std::vector<std::string> getAllIDs()
523b52664e2SAppaRao Puli     {
524b52664e2SAppaRao Puli         std::vector<std::string> idList;
525b52664e2SAppaRao Puli         for (const auto& it : subscriptionsMap)
526b52664e2SAppaRao Puli         {
527b52664e2SAppaRao Puli             idList.emplace_back(it.first);
528b52664e2SAppaRao Puli         }
529b52664e2SAppaRao Puli         return idList;
530b52664e2SAppaRao Puli     }
531b52664e2SAppaRao Puli 
5326ba8c82eSsunharis_in     bool sendTestEventLog()
5330b4bdd93SAppaRao Puli     {
5345e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
5350b4bdd93SAppaRao Puli         {
5360b4bdd93SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
5376ba8c82eSsunharis_in             if (!entry->sendTestEventLog())
5386ba8c82eSsunharis_in             {
5396ba8c82eSsunharis_in                 return false;
5400b4bdd93SAppaRao Puli             }
5410b4bdd93SAppaRao Puli         }
5426ba8c82eSsunharis_in         return true;
5436ba8c82eSsunharis_in     }
544e9a14131SAppaRao Puli 
545*b26ff34dSEd Tanous     static void sendTelemetryReportToSubs(
546*b26ff34dSEd Tanous         const std::string& reportId, const telemetry::TimestampReadings& var)
547*b26ff34dSEd Tanous     {
548*b26ff34dSEd Tanous         for (const auto& it :
549*b26ff34dSEd Tanous              EventServiceManager::getInstance().subscriptionsMap)
550*b26ff34dSEd Tanous         {
551*b26ff34dSEd Tanous             Subscription& entry = *it.second;
552*b26ff34dSEd Tanous             entry.filterAndSendReports(reportId, var);
553*b26ff34dSEd Tanous         }
554*b26ff34dSEd Tanous     }
555*b26ff34dSEd Tanous 
556f80a87f2SEd Tanous     void sendEvent(nlohmann::json::object_t eventMessage,
557f80a87f2SEd Tanous                    std::string_view origin, std::string_view resourceType)
55896330b99SSunitha Harish     {
559613dabeaSEd Tanous         eventMessage["EventId"] = eventId;
560f80a87f2SEd Tanous 
561613dabeaSEd Tanous         eventMessage["EventTimestamp"] =
562613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
563613dabeaSEd Tanous         eventMessage["OriginOfCondition"] = origin;
564613dabeaSEd Tanous 
565f80a87f2SEd Tanous         // MemberId is 0 : since we are sending one event record.
566788b091bSIgor Kanyuka         eventMessage["MemberId"] = "0";
56796330b99SSunitha Harish 
568f80a87f2SEd Tanous         messages.push_back(Event(std::to_string(eventId), eventMessage));
569f80a87f2SEd Tanous 
570f80a87f2SEd Tanous         for (auto& it : subscriptionsMap)
57196330b99SSunitha Harish         {
572f80a87f2SEd Tanous             std::shared_ptr<Subscription>& entry = it.second;
5735fe4ef35SMyung Bae             if (!eventMatchesFilter(*entry->userSub, eventMessage,
5745fe4ef35SMyung Bae                                     resourceType))
57596330b99SSunitha Harish             {
576f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Filter didn't match");
577f80a87f2SEd Tanous                 continue;
57896330b99SSunitha Harish             }
579f80a87f2SEd Tanous 
580f80a87f2SEd Tanous             nlohmann::json::array_t eventRecord;
581f80a87f2SEd Tanous             eventRecord.emplace_back(eventMessage);
582f80a87f2SEd Tanous 
583613dabeaSEd Tanous             nlohmann::json msgJson;
584613dabeaSEd Tanous 
585613dabeaSEd Tanous             msgJson["@odata.type"] = "#Event.v1_4_0.Event";
586613dabeaSEd Tanous             msgJson["Name"] = "Event Log";
587613dabeaSEd Tanous             msgJson["Id"] = eventId;
588f80a87f2SEd Tanous             msgJson["Events"] = std::move(eventRecord);
589f52c03c1SCarson Labrado 
590f52c03c1SCarson Labrado             std::string strMsg = msgJson.dump(
591f52c03c1SCarson Labrado                 2, ' ', true, nlohmann::json::error_handler_t::replace);
5926d799e14SEd Tanous             entry->sendEventToSubscriber(std::move(strMsg));
5938ece0e45SEd Tanous             eventId++; // increment the eventId
59496330b99SSunitha Harish         }
59596330b99SSunitha Harish     }
59696330b99SSunitha Harish 
5972558979cSP Dheeraj Srujan Kumar     void resetRedfishFilePosition()
5987f4eb588SAppaRao Puli     {
5992558979cSP Dheeraj Srujan Kumar         // Control would be here when Redfish file is created.
6002558979cSP Dheeraj Srujan Kumar         // Reset File Position as new file is created
6012558979cSP Dheeraj Srujan Kumar         redfishLogFilePosition = 0;
6022558979cSP Dheeraj Srujan Kumar     }
6032558979cSP Dheeraj Srujan Kumar 
6042558979cSP Dheeraj Srujan Kumar     void cacheRedfishLogFile()
6052558979cSP Dheeraj Srujan Kumar     {
6062558979cSP Dheeraj Srujan Kumar         // Open the redfish file and read till the last record.
6072558979cSP Dheeraj Srujan Kumar 
6087f4eb588SAppaRao Puli         std::ifstream logStream(redfishEventLogFile);
6097f4eb588SAppaRao Puli         if (!logStream.good())
6107f4eb588SAppaRao Puli         {
61162598e31SEd Tanous             BMCWEB_LOG_ERROR(" Redfish log file open failed ");
6127f4eb588SAppaRao Puli             return;
6137f4eb588SAppaRao Puli         }
6147f4eb588SAppaRao Puli         std::string logEntry;
6157f4eb588SAppaRao Puli         while (std::getline(logStream, logEntry))
6167f4eb588SAppaRao Puli         {
6172558979cSP Dheeraj Srujan Kumar             redfishLogFilePosition = logStream.tellg();
6187f4eb588SAppaRao Puli         }
6197f4eb588SAppaRao Puli     }
6207f4eb588SAppaRao Puli 
6217f4eb588SAppaRao Puli     void readEventLogsFromFile()
6227f4eb588SAppaRao Puli     {
6237f4eb588SAppaRao Puli         std::ifstream logStream(redfishEventLogFile);
6247f4eb588SAppaRao Puli         if (!logStream.good())
6257f4eb588SAppaRao Puli         {
62662598e31SEd Tanous             BMCWEB_LOG_ERROR(" Redfish log file open failed");
6277f4eb588SAppaRao Puli             return;
6287f4eb588SAppaRao Puli         }
6297f4eb588SAppaRao Puli 
6307f4eb588SAppaRao Puli         std::vector<EventLogObjectsType> eventRecords;
6317f4eb588SAppaRao Puli 
6327f4eb588SAppaRao Puli         std::string logEntry;
6332558979cSP Dheeraj Srujan Kumar 
63403d4d37cSAlexander Hansen         BMCWEB_LOG_DEBUG("Redfish log file: seek to {}",
63503d4d37cSAlexander Hansen                          static_cast<int>(redfishLogFilePosition));
63603d4d37cSAlexander Hansen 
6372558979cSP Dheeraj Srujan Kumar         // Get the read pointer to the next log to be read.
6382558979cSP Dheeraj Srujan Kumar         logStream.seekg(redfishLogFilePosition);
6392558979cSP Dheeraj Srujan Kumar 
6407f4eb588SAppaRao Puli         while (std::getline(logStream, logEntry))
6417f4eb588SAppaRao Puli         {
64203d4d37cSAlexander Hansen             BMCWEB_LOG_DEBUG("Redfish log file: found new event log entry");
6432558979cSP Dheeraj Srujan Kumar             // Update Pointer position
6442558979cSP Dheeraj Srujan Kumar             redfishLogFilePosition = logStream.tellg();
6452558979cSP Dheeraj Srujan Kumar 
6462558979cSP Dheeraj Srujan Kumar             std::string idStr;
6472558979cSP Dheeraj Srujan Kumar             if (!event_log::getUniqueEntryID(logEntry, idStr))
6487f4eb588SAppaRao Puli             {
64903d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG(
65003d4d37cSAlexander Hansen                     "Redfish log file: could not get unique entry id for {}",
65103d4d37cSAlexander Hansen                     logEntry);
6527f4eb588SAppaRao Puli                 continue;
6537f4eb588SAppaRao Puli             }
6547f4eb588SAppaRao Puli 
655e662eae8SEd Tanous             if (!serviceEnabled || noOfEventLogSubscribers == 0)
6567f4eb588SAppaRao Puli             {
6572558979cSP Dheeraj Srujan Kumar                 // If Service is not enabled, no need to compute
6582558979cSP Dheeraj Srujan Kumar                 // the remaining items below.
6592558979cSP Dheeraj Srujan Kumar                 // But, Loop must continue to keep track of Timestamp
66003d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG(
66103d4d37cSAlexander Hansen                     "Redfish log file: no subscribers / event service not enabled");
6627f4eb588SAppaRao Puli                 continue;
6637f4eb588SAppaRao Puli             }
6647f4eb588SAppaRao Puli 
6657f4eb588SAppaRao Puli             std::string timestamp;
6667f4eb588SAppaRao Puli             std::string messageID;
6675e715de6SAppaRao Puli             std::vector<std::string> messageArgs;
6687f4eb588SAppaRao Puli             if (event_log::getEventLogParams(logEntry, timestamp, messageID,
6697f4eb588SAppaRao Puli                                              messageArgs) != 0)
6707f4eb588SAppaRao Puli             {
67103d4d37cSAlexander Hansen                 BMCWEB_LOG_DEBUG("Read eventLog entry params failed for {}",
67203d4d37cSAlexander Hansen                                  logEntry);
6737f4eb588SAppaRao Puli                 continue;
6747f4eb588SAppaRao Puli             }
6757f4eb588SAppaRao Puli 
676f80a87f2SEd Tanous             eventRecords.emplace_back(idStr, timestamp, messageID, messageArgs);
6777f4eb588SAppaRao Puli         }
6787f4eb588SAppaRao Puli 
679e662eae8SEd Tanous         if (!serviceEnabled || noOfEventLogSubscribers == 0)
6802558979cSP Dheeraj Srujan Kumar         {
68162598e31SEd Tanous             BMCWEB_LOG_DEBUG("EventService disabled or no Subscriptions.");
6822558979cSP Dheeraj Srujan Kumar             return;
6832558979cSP Dheeraj Srujan Kumar         }
6842558979cSP Dheeraj Srujan Kumar 
6852558979cSP Dheeraj Srujan Kumar         if (eventRecords.empty())
6862558979cSP Dheeraj Srujan Kumar         {
6872558979cSP Dheeraj Srujan Kumar             // No Records to send
68862598e31SEd Tanous             BMCWEB_LOG_DEBUG("No log entries available to be transferred.");
6892558979cSP Dheeraj Srujan Kumar             return;
6902558979cSP Dheeraj Srujan Kumar         }
6912558979cSP Dheeraj Srujan Kumar 
6925e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
6937f4eb588SAppaRao Puli         {
6947f4eb588SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
6955fe4ef35SMyung Bae             if (entry->userSub->eventFormatType == "Event")
6967f4eb588SAppaRao Puli             {
6977f4eb588SAppaRao Puli                 entry->filterAndSendEventLogs(eventRecords);
6987f4eb588SAppaRao Puli             }
6997f4eb588SAppaRao Puli         }
7007f4eb588SAppaRao Puli     }
7017f4eb588SAppaRao Puli 
702156d6b00SAppaRao Puli     void unregisterMetricReportSignal()
703156d6b00SAppaRao Puli     {
7047d1cc387SAppaRao Puli         if (matchTelemetryMonitor)
7057d1cc387SAppaRao Puli         {
70662598e31SEd Tanous             BMCWEB_LOG_DEBUG("Metrics report signal - Unregister");
707156d6b00SAppaRao Puli             matchTelemetryMonitor.reset();
708156d6b00SAppaRao Puli             matchTelemetryMonitor = nullptr;
709156d6b00SAppaRao Puli         }
7107d1cc387SAppaRao Puli     }
711156d6b00SAppaRao Puli 
712156d6b00SAppaRao Puli     void registerMetricReportSignal()
713156d6b00SAppaRao Puli     {
7147d1cc387SAppaRao Puli         if (!serviceEnabled || matchTelemetryMonitor)
715156d6b00SAppaRao Puli         {
71662598e31SEd Tanous             BMCWEB_LOG_DEBUG("Not registering metric report signal.");
717156d6b00SAppaRao Puli             return;
718156d6b00SAppaRao Puli         }
719156d6b00SAppaRao Puli 
72062598e31SEd Tanous         BMCWEB_LOG_DEBUG("Metrics report signal - Register");
721c0353249SWludzik, Jozef         std::string matchStr = "type='signal',member='PropertiesChanged',"
722c0353249SWludzik, Jozef                                "interface='org.freedesktop.DBus.Properties',"
723c0353249SWludzik, Jozef                                "arg0=xyz.openbmc_project.Telemetry.Report";
724156d6b00SAppaRao Puli 
72559d494eeSPatrick Williams         matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match_t>(
72656d2396dSEd Tanous             *crow::connections::systemBus, matchStr, getReadingsForReport);
727156d6b00SAppaRao Puli     }
72823a21a1cSEd Tanous };
729b52664e2SAppaRao Puli 
730b52664e2SAppaRao Puli } // namespace redfish
731