#include "metric.hpp" #include "metrics/collection_data.hpp" #include "types/report_types.hpp" #include "types/sensor_types.hpp" #include "utils/labeled_tuple.hpp" #include "utils/transform.hpp" #include #include Metric::Metric(Sensors sensorsIn, OperationType operationTypeIn, CollectionTimeScope timeScopeIn, CollectionDuration collectionDurationIn, std::unique_ptr clockIn) : sensors(std::move(sensorsIn)), operationType(operationTypeIn), collectionTimeScope(timeScopeIn), collectionDuration(collectionDurationIn), collectionAlgorithms( metrics::makeCollectionData(sensors.size(), operationType, collectionTimeScope, collectionDuration)), clock(std::move(clockIn)) {} void Metric::registerForUpdates(interfaces::MetricListener& listener) { listeners.emplace_back(listener); } void Metric::unregisterFromUpdates(interfaces::MetricListener& listener) { listeners.erase( std::remove_if(listeners.begin(), listeners.end(), [&listener](const interfaces::MetricListener& item) { return &item == &listener; }), listeners.end()); } void Metric::initialize() { for (const auto& sensor : sensors) { sensor->registerForUpdates(weak_from_this()); } } void Metric::deinitialize() { for (const auto& sensor : sensors) { sensor->unregisterFromUpdates(weak_from_this()); } } const std::vector& Metric::getUpdatedReadings() { const auto steadyTimestamp = clock->steadyTimestamp(); const auto systemTimestamp = std::chrono::duration_cast(clock->systemTimestamp()) .count(); for (size_t i = 0; i < collectionAlgorithms.size(); ++i) { if (const auto value = collectionAlgorithms[i]->update(steadyTimestamp)) { if (i < readings.size()) { readings[i].timestamp = systemTimestamp; readings[i].value = *value; } else { if (i > readings.size()) { const auto idx = readings.size(); std::swap(collectionAlgorithms[i], collectionAlgorithms[idx]); std::swap(sensors[i], sensors[idx]); i = idx; } readings.emplace_back(sensors[i]->metadata(), *value, systemTimestamp); } } } return readings; } void Metric::sensorUpdated(interfaces::Sensor& notifier, Milliseconds timestamp, double value) { auto& data = findAssociatedData(notifier); double newValue = data.update(timestamp, value); if (data.updateLastValue(newValue)) { for (interfaces::MetricListener& listener : listeners) { listener.metricUpdated(); } } } metrics::CollectionData& Metric::findAssociatedData(const interfaces::Sensor& notifier) { auto it = std::find_if( sensors.begin(), sensors.end(), [¬ifier](const auto& sensor) { return sensor.get() == ¬ifier; }); auto index = std::distance(sensors.begin(), it); return *collectionAlgorithms.at(index); } LabeledMetricParameters Metric::dumpConfiguration() const { auto sensorPath = utils::transform(sensors, [this](const auto& sensor) { return LabeledSensorInfo(sensor->id().service, sensor->id().path, sensor->metadata()); }); return LabeledMetricParameters(std::move(sensorPath), operationType, collectionTimeScope, collectionDuration); } uint64_t Metric::metricCount() const { return sensors.size(); } void Metric::updateReadings(Milliseconds timestamp) { for (auto& data : collectionAlgorithms) { if (std::optional newValue = data->update(timestamp)) { if (data->updateLastValue(*newValue)) { for (interfaces::MetricListener& listener : listeners) { listener.metricUpdated(); } return; } } } } bool Metric::isTimerRequired() const { if (collectionTimeScope == CollectionTimeScope::point) { return false; } if (collectionTimeScope == CollectionTimeScope::startup && (operationType == OperationType::min || operationType == OperationType::max)) { return false; } return true; }