xref: /openbmc/telemetry/src/metric.cpp (revision 3a1c297a)
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                std::string idIn, CollectionTimeScope timeScopeIn,
15                CollectionDuration collectionDurationIn,
16                std::unique_ptr<interfaces::Clock> clockIn) :
17     id(std::move(idIn)),
18     sensors(std::move(sensorsIn)), operationType(operationTypeIn),
19     collectionTimeScope(timeScopeIn), 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(std::remove_if(
34                         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(id, 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(sensors.begin(), sensors.end(),
112                            [&notifier](const auto& sensor) {
113         return sensor.get() == &notifier;
114     });
115     auto index = std::distance(sensors.begin(), it);
116     return *collectionAlgorithms.at(index);
117 }
118 
119 LabeledMetricParameters Metric::dumpConfiguration() const
120 {
121     auto sensorPath = utils::transform(sensors, [this](const auto& sensor) {
122         return LabeledSensorInfo(sensor->id().service, sensor->id().path,
123                                  sensor->metadata());
124     });
125 
126     return LabeledMetricParameters(std::move(sensorPath), operationType, id,
127                                    collectionTimeScope, collectionDuration);
128 }
129 
130 uint64_t Metric::metricCount() const
131 {
132     return sensors.size();
133 }
134 
135 void Metric::updateReadings(Milliseconds timestamp)
136 {
137     for (auto& data : collectionAlgorithms)
138     {
139         if (std::optional<double> newValue = data->update(timestamp))
140         {
141             if (data->updateLastValue(*newValue))
142             {
143                 for (interfaces::MetricListener& listener : listeners)
144                 {
145                     listener.metricUpdated();
146                 }
147                 return;
148             }
149         }
150     }
151 }
152 
153 bool Metric::isTimerRequired() const
154 {
155     if (collectionTimeScope == CollectionTimeScope::point)
156     {
157         return false;
158     }
159 
160     if (collectionTimeScope == CollectionTimeScope::startup &&
161         (operationType == OperationType::min ||
162          operationType == OperationType::max))
163     {
164         return false;
165     }
166 
167     return true;
168 }
169