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