xref: /openbmc/telemetry/src/report_factory.cpp (revision 62c08e9b)
1 #include "report_factory.hpp"
2 
3 #include "metric.hpp"
4 #include "report.hpp"
5 #include "sensor.hpp"
6 #include "utils/clock.hpp"
7 #include "utils/conversion.hpp"
8 #include "utils/dbus_mapper.hpp"
9 #include "utils/transform.hpp"
10 
11 ReportFactory::ReportFactory(
12     std::shared_ptr<sdbusplus::asio::connection> bus,
13     const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
14     SensorCache& sensorCache) :
15     bus(std::move(bus)),
16     objServer(objServer), sensorCache(sensorCache)
17 {}
18 
19 std::unique_ptr<interfaces::Report> ReportFactory::make(
20     const std::string& id, const std::string& name,
21     const ReportingType reportingType,
22     const std::vector<ReportAction>& reportActions, Milliseconds period,
23     uint64_t appendLimit, const ReportUpdates reportUpdates,
24     interfaces::ReportManager& reportManager,
25     interfaces::JsonStorage& reportStorage,
26     std::vector<LabeledMetricParameters> labeledMetricParams, bool enabled,
27     Readings readings) const
28 {
29     auto metrics = utils::transform(
30         labeledMetricParams,
31         [this](const LabeledMetricParameters& param)
32             -> std::shared_ptr<interfaces::Metric> {
33             namespace ts = utils::tstring;
34 
35             return std::make_shared<Metric>(
36                 getSensors(param.at_label<ts::SensorPath>()),
37                 param.at_label<ts::OperationType>(), param.at_label<ts::Id>(),
38                 param.at_label<ts::CollectionTimeScope>(),
39                 param.at_label<ts::CollectionDuration>(),
40                 std::make_unique<Clock>());
41         });
42 
43     return std::make_unique<Report>(
44         bus->get_io_context(), objServer, id, name, reportingType,
45         reportActions, period, appendLimit, reportUpdates, reportManager,
46         reportStorage, std::move(metrics), *this, enabled,
47         std::make_unique<Clock>(), std::move(readings));
48 }
49 
50 void ReportFactory::updateMetrics(
51     std::vector<std::shared_ptr<interfaces::Metric>>& metrics, bool enabled,
52     const std::vector<LabeledMetricParameters>& labeledMetricParams) const
53 {
54     std::vector<std::shared_ptr<interfaces::Metric>> oldMetrics = metrics;
55     std::vector<std::shared_ptr<interfaces::Metric>> newMetrics;
56 
57     for (const auto& labeledMetricParam : labeledMetricParams)
58     {
59         auto existing = std::find_if(oldMetrics.begin(), oldMetrics.end(),
60                                      [labeledMetricParam](auto metric) {
61                                          return labeledMetricParam ==
62                                                 metric->dumpConfiguration();
63                                      });
64 
65         if (existing != oldMetrics.end())
66         {
67             newMetrics.emplace_back(*existing);
68             oldMetrics.erase(existing);
69             continue;
70         }
71 
72         namespace ts = utils::tstring;
73         newMetrics.emplace_back(std::make_shared<Metric>(
74             getSensors(labeledMetricParam.at_label<ts::SensorPath>()),
75             labeledMetricParam.at_label<ts::OperationType>(),
76             labeledMetricParam.at_label<ts::Id>(),
77             labeledMetricParam.at_label<ts::CollectionTimeScope>(),
78             labeledMetricParam.at_label<ts::CollectionDuration>(),
79             std::make_unique<Clock>()));
80 
81         if (enabled)
82         {
83             newMetrics.back()->initialize();
84         }
85     }
86 
87     if (enabled)
88     {
89         for (auto& metric : oldMetrics)
90         {
91             metric->deinitialize();
92         }
93     }
94 
95     metrics = std::move(newMetrics);
96 }
97 
98 Sensors ReportFactory::getSensors(
99     const std::vector<LabeledSensorInfo>& sensorPaths) const
100 {
101     using namespace utils::tstring;
102 
103     return utils::transform(
104         sensorPaths,
105         [this](const LabeledSensorInfo& sensorPath)
106             -> std::shared_ptr<interfaces::Sensor> {
107             return sensorCache.makeSensor<Sensor>(
108                 sensorPath.at_label<Service>(), sensorPath.at_label<Path>(),
109                 sensorPath.at_label<Metadata>(), bus->get_io_context(), bus);
110         });
111 }
112 
113 std::vector<LabeledMetricParameters> ReportFactory::convertMetricParams(
114     boost::asio::yield_context& yield,
115     const ReadingParameters& metricParams) const
116 {
117     if (metricParams.empty())
118     {
119         return {};
120     }
121 
122     auto tree = utils::getSubTreeSensors(yield, bus);
123     return getMetricParamsFromSensorTree(metricParams, tree);
124 }
125 
126 std::vector<LabeledMetricParameters> ReportFactory::convertMetricParams(
127     const ReadingParameters& metricParams) const
128 {
129     if (metricParams.empty())
130     {
131         return {};
132     }
133 
134     auto tree = utils::getSubTreeSensors(bus);
135     return getMetricParamsFromSensorTree(metricParams, tree);
136 }
137 
138 std::vector<LabeledMetricParameters>
139     ReportFactory::getMetricParamsFromSensorTree(
140         const ReadingParameters& metricParams,
141         const std::vector<utils::SensorTree>& tree) const
142 {
143     try
144     {
145         return utils::transform(metricParams, [&tree](const auto& item) {
146             auto [sensorPaths, operationType, id, collectionTimeScope,
147                   collectionDuration] = item;
148 
149             std::vector<LabeledSensorInfo> sensorParameters;
150 
151             for (const auto& [sensorPath, metadata] : sensorPaths)
152             {
153                 auto it = std::find_if(tree.begin(), tree.end(),
154                                        [path = sensorPath](const auto& v) {
155                                            return v.first == path;
156                                        });
157 
158                 if (it != tree.end() && it->second.size() == 1)
159                 {
160                     const auto& [service, ifaces] = it->second.front();
161                     sensorParameters.emplace_back(service, sensorPath,
162                                                   metadata);
163                 }
164             }
165 
166             if (sensorParameters.size() != sensorPaths.size())
167             {
168                 throw errors::InvalidArgument("ReadingParameters",
169                                               "Service not found.");
170             }
171 
172             if (operationType.empty())
173             {
174                 operationType = utils::enumToString(OperationType::avg);
175             }
176             else if (operationType == "SINGLE")
177             {
178                 operationType = utils::enumToString(OperationType::avg);
179                 collectionTimeScope =
180                     utils::enumToString(CollectionTimeScope::point);
181             }
182 
183             if (collectionTimeScope.empty())
184             {
185                 collectionTimeScope =
186                     utils::enumToString(CollectionTimeScope::point);
187             }
188 
189             return LabeledMetricParameters(
190                 std::move(sensorParameters),
191                 utils::toOperationType(operationType), id,
192                 utils::toCollectionTimeScope(collectionTimeScope),
193                 CollectionDuration(Milliseconds(collectionDuration)));
194         });
195     }
196     catch (const errors::InvalidArgument& e)
197     {
198         if (e.propertyName == "ReadingParameters")
199         {
200             throw;
201         }
202 
203         using namespace std::literals::string_literals;
204         throw errors::InvalidArgument("ReadingParameters."s + e.propertyName);
205     }
206 }
207