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" 28*2ac69850SEd Tanous #include "utility.hpp" 29*2ac69850SEd Tanous #include "utils/dbus_event_log_entry.hpp" 30*2ac69850SEd 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> 48*2ac69850SEd 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}; 71*2ac69850SEd 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 268*2ac69850SEd Tanous if (serviceEnabled) 2697d1cc387SAppaRao Puli { 270*2ac69850SEd Tanous if (noOfMetricReportSubscribers > 0U) 2717d1cc387SAppaRao Puli { 272*2ac69850SEd Tanous if (!matchTelemetryMonitor) 273*2ac69850SEd Tanous { 274*2ac69850SEd Tanous matchTelemetryMonitor.emplace(); 275*2ac69850SEd Tanous } 2767d1cc387SAppaRao Puli } 2777d1cc387SAppaRao Puli else 2787d1cc387SAppaRao Puli { 279*2ac69850SEd Tanous matchTelemetryMonitor.reset(); 2807d1cc387SAppaRao Puli } 281*2ac69850SEd Tanous } 282*2ac69850SEd Tanous else 283*2ac69850SEd Tanous { 284*2ac69850SEd Tanous matchTelemetryMonitor.reset(); 285*2ac69850SEd Tanous } 286*2ac69850SEd Tanous 287*2ac69850SEd Tanous if (serviceEnabled != cfg.enabled) 288*2ac69850SEd Tanous { 289*2ac69850SEd 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 { 347*2ac69850SEd Tanous if (!matchTelemetryMonitor) 348*2ac69850SEd Tanous { 349*2ac69850SEd Tanous matchTelemetryMonitor.emplace(); 350*2ac69850SEd Tanous } 3517d1cc387SAppaRao Puli } 3527d1cc387SAppaRao Puli else 3537d1cc387SAppaRao Puli { 354*2ac69850SEd 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 } 417*2ac69850SEd 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 561b26ff34dSEd Tanous static void sendTelemetryReportToSubs( 562b26ff34dSEd Tanous const std::string& reportId, const telemetry::TimestampReadings& var) 563b26ff34dSEd Tanous { 564b26ff34dSEd Tanous for (const auto& it : 565b26ff34dSEd Tanous EventServiceManager::getInstance().subscriptionsMap) 566b26ff34dSEd Tanous { 567b26ff34dSEd Tanous Subscription& entry = *it.second; 568b26ff34dSEd Tanous entry.filterAndSendReports(reportId, var); 569b26ff34dSEd Tanous } 570b26ff34dSEd Tanous } 571b26ff34dSEd Tanous 572f80a87f2SEd Tanous void sendEvent(nlohmann::json::object_t eventMessage, 573f80a87f2SEd Tanous std::string_view origin, std::string_view resourceType) 57496330b99SSunitha Harish { 575613dabeaSEd Tanous eventMessage["EventId"] = eventId; 576f80a87f2SEd Tanous 577613dabeaSEd Tanous eventMessage["EventTimestamp"] = 578613dabeaSEd Tanous redfish::time_utils::getDateTimeOffsetNow().first; 579613dabeaSEd Tanous eventMessage["OriginOfCondition"] = origin; 580613dabeaSEd Tanous 581f80a87f2SEd Tanous // MemberId is 0 : since we are sending one event record. 582788b091bSIgor Kanyuka eventMessage["MemberId"] = "0"; 58396330b99SSunitha Harish 584f80a87f2SEd Tanous messages.push_back(Event(std::to_string(eventId), eventMessage)); 585f80a87f2SEd Tanous 586f80a87f2SEd Tanous for (auto& it : subscriptionsMap) 58796330b99SSunitha Harish { 588f80a87f2SEd Tanous std::shared_ptr<Subscription>& entry = it.second; 5895fe4ef35SMyung Bae if (!eventMatchesFilter(*entry->userSub, eventMessage, 5905fe4ef35SMyung Bae resourceType)) 59196330b99SSunitha Harish { 592f80a87f2SEd Tanous BMCWEB_LOG_DEBUG("Filter didn't match"); 593f80a87f2SEd Tanous continue; 59496330b99SSunitha Harish } 595f80a87f2SEd Tanous 596f80a87f2SEd Tanous nlohmann::json::array_t eventRecord; 597f80a87f2SEd Tanous eventRecord.emplace_back(eventMessage); 598f80a87f2SEd Tanous 599613dabeaSEd Tanous nlohmann::json msgJson; 600613dabeaSEd Tanous 601613dabeaSEd Tanous msgJson["@odata.type"] = "#Event.v1_4_0.Event"; 602613dabeaSEd Tanous msgJson["Name"] = "Event Log"; 603613dabeaSEd Tanous msgJson["Id"] = eventId; 604f80a87f2SEd Tanous msgJson["Events"] = std::move(eventRecord); 605f52c03c1SCarson Labrado 606f52c03c1SCarson Labrado std::string strMsg = msgJson.dump( 607f52c03c1SCarson Labrado 2, ' ', true, nlohmann::json::error_handler_t::replace); 6086d799e14SEd Tanous entry->sendEventToSubscriber(std::move(strMsg)); 6098ece0e45SEd Tanous eventId++; // increment the eventId 61096330b99SSunitha Harish } 61196330b99SSunitha Harish } 61296330b99SSunitha Harish 6132558979cSP Dheeraj Srujan Kumar void resetRedfishFilePosition() 6147f4eb588SAppaRao Puli { 6152558979cSP Dheeraj Srujan Kumar // Control would be here when Redfish file is created. 6162558979cSP Dheeraj Srujan Kumar // Reset File Position as new file is created 6172558979cSP Dheeraj Srujan Kumar redfishLogFilePosition = 0; 6182558979cSP Dheeraj Srujan Kumar } 6192558979cSP Dheeraj Srujan Kumar 6202558979cSP Dheeraj Srujan Kumar void cacheRedfishLogFile() 6212558979cSP Dheeraj Srujan Kumar { 6222558979cSP Dheeraj Srujan Kumar // Open the redfish file and read till the last record. 6232558979cSP Dheeraj Srujan Kumar 6247f4eb588SAppaRao Puli std::ifstream logStream(redfishEventLogFile); 6257f4eb588SAppaRao Puli if (!logStream.good()) 6267f4eb588SAppaRao Puli { 62762598e31SEd Tanous BMCWEB_LOG_ERROR(" Redfish log file open failed "); 6287f4eb588SAppaRao Puli return; 6297f4eb588SAppaRao Puli } 6307f4eb588SAppaRao Puli std::string logEntry; 6317f4eb588SAppaRao Puli while (std::getline(logStream, logEntry)) 6327f4eb588SAppaRao Puli { 6332558979cSP Dheeraj Srujan Kumar redfishLogFilePosition = logStream.tellg(); 6347f4eb588SAppaRao Puli } 6357f4eb588SAppaRao Puli } 6367f4eb588SAppaRao Puli 6377f4eb588SAppaRao Puli void readEventLogsFromFile() 6387f4eb588SAppaRao Puli { 6397f4eb588SAppaRao Puli std::ifstream logStream(redfishEventLogFile); 6407f4eb588SAppaRao Puli if (!logStream.good()) 6417f4eb588SAppaRao Puli { 64262598e31SEd Tanous BMCWEB_LOG_ERROR(" Redfish log file open failed"); 6437f4eb588SAppaRao Puli return; 6447f4eb588SAppaRao Puli } 6457f4eb588SAppaRao Puli 6467f4eb588SAppaRao Puli std::vector<EventLogObjectsType> eventRecords; 6477f4eb588SAppaRao Puli 6487f4eb588SAppaRao Puli std::string logEntry; 6492558979cSP Dheeraj Srujan Kumar 65003d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG("Redfish log file: seek to {}", 65103d4d37cSAlexander Hansen static_cast<int>(redfishLogFilePosition)); 65203d4d37cSAlexander Hansen 6532558979cSP Dheeraj Srujan Kumar // Get the read pointer to the next log to be read. 6542558979cSP Dheeraj Srujan Kumar logStream.seekg(redfishLogFilePosition); 6552558979cSP Dheeraj Srujan Kumar 6567f4eb588SAppaRao Puli while (std::getline(logStream, logEntry)) 6577f4eb588SAppaRao Puli { 65803d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG("Redfish log file: found new event log entry"); 6592558979cSP Dheeraj Srujan Kumar // Update Pointer position 6602558979cSP Dheeraj Srujan Kumar redfishLogFilePosition = logStream.tellg(); 6612558979cSP Dheeraj Srujan Kumar 6622558979cSP Dheeraj Srujan Kumar std::string idStr; 6632558979cSP Dheeraj Srujan Kumar if (!event_log::getUniqueEntryID(logEntry, idStr)) 6647f4eb588SAppaRao Puli { 66503d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG( 66603d4d37cSAlexander Hansen "Redfish log file: could not get unique entry id for {}", 66703d4d37cSAlexander Hansen logEntry); 6687f4eb588SAppaRao Puli continue; 6697f4eb588SAppaRao Puli } 6707f4eb588SAppaRao Puli 671e662eae8SEd Tanous if (!serviceEnabled || noOfEventLogSubscribers == 0) 6727f4eb588SAppaRao Puli { 6732558979cSP Dheeraj Srujan Kumar // If Service is not enabled, no need to compute 6742558979cSP Dheeraj Srujan Kumar // the remaining items below. 6752558979cSP Dheeraj Srujan Kumar // But, Loop must continue to keep track of Timestamp 67603d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG( 67703d4d37cSAlexander Hansen "Redfish log file: no subscribers / event service not enabled"); 6787f4eb588SAppaRao Puli continue; 6797f4eb588SAppaRao Puli } 6807f4eb588SAppaRao Puli 6817f4eb588SAppaRao Puli std::string timestamp; 6827f4eb588SAppaRao Puli std::string messageID; 6835e715de6SAppaRao Puli std::vector<std::string> messageArgs; 6847f4eb588SAppaRao Puli if (event_log::getEventLogParams(logEntry, timestamp, messageID, 6857f4eb588SAppaRao Puli messageArgs) != 0) 6867f4eb588SAppaRao Puli { 68703d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG("Read eventLog entry params failed for {}", 68803d4d37cSAlexander Hansen logEntry); 6897f4eb588SAppaRao Puli continue; 6907f4eb588SAppaRao Puli } 6917f4eb588SAppaRao Puli 692f80a87f2SEd Tanous eventRecords.emplace_back(idStr, timestamp, messageID, messageArgs); 6937f4eb588SAppaRao Puli } 6947f4eb588SAppaRao Puli 695e662eae8SEd Tanous if (!serviceEnabled || noOfEventLogSubscribers == 0) 6962558979cSP Dheeraj Srujan Kumar { 69762598e31SEd Tanous BMCWEB_LOG_DEBUG("EventService disabled or no Subscriptions."); 6982558979cSP Dheeraj Srujan Kumar return; 6992558979cSP Dheeraj Srujan Kumar } 7002558979cSP Dheeraj Srujan Kumar 7012558979cSP Dheeraj Srujan Kumar if (eventRecords.empty()) 7022558979cSP Dheeraj Srujan Kumar { 7032558979cSP Dheeraj Srujan Kumar // No Records to send 70462598e31SEd Tanous BMCWEB_LOG_DEBUG("No log entries available to be transferred."); 7052558979cSP Dheeraj Srujan Kumar return; 7062558979cSP Dheeraj Srujan Kumar } 7072558979cSP Dheeraj Srujan Kumar 7085e44e3d8SAppaRao Puli for (const auto& it : subscriptionsMap) 7097f4eb588SAppaRao Puli { 7107f4eb588SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 7115fe4ef35SMyung Bae if (entry->userSub->eventFormatType == "Event") 7127f4eb588SAppaRao Puli { 7137f4eb588SAppaRao Puli entry->filterAndSendEventLogs(eventRecords); 7147f4eb588SAppaRao Puli } 7157f4eb588SAppaRao Puli } 7167f4eb588SAppaRao Puli } 71723a21a1cSEd Tanous }; 718b52664e2SAppaRao Puli 719b52664e2SAppaRao Puli } // namespace redfish 720