xref: /openbmc/telemetry/src/report_factory.cpp (revision 1cdd7e4f)
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 ReadingParameters& metricParams) const
53 {
54     auto labeledMetricParams = convertMetricParams(metricParams);
55     std::vector<std::shared_ptr<interfaces::Metric>> oldMetrics = metrics;
56     std::vector<std::shared_ptr<interfaces::Metric>> newMetrics;
57 
58     for (const auto& labeledMetricParam : labeledMetricParams)
59     {
60         auto existing = std::find_if(oldMetrics.begin(), oldMetrics.end(),
61                                      [labeledMetricParam](auto metric) {
62                                          return labeledMetricParam ==
63                                                 metric->dumpConfiguration();
64                                      });
65 
66         if (existing != oldMetrics.end())
67         {
68             newMetrics.emplace_back(*existing);
69             oldMetrics.erase(existing);
70             continue;
71         }
72 
73         namespace ts = utils::tstring;
74         newMetrics.emplace_back(std::make_shared<Metric>(
75             getSensors(labeledMetricParam.at_label<ts::SensorPath>()),
76             labeledMetricParam.at_label<ts::OperationType>(),
77             labeledMetricParam.at_label<ts::Id>(),
78             labeledMetricParam.at_label<ts::CollectionTimeScope>(),
79             labeledMetricParam.at_label<ts::CollectionDuration>(),
80             std::make_unique<Clock>()));
81 
82         if (enabled)
83         {
84             newMetrics.back()->initialize();
85         }
86     }
87 
88     if (enabled)
89     {
90         for (auto& metric : oldMetrics)
91         {
92             metric->deinitialize();
93         }
94     }
95 
96     metrics = std::move(newMetrics);
97 }
98 
99 Sensors ReportFactory::getSensors(
100     const std::vector<LabeledSensorInfo>& sensorPaths) const
101 {
102     using namespace utils::tstring;
103 
104     return utils::transform(
105         sensorPaths,
106         [this](const LabeledSensorInfo& sensorPath)
107             -> std::shared_ptr<interfaces::Sensor> {
108             return sensorCache.makeSensor<Sensor>(
109                 sensorPath.at_label<Service>(), sensorPath.at_label<Path>(),
110                 sensorPath.at_label<Metadata>(), bus->get_io_context(), bus);
111         });
112 }
113 
114 std::vector<LabeledMetricParameters> ReportFactory::convertMetricParams(
115     boost::asio::yield_context& yield,
116     const ReadingParameters& metricParams) const
117 {
118     if (metricParams.empty())
119     {
120         return {};
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     auto tree = utils::getSubTreeSensors(bus);
134     return getMetricParamsFromSensorTree(metricParams, tree);
135 }
136 
137 std::vector<LabeledMetricParameters>
138     ReportFactory::getMetricParamsFromSensorTree(
139         const ReadingParameters& metricParams,
140         const std::vector<utils::SensorTree>& tree) const
141 {
142     return utils::transform(metricParams, [&tree](const auto& item) {
143         auto [sensorPaths, operationType, id, collectionTimeScope,
144               collectionDuration] = item;
145 
146         std::vector<LabeledSensorInfo> sensorParameters;
147 
148         for (const auto& [sensorPath, metadata] : sensorPaths)
149         {
150             auto it = std::find_if(
151                 tree.begin(), tree.end(),
152                 [path = sensorPath](const auto& v) { return v.first == path; });
153 
154             if (it != tree.end() && it->second.size() == 1)
155             {
156                 const auto& [service, ifaces] = it->second.front();
157                 sensorParameters.emplace_back(service, sensorPath, metadata);
158             }
159         }
160 
161         if (sensorParameters.size() != sensorPaths.size())
162         {
163             throw sdbusplus::exception::SdBusError(
164                 static_cast<int>(std::errc::invalid_argument),
165                 "Could not find service for provided sensors");
166         }
167 
168         if (operationType.empty())
169         {
170             operationType = utils::enumToString(OperationType::avg);
171         }
172         else if (operationType == "SINGLE")
173         {
174             operationType = utils::enumToString(OperationType::avg);
175             collectionTimeScope =
176                 utils::enumToString(CollectionTimeScope::point);
177         }
178 
179         if (collectionTimeScope.empty())
180         {
181             collectionTimeScope =
182                 utils::enumToString(CollectionTimeScope::point);
183         }
184 
185         return LabeledMetricParameters(
186             std::move(sensorParameters), utils::toOperationType(operationType),
187             id, utils::toCollectionTimeScope(collectionTimeScope),
188             CollectionDuration(Milliseconds(collectionDuration)));
189     });
190 }
191