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