1c8e3a64aSKrzysztof Grobelny #include "metric.hpp" 26ccfcbf5SKrzysztof Grobelny 38069771cSKrzysztof Grobelny #include "details/collection_function.hpp" 4dcc4e193SKrzysztof Grobelny #include "types/report_types.hpp" 53a617023SSzymon Dompke #include "utils/labeled_tuple.hpp" 66ccfcbf5SKrzysztof Grobelny #include "utils/transform.hpp" 76ccfcbf5SKrzysztof Grobelny 86ccfcbf5SKrzysztof Grobelny #include <algorithm> 96ccfcbf5SKrzysztof Grobelny 108069771cSKrzysztof Grobelny class Metric::CollectionData 118069771cSKrzysztof Grobelny { 128069771cSKrzysztof Grobelny public: 138069771cSKrzysztof Grobelny using ReadingItem = details::ReadingItem; 148069771cSKrzysztof Grobelny 158069771cSKrzysztof Grobelny virtual ~CollectionData() = default; 168069771cSKrzysztof Grobelny 178069771cSKrzysztof Grobelny virtual ReadingItem update(uint64_t timestamp) = 0; 188069771cSKrzysztof Grobelny virtual ReadingItem update(uint64_t timestamp, double value) = 0; 198069771cSKrzysztof Grobelny }; 208069771cSKrzysztof Grobelny 218069771cSKrzysztof Grobelny class Metric::DataPoint : public Metric::CollectionData 228069771cSKrzysztof Grobelny { 238069771cSKrzysztof Grobelny public: 248069771cSKrzysztof Grobelny ReadingItem update(uint64_t timestamp) override 258069771cSKrzysztof Grobelny { 268069771cSKrzysztof Grobelny return ReadingItem{lastTimestamp, lastReading}; 278069771cSKrzysztof Grobelny } 288069771cSKrzysztof Grobelny 298069771cSKrzysztof Grobelny ReadingItem update(uint64_t timestamp, double reading) override 308069771cSKrzysztof Grobelny { 318069771cSKrzysztof Grobelny lastTimestamp = timestamp; 328069771cSKrzysztof Grobelny lastReading = reading; 338069771cSKrzysztof Grobelny return update(timestamp); 348069771cSKrzysztof Grobelny } 358069771cSKrzysztof Grobelny 368069771cSKrzysztof Grobelny private: 378069771cSKrzysztof Grobelny uint64_t lastTimestamp = 0u; 388069771cSKrzysztof Grobelny double lastReading = 0.0; 398069771cSKrzysztof Grobelny }; 408069771cSKrzysztof Grobelny 418069771cSKrzysztof Grobelny class Metric::DataInterval : public Metric::CollectionData 428069771cSKrzysztof Grobelny { 438069771cSKrzysztof Grobelny public: 448069771cSKrzysztof Grobelny DataInterval(std::shared_ptr<details::CollectionFunction> function, 458069771cSKrzysztof Grobelny CollectionDuration duration) : 468069771cSKrzysztof Grobelny function(std::move(function)), 478069771cSKrzysztof Grobelny duration(duration) 488069771cSKrzysztof Grobelny {} 498069771cSKrzysztof Grobelny 508069771cSKrzysztof Grobelny ReadingItem update(uint64_t timestamp) override 518069771cSKrzysztof Grobelny { 528069771cSKrzysztof Grobelny if (readings.size() > 0) 538069771cSKrzysztof Grobelny { 548069771cSKrzysztof Grobelny auto it = readings.begin(); 558069771cSKrzysztof Grobelny for (auto kt = std::next(readings.rbegin()); kt != readings.rend(); 568069771cSKrzysztof Grobelny ++kt) 578069771cSKrzysztof Grobelny { 588069771cSKrzysztof Grobelny const auto& [nextItemTimestamp, nextItemReading] = 598069771cSKrzysztof Grobelny *std::prev(kt); 608069771cSKrzysztof Grobelny if (timestamp >= nextItemTimestamp && 618069771cSKrzysztof Grobelny static_cast<uint64_t>(timestamp - nextItemTimestamp) > 628069771cSKrzysztof Grobelny duration.t.count()) 638069771cSKrzysztof Grobelny { 648069771cSKrzysztof Grobelny it = kt.base(); 658069771cSKrzysztof Grobelny break; 668069771cSKrzysztof Grobelny } 678069771cSKrzysztof Grobelny } 688069771cSKrzysztof Grobelny readings.erase(readings.begin(), it); 698069771cSKrzysztof Grobelny 708069771cSKrzysztof Grobelny if (timestamp > duration.t.count()) 718069771cSKrzysztof Grobelny { 728069771cSKrzysztof Grobelny readings.front().first = std::max( 738069771cSKrzysztof Grobelny readings.front().first, timestamp - duration.t.count()); 748069771cSKrzysztof Grobelny } 758069771cSKrzysztof Grobelny } 768069771cSKrzysztof Grobelny 778069771cSKrzysztof Grobelny return function->calculate(readings, timestamp); 788069771cSKrzysztof Grobelny } 798069771cSKrzysztof Grobelny 808069771cSKrzysztof Grobelny ReadingItem update(uint64_t timestamp, double reading) override 818069771cSKrzysztof Grobelny { 828069771cSKrzysztof Grobelny readings.emplace_back(timestamp, reading); 838069771cSKrzysztof Grobelny return update(timestamp); 848069771cSKrzysztof Grobelny } 858069771cSKrzysztof Grobelny 868069771cSKrzysztof Grobelny private: 878069771cSKrzysztof Grobelny std::shared_ptr<details::CollectionFunction> function; 888069771cSKrzysztof Grobelny std::vector<ReadingItem> readings; 898069771cSKrzysztof Grobelny CollectionDuration duration; 908069771cSKrzysztof Grobelny }; 918069771cSKrzysztof Grobelny 928069771cSKrzysztof Grobelny class Metric::DataStartup : public Metric::CollectionData 938069771cSKrzysztof Grobelny { 948069771cSKrzysztof Grobelny public: 958069771cSKrzysztof Grobelny DataStartup(std::shared_ptr<details::CollectionFunction> function) : 968069771cSKrzysztof Grobelny function(std::move(function)) 978069771cSKrzysztof Grobelny {} 988069771cSKrzysztof Grobelny 998069771cSKrzysztof Grobelny ReadingItem update(uint64_t timestamp) override 1008069771cSKrzysztof Grobelny { 1018069771cSKrzysztof Grobelny return function->calculateForStartupInterval(readings, timestamp); 1028069771cSKrzysztof Grobelny } 1038069771cSKrzysztof Grobelny 1048069771cSKrzysztof Grobelny ReadingItem update(uint64_t timestamp, double reading) override 1058069771cSKrzysztof Grobelny { 1068069771cSKrzysztof Grobelny readings.emplace_back(timestamp, reading); 1078069771cSKrzysztof Grobelny return function->calculateForStartupInterval(readings, timestamp); 1088069771cSKrzysztof Grobelny } 1098069771cSKrzysztof Grobelny 1108069771cSKrzysztof Grobelny private: 1118069771cSKrzysztof Grobelny std::shared_ptr<details::CollectionFunction> function; 1128069771cSKrzysztof Grobelny std::vector<ReadingItem> readings; 1138069771cSKrzysztof Grobelny }; 1148069771cSKrzysztof Grobelny 115dcc4e193SKrzysztof Grobelny Metric::Metric(Sensors sensorsIn, OperationType operationTypeIn, 116dcc4e193SKrzysztof Grobelny std::string idIn, std::string metadataIn, 117dcc4e193SKrzysztof Grobelny CollectionTimeScope timeScopeIn, 1188069771cSKrzysztof Grobelny CollectionDuration collectionDurationIn, 1198069771cSKrzysztof Grobelny std::unique_ptr<interfaces::Clock> clockIn) : 120dcc4e193SKrzysztof Grobelny id(idIn), 121dcc4e193SKrzysztof Grobelny metadata(metadataIn), 122dcc4e193SKrzysztof Grobelny readings(sensorsIn.size(), 1238069771cSKrzysztof Grobelny MetricValue{std::move(idIn), std::move(metadataIn), 0.0, 0u}), 124dcc4e193SKrzysztof Grobelny sensors(std::move(sensorsIn)), operationType(operationTypeIn), 1258069771cSKrzysztof Grobelny collectionTimeScope(timeScopeIn), collectionDuration(collectionDurationIn), 1268069771cSKrzysztof Grobelny collectionAlgorithms(makeCollectionData(sensors.size(), operationType, 1278069771cSKrzysztof Grobelny collectionTimeScope, 1288069771cSKrzysztof Grobelny collectionDuration)), 1298069771cSKrzysztof Grobelny clock(std::move(clockIn)) 130dcc4e193SKrzysztof Grobelny { 1318069771cSKrzysztof Grobelny attemptUnpackJsonMetadata(); 132dcc4e193SKrzysztof Grobelny } 1336ccfcbf5SKrzysztof Grobelny 1348069771cSKrzysztof Grobelny Metric::~Metric() = default; 1358069771cSKrzysztof Grobelny 1366ccfcbf5SKrzysztof Grobelny void Metric::initialize() 1376ccfcbf5SKrzysztof Grobelny { 138dcc4e193SKrzysztof Grobelny for (const auto& sensor : sensors) 139dcc4e193SKrzysztof Grobelny { 1406ccfcbf5SKrzysztof Grobelny sensor->registerForUpdates(weak_from_this()); 1416ccfcbf5SKrzysztof Grobelny } 142dcc4e193SKrzysztof Grobelny } 143e8fc5751SKrzysztof Grobelny 144*7e098e93SLukasz Kazmierczak void Metric::deinitialize() 145*7e098e93SLukasz Kazmierczak { 146*7e098e93SLukasz Kazmierczak for (const auto& sensor : sensors) 147*7e098e93SLukasz Kazmierczak { 148*7e098e93SLukasz Kazmierczak sensor->unregisterFromUpdates(weak_from_this()); 149*7e098e93SLukasz Kazmierczak } 150*7e098e93SLukasz Kazmierczak } 151*7e098e93SLukasz Kazmierczak 1528069771cSKrzysztof Grobelny std::vector<MetricValue> Metric::getReadings() const 153e8fc5751SKrzysztof Grobelny { 1548069771cSKrzysztof Grobelny const auto timestamp = clock->timestamp(); 1558069771cSKrzysztof Grobelny auto resultReadings = readings; 1568069771cSKrzysztof Grobelny 1578069771cSKrzysztof Grobelny for (size_t i = 0; i < resultReadings.size(); ++i) 1588069771cSKrzysztof Grobelny { 1598069771cSKrzysztof Grobelny std::tie(resultReadings[i].timestamp, resultReadings[i].value) = 1608069771cSKrzysztof Grobelny collectionAlgorithms[i]->update(timestamp); 1618069771cSKrzysztof Grobelny } 1628069771cSKrzysztof Grobelny 1638069771cSKrzysztof Grobelny return resultReadings; 1646ccfcbf5SKrzysztof Grobelny } 1656ccfcbf5SKrzysztof Grobelny 166e8fc5751SKrzysztof Grobelny void Metric::sensorUpdated(interfaces::Sensor& notifier, uint64_t timestamp) 1676ccfcbf5SKrzysztof Grobelny { 1688069771cSKrzysztof Grobelny findAssociatedData(notifier).update(timestamp); 1696ccfcbf5SKrzysztof Grobelny } 1706ccfcbf5SKrzysztof Grobelny 171e8fc5751SKrzysztof Grobelny void Metric::sensorUpdated(interfaces::Sensor& notifier, uint64_t timestamp, 1726ccfcbf5SKrzysztof Grobelny double value) 1736ccfcbf5SKrzysztof Grobelny { 1748069771cSKrzysztof Grobelny findAssociatedData(notifier).update(timestamp, value); 1756ccfcbf5SKrzysztof Grobelny } 1766ccfcbf5SKrzysztof Grobelny 1778069771cSKrzysztof Grobelny Metric::CollectionData& 1788069771cSKrzysztof Grobelny Metric::findAssociatedData(const interfaces::Sensor& notifier) 1796ccfcbf5SKrzysztof Grobelny { 180dcc4e193SKrzysztof Grobelny auto it = std::find_if( 181dcc4e193SKrzysztof Grobelny sensors.begin(), sensors.end(), 182dcc4e193SKrzysztof Grobelny [¬ifier](const auto& sensor) { return sensor.get() == ¬ifier; }); 183dcc4e193SKrzysztof Grobelny auto index = std::distance(sensors.begin(), it); 1848069771cSKrzysztof Grobelny return *collectionAlgorithms.at(index); 1856ccfcbf5SKrzysztof Grobelny } 1866ccfcbf5SKrzysztof Grobelny 187d2238194SKrzysztof Grobelny LabeledMetricParameters Metric::dumpConfiguration() const 1886ccfcbf5SKrzysztof Grobelny { 189dcc4e193SKrzysztof Grobelny auto sensorPath = utils::transform(sensors, [this](const auto& sensor) { 190dcc4e193SKrzysztof Grobelny return LabeledSensorParameters(sensor->id().service, sensor->id().path); 191dcc4e193SKrzysztof Grobelny }); 192dcc4e193SKrzysztof Grobelny 193dcc4e193SKrzysztof Grobelny return LabeledMetricParameters(std::move(sensorPath), operationType, id, 1948069771cSKrzysztof Grobelny metadata, collectionTimeScope, 1958069771cSKrzysztof Grobelny collectionDuration); 196dcc4e193SKrzysztof Grobelny } 197dcc4e193SKrzysztof Grobelny 1988069771cSKrzysztof Grobelny std::vector<std::unique_ptr<Metric::CollectionData>> 1998069771cSKrzysztof Grobelny Metric::makeCollectionData(size_t size, OperationType op, 2008069771cSKrzysztof Grobelny CollectionTimeScope timeScope, 2018069771cSKrzysztof Grobelny CollectionDuration duration) 2028069771cSKrzysztof Grobelny { 2038069771cSKrzysztof Grobelny using namespace std::string_literals; 2048069771cSKrzysztof Grobelny 2058069771cSKrzysztof Grobelny std::vector<std::unique_ptr<Metric::CollectionData>> result; 2068069771cSKrzysztof Grobelny 2078069771cSKrzysztof Grobelny result.reserve(size); 2088069771cSKrzysztof Grobelny 2098069771cSKrzysztof Grobelny switch (timeScope) 2108069771cSKrzysztof Grobelny { 2118069771cSKrzysztof Grobelny case CollectionTimeScope::interval: 2128069771cSKrzysztof Grobelny std::generate_n( 2138069771cSKrzysztof Grobelny std::back_inserter(result), size, 2148069771cSKrzysztof Grobelny [cf = details::makeCollectionFunction(op), duration] { 2158069771cSKrzysztof Grobelny return std::make_unique<DataInterval>(cf, duration); 2168069771cSKrzysztof Grobelny }); 2178069771cSKrzysztof Grobelny break; 2188069771cSKrzysztof Grobelny case CollectionTimeScope::point: 2198069771cSKrzysztof Grobelny std::generate_n(std::back_inserter(result), size, 2208069771cSKrzysztof Grobelny [] { return std::make_unique<DataPoint>(); }); 2218069771cSKrzysztof Grobelny break; 2228069771cSKrzysztof Grobelny case CollectionTimeScope::startup: 2238069771cSKrzysztof Grobelny std::generate_n(std::back_inserter(result), size, 2248069771cSKrzysztof Grobelny [cf = details::makeCollectionFunction(op)] { 2258069771cSKrzysztof Grobelny return std::make_unique<DataStartup>(cf); 2268069771cSKrzysztof Grobelny }); 2278069771cSKrzysztof Grobelny break; 2288069771cSKrzysztof Grobelny default: 2298069771cSKrzysztof Grobelny throw std::runtime_error("timeScope: "s + 2308069771cSKrzysztof Grobelny utils::enumToString(timeScope) + 2318069771cSKrzysztof Grobelny " is not supported"s); 2328069771cSKrzysztof Grobelny } 2338069771cSKrzysztof Grobelny 2348069771cSKrzysztof Grobelny return result; 2358069771cSKrzysztof Grobelny } 2368069771cSKrzysztof Grobelny 2378069771cSKrzysztof Grobelny void Metric::attemptUnpackJsonMetadata() 238dcc4e193SKrzysztof Grobelny { 2393a617023SSzymon Dompke using MetricMetadata = 2403a617023SSzymon Dompke utils::LabeledTuple<std::tuple<std::vector<std::string>>, 2413a617023SSzymon Dompke utils::tstring::MetricProperties>; 2423a617023SSzymon Dompke 2433a617023SSzymon Dompke using ReadingMetadata = 2443a617023SSzymon Dompke utils::LabeledTuple<std::tuple<std::string, std::string>, 2453a617023SSzymon Dompke utils::tstring::SensorDbusPath, 2463a617023SSzymon Dompke utils::tstring::SensorRedfishUri>; 247dcc4e193SKrzysztof Grobelny try 248dcc4e193SKrzysztof Grobelny { 2493a617023SSzymon Dompke const MetricMetadata parsedMetadata = 2503a617023SSzymon Dompke nlohmann::json::parse(metadata).get<MetricMetadata>(); 2513a617023SSzymon Dompke 2523a617023SSzymon Dompke if (readings.size() == parsedMetadata.at_index<0>().size()) 253dcc4e193SKrzysztof Grobelny { 254dcc4e193SKrzysztof Grobelny for (size_t i = 0; i < readings.size(); ++i) 255dcc4e193SKrzysztof Grobelny { 2563a617023SSzymon Dompke ReadingMetadata readingMetadata{ 2573a617023SSzymon Dompke sensors[i]->id().path, parsedMetadata.at_index<0>()[i]}; 2583a617023SSzymon Dompke readings[i].metadata = readingMetadata.dump(); 259dcc4e193SKrzysztof Grobelny } 260dcc4e193SKrzysztof Grobelny } 261dcc4e193SKrzysztof Grobelny } 2628069771cSKrzysztof Grobelny catch (const nlohmann::json::exception&) 263dcc4e193SKrzysztof Grobelny {} 2646ccfcbf5SKrzysztof Grobelny } 265