1b52664e2SAppaRao Puli /* 26be832e2SEd Tanous Copyright (c) 2020 Intel Corporation 36be832e2SEd Tanous 46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License"); 56be832e2SEd Tanous you may not use this file except in compliance with the License. 66be832e2SEd Tanous You may obtain a copy of the License at 76be832e2SEd Tanous 86be832e2SEd Tanous http://www.apache.org/licenses/LICENSE-2.0 96be832e2SEd Tanous 106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software 116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS, 126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136be832e2SEd Tanous See the License for the specific language governing permissions and 146be832e2SEd Tanous limitations under the License. 15b52664e2SAppaRao Puli */ 16b52664e2SAppaRao Puli #pragma once 173ccb3adbSEd Tanous #include "dbus_utility.hpp" 183ccb3adbSEd Tanous #include "error_messages.hpp" 19b80ba2e4SAlexander Hansen #include "event_log.hpp" 20d3a48a14SEd Tanous #include "event_matches_filter.hpp" 213ccb3adbSEd Tanous #include "event_service_store.hpp" 22*2185ddeaSEd Tanous #include "filesystem_log_watcher.hpp" 23c0353249SWludzik, Jozef #include "metric_report.hpp" 242c6ffdb0SEd Tanous #include "ossl_random.hpp" 253ccb3adbSEd Tanous #include "persistent_data.hpp" 2602c1e29fSAlexander Hansen #include "subscription.hpp" 275b90429aSEd Tanous #include "utils/time_utils.hpp" 287f4eb588SAppaRao Puli 297f4eb588SAppaRao Puli #include <sys/inotify.h> 30b52664e2SAppaRao Puli 31fb4fd5d4SZhenfei Tai #include <boost/asio/io_context.hpp> 32f80a87f2SEd Tanous #include <boost/circular_buffer.hpp> 33b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp> 34ef4c65b7SEd Tanous #include <boost/url/format.hpp> 354a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp> 36b5b40605Snitroglycerine #include <sdbusplus/bus/match.hpp> 371214b7e7SGunnar Mills 385e44e3d8SAppaRao Puli #include <algorithm> 39b52664e2SAppaRao Puli #include <cstdlib> 40b52664e2SAppaRao Puli #include <ctime> 41a14c9113SEd Tanous #include <format> 421bf712bcSAyushi Smriti #include <fstream> 43b52664e2SAppaRao Puli #include <memory> 44a14c9113SEd Tanous #include <string> 4556ba386dSMyung Bae #include <string_view> 465fe4ef35SMyung Bae #include <utility> 47b52664e2SAppaRao Puli 48b52664e2SAppaRao Puli namespace redfish 49b52664e2SAppaRao Puli { 50156d6b00SAppaRao Puli 51156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event"; 52156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport"; 53156d6b00SAppaRao Puli 541bf712bcSAyushi Smriti static constexpr const char* eventServiceFile = 551bf712bcSAyushi Smriti "/var/lib/bmcweb/eventservice_config.json"; 561bf712bcSAyushi Smriti 574642bf8fSGeorge Liu static constexpr const char* redfishEventLogFile = "/var/log/redfish"; 584642bf8fSGeorge Liu 59b52664e2SAppaRao Puli class EventServiceManager 60b52664e2SAppaRao Puli { 61b52664e2SAppaRao Puli private: 62d3a9e084SEd Tanous bool serviceEnabled = false; 63d3a9e084SEd Tanous uint32_t retryAttempts = 0; 64d3a9e084SEd Tanous uint32_t retryTimeoutInterval = 0; 657d1cc387SAppaRao Puli 662558979cSP Dheeraj Srujan Kumar std::streampos redfishLogFilePosition{0}; 679f616dd1SEd Tanous size_t noOfEventLogSubscribers{0}; 689f616dd1SEd Tanous size_t noOfMetricReportSubscribers{0}; 6959d494eeSPatrick Williams std::shared_ptr<sdbusplus::bus::match_t> matchTelemetryMonitor; 70b52664e2SAppaRao Puli boost::container::flat_map<std::string, std::shared_ptr<Subscription>> 71b52664e2SAppaRao Puli subscriptionsMap; 72b52664e2SAppaRao Puli 739f616dd1SEd Tanous uint64_t eventId{1}; 7496330b99SSunitha Harish 75f80a87f2SEd Tanous struct Event 76f80a87f2SEd Tanous { 77f80a87f2SEd Tanous std::string id; 78f80a87f2SEd Tanous nlohmann::json message; 79f80a87f2SEd Tanous }; 80f80a87f2SEd Tanous 81f80a87f2SEd Tanous constexpr static size_t maxMessages = 200; 82f80a87f2SEd Tanous boost::circular_buffer<Event> messages{maxMessages}; 83f80a87f2SEd Tanous 84f8ca6d79SEd Tanous boost::asio::io_context& ioc; 85f8ca6d79SEd Tanous 86b52664e2SAppaRao Puli public: 879f616dd1SEd Tanous EventServiceManager(const EventServiceManager&) = delete; 889f616dd1SEd Tanous EventServiceManager& operator=(const EventServiceManager&) = delete; 899f616dd1SEd Tanous EventServiceManager(EventServiceManager&&) = delete; 909f616dd1SEd Tanous EventServiceManager& operator=(EventServiceManager&&) = delete; 91ecd6a3a2SEd Tanous ~EventServiceManager() = default; 929f616dd1SEd Tanous 93f8ca6d79SEd Tanous explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn) 94b52664e2SAppaRao Puli { 95f8ca6d79SEd Tanous // Load config from persist store. 96f8ca6d79SEd Tanous initConfig(); 97f8ca6d79SEd Tanous } 98f8ca6d79SEd Tanous 99f8ca6d79SEd Tanous static EventServiceManager& 100f8ca6d79SEd Tanous getInstance(boost::asio::io_context* ioc = nullptr) 101f8ca6d79SEd Tanous { 102f8ca6d79SEd Tanous static EventServiceManager handler(*ioc); 103b52664e2SAppaRao Puli return handler; 104b52664e2SAppaRao Puli } 105b52664e2SAppaRao Puli 1061bf712bcSAyushi Smriti void initConfig() 1071bf712bcSAyushi Smriti { 10828afb49cSJunLin Chen loadOldBehavior(); 1091bf712bcSAyushi Smriti 11028afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 11128afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 11228afb49cSJunLin Chen .getEventServiceConfig(); 1131bf712bcSAyushi Smriti 11428afb49cSJunLin Chen serviceEnabled = eventServiceConfig.enabled; 11528afb49cSJunLin Chen retryAttempts = eventServiceConfig.retryAttempts; 11628afb49cSJunLin Chen retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval; 1171bf712bcSAyushi Smriti 11828afb49cSJunLin Chen for (const auto& it : persistent_data::EventServiceStore::getInstance() 11928afb49cSJunLin Chen .subscriptionsConfigMap) 1201bf712bcSAyushi Smriti { 1215fe4ef35SMyung Bae std::shared_ptr<persistent_data::UserSubscription> newSub = 1225fe4ef35SMyung Bae it.second; 1234bbf237fSAppaRao Puli 1246fd29553SEd Tanous boost::system::result<boost::urls::url> url = 1255fe4ef35SMyung Bae boost::urls::parse_absolute_uri(newSub->destinationUrl); 1261bf712bcSAyushi Smriti 127a716aa74SEd Tanous if (!url) 1281bf712bcSAyushi Smriti { 12962598e31SEd Tanous BMCWEB_LOG_ERROR( 13062598e31SEd Tanous "Failed to validate and split destination url"); 1311bf712bcSAyushi Smriti continue; 1321bf712bcSAyushi Smriti } 1331bf712bcSAyushi Smriti std::shared_ptr<Subscription> subValue = 13421a94d5cSMyung Bae std::make_shared<Subscription>(newSub, *url, ioc); 1355fe4ef35SMyung Bae std::string id = subValue->userSub->id; 136a0969c70SMyung Bae subValue->deleter = [id]() { 137a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 138a0969c70SMyung Bae }; 1391bf712bcSAyushi Smriti 140a0969c70SMyung Bae subscriptionsMap.emplace(id, subValue); 14128afb49cSJunLin Chen 14228afb49cSJunLin Chen updateNoOfSubscribersCount(); 14328afb49cSJunLin Chen 14483328316SEd Tanous if constexpr (!BMCWEB_REDFISH_DBUS_LOG) 14583328316SEd Tanous { 1462558979cSP Dheeraj Srujan Kumar cacheRedfishLogFile(); 14783328316SEd Tanous } 1482558979cSP Dheeraj Srujan Kumar 14928afb49cSJunLin Chen // Update retry configuration. 15028afb49cSJunLin Chen subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 1511bf712bcSAyushi Smriti } 1521bf712bcSAyushi Smriti } 1531bf712bcSAyushi Smriti 15456d2396dSEd Tanous static void loadOldBehavior() 155b52664e2SAppaRao Puli { 15628afb49cSJunLin Chen std::ifstream eventConfigFile(eventServiceFile); 15728afb49cSJunLin Chen if (!eventConfigFile.good()) 1581bf712bcSAyushi Smriti { 15962598e31SEd Tanous BMCWEB_LOG_DEBUG("Old eventService config not exist"); 16028afb49cSJunLin Chen return; 16128afb49cSJunLin Chen } 16228afb49cSJunLin Chen auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false); 16328afb49cSJunLin Chen if (jsonData.is_discarded()) 1644bbf237fSAppaRao Puli { 16562598e31SEd Tanous BMCWEB_LOG_ERROR("Old eventService config parse error."); 16628afb49cSJunLin Chen return; 16728afb49cSJunLin Chen } 16828afb49cSJunLin Chen 1690bdda665SEd Tanous const nlohmann::json::object_t* obj = 1700bdda665SEd Tanous jsonData.get_ptr<const nlohmann::json::object_t*>(); 1710bdda665SEd Tanous for (const auto& item : *obj) 17228afb49cSJunLin Chen { 1730bdda665SEd Tanous if (item.first == "Configuration") 17428afb49cSJunLin Chen { 17528afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 17628afb49cSJunLin Chen .getEventServiceConfig() 1770bdda665SEd Tanous .fromJson(item.second); 17828afb49cSJunLin Chen } 1790bdda665SEd Tanous else if (item.first == "Subscriptions") 18028afb49cSJunLin Chen { 1810bdda665SEd Tanous for (const auto& elem : item.second) 18228afb49cSJunLin Chen { 1834b712a29SEd Tanous std::optional<persistent_data::UserSubscription> 18428afb49cSJunLin Chen newSubscription = 18528afb49cSJunLin Chen persistent_data::UserSubscription::fromJson(elem, 18628afb49cSJunLin Chen true); 1874b712a29SEd Tanous if (!newSubscription) 18828afb49cSJunLin Chen { 18962598e31SEd Tanous BMCWEB_LOG_ERROR("Problem reading subscription " 19062598e31SEd Tanous "from old persistent store"); 1914bbf237fSAppaRao Puli continue; 1924bbf237fSAppaRao Puli } 1934b712a29SEd Tanous persistent_data::UserSubscription& newSub = 1944b712a29SEd Tanous *newSubscription; 1951bf712bcSAyushi Smriti 19628afb49cSJunLin Chen std::uniform_int_distribution<uint32_t> dist(0); 19728afb49cSJunLin Chen bmcweb::OpenSSLGenerator gen; 1981bf712bcSAyushi Smriti 19928afb49cSJunLin Chen std::string id; 2001bf712bcSAyushi Smriti 20128afb49cSJunLin Chen int retry = 3; 202e662eae8SEd Tanous while (retry != 0) 2031bf712bcSAyushi Smriti { 20428afb49cSJunLin Chen id = std::to_string(dist(gen)); 20528afb49cSJunLin Chen if (gen.error()) 2067d1cc387SAppaRao Puli { 20728afb49cSJunLin Chen retry = 0; 20828afb49cSJunLin Chen break; 20928afb49cSJunLin Chen } 2104b712a29SEd Tanous newSub.id = id; 21128afb49cSJunLin Chen auto inserted = 21228afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 2135fe4ef35SMyung Bae .subscriptionsConfigMap.insert(std::pair( 2145fe4ef35SMyung Bae id, std::make_shared< 2155fe4ef35SMyung Bae persistent_data::UserSubscription>( 2165fe4ef35SMyung Bae newSub))); 21728afb49cSJunLin Chen if (inserted.second) 21828afb49cSJunLin Chen { 21928afb49cSJunLin Chen break; 22028afb49cSJunLin Chen } 22128afb49cSJunLin Chen --retry; 2227d1cc387SAppaRao Puli } 2237d1cc387SAppaRao Puli 22428afb49cSJunLin Chen if (retry <= 0) 22528afb49cSJunLin Chen { 22662598e31SEd Tanous BMCWEB_LOG_ERROR( 22762598e31SEd Tanous "Failed to generate random number from old " 22862598e31SEd Tanous "persistent store"); 22928afb49cSJunLin Chen continue; 23028afb49cSJunLin Chen } 23128afb49cSJunLin Chen } 23228afb49cSJunLin Chen } 23328afb49cSJunLin Chen 23428afb49cSJunLin Chen persistent_data::getConfig().writeData(); 2354c521c3cSEd Tanous std::error_code ec; 2364c521c3cSEd Tanous std::filesystem::remove(eventServiceFile, ec); 2374c521c3cSEd Tanous if (ec) 2384c521c3cSEd Tanous { 2394c521c3cSEd Tanous BMCWEB_LOG_DEBUG( 2404c521c3cSEd Tanous "Failed to remove old event service file. Ignoring"); 2414c521c3cSEd Tanous } 2424c521c3cSEd Tanous else 2434c521c3cSEd Tanous { 24462598e31SEd Tanous BMCWEB_LOG_DEBUG("Remove old eventservice config"); 24528afb49cSJunLin Chen } 24628afb49cSJunLin Chen } 2474c521c3cSEd Tanous } 24828afb49cSJunLin Chen 2499eb808c1SEd Tanous void updateSubscriptionData() const 25028afb49cSJunLin Chen { 25128afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 25228afb49cSJunLin Chen .eventServiceConfig.enabled = serviceEnabled; 25328afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 25428afb49cSJunLin Chen .eventServiceConfig.retryAttempts = retryAttempts; 25528afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 25628afb49cSJunLin Chen .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval; 25728afb49cSJunLin Chen 25828afb49cSJunLin Chen persistent_data::getConfig().writeData(); 25928afb49cSJunLin Chen } 26028afb49cSJunLin Chen 26128afb49cSJunLin Chen void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg) 2627d1cc387SAppaRao Puli { 2637d1cc387SAppaRao Puli bool updateConfig = false; 264fe44eb0bSAyushi Smriti bool updateRetryCfg = false; 2657d1cc387SAppaRao Puli 26628afb49cSJunLin Chen if (serviceEnabled != cfg.enabled) 2677d1cc387SAppaRao Puli { 26828afb49cSJunLin Chen serviceEnabled = cfg.enabled; 269e662eae8SEd Tanous if (serviceEnabled && noOfMetricReportSubscribers != 0U) 2707d1cc387SAppaRao Puli { 2717d1cc387SAppaRao Puli registerMetricReportSignal(); 2727d1cc387SAppaRao Puli } 2737d1cc387SAppaRao Puli else 2747d1cc387SAppaRao Puli { 2757d1cc387SAppaRao Puli unregisterMetricReportSignal(); 2767d1cc387SAppaRao Puli } 2777d1cc387SAppaRao Puli updateConfig = true; 2787d1cc387SAppaRao Puli } 2797d1cc387SAppaRao Puli 28028afb49cSJunLin Chen if (retryAttempts != cfg.retryAttempts) 2817d1cc387SAppaRao Puli { 28228afb49cSJunLin Chen retryAttempts = cfg.retryAttempts; 2837d1cc387SAppaRao Puli updateConfig = true; 284fe44eb0bSAyushi Smriti updateRetryCfg = true; 2857d1cc387SAppaRao Puli } 2867d1cc387SAppaRao Puli 28728afb49cSJunLin Chen if (retryTimeoutInterval != cfg.retryTimeoutInterval) 2887d1cc387SAppaRao Puli { 28928afb49cSJunLin Chen retryTimeoutInterval = cfg.retryTimeoutInterval; 2907d1cc387SAppaRao Puli updateConfig = true; 291fe44eb0bSAyushi Smriti updateRetryCfg = true; 2927d1cc387SAppaRao Puli } 2937d1cc387SAppaRao Puli 2947d1cc387SAppaRao Puli if (updateConfig) 2957d1cc387SAppaRao Puli { 2967d1cc387SAppaRao Puli updateSubscriptionData(); 2977d1cc387SAppaRao Puli } 298fe44eb0bSAyushi Smriti 299fe44eb0bSAyushi Smriti if (updateRetryCfg) 300fe44eb0bSAyushi Smriti { 301fe44eb0bSAyushi Smriti // Update the changed retry config to all subscriptions 302fe44eb0bSAyushi Smriti for (const auto& it : 303fe44eb0bSAyushi Smriti EventServiceManager::getInstance().subscriptionsMap) 304fe44eb0bSAyushi Smriti { 3055e44e3d8SAppaRao Puli Subscription& entry = *it.second; 3065e44e3d8SAppaRao Puli entry.updateRetryConfig(retryAttempts, retryTimeoutInterval); 307fe44eb0bSAyushi Smriti } 308fe44eb0bSAyushi Smriti } 3097d1cc387SAppaRao Puli } 3107d1cc387SAppaRao Puli 3117d1cc387SAppaRao Puli void updateNoOfSubscribersCount() 3127d1cc387SAppaRao Puli { 3137d1cc387SAppaRao Puli size_t eventLogSubCount = 0; 3147d1cc387SAppaRao Puli size_t metricReportSubCount = 0; 3157d1cc387SAppaRao Puli for (const auto& it : subscriptionsMap) 3167d1cc387SAppaRao Puli { 3177d1cc387SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 3185fe4ef35SMyung Bae if (entry->userSub->eventFormatType == eventFormatType) 3197d1cc387SAppaRao Puli { 3207d1cc387SAppaRao Puli eventLogSubCount++; 3217d1cc387SAppaRao Puli } 3225fe4ef35SMyung Bae else if (entry->userSub->eventFormatType == metricReportFormatType) 3237d1cc387SAppaRao Puli { 3247d1cc387SAppaRao Puli metricReportSubCount++; 3257d1cc387SAppaRao Puli } 3267d1cc387SAppaRao Puli } 3277d1cc387SAppaRao Puli 3287d1cc387SAppaRao Puli noOfEventLogSubscribers = eventLogSubCount; 3297d1cc387SAppaRao Puli if (noOfMetricReportSubscribers != metricReportSubCount) 3307d1cc387SAppaRao Puli { 3317d1cc387SAppaRao Puli noOfMetricReportSubscribers = metricReportSubCount; 332e662eae8SEd Tanous if (noOfMetricReportSubscribers != 0U) 3337d1cc387SAppaRao Puli { 3347d1cc387SAppaRao Puli registerMetricReportSignal(); 3357d1cc387SAppaRao Puli } 3367d1cc387SAppaRao Puli else 3377d1cc387SAppaRao Puli { 3387d1cc387SAppaRao Puli unregisterMetricReportSignal(); 3397d1cc387SAppaRao Puli } 3407d1cc387SAppaRao Puli } 3417d1cc387SAppaRao Puli } 3427d1cc387SAppaRao Puli 343b52664e2SAppaRao Puli std::shared_ptr<Subscription> getSubscription(const std::string& id) 344b52664e2SAppaRao Puli { 345b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 346b52664e2SAppaRao Puli if (obj == subscriptionsMap.end()) 347b52664e2SAppaRao Puli { 34862598e31SEd Tanous BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id); 349b52664e2SAppaRao Puli return nullptr; 350b52664e2SAppaRao Puli } 351b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = obj->second; 352b52664e2SAppaRao Puli return subValue; 353b52664e2SAppaRao Puli } 354b52664e2SAppaRao Puli 355f80a87f2SEd Tanous std::string 356f80a87f2SEd Tanous addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue) 357b52664e2SAppaRao Puli { 358fc76b8acSEd Tanous std::uniform_int_distribution<uint32_t> dist(0); 359fc76b8acSEd Tanous bmcweb::OpenSSLGenerator gen; 360fc76b8acSEd Tanous 361b52664e2SAppaRao Puli std::string id; 362b52664e2SAppaRao Puli 363b52664e2SAppaRao Puli int retry = 3; 364e662eae8SEd Tanous while (retry != 0) 365b52664e2SAppaRao Puli { 366fc76b8acSEd Tanous id = std::to_string(dist(gen)); 367fc76b8acSEd Tanous if (gen.error()) 368fc76b8acSEd Tanous { 369fc76b8acSEd Tanous retry = 0; 370fc76b8acSEd Tanous break; 371fc76b8acSEd Tanous } 372b52664e2SAppaRao Puli auto inserted = subscriptionsMap.insert(std::pair(id, subValue)); 373b52664e2SAppaRao Puli if (inserted.second) 374b52664e2SAppaRao Puli { 375b52664e2SAppaRao Puli break; 376b52664e2SAppaRao Puli } 377b52664e2SAppaRao Puli --retry; 37823a21a1cSEd Tanous } 379b52664e2SAppaRao Puli 380b52664e2SAppaRao Puli if (retry <= 0) 381b52664e2SAppaRao Puli { 38262598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to generate random number"); 383abb93cddSEd Tanous return ""; 384b52664e2SAppaRao Puli } 385b52664e2SAppaRao Puli 38656ba386dSMyung Bae // Set Subscription ID for back trace 3875fe4ef35SMyung Bae subValue->userSub->id = id; 388a14c9113SEd Tanous 38928afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 3905fe4ef35SMyung Bae .subscriptionsConfigMap.emplace(id, subValue->userSub); 39128afb49cSJunLin Chen 3927d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 3931bf712bcSAyushi Smriti 39483328316SEd Tanous if constexpr (!BMCWEB_REDFISH_DBUS_LOG) 39583328316SEd Tanous { 3962558979cSP Dheeraj Srujan Kumar if (redfishLogFilePosition != 0) 3977f4eb588SAppaRao Puli { 3982558979cSP Dheeraj Srujan Kumar cacheRedfishLogFile(); 3997f4eb588SAppaRao Puli } 40083328316SEd Tanous } 401fe44eb0bSAyushi Smriti // Update retry configuration. 402fe44eb0bSAyushi Smriti subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 403fe44eb0bSAyushi Smriti 404f80a87f2SEd Tanous return id; 405f80a87f2SEd Tanous } 406f80a87f2SEd Tanous 407f80a87f2SEd Tanous std::string 408f80a87f2SEd Tanous addSSESubscription(const std::shared_ptr<Subscription>& subValue, 409f80a87f2SEd Tanous std::string_view lastEventId) 410f80a87f2SEd Tanous { 411f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 412f80a87f2SEd Tanous 413f80a87f2SEd Tanous if (!lastEventId.empty()) 414f80a87f2SEd Tanous { 415f80a87f2SEd Tanous BMCWEB_LOG_INFO("Attempting to find message for last id {}", 416f80a87f2SEd Tanous lastEventId); 417f80a87f2SEd Tanous boost::circular_buffer<Event>::iterator lastEvent = 418f80a87f2SEd Tanous std::find_if(messages.begin(), messages.end(), 419f80a87f2SEd Tanous [&lastEventId](const Event& event) { 420f80a87f2SEd Tanous return event.id == lastEventId; 421f80a87f2SEd Tanous }); 422f80a87f2SEd Tanous // Can't find a matching ID 423f80a87f2SEd Tanous if (lastEvent == messages.end()) 424f80a87f2SEd Tanous { 425f80a87f2SEd Tanous nlohmann::json msg = messages::eventBufferExceeded(); 426f80a87f2SEd Tanous // If the buffer overloaded, send all messages. 4276d799e14SEd Tanous subValue->sendEventToSubscriber(msg); 428f80a87f2SEd Tanous lastEvent = messages.begin(); 429f80a87f2SEd Tanous } 430f80a87f2SEd Tanous else 431f80a87f2SEd Tanous { 432f80a87f2SEd Tanous // Skip the last event the user already has 433f80a87f2SEd Tanous lastEvent++; 434f80a87f2SEd Tanous } 435f80a87f2SEd Tanous 436f80a87f2SEd Tanous for (boost::circular_buffer<Event>::const_iterator event = 437f80a87f2SEd Tanous lastEvent; 438f80a87f2SEd Tanous lastEvent != messages.end(); lastEvent++) 439f80a87f2SEd Tanous { 4406d799e14SEd Tanous subValue->sendEventToSubscriber(event->message); 441f80a87f2SEd Tanous } 442f80a87f2SEd Tanous } 443f80a87f2SEd Tanous return id; 444f80a87f2SEd Tanous } 445f80a87f2SEd Tanous 446f80a87f2SEd Tanous std::string 447f80a87f2SEd Tanous addPushSubscription(const std::shared_ptr<Subscription>& subValue) 448f80a87f2SEd Tanous { 449f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 450a0969c70SMyung Bae subValue->deleter = [id]() { 451a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 452a0969c70SMyung Bae }; 453f80a87f2SEd Tanous updateSubscriptionData(); 454b52664e2SAppaRao Puli return id; 455b52664e2SAppaRao Puli } 456b52664e2SAppaRao Puli 457b52664e2SAppaRao Puli bool isSubscriptionExist(const std::string& id) 458b52664e2SAppaRao Puli { 459b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 46055f79e6fSEd Tanous return obj != subscriptionsMap.end(); 461b52664e2SAppaRao Puli } 462b52664e2SAppaRao Puli 4634b712a29SEd Tanous bool deleteSubscription(const std::string& id) 464b52664e2SAppaRao Puli { 465b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 4664b712a29SEd Tanous if (obj == subscriptionsMap.end()) 467b52664e2SAppaRao Puli { 4684b712a29SEd Tanous BMCWEB_LOG_WARNING("Could not find subscription with id {}", id); 4694b712a29SEd Tanous return false; 4704b712a29SEd Tanous } 471b52664e2SAppaRao Puli subscriptionsMap.erase(obj); 4724b712a29SEd Tanous auto& event = persistent_data::EventServiceStore::getInstance(); 4734b712a29SEd Tanous auto persistentObj = event.subscriptionsConfigMap.find(id); 4744b712a29SEd Tanous if (persistentObj == event.subscriptionsConfigMap.end()) 4754b712a29SEd Tanous { 4764b712a29SEd Tanous BMCWEB_LOG_ERROR("Subscription wasn't in persistent data"); 4774b712a29SEd Tanous return true; 4784b712a29SEd Tanous } 47928afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 4804b712a29SEd Tanous .subscriptionsConfigMap.erase(persistentObj); 4817d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 482b52664e2SAppaRao Puli updateSubscriptionData(); 4834b712a29SEd Tanous 4844b712a29SEd Tanous return true; 485b52664e2SAppaRao Puli } 486b52664e2SAppaRao Puli 4875e44e3d8SAppaRao Puli void deleteSseSubscription(const crow::sse_socket::Connection& thisConn) 4885e44e3d8SAppaRao Puli { 489bdbfae2aSEd Tanous for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();) 4905e44e3d8SAppaRao Puli { 491bdbfae2aSEd Tanous std::shared_ptr<Subscription> entry = it->second; 4925e44e3d8SAppaRao Puli bool entryIsThisConn = entry->matchSseId(thisConn); 4935e44e3d8SAppaRao Puli if (entryIsThisConn) 4945e44e3d8SAppaRao Puli { 4955e44e3d8SAppaRao Puli persistent_data::EventServiceStore::getInstance() 4965fe4ef35SMyung Bae .subscriptionsConfigMap.erase(entry->userSub->id); 497bdbfae2aSEd Tanous it = subscriptionsMap.erase(it); 4985e44e3d8SAppaRao Puli return; 4995e44e3d8SAppaRao Puli } 500bdbfae2aSEd Tanous it++; 5015e44e3d8SAppaRao Puli } 5025e44e3d8SAppaRao Puli } 5035e44e3d8SAppaRao Puli 5045e44e3d8SAppaRao Puli size_t getNumberOfSubscriptions() const 505b52664e2SAppaRao Puli { 506b52664e2SAppaRao Puli return subscriptionsMap.size(); 507b52664e2SAppaRao Puli } 508b52664e2SAppaRao Puli 5095e44e3d8SAppaRao Puli size_t getNumberOfSSESubscriptions() const 5105e44e3d8SAppaRao Puli { 5113544d2a7SEd Tanous auto size = std::ranges::count_if( 5123544d2a7SEd Tanous subscriptionsMap, 5135e44e3d8SAppaRao Puli [](const std::pair<std::string, std::shared_ptr<Subscription>>& 5145e44e3d8SAppaRao Puli entry) { 5155fe4ef35SMyung Bae return (entry.second->userSub->subscriptionType == 5164b712a29SEd Tanous subscriptionTypeSSE); 5175e44e3d8SAppaRao Puli }); 5185e44e3d8SAppaRao Puli return static_cast<size_t>(size); 5195e44e3d8SAppaRao Puli } 5205e44e3d8SAppaRao Puli 521b52664e2SAppaRao Puli std::vector<std::string> getAllIDs() 522b52664e2SAppaRao Puli { 523b52664e2SAppaRao Puli std::vector<std::string> idList; 524b52664e2SAppaRao Puli for (const auto& it : subscriptionsMap) 525b52664e2SAppaRao Puli { 526b52664e2SAppaRao Puli idList.emplace_back(it.first); 527b52664e2SAppaRao Puli } 528b52664e2SAppaRao Puli return idList; 529b52664e2SAppaRao Puli } 530b52664e2SAppaRao Puli 5316ba8c82eSsunharis_in bool sendTestEventLog() 5320b4bdd93SAppaRao Puli { 5335e44e3d8SAppaRao Puli for (const auto& it : subscriptionsMap) 5340b4bdd93SAppaRao Puli { 5350b4bdd93SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 5366ba8c82eSsunharis_in if (!entry->sendTestEventLog()) 5376ba8c82eSsunharis_in { 5386ba8c82eSsunharis_in return false; 5390b4bdd93SAppaRao Puli } 5400b4bdd93SAppaRao Puli } 5416ba8c82eSsunharis_in return true; 5426ba8c82eSsunharis_in } 543e9a14131SAppaRao Puli 544f80a87f2SEd Tanous void sendEvent(nlohmann::json::object_t eventMessage, 545f80a87f2SEd Tanous std::string_view origin, std::string_view resourceType) 54696330b99SSunitha Harish { 547613dabeaSEd Tanous eventMessage["EventId"] = eventId; 548f80a87f2SEd Tanous 549613dabeaSEd Tanous eventMessage["EventTimestamp"] = 550613dabeaSEd Tanous redfish::time_utils::getDateTimeOffsetNow().first; 551613dabeaSEd Tanous eventMessage["OriginOfCondition"] = origin; 552613dabeaSEd Tanous 553f80a87f2SEd Tanous // MemberId is 0 : since we are sending one event record. 554788b091bSIgor Kanyuka eventMessage["MemberId"] = "0"; 55596330b99SSunitha Harish 556f80a87f2SEd Tanous messages.push_back(Event(std::to_string(eventId), eventMessage)); 557f80a87f2SEd Tanous 558f80a87f2SEd Tanous for (auto& it : subscriptionsMap) 55996330b99SSunitha Harish { 560f80a87f2SEd Tanous std::shared_ptr<Subscription>& entry = it.second; 5615fe4ef35SMyung Bae if (!eventMatchesFilter(*entry->userSub, eventMessage, 5625fe4ef35SMyung Bae resourceType)) 56396330b99SSunitha Harish { 564f80a87f2SEd Tanous BMCWEB_LOG_DEBUG("Filter didn't match"); 565f80a87f2SEd Tanous continue; 56696330b99SSunitha Harish } 567f80a87f2SEd Tanous 568f80a87f2SEd Tanous nlohmann::json::array_t eventRecord; 569f80a87f2SEd Tanous eventRecord.emplace_back(eventMessage); 570f80a87f2SEd Tanous 571613dabeaSEd Tanous nlohmann::json msgJson; 572613dabeaSEd Tanous 573613dabeaSEd Tanous msgJson["@odata.type"] = "#Event.v1_4_0.Event"; 574613dabeaSEd Tanous msgJson["Name"] = "Event Log"; 575613dabeaSEd Tanous msgJson["Id"] = eventId; 576f80a87f2SEd Tanous msgJson["Events"] = std::move(eventRecord); 577f52c03c1SCarson Labrado 578f52c03c1SCarson Labrado std::string strMsg = msgJson.dump( 579f52c03c1SCarson Labrado 2, ' ', true, nlohmann::json::error_handler_t::replace); 5806d799e14SEd Tanous entry->sendEventToSubscriber(std::move(strMsg)); 5818ece0e45SEd Tanous eventId++; // increment the eventId 58296330b99SSunitha Harish } 58396330b99SSunitha Harish } 58496330b99SSunitha Harish 5852558979cSP Dheeraj Srujan Kumar void resetRedfishFilePosition() 5867f4eb588SAppaRao Puli { 5872558979cSP Dheeraj Srujan Kumar // Control would be here when Redfish file is created. 5882558979cSP Dheeraj Srujan Kumar // Reset File Position as new file is created 5892558979cSP Dheeraj Srujan Kumar redfishLogFilePosition = 0; 5902558979cSP Dheeraj Srujan Kumar } 5912558979cSP Dheeraj Srujan Kumar 5922558979cSP Dheeraj Srujan Kumar void cacheRedfishLogFile() 5932558979cSP Dheeraj Srujan Kumar { 5942558979cSP Dheeraj Srujan Kumar // Open the redfish file and read till the last record. 5952558979cSP Dheeraj Srujan Kumar 5967f4eb588SAppaRao Puli std::ifstream logStream(redfishEventLogFile); 5977f4eb588SAppaRao Puli if (!logStream.good()) 5987f4eb588SAppaRao Puli { 59962598e31SEd Tanous BMCWEB_LOG_ERROR(" Redfish log file open failed "); 6007f4eb588SAppaRao Puli return; 6017f4eb588SAppaRao Puli } 6027f4eb588SAppaRao Puli std::string logEntry; 6037f4eb588SAppaRao Puli while (std::getline(logStream, logEntry)) 6047f4eb588SAppaRao Puli { 6052558979cSP Dheeraj Srujan Kumar redfishLogFilePosition = logStream.tellg(); 6067f4eb588SAppaRao Puli } 6077f4eb588SAppaRao Puli } 6087f4eb588SAppaRao Puli 6097f4eb588SAppaRao Puli void readEventLogsFromFile() 6107f4eb588SAppaRao Puli { 6117f4eb588SAppaRao Puli std::ifstream logStream(redfishEventLogFile); 6127f4eb588SAppaRao Puli if (!logStream.good()) 6137f4eb588SAppaRao Puli { 61462598e31SEd Tanous BMCWEB_LOG_ERROR(" Redfish log file open failed"); 6157f4eb588SAppaRao Puli return; 6167f4eb588SAppaRao Puli } 6177f4eb588SAppaRao Puli 6187f4eb588SAppaRao Puli std::vector<EventLogObjectsType> eventRecords; 6197f4eb588SAppaRao Puli 6207f4eb588SAppaRao Puli std::string logEntry; 6212558979cSP Dheeraj Srujan Kumar 62203d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG("Redfish log file: seek to {}", 62303d4d37cSAlexander Hansen static_cast<int>(redfishLogFilePosition)); 62403d4d37cSAlexander Hansen 6252558979cSP Dheeraj Srujan Kumar // Get the read pointer to the next log to be read. 6262558979cSP Dheeraj Srujan Kumar logStream.seekg(redfishLogFilePosition); 6272558979cSP Dheeraj Srujan Kumar 6287f4eb588SAppaRao Puli while (std::getline(logStream, logEntry)) 6297f4eb588SAppaRao Puli { 63003d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG("Redfish log file: found new event log entry"); 6312558979cSP Dheeraj Srujan Kumar // Update Pointer position 6322558979cSP Dheeraj Srujan Kumar redfishLogFilePosition = logStream.tellg(); 6332558979cSP Dheeraj Srujan Kumar 6342558979cSP Dheeraj Srujan Kumar std::string idStr; 6352558979cSP Dheeraj Srujan Kumar if (!event_log::getUniqueEntryID(logEntry, idStr)) 6367f4eb588SAppaRao Puli { 63703d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG( 63803d4d37cSAlexander Hansen "Redfish log file: could not get unique entry id for {}", 63903d4d37cSAlexander Hansen logEntry); 6407f4eb588SAppaRao Puli continue; 6417f4eb588SAppaRao Puli } 6427f4eb588SAppaRao Puli 643e662eae8SEd Tanous if (!serviceEnabled || noOfEventLogSubscribers == 0) 6447f4eb588SAppaRao Puli { 6452558979cSP Dheeraj Srujan Kumar // If Service is not enabled, no need to compute 6462558979cSP Dheeraj Srujan Kumar // the remaining items below. 6472558979cSP Dheeraj Srujan Kumar // But, Loop must continue to keep track of Timestamp 64803d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG( 64903d4d37cSAlexander Hansen "Redfish log file: no subscribers / event service not enabled"); 6507f4eb588SAppaRao Puli continue; 6517f4eb588SAppaRao Puli } 6527f4eb588SAppaRao Puli 6537f4eb588SAppaRao Puli std::string timestamp; 6547f4eb588SAppaRao Puli std::string messageID; 6555e715de6SAppaRao Puli std::vector<std::string> messageArgs; 6567f4eb588SAppaRao Puli if (event_log::getEventLogParams(logEntry, timestamp, messageID, 6577f4eb588SAppaRao Puli messageArgs) != 0) 6587f4eb588SAppaRao Puli { 65903d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG("Read eventLog entry params failed for {}", 66003d4d37cSAlexander Hansen logEntry); 6617f4eb588SAppaRao Puli continue; 6627f4eb588SAppaRao Puli } 6637f4eb588SAppaRao Puli 664f80a87f2SEd Tanous eventRecords.emplace_back(idStr, timestamp, messageID, messageArgs); 6657f4eb588SAppaRao Puli } 6667f4eb588SAppaRao Puli 667e662eae8SEd Tanous if (!serviceEnabled || noOfEventLogSubscribers == 0) 6682558979cSP Dheeraj Srujan Kumar { 66962598e31SEd Tanous BMCWEB_LOG_DEBUG("EventService disabled or no Subscriptions."); 6702558979cSP Dheeraj Srujan Kumar return; 6712558979cSP Dheeraj Srujan Kumar } 6722558979cSP Dheeraj Srujan Kumar 6732558979cSP Dheeraj Srujan Kumar if (eventRecords.empty()) 6742558979cSP Dheeraj Srujan Kumar { 6752558979cSP Dheeraj Srujan Kumar // No Records to send 67662598e31SEd Tanous BMCWEB_LOG_DEBUG("No log entries available to be transferred."); 6772558979cSP Dheeraj Srujan Kumar return; 6782558979cSP Dheeraj Srujan Kumar } 6792558979cSP Dheeraj Srujan Kumar 6805e44e3d8SAppaRao Puli for (const auto& it : subscriptionsMap) 6817f4eb588SAppaRao Puli { 6827f4eb588SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 6835fe4ef35SMyung Bae if (entry->userSub->eventFormatType == "Event") 6847f4eb588SAppaRao Puli { 6857f4eb588SAppaRao Puli entry->filterAndSendEventLogs(eventRecords); 6867f4eb588SAppaRao Puli } 6877f4eb588SAppaRao Puli } 6887f4eb588SAppaRao Puli } 6897f4eb588SAppaRao Puli 69059d494eeSPatrick Williams static void getReadingsForReport(sdbusplus::message_t& msg) 691156d6b00SAppaRao Puli { 69256d2396dSEd Tanous if (msg.is_method_error()) 69356d2396dSEd Tanous { 69462598e31SEd Tanous BMCWEB_LOG_ERROR("TelemetryMonitor Signal error"); 69556d2396dSEd Tanous return; 69656d2396dSEd Tanous } 69756d2396dSEd Tanous 698c0353249SWludzik, Jozef sdbusplus::message::object_path path(msg.get_path()); 699c0353249SWludzik, Jozef std::string id = path.filename(); 700c0353249SWludzik, Jozef if (id.empty()) 701156d6b00SAppaRao Puli { 70262598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to get Id from path"); 703156d6b00SAppaRao Puli return; 704156d6b00SAppaRao Puli } 705156d6b00SAppaRao Puli 706c0353249SWludzik, Jozef std::string interface; 707b9d36b47SEd Tanous dbus::utility::DBusPropertiesMap props; 708c0353249SWludzik, Jozef std::vector<std::string> invalidProps; 709c0353249SWludzik, Jozef msg.read(interface, props, invalidProps); 710c0353249SWludzik, Jozef 711bd79bce8SPatrick Williams auto found = std::ranges::find_if(props, [](const auto& x) { 712bd79bce8SPatrick Williams return x.first == "Readings"; 713bd79bce8SPatrick Williams }); 714c0353249SWludzik, Jozef if (found == props.end()) 715156d6b00SAppaRao Puli { 71662598e31SEd Tanous BMCWEB_LOG_INFO("Failed to get Readings from Report properties"); 717156d6b00SAppaRao Puli return; 718156d6b00SAppaRao Puli } 719156d6b00SAppaRao Puli 7201e1e598dSJonathan Doman const telemetry::TimestampReadings* readings = 7211e1e598dSJonathan Doman std::get_if<telemetry::TimestampReadings>(&found->second); 722e662eae8SEd Tanous if (readings == nullptr) 7231e1e598dSJonathan Doman { 72462598e31SEd Tanous BMCWEB_LOG_INFO("Failed to get Readings from Report properties"); 7251e1e598dSJonathan Doman return; 7261e1e598dSJonathan Doman } 7271e1e598dSJonathan Doman 728156d6b00SAppaRao Puli for (const auto& it : 729156d6b00SAppaRao Puli EventServiceManager::getInstance().subscriptionsMap) 730156d6b00SAppaRao Puli { 731e05aec50SEd Tanous Subscription& entry = *it.second; 7325fe4ef35SMyung Bae if (entry.userSub->eventFormatType == metricReportFormatType) 733156d6b00SAppaRao Puli { 7341e1e598dSJonathan Doman entry.filterAndSendReports(id, *readings); 735156d6b00SAppaRao Puli } 736156d6b00SAppaRao Puli } 737156d6b00SAppaRao Puli } 738156d6b00SAppaRao Puli 739156d6b00SAppaRao Puli void unregisterMetricReportSignal() 740156d6b00SAppaRao Puli { 7417d1cc387SAppaRao Puli if (matchTelemetryMonitor) 7427d1cc387SAppaRao Puli { 74362598e31SEd Tanous BMCWEB_LOG_DEBUG("Metrics report signal - Unregister"); 744156d6b00SAppaRao Puli matchTelemetryMonitor.reset(); 745156d6b00SAppaRao Puli matchTelemetryMonitor = nullptr; 746156d6b00SAppaRao Puli } 7477d1cc387SAppaRao Puli } 748156d6b00SAppaRao Puli 749156d6b00SAppaRao Puli void registerMetricReportSignal() 750156d6b00SAppaRao Puli { 7517d1cc387SAppaRao Puli if (!serviceEnabled || matchTelemetryMonitor) 752156d6b00SAppaRao Puli { 75362598e31SEd Tanous BMCWEB_LOG_DEBUG("Not registering metric report signal."); 754156d6b00SAppaRao Puli return; 755156d6b00SAppaRao Puli } 756156d6b00SAppaRao Puli 75762598e31SEd Tanous BMCWEB_LOG_DEBUG("Metrics report signal - Register"); 758c0353249SWludzik, Jozef std::string matchStr = "type='signal',member='PropertiesChanged'," 759c0353249SWludzik, Jozef "interface='org.freedesktop.DBus.Properties'," 760c0353249SWludzik, Jozef "arg0=xyz.openbmc_project.Telemetry.Report"; 761156d6b00SAppaRao Puli 76259d494eeSPatrick Williams matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match_t>( 76356d2396dSEd Tanous *crow::connections::systemBus, matchStr, getReadingsForReport); 764156d6b00SAppaRao Puli } 76523a21a1cSEd Tanous }; 766b52664e2SAppaRao Puli 767b52664e2SAppaRao Puli } // namespace redfish 768