xref: /openbmc/telemetry/src/metric.cpp (revision c7935fa1)
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 
Metric(Sensors sensorsIn,OperationType operationTypeIn,CollectionTimeScope timeScopeIn,CollectionDuration collectionDurationIn,std::unique_ptr<interfaces::Clock> clockIn)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 
registerForUpdates(interfaces::MetricListener & listener)26 void Metric::registerForUpdates(interfaces::MetricListener& listener)
27 {
28     listeners.emplace_back(listener);
29 }
30 
unregisterFromUpdates(interfaces::MetricListener & listener)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 
initialize()41 void Metric::initialize()
42 {
43     for (const auto& sensor : sensors)
44     {
45         sensor->registerForUpdates(weak_from_this());
46     }
47 }
48 
deinitialize()49 void Metric::deinitialize()
50 {
51     for (const auto& sensor : sensors)
52     {
53         sensor->unregisterFromUpdates(weak_from_this());
54     }
55 }
56 
getUpdatedReadings()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 
sensorUpdated(interfaces::Sensor & notifier,Milliseconds timestamp,double value)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&
findAssociatedData(const interfaces::Sensor & notifier)109     Metric::findAssociatedData(const interfaces::Sensor& notifier)
110 {
111     auto it = std::find_if(
112         sensors.begin(), sensors.end(),
113         [&notifier](const auto& sensor) { return sensor.get() == &notifier; });
114     auto index = std::distance(sensors.begin(), it);
115     return *collectionAlgorithms.at(index);
116 }
117 
dumpConfiguration() const118 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 
metricCount() const129 uint64_t Metric::metricCount() const
130 {
131     return sensors.size();
132 }
133 
updateReadings(Milliseconds timestamp)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 
isTimerRequired() const152 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