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" 19*b80ba2e4SAlexander Hansen #include "event_log.hpp" 20d3a48a14SEd Tanous #include "event_matches_filter.hpp" 213ccb3adbSEd Tanous #include "event_service_store.hpp" 22c0353249SWludzik, Jozef #include "metric_report.hpp" 232c6ffdb0SEd Tanous #include "ossl_random.hpp" 243ccb3adbSEd Tanous #include "persistent_data.hpp" 257f4eb588SAppaRao Puli #include "registries.hpp" 268dab0f58SEd Tanous #include "registries_selector.hpp" 2750ebd4afSEd Tanous #include "str_utility.hpp" 2802c1e29fSAlexander Hansen #include "subscription.hpp" 295b90429aSEd Tanous #include "utils/time_utils.hpp" 307f4eb588SAppaRao Puli 317f4eb588SAppaRao Puli #include <sys/inotify.h> 32b52664e2SAppaRao 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> 38b5b40605Snitroglycerine #include <sdbusplus/bus/match.hpp> 391214b7e7SGunnar Mills 405e44e3d8SAppaRao Puli #include <algorithm> 41b52664e2SAppaRao Puli #include <cstdlib> 42b52664e2SAppaRao Puli #include <ctime> 43a14c9113SEd Tanous #include <format> 441bf712bcSAyushi Smriti #include <fstream> 45b52664e2SAppaRao Puli #include <memory> 4626702d01SEd Tanous #include <span> 47a14c9113SEd Tanous #include <string> 4856ba386dSMyung Bae #include <string_view> 495fe4ef35SMyung Bae #include <utility> 50b52664e2SAppaRao Puli 51b52664e2SAppaRao Puli namespace redfish 52b52664e2SAppaRao Puli { 53156d6b00SAppaRao Puli 54156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event"; 55156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport"; 56156d6b00SAppaRao Puli 571bf712bcSAyushi Smriti static constexpr const char* eventServiceFile = 581bf712bcSAyushi Smriti "/var/lib/bmcweb/eventservice_config.json"; 591bf712bcSAyushi Smriti 60cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 614642bf8fSGeorge Liu static std::optional<boost::asio::posix::stream_descriptor> inotifyConn; 624642bf8fSGeorge Liu static constexpr const char* redfishEventLogDir = "/var/log"; 634642bf8fSGeorge Liu static constexpr const char* redfishEventLogFile = "/var/log/redfish"; 644642bf8fSGeorge Liu static constexpr const size_t iEventSize = sizeof(inotify_event); 65cf9e417dSEd Tanous 66cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 674642bf8fSGeorge Liu static int inotifyFd = -1; 68cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 694642bf8fSGeorge Liu static int dirWatchDesc = -1; 70cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 714642bf8fSGeorge Liu static int fileWatchDesc = -1; 724642bf8fSGeorge Liu 73fffb8c1fSEd Tanous namespace registries 744642bf8fSGeorge Liu { 75*b80ba2e4SAlexander Hansen inline const Message* 767f4eb588SAppaRao Puli getMsgFromRegistry(const std::string& messageKey, 7726702d01SEd Tanous const std::span<const MessageEntry>& registry) 787f4eb588SAppaRao Puli { 793544d2a7SEd Tanous std::span<const MessageEntry>::iterator messageIt = std::ranges::find_if( 803544d2a7SEd Tanous registry, [&messageKey](const MessageEntry& messageEntry) { 8155f79e6fSEd Tanous return messageKey == messageEntry.first; 827f4eb588SAppaRao Puli }); 8326702d01SEd Tanous if (messageIt != registry.end()) 847f4eb588SAppaRao Puli { 857f4eb588SAppaRao Puli return &messageIt->second; 867f4eb588SAppaRao Puli } 877f4eb588SAppaRao Puli 887f4eb588SAppaRao Puli return nullptr; 897f4eb588SAppaRao Puli } 907f4eb588SAppaRao Puli 91*b80ba2e4SAlexander Hansen inline const Message* formatMessage(std::string_view messageID) 927f4eb588SAppaRao Puli { 937f4eb588SAppaRao Puli // Redfish MessageIds are in the form 947f4eb588SAppaRao Puli // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find 957f4eb588SAppaRao Puli // the right Message 967f4eb588SAppaRao Puli std::vector<std::string> fields; 977f4eb588SAppaRao Puli fields.reserve(4); 9850ebd4afSEd Tanous 9950ebd4afSEd Tanous bmcweb::split(fields, messageID, '.'); 1007f4eb588SAppaRao Puli if (fields.size() != 4) 1017f4eb588SAppaRao Puli { 1027f4eb588SAppaRao Puli return nullptr; 1037f4eb588SAppaRao Puli } 10402cad96eSEd Tanous const std::string& registryName = fields[0]; 10502cad96eSEd Tanous const std::string& messageKey = fields[3]; 1067f4eb588SAppaRao Puli 1077f4eb588SAppaRao Puli // Find the right registry and check it for the MessageKey 108b304bd79SP Dheeraj Srujan Kumar return getMsgFromRegistry(messageKey, getRegistryFromPrefix(registryName)); 1097f4eb588SAppaRao Puli } 110fffb8c1fSEd Tanous } // namespace registries 1117f4eb588SAppaRao Puli 112b52664e2SAppaRao Puli class EventServiceManager 113b52664e2SAppaRao Puli { 114b52664e2SAppaRao Puli private: 115d3a9e084SEd Tanous bool serviceEnabled = false; 116d3a9e084SEd Tanous uint32_t retryAttempts = 0; 117d3a9e084SEd Tanous uint32_t retryTimeoutInterval = 0; 1187d1cc387SAppaRao Puli 1192558979cSP Dheeraj Srujan Kumar std::streampos redfishLogFilePosition{0}; 1209f616dd1SEd Tanous size_t noOfEventLogSubscribers{0}; 1219f616dd1SEd Tanous size_t noOfMetricReportSubscribers{0}; 12259d494eeSPatrick Williams std::shared_ptr<sdbusplus::bus::match_t> matchTelemetryMonitor; 123b52664e2SAppaRao Puli boost::container::flat_map<std::string, std::shared_ptr<Subscription>> 124b52664e2SAppaRao Puli subscriptionsMap; 125b52664e2SAppaRao Puli 1269f616dd1SEd Tanous uint64_t eventId{1}; 12796330b99SSunitha Harish 128f80a87f2SEd Tanous struct Event 129f80a87f2SEd Tanous { 130f80a87f2SEd Tanous std::string id; 131f80a87f2SEd Tanous nlohmann::json message; 132f80a87f2SEd Tanous }; 133f80a87f2SEd Tanous 134f80a87f2SEd Tanous constexpr static size_t maxMessages = 200; 135f80a87f2SEd Tanous boost::circular_buffer<Event> messages{maxMessages}; 136f80a87f2SEd Tanous 137f8ca6d79SEd Tanous boost::asio::io_context& ioc; 138f8ca6d79SEd Tanous 139b52664e2SAppaRao Puli public: 1409f616dd1SEd Tanous EventServiceManager(const EventServiceManager&) = delete; 1419f616dd1SEd Tanous EventServiceManager& operator=(const EventServiceManager&) = delete; 1429f616dd1SEd Tanous EventServiceManager(EventServiceManager&&) = delete; 1439f616dd1SEd Tanous EventServiceManager& operator=(EventServiceManager&&) = delete; 144ecd6a3a2SEd Tanous ~EventServiceManager() = default; 1459f616dd1SEd Tanous 146f8ca6d79SEd Tanous explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn) 147b52664e2SAppaRao Puli { 148f8ca6d79SEd Tanous // Load config from persist store. 149f8ca6d79SEd Tanous initConfig(); 150f8ca6d79SEd Tanous } 151f8ca6d79SEd Tanous 152f8ca6d79SEd Tanous static EventServiceManager& 153f8ca6d79SEd Tanous getInstance(boost::asio::io_context* ioc = nullptr) 154f8ca6d79SEd Tanous { 155f8ca6d79SEd Tanous static EventServiceManager handler(*ioc); 156b52664e2SAppaRao Puli return handler; 157b52664e2SAppaRao Puli } 158b52664e2SAppaRao Puli 1591bf712bcSAyushi Smriti void initConfig() 1601bf712bcSAyushi Smriti { 16128afb49cSJunLin Chen loadOldBehavior(); 1621bf712bcSAyushi Smriti 16328afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 16428afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 16528afb49cSJunLin Chen .getEventServiceConfig(); 1661bf712bcSAyushi Smriti 16728afb49cSJunLin Chen serviceEnabled = eventServiceConfig.enabled; 16828afb49cSJunLin Chen retryAttempts = eventServiceConfig.retryAttempts; 16928afb49cSJunLin Chen retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval; 1701bf712bcSAyushi Smriti 17128afb49cSJunLin Chen for (const auto& it : persistent_data::EventServiceStore::getInstance() 17228afb49cSJunLin Chen .subscriptionsConfigMap) 1731bf712bcSAyushi Smriti { 1745fe4ef35SMyung Bae std::shared_ptr<persistent_data::UserSubscription> newSub = 1755fe4ef35SMyung Bae it.second; 1764bbf237fSAppaRao Puli 1776fd29553SEd Tanous boost::system::result<boost::urls::url> url = 1785fe4ef35SMyung Bae boost::urls::parse_absolute_uri(newSub->destinationUrl); 1791bf712bcSAyushi Smriti 180a716aa74SEd Tanous if (!url) 1811bf712bcSAyushi Smriti { 18262598e31SEd Tanous BMCWEB_LOG_ERROR( 18362598e31SEd Tanous "Failed to validate and split destination url"); 1841bf712bcSAyushi Smriti continue; 1851bf712bcSAyushi Smriti } 1861bf712bcSAyushi Smriti std::shared_ptr<Subscription> subValue = 18721a94d5cSMyung Bae std::make_shared<Subscription>(newSub, *url, ioc); 1885fe4ef35SMyung Bae std::string id = subValue->userSub->id; 189a0969c70SMyung Bae subValue->deleter = [id]() { 190a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 191a0969c70SMyung Bae }; 1921bf712bcSAyushi Smriti 193a0969c70SMyung Bae subscriptionsMap.emplace(id, subValue); 19428afb49cSJunLin Chen 19528afb49cSJunLin Chen updateNoOfSubscribersCount(); 19628afb49cSJunLin Chen 19783328316SEd Tanous if constexpr (!BMCWEB_REDFISH_DBUS_LOG) 19883328316SEd Tanous { 1992558979cSP Dheeraj Srujan Kumar cacheRedfishLogFile(); 20083328316SEd Tanous } 2012558979cSP Dheeraj Srujan Kumar 20228afb49cSJunLin Chen // Update retry configuration. 20328afb49cSJunLin Chen subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 2041bf712bcSAyushi Smriti } 2051bf712bcSAyushi Smriti } 2061bf712bcSAyushi Smriti 20756d2396dSEd Tanous static void loadOldBehavior() 208b52664e2SAppaRao Puli { 20928afb49cSJunLin Chen std::ifstream eventConfigFile(eventServiceFile); 21028afb49cSJunLin Chen if (!eventConfigFile.good()) 2111bf712bcSAyushi Smriti { 21262598e31SEd Tanous BMCWEB_LOG_DEBUG("Old eventService config not exist"); 21328afb49cSJunLin Chen return; 21428afb49cSJunLin Chen } 21528afb49cSJunLin Chen auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false); 21628afb49cSJunLin Chen if (jsonData.is_discarded()) 2174bbf237fSAppaRao Puli { 21862598e31SEd Tanous BMCWEB_LOG_ERROR("Old eventService config parse error."); 21928afb49cSJunLin Chen return; 22028afb49cSJunLin Chen } 22128afb49cSJunLin Chen 2220bdda665SEd Tanous const nlohmann::json::object_t* obj = 2230bdda665SEd Tanous jsonData.get_ptr<const nlohmann::json::object_t*>(); 2240bdda665SEd Tanous for (const auto& item : *obj) 22528afb49cSJunLin Chen { 2260bdda665SEd Tanous if (item.first == "Configuration") 22728afb49cSJunLin Chen { 22828afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 22928afb49cSJunLin Chen .getEventServiceConfig() 2300bdda665SEd Tanous .fromJson(item.second); 23128afb49cSJunLin Chen } 2320bdda665SEd Tanous else if (item.first == "Subscriptions") 23328afb49cSJunLin Chen { 2340bdda665SEd Tanous for (const auto& elem : item.second) 23528afb49cSJunLin Chen { 2364b712a29SEd Tanous std::optional<persistent_data::UserSubscription> 23728afb49cSJunLin Chen newSubscription = 23828afb49cSJunLin Chen persistent_data::UserSubscription::fromJson(elem, 23928afb49cSJunLin Chen true); 2404b712a29SEd Tanous if (!newSubscription) 24128afb49cSJunLin Chen { 24262598e31SEd Tanous BMCWEB_LOG_ERROR("Problem reading subscription " 24362598e31SEd Tanous "from old persistent store"); 2444bbf237fSAppaRao Puli continue; 2454bbf237fSAppaRao Puli } 2464b712a29SEd Tanous persistent_data::UserSubscription& newSub = 2474b712a29SEd Tanous *newSubscription; 2481bf712bcSAyushi Smriti 24928afb49cSJunLin Chen std::uniform_int_distribution<uint32_t> dist(0); 25028afb49cSJunLin Chen bmcweb::OpenSSLGenerator gen; 2511bf712bcSAyushi Smriti 25228afb49cSJunLin Chen std::string id; 2531bf712bcSAyushi Smriti 25428afb49cSJunLin Chen int retry = 3; 255e662eae8SEd Tanous while (retry != 0) 2561bf712bcSAyushi Smriti { 25728afb49cSJunLin Chen id = std::to_string(dist(gen)); 25828afb49cSJunLin Chen if (gen.error()) 2597d1cc387SAppaRao Puli { 26028afb49cSJunLin Chen retry = 0; 26128afb49cSJunLin Chen break; 26228afb49cSJunLin Chen } 2634b712a29SEd Tanous newSub.id = id; 26428afb49cSJunLin Chen auto inserted = 26528afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 2665fe4ef35SMyung Bae .subscriptionsConfigMap.insert(std::pair( 2675fe4ef35SMyung Bae id, std::make_shared< 2685fe4ef35SMyung Bae persistent_data::UserSubscription>( 2695fe4ef35SMyung Bae newSub))); 27028afb49cSJunLin Chen if (inserted.second) 27128afb49cSJunLin Chen { 27228afb49cSJunLin Chen break; 27328afb49cSJunLin Chen } 27428afb49cSJunLin Chen --retry; 2757d1cc387SAppaRao Puli } 2767d1cc387SAppaRao Puli 27728afb49cSJunLin Chen if (retry <= 0) 27828afb49cSJunLin Chen { 27962598e31SEd Tanous BMCWEB_LOG_ERROR( 28062598e31SEd Tanous "Failed to generate random number from old " 28162598e31SEd Tanous "persistent store"); 28228afb49cSJunLin Chen continue; 28328afb49cSJunLin Chen } 28428afb49cSJunLin Chen } 28528afb49cSJunLin Chen } 28628afb49cSJunLin Chen 28728afb49cSJunLin Chen persistent_data::getConfig().writeData(); 2884c521c3cSEd Tanous std::error_code ec; 2894c521c3cSEd Tanous std::filesystem::remove(eventServiceFile, ec); 2904c521c3cSEd Tanous if (ec) 2914c521c3cSEd Tanous { 2924c521c3cSEd Tanous BMCWEB_LOG_DEBUG( 2934c521c3cSEd Tanous "Failed to remove old event service file. Ignoring"); 2944c521c3cSEd Tanous } 2954c521c3cSEd Tanous else 2964c521c3cSEd Tanous { 29762598e31SEd Tanous BMCWEB_LOG_DEBUG("Remove old eventservice config"); 29828afb49cSJunLin Chen } 29928afb49cSJunLin Chen } 3004c521c3cSEd Tanous } 30128afb49cSJunLin Chen 3029eb808c1SEd Tanous void updateSubscriptionData() const 30328afb49cSJunLin Chen { 30428afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 30528afb49cSJunLin Chen .eventServiceConfig.enabled = serviceEnabled; 30628afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 30728afb49cSJunLin Chen .eventServiceConfig.retryAttempts = retryAttempts; 30828afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 30928afb49cSJunLin Chen .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval; 31028afb49cSJunLin Chen 31128afb49cSJunLin Chen persistent_data::getConfig().writeData(); 31228afb49cSJunLin Chen } 31328afb49cSJunLin Chen 31428afb49cSJunLin Chen void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg) 3157d1cc387SAppaRao Puli { 3167d1cc387SAppaRao Puli bool updateConfig = false; 317fe44eb0bSAyushi Smriti bool updateRetryCfg = false; 3187d1cc387SAppaRao Puli 31928afb49cSJunLin Chen if (serviceEnabled != cfg.enabled) 3207d1cc387SAppaRao Puli { 32128afb49cSJunLin Chen serviceEnabled = cfg.enabled; 322e662eae8SEd Tanous if (serviceEnabled && noOfMetricReportSubscribers != 0U) 3237d1cc387SAppaRao Puli { 3247d1cc387SAppaRao Puli registerMetricReportSignal(); 3257d1cc387SAppaRao Puli } 3267d1cc387SAppaRao Puli else 3277d1cc387SAppaRao Puli { 3287d1cc387SAppaRao Puli unregisterMetricReportSignal(); 3297d1cc387SAppaRao Puli } 3307d1cc387SAppaRao Puli updateConfig = true; 3317d1cc387SAppaRao Puli } 3327d1cc387SAppaRao Puli 33328afb49cSJunLin Chen if (retryAttempts != cfg.retryAttempts) 3347d1cc387SAppaRao Puli { 33528afb49cSJunLin Chen retryAttempts = cfg.retryAttempts; 3367d1cc387SAppaRao Puli updateConfig = true; 337fe44eb0bSAyushi Smriti updateRetryCfg = true; 3387d1cc387SAppaRao Puli } 3397d1cc387SAppaRao Puli 34028afb49cSJunLin Chen if (retryTimeoutInterval != cfg.retryTimeoutInterval) 3417d1cc387SAppaRao Puli { 34228afb49cSJunLin Chen retryTimeoutInterval = cfg.retryTimeoutInterval; 3437d1cc387SAppaRao Puli updateConfig = true; 344fe44eb0bSAyushi Smriti updateRetryCfg = true; 3457d1cc387SAppaRao Puli } 3467d1cc387SAppaRao Puli 3477d1cc387SAppaRao Puli if (updateConfig) 3487d1cc387SAppaRao Puli { 3497d1cc387SAppaRao Puli updateSubscriptionData(); 3507d1cc387SAppaRao Puli } 351fe44eb0bSAyushi Smriti 352fe44eb0bSAyushi Smriti if (updateRetryCfg) 353fe44eb0bSAyushi Smriti { 354fe44eb0bSAyushi Smriti // Update the changed retry config to all subscriptions 355fe44eb0bSAyushi Smriti for (const auto& it : 356fe44eb0bSAyushi Smriti EventServiceManager::getInstance().subscriptionsMap) 357fe44eb0bSAyushi Smriti { 3585e44e3d8SAppaRao Puli Subscription& entry = *it.second; 3595e44e3d8SAppaRao Puli entry.updateRetryConfig(retryAttempts, retryTimeoutInterval); 360fe44eb0bSAyushi Smriti } 361fe44eb0bSAyushi Smriti } 3627d1cc387SAppaRao Puli } 3637d1cc387SAppaRao Puli 3647d1cc387SAppaRao Puli void updateNoOfSubscribersCount() 3657d1cc387SAppaRao Puli { 3667d1cc387SAppaRao Puli size_t eventLogSubCount = 0; 3677d1cc387SAppaRao Puli size_t metricReportSubCount = 0; 3687d1cc387SAppaRao Puli for (const auto& it : subscriptionsMap) 3697d1cc387SAppaRao Puli { 3707d1cc387SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 3715fe4ef35SMyung Bae if (entry->userSub->eventFormatType == eventFormatType) 3727d1cc387SAppaRao Puli { 3737d1cc387SAppaRao Puli eventLogSubCount++; 3747d1cc387SAppaRao Puli } 3755fe4ef35SMyung Bae else if (entry->userSub->eventFormatType == metricReportFormatType) 3767d1cc387SAppaRao Puli { 3777d1cc387SAppaRao Puli metricReportSubCount++; 3787d1cc387SAppaRao Puli } 3797d1cc387SAppaRao Puli } 3807d1cc387SAppaRao Puli 3817d1cc387SAppaRao Puli noOfEventLogSubscribers = eventLogSubCount; 3827d1cc387SAppaRao Puli if (noOfMetricReportSubscribers != metricReportSubCount) 3837d1cc387SAppaRao Puli { 3847d1cc387SAppaRao Puli noOfMetricReportSubscribers = metricReportSubCount; 385e662eae8SEd Tanous if (noOfMetricReportSubscribers != 0U) 3867d1cc387SAppaRao Puli { 3877d1cc387SAppaRao Puli registerMetricReportSignal(); 3887d1cc387SAppaRao Puli } 3897d1cc387SAppaRao Puli else 3907d1cc387SAppaRao Puli { 3917d1cc387SAppaRao Puli unregisterMetricReportSignal(); 3927d1cc387SAppaRao Puli } 3937d1cc387SAppaRao Puli } 3947d1cc387SAppaRao Puli } 3957d1cc387SAppaRao Puli 396b52664e2SAppaRao Puli std::shared_ptr<Subscription> getSubscription(const std::string& id) 397b52664e2SAppaRao Puli { 398b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 399b52664e2SAppaRao Puli if (obj == subscriptionsMap.end()) 400b52664e2SAppaRao Puli { 40162598e31SEd Tanous BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id); 402b52664e2SAppaRao Puli return nullptr; 403b52664e2SAppaRao Puli } 404b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = obj->second; 405b52664e2SAppaRao Puli return subValue; 406b52664e2SAppaRao Puli } 407b52664e2SAppaRao Puli 408f80a87f2SEd Tanous std::string 409f80a87f2SEd Tanous addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue) 410b52664e2SAppaRao Puli { 411fc76b8acSEd Tanous std::uniform_int_distribution<uint32_t> dist(0); 412fc76b8acSEd Tanous bmcweb::OpenSSLGenerator gen; 413fc76b8acSEd Tanous 414b52664e2SAppaRao Puli std::string id; 415b52664e2SAppaRao Puli 416b52664e2SAppaRao Puli int retry = 3; 417e662eae8SEd Tanous while (retry != 0) 418b52664e2SAppaRao Puli { 419fc76b8acSEd Tanous id = std::to_string(dist(gen)); 420fc76b8acSEd Tanous if (gen.error()) 421fc76b8acSEd Tanous { 422fc76b8acSEd Tanous retry = 0; 423fc76b8acSEd Tanous break; 424fc76b8acSEd Tanous } 425b52664e2SAppaRao Puli auto inserted = subscriptionsMap.insert(std::pair(id, subValue)); 426b52664e2SAppaRao Puli if (inserted.second) 427b52664e2SAppaRao Puli { 428b52664e2SAppaRao Puli break; 429b52664e2SAppaRao Puli } 430b52664e2SAppaRao Puli --retry; 43123a21a1cSEd Tanous } 432b52664e2SAppaRao Puli 433b52664e2SAppaRao Puli if (retry <= 0) 434b52664e2SAppaRao Puli { 43562598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to generate random number"); 436abb93cddSEd Tanous return ""; 437b52664e2SAppaRao Puli } 438b52664e2SAppaRao Puli 43956ba386dSMyung Bae // Set Subscription ID for back trace 4405fe4ef35SMyung Bae subValue->userSub->id = id; 441a14c9113SEd Tanous 44228afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 4435fe4ef35SMyung Bae .subscriptionsConfigMap.emplace(id, subValue->userSub); 44428afb49cSJunLin Chen 4457d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 4461bf712bcSAyushi Smriti 44783328316SEd Tanous if constexpr (!BMCWEB_REDFISH_DBUS_LOG) 44883328316SEd Tanous { 4492558979cSP Dheeraj Srujan Kumar if (redfishLogFilePosition != 0) 4507f4eb588SAppaRao Puli { 4512558979cSP Dheeraj Srujan Kumar cacheRedfishLogFile(); 4527f4eb588SAppaRao Puli } 45383328316SEd Tanous } 454fe44eb0bSAyushi Smriti // Update retry configuration. 455fe44eb0bSAyushi Smriti subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 456fe44eb0bSAyushi Smriti 457f80a87f2SEd Tanous return id; 458f80a87f2SEd Tanous } 459f80a87f2SEd Tanous 460f80a87f2SEd Tanous std::string 461f80a87f2SEd Tanous addSSESubscription(const std::shared_ptr<Subscription>& subValue, 462f80a87f2SEd Tanous std::string_view lastEventId) 463f80a87f2SEd Tanous { 464f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 465f80a87f2SEd Tanous 466f80a87f2SEd Tanous if (!lastEventId.empty()) 467f80a87f2SEd Tanous { 468f80a87f2SEd Tanous BMCWEB_LOG_INFO("Attempting to find message for last id {}", 469f80a87f2SEd Tanous lastEventId); 470f80a87f2SEd Tanous boost::circular_buffer<Event>::iterator lastEvent = 471f80a87f2SEd Tanous std::find_if(messages.begin(), messages.end(), 472f80a87f2SEd Tanous [&lastEventId](const Event& event) { 473f80a87f2SEd Tanous return event.id == lastEventId; 474f80a87f2SEd Tanous }); 475f80a87f2SEd Tanous // Can't find a matching ID 476f80a87f2SEd Tanous if (lastEvent == messages.end()) 477f80a87f2SEd Tanous { 478f80a87f2SEd Tanous nlohmann::json msg = messages::eventBufferExceeded(); 479f80a87f2SEd Tanous // If the buffer overloaded, send all messages. 4806d799e14SEd Tanous subValue->sendEventToSubscriber(msg); 481f80a87f2SEd Tanous lastEvent = messages.begin(); 482f80a87f2SEd Tanous } 483f80a87f2SEd Tanous else 484f80a87f2SEd Tanous { 485f80a87f2SEd Tanous // Skip the last event the user already has 486f80a87f2SEd Tanous lastEvent++; 487f80a87f2SEd Tanous } 488f80a87f2SEd Tanous 489f80a87f2SEd Tanous for (boost::circular_buffer<Event>::const_iterator event = 490f80a87f2SEd Tanous lastEvent; 491f80a87f2SEd Tanous lastEvent != messages.end(); lastEvent++) 492f80a87f2SEd Tanous { 4936d799e14SEd Tanous subValue->sendEventToSubscriber(event->message); 494f80a87f2SEd Tanous } 495f80a87f2SEd Tanous } 496f80a87f2SEd Tanous return id; 497f80a87f2SEd Tanous } 498f80a87f2SEd Tanous 499f80a87f2SEd Tanous std::string 500f80a87f2SEd Tanous addPushSubscription(const std::shared_ptr<Subscription>& subValue) 501f80a87f2SEd Tanous { 502f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 503a0969c70SMyung Bae subValue->deleter = [id]() { 504a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 505a0969c70SMyung Bae }; 506f80a87f2SEd Tanous updateSubscriptionData(); 507b52664e2SAppaRao Puli return id; 508b52664e2SAppaRao Puli } 509b52664e2SAppaRao Puli 510b52664e2SAppaRao Puli bool isSubscriptionExist(const std::string& id) 511b52664e2SAppaRao Puli { 512b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 51355f79e6fSEd Tanous return obj != subscriptionsMap.end(); 514b52664e2SAppaRao Puli } 515b52664e2SAppaRao Puli 5164b712a29SEd Tanous bool deleteSubscription(const std::string& id) 517b52664e2SAppaRao Puli { 518b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 5194b712a29SEd Tanous if (obj == subscriptionsMap.end()) 520b52664e2SAppaRao Puli { 5214b712a29SEd Tanous BMCWEB_LOG_WARNING("Could not find subscription with id {}", id); 5224b712a29SEd Tanous return false; 5234b712a29SEd Tanous } 524b52664e2SAppaRao Puli subscriptionsMap.erase(obj); 5254b712a29SEd Tanous auto& event = persistent_data::EventServiceStore::getInstance(); 5264b712a29SEd Tanous auto persistentObj = event.subscriptionsConfigMap.find(id); 5274b712a29SEd Tanous if (persistentObj == event.subscriptionsConfigMap.end()) 5284b712a29SEd Tanous { 5294b712a29SEd Tanous BMCWEB_LOG_ERROR("Subscription wasn't in persistent data"); 5304b712a29SEd Tanous return true; 5314b712a29SEd Tanous } 53228afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 5334b712a29SEd Tanous .subscriptionsConfigMap.erase(persistentObj); 5347d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 535b52664e2SAppaRao Puli updateSubscriptionData(); 5364b712a29SEd Tanous 5374b712a29SEd Tanous return true; 538b52664e2SAppaRao Puli } 539b52664e2SAppaRao Puli 5405e44e3d8SAppaRao Puli void deleteSseSubscription(const crow::sse_socket::Connection& thisConn) 5415e44e3d8SAppaRao Puli { 542bdbfae2aSEd Tanous for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();) 5435e44e3d8SAppaRao Puli { 544bdbfae2aSEd Tanous std::shared_ptr<Subscription> entry = it->second; 5455e44e3d8SAppaRao Puli bool entryIsThisConn = entry->matchSseId(thisConn); 5465e44e3d8SAppaRao Puli if (entryIsThisConn) 5475e44e3d8SAppaRao Puli { 5485e44e3d8SAppaRao Puli persistent_data::EventServiceStore::getInstance() 5495fe4ef35SMyung Bae .subscriptionsConfigMap.erase(entry->userSub->id); 550bdbfae2aSEd Tanous it = subscriptionsMap.erase(it); 5515e44e3d8SAppaRao Puli return; 5525e44e3d8SAppaRao Puli } 553bdbfae2aSEd Tanous it++; 5545e44e3d8SAppaRao Puli } 5555e44e3d8SAppaRao Puli } 5565e44e3d8SAppaRao Puli 5575e44e3d8SAppaRao Puli size_t getNumberOfSubscriptions() const 558b52664e2SAppaRao Puli { 559b52664e2SAppaRao Puli return subscriptionsMap.size(); 560b52664e2SAppaRao Puli } 561b52664e2SAppaRao Puli 5625e44e3d8SAppaRao Puli size_t getNumberOfSSESubscriptions() const 5635e44e3d8SAppaRao Puli { 5643544d2a7SEd Tanous auto size = std::ranges::count_if( 5653544d2a7SEd Tanous subscriptionsMap, 5665e44e3d8SAppaRao Puli [](const std::pair<std::string, std::shared_ptr<Subscription>>& 5675e44e3d8SAppaRao Puli entry) { 5685fe4ef35SMyung Bae return (entry.second->userSub->subscriptionType == 5694b712a29SEd Tanous subscriptionTypeSSE); 5705e44e3d8SAppaRao Puli }); 5715e44e3d8SAppaRao Puli return static_cast<size_t>(size); 5725e44e3d8SAppaRao Puli } 5735e44e3d8SAppaRao Puli 574b52664e2SAppaRao Puli std::vector<std::string> getAllIDs() 575b52664e2SAppaRao Puli { 576b52664e2SAppaRao Puli std::vector<std::string> idList; 577b52664e2SAppaRao Puli for (const auto& it : subscriptionsMap) 578b52664e2SAppaRao Puli { 579b52664e2SAppaRao Puli idList.emplace_back(it.first); 580b52664e2SAppaRao Puli } 581b52664e2SAppaRao Puli return idList; 582b52664e2SAppaRao Puli } 583b52664e2SAppaRao Puli 5846ba8c82eSsunharis_in bool sendTestEventLog() 5850b4bdd93SAppaRao Puli { 5865e44e3d8SAppaRao Puli for (const auto& it : subscriptionsMap) 5870b4bdd93SAppaRao Puli { 5880b4bdd93SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 5896ba8c82eSsunharis_in if (!entry->sendTestEventLog()) 5906ba8c82eSsunharis_in { 5916ba8c82eSsunharis_in return false; 5920b4bdd93SAppaRao Puli } 5930b4bdd93SAppaRao Puli } 5946ba8c82eSsunharis_in return true; 5956ba8c82eSsunharis_in } 596e9a14131SAppaRao Puli 597f80a87f2SEd Tanous void sendEvent(nlohmann::json::object_t eventMessage, 598f80a87f2SEd Tanous std::string_view origin, std::string_view resourceType) 59996330b99SSunitha Harish { 600613dabeaSEd Tanous eventMessage["EventId"] = eventId; 601f80a87f2SEd Tanous 602613dabeaSEd Tanous eventMessage["EventTimestamp"] = 603613dabeaSEd Tanous redfish::time_utils::getDateTimeOffsetNow().first; 604613dabeaSEd Tanous eventMessage["OriginOfCondition"] = origin; 605613dabeaSEd Tanous 606f80a87f2SEd Tanous // MemberId is 0 : since we are sending one event record. 607788b091bSIgor Kanyuka eventMessage["MemberId"] = "0"; 60896330b99SSunitha Harish 609f80a87f2SEd Tanous messages.push_back(Event(std::to_string(eventId), eventMessage)); 610f80a87f2SEd Tanous 611f80a87f2SEd Tanous for (auto& it : subscriptionsMap) 61296330b99SSunitha Harish { 613f80a87f2SEd Tanous std::shared_ptr<Subscription>& entry = it.second; 6145fe4ef35SMyung Bae if (!eventMatchesFilter(*entry->userSub, eventMessage, 6155fe4ef35SMyung Bae resourceType)) 61696330b99SSunitha Harish { 617f80a87f2SEd Tanous BMCWEB_LOG_DEBUG("Filter didn't match"); 618f80a87f2SEd Tanous continue; 61996330b99SSunitha Harish } 620f80a87f2SEd Tanous 621f80a87f2SEd Tanous nlohmann::json::array_t eventRecord; 622f80a87f2SEd Tanous eventRecord.emplace_back(eventMessage); 623f80a87f2SEd Tanous 624613dabeaSEd Tanous nlohmann::json msgJson; 625613dabeaSEd Tanous 626613dabeaSEd Tanous msgJson["@odata.type"] = "#Event.v1_4_0.Event"; 627613dabeaSEd Tanous msgJson["Name"] = "Event Log"; 628613dabeaSEd Tanous msgJson["Id"] = eventId; 629f80a87f2SEd Tanous msgJson["Events"] = std::move(eventRecord); 630f52c03c1SCarson Labrado 631f52c03c1SCarson Labrado std::string strMsg = msgJson.dump( 632f52c03c1SCarson Labrado 2, ' ', true, nlohmann::json::error_handler_t::replace); 6336d799e14SEd Tanous entry->sendEventToSubscriber(std::move(strMsg)); 6348ece0e45SEd Tanous eventId++; // increment the eventId 63596330b99SSunitha Harish } 63696330b99SSunitha Harish } 63796330b99SSunitha Harish 6382558979cSP Dheeraj Srujan Kumar void resetRedfishFilePosition() 6397f4eb588SAppaRao Puli { 6402558979cSP Dheeraj Srujan Kumar // Control would be here when Redfish file is created. 6412558979cSP Dheeraj Srujan Kumar // Reset File Position as new file is created 6422558979cSP Dheeraj Srujan Kumar redfishLogFilePosition = 0; 6432558979cSP Dheeraj Srujan Kumar } 6442558979cSP Dheeraj Srujan Kumar 6452558979cSP Dheeraj Srujan Kumar void cacheRedfishLogFile() 6462558979cSP Dheeraj Srujan Kumar { 6472558979cSP Dheeraj Srujan Kumar // Open the redfish file and read till the last record. 6482558979cSP Dheeraj Srujan Kumar 6497f4eb588SAppaRao Puli std::ifstream logStream(redfishEventLogFile); 6507f4eb588SAppaRao Puli if (!logStream.good()) 6517f4eb588SAppaRao Puli { 65262598e31SEd Tanous BMCWEB_LOG_ERROR(" Redfish log file open failed "); 6537f4eb588SAppaRao Puli return; 6547f4eb588SAppaRao Puli } 6557f4eb588SAppaRao Puli std::string logEntry; 6567f4eb588SAppaRao Puli while (std::getline(logStream, logEntry)) 6577f4eb588SAppaRao Puli { 6582558979cSP Dheeraj Srujan Kumar redfishLogFilePosition = logStream.tellg(); 6597f4eb588SAppaRao Puli } 6607f4eb588SAppaRao Puli } 6617f4eb588SAppaRao Puli 6627f4eb588SAppaRao Puli void readEventLogsFromFile() 6637f4eb588SAppaRao Puli { 6647f4eb588SAppaRao Puli std::ifstream logStream(redfishEventLogFile); 6657f4eb588SAppaRao Puli if (!logStream.good()) 6667f4eb588SAppaRao Puli { 66762598e31SEd Tanous BMCWEB_LOG_ERROR(" Redfish log file open failed"); 6687f4eb588SAppaRao Puli return; 6697f4eb588SAppaRao Puli } 6707f4eb588SAppaRao Puli 6717f4eb588SAppaRao Puli std::vector<EventLogObjectsType> eventRecords; 6727f4eb588SAppaRao Puli 6737f4eb588SAppaRao Puli std::string logEntry; 6742558979cSP Dheeraj Srujan Kumar 67503d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG("Redfish log file: seek to {}", 67603d4d37cSAlexander Hansen static_cast<int>(redfishLogFilePosition)); 67703d4d37cSAlexander Hansen 6782558979cSP Dheeraj Srujan Kumar // Get the read pointer to the next log to be read. 6792558979cSP Dheeraj Srujan Kumar logStream.seekg(redfishLogFilePosition); 6802558979cSP Dheeraj Srujan Kumar 6817f4eb588SAppaRao Puli while (std::getline(logStream, logEntry)) 6827f4eb588SAppaRao Puli { 68303d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG("Redfish log file: found new event log entry"); 6842558979cSP Dheeraj Srujan Kumar // Update Pointer position 6852558979cSP Dheeraj Srujan Kumar redfishLogFilePosition = logStream.tellg(); 6862558979cSP Dheeraj Srujan Kumar 6872558979cSP Dheeraj Srujan Kumar std::string idStr; 6882558979cSP Dheeraj Srujan Kumar if (!event_log::getUniqueEntryID(logEntry, idStr)) 6897f4eb588SAppaRao Puli { 69003d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG( 69103d4d37cSAlexander Hansen "Redfish log file: could not get unique entry id for {}", 69203d4d37cSAlexander Hansen logEntry); 6937f4eb588SAppaRao Puli continue; 6947f4eb588SAppaRao Puli } 6957f4eb588SAppaRao Puli 696e662eae8SEd Tanous if (!serviceEnabled || noOfEventLogSubscribers == 0) 6977f4eb588SAppaRao Puli { 6982558979cSP Dheeraj Srujan Kumar // If Service is not enabled, no need to compute 6992558979cSP Dheeraj Srujan Kumar // the remaining items below. 7002558979cSP Dheeraj Srujan Kumar // But, Loop must continue to keep track of Timestamp 70103d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG( 70203d4d37cSAlexander Hansen "Redfish log file: no subscribers / event service not enabled"); 7037f4eb588SAppaRao Puli continue; 7047f4eb588SAppaRao Puli } 7057f4eb588SAppaRao Puli 7067f4eb588SAppaRao Puli std::string timestamp; 7077f4eb588SAppaRao Puli std::string messageID; 7085e715de6SAppaRao Puli std::vector<std::string> messageArgs; 7097f4eb588SAppaRao Puli if (event_log::getEventLogParams(logEntry, timestamp, messageID, 7107f4eb588SAppaRao Puli messageArgs) != 0) 7117f4eb588SAppaRao Puli { 71203d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG("Read eventLog entry params failed for {}", 71303d4d37cSAlexander Hansen logEntry); 7147f4eb588SAppaRao Puli continue; 7157f4eb588SAppaRao Puli } 7167f4eb588SAppaRao Puli 717f80a87f2SEd Tanous eventRecords.emplace_back(idStr, timestamp, messageID, messageArgs); 7187f4eb588SAppaRao Puli } 7197f4eb588SAppaRao Puli 720e662eae8SEd Tanous if (!serviceEnabled || noOfEventLogSubscribers == 0) 7212558979cSP Dheeraj Srujan Kumar { 72262598e31SEd Tanous BMCWEB_LOG_DEBUG("EventService disabled or no Subscriptions."); 7232558979cSP Dheeraj Srujan Kumar return; 7242558979cSP Dheeraj Srujan Kumar } 7252558979cSP Dheeraj Srujan Kumar 7262558979cSP Dheeraj Srujan Kumar if (eventRecords.empty()) 7272558979cSP Dheeraj Srujan Kumar { 7282558979cSP Dheeraj Srujan Kumar // No Records to send 72962598e31SEd Tanous BMCWEB_LOG_DEBUG("No log entries available to be transferred."); 7302558979cSP Dheeraj Srujan Kumar return; 7312558979cSP Dheeraj Srujan Kumar } 7322558979cSP Dheeraj Srujan Kumar 7335e44e3d8SAppaRao Puli for (const auto& it : subscriptionsMap) 7347f4eb588SAppaRao Puli { 7357f4eb588SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 7365fe4ef35SMyung Bae if (entry->userSub->eventFormatType == "Event") 7377f4eb588SAppaRao Puli { 7387f4eb588SAppaRao Puli entry->filterAndSendEventLogs(eventRecords); 7397f4eb588SAppaRao Puli } 7407f4eb588SAppaRao Puli } 7417f4eb588SAppaRao Puli } 7427f4eb588SAppaRao Puli 7437f4eb588SAppaRao Puli static void watchRedfishEventLogFile() 7447f4eb588SAppaRao Puli { 7456a9f85f9SAppaRao Puli if (!inotifyConn) 7467f4eb588SAppaRao Puli { 74703d4d37cSAlexander Hansen BMCWEB_LOG_ERROR("inotify Connection is not present"); 7487f4eb588SAppaRao Puli return; 7497f4eb588SAppaRao Puli } 7507f4eb588SAppaRao Puli 7517f4eb588SAppaRao Puli static std::array<char, 1024> readBuffer; 7527f4eb588SAppaRao Puli 753bd79bce8SPatrick Williams inotifyConn->async_read_some( 754bd79bce8SPatrick Williams boost::asio::buffer(readBuffer), 7557f4eb588SAppaRao Puli [&](const boost::system::error_code& ec, 7567f4eb588SAppaRao Puli const std::size_t& bytesTransferred) { 7579ed3f90aSEd Tanous if (ec == boost::asio::error::operation_aborted) 7589ed3f90aSEd Tanous { 7599ed3f90aSEd Tanous BMCWEB_LOG_DEBUG("Inotify was canceled (shutdown?)"); 7609ed3f90aSEd Tanous return; 7619ed3f90aSEd Tanous } 7627f4eb588SAppaRao Puli if (ec) 7637f4eb588SAppaRao Puli { 76462598e31SEd Tanous BMCWEB_LOG_ERROR("Callback Error: {}", ec.message()); 7657f4eb588SAppaRao Puli return; 7667f4eb588SAppaRao Puli } 76703d4d37cSAlexander Hansen 76803d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG("reading {} via inotify", bytesTransferred); 76903d4d37cSAlexander Hansen 7707f4eb588SAppaRao Puli std::size_t index = 0; 771b792cc56SAppaRao Puli while ((index + iEventSize) <= bytesTransferred) 7727f4eb588SAppaRao Puli { 773d3a9e084SEd Tanous struct inotify_event event 774d3a9e084SEd Tanous {}; 775b792cc56SAppaRao Puli std::memcpy(&event, &readBuffer[index], iEventSize); 776b792cc56SAppaRao Puli if (event.wd == dirWatchDesc) 777b792cc56SAppaRao Puli { 778b792cc56SAppaRao Puli if ((event.len == 0) || 779b792cc56SAppaRao Puli (index + iEventSize + event.len > bytesTransferred)) 780b792cc56SAppaRao Puli { 781b792cc56SAppaRao Puli index += (iEventSize + event.len); 782b792cc56SAppaRao Puli continue; 783b792cc56SAppaRao Puli } 784b792cc56SAppaRao Puli 7854f568f74SJiaqing Zhao std::string fileName(&readBuffer[index + iEventSize]); 7864f568f74SJiaqing Zhao if (fileName != "redfish") 787b792cc56SAppaRao Puli { 788b792cc56SAppaRao Puli index += (iEventSize + event.len); 789b792cc56SAppaRao Puli continue; 790b792cc56SAppaRao Puli } 791b792cc56SAppaRao Puli 79262598e31SEd Tanous BMCWEB_LOG_DEBUG( 79362598e31SEd Tanous "Redfish log file created/deleted. event.name: {}", 79462598e31SEd Tanous fileName); 795b792cc56SAppaRao Puli if (event.mask == IN_CREATE) 796b792cc56SAppaRao Puli { 797b792cc56SAppaRao Puli if (fileWatchDesc != -1) 798b792cc56SAppaRao Puli { 79962598e31SEd Tanous BMCWEB_LOG_DEBUG( 80062598e31SEd Tanous "Remove and Add inotify watcher on " 80162598e31SEd Tanous "redfish event log file"); 802016761afSAppaRao Puli // Remove existing inotify watcher and add 803016761afSAppaRao Puli // with new redfish event log file. 804016761afSAppaRao Puli inotify_rm_watch(inotifyFd, fileWatchDesc); 805016761afSAppaRao Puli fileWatchDesc = -1; 806b792cc56SAppaRao Puli } 807b792cc56SAppaRao Puli 808b792cc56SAppaRao Puli fileWatchDesc = inotify_add_watch( 809b792cc56SAppaRao Puli inotifyFd, redfishEventLogFile, IN_MODIFY); 810b792cc56SAppaRao Puli if (fileWatchDesc == -1) 811b792cc56SAppaRao Puli { 81262598e31SEd Tanous BMCWEB_LOG_ERROR("inotify_add_watch failed for " 81362598e31SEd Tanous "redfish log file."); 814b792cc56SAppaRao Puli return; 815b792cc56SAppaRao Puli } 816b792cc56SAppaRao Puli 817b792cc56SAppaRao Puli EventServiceManager::getInstance() 8182558979cSP Dheeraj Srujan Kumar .resetRedfishFilePosition(); 819b792cc56SAppaRao Puli EventServiceManager::getInstance() 820b792cc56SAppaRao Puli .readEventLogsFromFile(); 821b792cc56SAppaRao Puli } 822b792cc56SAppaRao Puli else if ((event.mask == IN_DELETE) || 823b792cc56SAppaRao Puli (event.mask == IN_MOVED_TO)) 824b792cc56SAppaRao Puli { 825b792cc56SAppaRao Puli if (fileWatchDesc != -1) 826b792cc56SAppaRao Puli { 827b792cc56SAppaRao Puli inotify_rm_watch(inotifyFd, fileWatchDesc); 828b792cc56SAppaRao Puli fileWatchDesc = -1; 829b792cc56SAppaRao Puli } 830b792cc56SAppaRao Puli } 831b792cc56SAppaRao Puli } 832b792cc56SAppaRao Puli else if (event.wd == fileWatchDesc) 833b792cc56SAppaRao Puli { 834b792cc56SAppaRao Puli if (event.mask == IN_MODIFY) 8357f4eb588SAppaRao Puli { 8367f4eb588SAppaRao Puli EventServiceManager::getInstance() 8377f4eb588SAppaRao Puli .readEventLogsFromFile(); 8387f4eb588SAppaRao Puli } 839b792cc56SAppaRao Puli } 840b792cc56SAppaRao Puli index += (iEventSize + event.len); 8417f4eb588SAppaRao Puli } 8427f4eb588SAppaRao Puli 8437f4eb588SAppaRao Puli watchRedfishEventLogFile(); 8447f4eb588SAppaRao Puli }); 8457f4eb588SAppaRao Puli } 8467f4eb588SAppaRao Puli 8477f4eb588SAppaRao Puli static int startEventLogMonitor(boost::asio::io_context& ioc) 8487f4eb588SAppaRao Puli { 84903d4d37cSAlexander Hansen BMCWEB_LOG_DEBUG("starting Event Log Monitor"); 85003d4d37cSAlexander Hansen 85123a21a1cSEd Tanous inotifyConn.emplace(ioc); 852b792cc56SAppaRao Puli inotifyFd = inotify_init1(IN_NONBLOCK); 853b792cc56SAppaRao Puli if (inotifyFd == -1) 8547f4eb588SAppaRao Puli { 85562598e31SEd Tanous BMCWEB_LOG_ERROR("inotify_init1 failed."); 8567f4eb588SAppaRao Puli return -1; 8577f4eb588SAppaRao Puli } 858b792cc56SAppaRao Puli 859b792cc56SAppaRao Puli // Add watch on directory to handle redfish event log file 860b792cc56SAppaRao Puli // create/delete. 861b792cc56SAppaRao Puli dirWatchDesc = inotify_add_watch(inotifyFd, redfishEventLogDir, 862b792cc56SAppaRao Puli IN_CREATE | IN_MOVED_TO | IN_DELETE); 863b792cc56SAppaRao Puli if (dirWatchDesc == -1) 8647f4eb588SAppaRao Puli { 86562598e31SEd Tanous BMCWEB_LOG_ERROR( 86662598e31SEd Tanous "inotify_add_watch failed for event log directory."); 8677f4eb588SAppaRao Puli return -1; 8687f4eb588SAppaRao Puli } 8697f4eb588SAppaRao Puli 870b792cc56SAppaRao Puli // Watch redfish event log file for modifications. 871bd79bce8SPatrick Williams fileWatchDesc = 872bd79bce8SPatrick Williams inotify_add_watch(inotifyFd, redfishEventLogFile, IN_MODIFY); 873b792cc56SAppaRao Puli if (fileWatchDesc == -1) 874b792cc56SAppaRao Puli { 87562598e31SEd Tanous BMCWEB_LOG_ERROR("inotify_add_watch failed for redfish log file."); 876b792cc56SAppaRao Puli // Don't return error if file not exist. 877b792cc56SAppaRao Puli // Watch on directory will handle create/delete of file. 878b792cc56SAppaRao Puli } 879b792cc56SAppaRao Puli 8807f4eb588SAppaRao Puli // monitor redfish event log file 881b792cc56SAppaRao Puli inotifyConn->assign(inotifyFd); 8827f4eb588SAppaRao Puli watchRedfishEventLogFile(); 8837f4eb588SAppaRao Puli 8847f4eb588SAppaRao Puli return 0; 8857f4eb588SAppaRao Puli } 8867f4eb588SAppaRao Puli 8879ed3f90aSEd Tanous static void stopEventLogMonitor() 8889ed3f90aSEd Tanous { 8899ed3f90aSEd Tanous inotifyConn.reset(); 8909ed3f90aSEd Tanous } 8919ed3f90aSEd Tanous 89259d494eeSPatrick Williams static void getReadingsForReport(sdbusplus::message_t& msg) 893156d6b00SAppaRao Puli { 89456d2396dSEd Tanous if (msg.is_method_error()) 89556d2396dSEd Tanous { 89662598e31SEd Tanous BMCWEB_LOG_ERROR("TelemetryMonitor Signal error"); 89756d2396dSEd Tanous return; 89856d2396dSEd Tanous } 89956d2396dSEd Tanous 900c0353249SWludzik, Jozef sdbusplus::message::object_path path(msg.get_path()); 901c0353249SWludzik, Jozef std::string id = path.filename(); 902c0353249SWludzik, Jozef if (id.empty()) 903156d6b00SAppaRao Puli { 90462598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to get Id from path"); 905156d6b00SAppaRao Puli return; 906156d6b00SAppaRao Puli } 907156d6b00SAppaRao Puli 908c0353249SWludzik, Jozef std::string interface; 909b9d36b47SEd Tanous dbus::utility::DBusPropertiesMap props; 910c0353249SWludzik, Jozef std::vector<std::string> invalidProps; 911c0353249SWludzik, Jozef msg.read(interface, props, invalidProps); 912c0353249SWludzik, Jozef 913bd79bce8SPatrick Williams auto found = std::ranges::find_if(props, [](const auto& x) { 914bd79bce8SPatrick Williams return x.first == "Readings"; 915bd79bce8SPatrick Williams }); 916c0353249SWludzik, Jozef if (found == props.end()) 917156d6b00SAppaRao Puli { 91862598e31SEd Tanous BMCWEB_LOG_INFO("Failed to get Readings from Report properties"); 919156d6b00SAppaRao Puli return; 920156d6b00SAppaRao Puli } 921156d6b00SAppaRao Puli 9221e1e598dSJonathan Doman const telemetry::TimestampReadings* readings = 9231e1e598dSJonathan Doman std::get_if<telemetry::TimestampReadings>(&found->second); 924e662eae8SEd Tanous if (readings == nullptr) 9251e1e598dSJonathan Doman { 92662598e31SEd Tanous BMCWEB_LOG_INFO("Failed to get Readings from Report properties"); 9271e1e598dSJonathan Doman return; 9281e1e598dSJonathan Doman } 9291e1e598dSJonathan Doman 930156d6b00SAppaRao Puli for (const auto& it : 931156d6b00SAppaRao Puli EventServiceManager::getInstance().subscriptionsMap) 932156d6b00SAppaRao Puli { 933e05aec50SEd Tanous Subscription& entry = *it.second; 9345fe4ef35SMyung Bae if (entry.userSub->eventFormatType == metricReportFormatType) 935156d6b00SAppaRao Puli { 9361e1e598dSJonathan Doman entry.filterAndSendReports(id, *readings); 937156d6b00SAppaRao Puli } 938156d6b00SAppaRao Puli } 939156d6b00SAppaRao Puli } 940156d6b00SAppaRao Puli 941156d6b00SAppaRao Puli void unregisterMetricReportSignal() 942156d6b00SAppaRao Puli { 9437d1cc387SAppaRao Puli if (matchTelemetryMonitor) 9447d1cc387SAppaRao Puli { 94562598e31SEd Tanous BMCWEB_LOG_DEBUG("Metrics report signal - Unregister"); 946156d6b00SAppaRao Puli matchTelemetryMonitor.reset(); 947156d6b00SAppaRao Puli matchTelemetryMonitor = nullptr; 948156d6b00SAppaRao Puli } 9497d1cc387SAppaRao Puli } 950156d6b00SAppaRao Puli 951156d6b00SAppaRao Puli void registerMetricReportSignal() 952156d6b00SAppaRao Puli { 9537d1cc387SAppaRao Puli if (!serviceEnabled || matchTelemetryMonitor) 954156d6b00SAppaRao Puli { 95562598e31SEd Tanous BMCWEB_LOG_DEBUG("Not registering metric report signal."); 956156d6b00SAppaRao Puli return; 957156d6b00SAppaRao Puli } 958156d6b00SAppaRao Puli 95962598e31SEd Tanous BMCWEB_LOG_DEBUG("Metrics report signal - Register"); 960c0353249SWludzik, Jozef std::string matchStr = "type='signal',member='PropertiesChanged'," 961c0353249SWludzik, Jozef "interface='org.freedesktop.DBus.Properties'," 962c0353249SWludzik, Jozef "arg0=xyz.openbmc_project.Telemetry.Report"; 963156d6b00SAppaRao Puli 96459d494eeSPatrick Williams matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match_t>( 96556d2396dSEd Tanous *crow::connections::systemBus, matchStr, getReadingsForReport); 966156d6b00SAppaRao Puli } 96723a21a1cSEd Tanous }; 968b52664e2SAppaRao Puli 969b52664e2SAppaRao Puli } // namespace redfish 970