xref: /openbmc/telemetry/src/report_factory.cpp (revision c7935fa1)
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 
ReportFactory(std::shared_ptr<sdbusplus::asio::connection> bus,const std::shared_ptr<sdbusplus::asio::object_server> & objServer,SensorCache & sensorCache)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 
make(const std::string & id,const std::string & name,const ReportingType reportingType,const std::vector<ReportAction> & reportActions,Milliseconds period,uint64_t appendLimit,const ReportUpdates reportUpdates,interfaces::ReportManager & reportManager,interfaces::JsonStorage & reportStorage,std::vector<LabeledMetricParameters> labeledMetricParams,bool enabled,Readings readings) const19 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(labeledMetricParams,
30                                     [this](const LabeledMetricParameters& param)
31                                         -> std::shared_ptr<interfaces::Metric> {
32         namespace ts = utils::tstring;
33 
34         return std::make_shared<Metric>(
35             getSensors(param.at_label<ts::SensorPath>()),
36             param.at_label<ts::OperationType>(),
37             param.at_label<ts::CollectionTimeScope>(),
38             param.at_label<ts::CollectionDuration>(),
39             std::make_unique<Clock>());
40     });
41 
42     return std::make_unique<Report>(
43         bus->get_io_context(), objServer, id, name, reportingType,
44         reportActions, period, appendLimit, reportUpdates, reportManager,
45         reportStorage, std::move(metrics), *this, enabled,
46         std::make_unique<Clock>(), std::move(readings));
47 }
48 
updateMetrics(std::vector<std::shared_ptr<interfaces::Metric>> & metrics,bool enabled,const std::vector<LabeledMetricParameters> & labeledMetricParams) const49 void ReportFactory::updateMetrics(
50     std::vector<std::shared_ptr<interfaces::Metric>>& metrics, bool enabled,
51     const std::vector<LabeledMetricParameters>& labeledMetricParams) const
52 {
53     std::vector<std::shared_ptr<interfaces::Metric>> oldMetrics = metrics;
54     std::vector<std::shared_ptr<interfaces::Metric>> newMetrics;
55 
56     for (const auto& labeledMetricParam : labeledMetricParams)
57     {
58         auto existing = std::find_if(oldMetrics.begin(), oldMetrics.end(),
59                                      [labeledMetricParam](auto metric) {
60             return labeledMetricParam == metric->dumpConfiguration();
61         });
62 
63         if (existing != oldMetrics.end())
64         {
65             newMetrics.emplace_back(*existing);
66             oldMetrics.erase(existing);
67             continue;
68         }
69 
70         namespace ts = utils::tstring;
71         newMetrics.emplace_back(std::make_shared<Metric>(
72             getSensors(labeledMetricParam.at_label<ts::SensorPath>()),
73             labeledMetricParam.at_label<ts::OperationType>(),
74             labeledMetricParam.at_label<ts::CollectionTimeScope>(),
75             labeledMetricParam.at_label<ts::CollectionDuration>(),
76             std::make_unique<Clock>()));
77 
78         if (enabled)
79         {
80             newMetrics.back()->initialize();
81         }
82     }
83 
84     if (enabled)
85     {
86         for (auto& metric : oldMetrics)
87         {
88             metric->deinitialize();
89         }
90     }
91 
92     metrics = std::move(newMetrics);
93 }
94 
getSensors(const std::vector<LabeledSensorInfo> & sensorPaths) const95 Sensors ReportFactory::getSensors(
96     const std::vector<LabeledSensorInfo>& sensorPaths) const
97 {
98     using namespace utils::tstring;
99 
100     return utils::transform(sensorPaths,
101                             [this](const LabeledSensorInfo& sensorPath)
102                                 -> std::shared_ptr<interfaces::Sensor> {
103         return sensorCache.makeSensor<Sensor>(
104             sensorPath.at_label<Service>(), sensorPath.at_label<Path>(),
105             sensorPath.at_label<Metadata>(), bus->get_io_context(), bus);
106     });
107 }
108 
convertMetricParams(boost::asio::yield_context & yield,const ReadingParameters & metricParams) const109 std::vector<LabeledMetricParameters> ReportFactory::convertMetricParams(
110     boost::asio::yield_context& yield,
111     const ReadingParameters& metricParams) const
112 {
113     if (metricParams.empty())
114     {
115         return {};
116     }
117 
118     auto tree = utils::getSubTreeSensors(yield, bus);
119     return getMetricParamsFromSensorTree(metricParams, tree);
120 }
121 
convertMetricParams(const ReadingParameters & metricParams) const122 std::vector<LabeledMetricParameters> ReportFactory::convertMetricParams(
123     const ReadingParameters& metricParams) const
124 {
125     if (metricParams.empty())
126     {
127         return {};
128     }
129 
130     auto tree = utils::getSubTreeSensors(bus);
131     return getMetricParamsFromSensorTree(metricParams, tree);
132 }
133 
134 std::vector<LabeledMetricParameters>
getMetricParamsFromSensorTree(const ReadingParameters & metricParams,const std::vector<utils::SensorTree> & tree) const135     ReportFactory::getMetricParamsFromSensorTree(
136         const ReadingParameters& metricParams,
137         const std::vector<utils::SensorTree>& tree) const
138 {
139     try
140     {
141         return utils::transform(metricParams, [&tree](const auto& item) {
142             auto [sensorPaths, operationType, collectionTimeScope,
143                   collectionDuration] = item;
144 
145             std::vector<LabeledSensorInfo> sensorParameters;
146 
147             for (const auto& [sensorPath, metadata] : sensorPaths)
148             {
149                 auto it = std::find_if(tree.begin(), tree.end(),
150                                        [path = sensorPath](const auto& v) {
151                     return v.first == path;
152                 });
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,
158                                                   metadata);
159                 }
160             }
161 
162             if (sensorParameters.size() != sensorPaths.size())
163             {
164                 throw errors::InvalidArgument("ReadingParameters",
165                                               "Service not found.");
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),
187                 utils::toOperationType(operationType),
188                 utils::toCollectionTimeScope(collectionTimeScope),
189                 CollectionDuration(Milliseconds(collectionDuration)));
190         });
191     }
192     catch (const errors::InvalidArgument& e)
193     {
194         if (e.propertyName == "ReadingParameters")
195         {
196             throw;
197         }
198 
199         using namespace std::literals::string_literals;
200         throw errors::InvalidArgument("ReadingParameters."s + e.propertyName);
201     }
202 }
203