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