1 #include "metric.hpp" 2 3 #include "metrics/collection_data.hpp" 4 #include "types/report_types.hpp" 5 #include "types/sensor_types.hpp" 6 #include "utils/labeled_tuple.hpp" 7 #include "utils/transform.hpp" 8 9 #include <sdbusplus/exception.hpp> 10 11 #include <algorithm> 12 13 Metric::Metric(Sensors sensorsIn, OperationType operationTypeIn, 14 CollectionTimeScope timeScopeIn, 15 CollectionDuration collectionDurationIn, 16 std::unique_ptr<interfaces::Clock> clockIn) : 17 sensors(std::move(sensorsIn)), operationType(operationTypeIn), 18 collectionTimeScope(timeScopeIn), collectionDuration(collectionDurationIn), 19 collectionAlgorithms( 20 metrics::makeCollectionData(sensors.size(), operationType, 21 collectionTimeScope, collectionDuration)), 22 clock(std::move(clockIn)) 23 {} 24 25 void Metric::registerForUpdates(interfaces::MetricListener& listener) 26 { 27 listeners.emplace_back(listener); 28 } 29 30 void Metric::unregisterFromUpdates(interfaces::MetricListener& listener) 31 { 32 listeners.erase( 33 std::remove_if(listeners.begin(), listeners.end(), 34 [&listener](const interfaces::MetricListener& item) { 35 return &item == &listener; 36 }), 37 listeners.end()); 38 } 39 40 void Metric::initialize() 41 { 42 for (const auto& sensor : sensors) 43 { 44 sensor->registerForUpdates(weak_from_this()); 45 } 46 } 47 48 void Metric::deinitialize() 49 { 50 for (const auto& sensor : sensors) 51 { 52 sensor->unregisterFromUpdates(weak_from_this()); 53 } 54 } 55 56 const std::vector<MetricValue>& Metric::getUpdatedReadings() 57 { 58 const auto steadyTimestamp = clock->steadyTimestamp(); 59 const auto systemTimestamp = 60 std::chrono::duration_cast<Milliseconds>(clock->systemTimestamp()) 61 .count(); 62 63 for (size_t i = 0; i < collectionAlgorithms.size(); ++i) 64 { 65 if (const auto value = collectionAlgorithms[i]->update(steadyTimestamp)) 66 { 67 if (i < readings.size()) 68 { 69 readings[i].timestamp = systemTimestamp; 70 readings[i].value = *value; 71 } 72 else 73 { 74 if (i > readings.size()) 75 { 76 const auto idx = readings.size(); 77 std::swap(collectionAlgorithms[i], 78 collectionAlgorithms[idx]); 79 std::swap(sensors[i], sensors[idx]); 80 i = idx; 81 } 82 83 readings.emplace_back(sensors[i]->metadata(), *value, 84 systemTimestamp); 85 } 86 } 87 } 88 89 return readings; 90 } 91 92 void Metric::sensorUpdated(interfaces::Sensor& notifier, Milliseconds timestamp, 93 double value) 94 { 95 auto& data = findAssociatedData(notifier); 96 double newValue = data.update(timestamp, value); 97 98 if (data.updateLastValue(newValue)) 99 { 100 for (interfaces::MetricListener& listener : listeners) 101 { 102 listener.metricUpdated(); 103 } 104 } 105 } 106 107 metrics::CollectionData& 108 Metric::findAssociatedData(const interfaces::Sensor& notifier) 109 { 110 auto it = std::find_if( 111 sensors.begin(), sensors.end(), 112 [¬ifier](const auto& sensor) { return sensor.get() == ¬ifier; }); 113 auto index = std::distance(sensors.begin(), it); 114 return *collectionAlgorithms.at(index); 115 } 116 117 LabeledMetricParameters Metric::dumpConfiguration() const 118 { 119 auto sensorPath = utils::transform(sensors, [this](const auto& sensor) { 120 return LabeledSensorInfo(sensor->id().service, sensor->id().path, 121 sensor->metadata()); 122 }); 123 124 return LabeledMetricParameters(std::move(sensorPath), operationType, 125 collectionTimeScope, collectionDuration); 126 } 127 128 uint64_t Metric::metricCount() const 129 { 130 return sensors.size(); 131 } 132 133 void Metric::updateReadings(Milliseconds timestamp) 134 { 135 for (auto& data : collectionAlgorithms) 136 { 137 if (std::optional<double> newValue = data->update(timestamp)) 138 { 139 if (data->updateLastValue(*newValue)) 140 { 141 for (interfaces::MetricListener& listener : listeners) 142 { 143 listener.metricUpdated(); 144 } 145 return; 146 } 147 } 148 } 149 } 150 151 bool Metric::isTimerRequired() const 152 { 153 if (collectionTimeScope == CollectionTimeScope::point) 154 { 155 return false; 156 } 157 158 if (collectionTimeScope == CollectionTimeScope::startup && 159 (operationType == OperationType::min || 160 operationType == OperationType::max)) 161 { 162 return false; 163 } 164 165 return true; 166 } 167