1 #include "report.hpp" 2 3 #include "report_manager.hpp" 4 #include "utils/transform.hpp" 5 6 #include <phosphor-logging/log.hpp> 7 8 #include <numeric> 9 10 Report::Report(boost::asio::io_context& ioc, 11 const std::shared_ptr<sdbusplus::asio::object_server>& objServer, 12 const std::string& reportName, 13 const std::string& reportingTypeIn, 14 const bool emitsReadingsUpdateIn, 15 const bool logToMetricReportsCollectionIn, 16 const std::chrono::milliseconds intervalIn, 17 const ReadingParameters& readingParametersIn, 18 interfaces::ReportManager& reportManager, 19 interfaces::JsonStorage& reportStorageIn, 20 std::vector<std::shared_ptr<interfaces::Metric>> metrics) : 21 name(reportName), 22 path(reportDir + name), reportingType(reportingTypeIn), 23 interval(intervalIn), emitsReadingsUpdate(emitsReadingsUpdateIn), 24 logToMetricReportsCollection(logToMetricReportsCollectionIn), 25 readingParameters(readingParametersIn), objServer(objServer), 26 metrics(std::move(metrics)), timer(ioc), 27 fileName(std::to_string(std::hash<std::string>{}(name))), 28 reportStorage(reportStorageIn) 29 { 30 for (auto& metric : this->metrics) 31 { 32 metric->initialize(); 33 } 34 35 deleteIface = objServer->add_unique_interface( 36 path, deleteIfaceName, [this, &ioc, &reportManager](auto& dbusIface) { 37 dbusIface.register_method("Delete", [this, &ioc, &reportManager] { 38 if (persistency) 39 { 40 reportStorage.remove(fileName); 41 } 42 boost::asio::post(ioc, [this, &reportManager] { 43 reportManager.removeReport(this); 44 }); 45 }); 46 }); 47 48 reportIface = objServer->add_unique_interface( 49 path, reportIfaceName, [this](auto& dbusIface) { 50 dbusIface.register_property_rw( 51 "Interval", static_cast<uint64_t>(interval.count()), 52 sdbusplus::vtable::property_::emits_change, 53 [this](uint64_t newVal, auto&) { 54 std::chrono::milliseconds newValT(newVal); 55 if (newValT < ReportManager::minInterval) 56 { 57 return false; 58 } 59 interval = newValT; 60 return true; 61 }, 62 [this](const auto&) { 63 return static_cast<uint64_t>(interval.count()); 64 }); 65 persistency = storeConfiguration(); 66 dbusIface.register_property_rw( 67 "Persistency", persistency, 68 sdbusplus::vtable::property_::emits_change, 69 [this](bool newVal, const auto&) { 70 if (newVal == persistency) 71 { 72 return true; 73 } 74 if (newVal) 75 { 76 persistency = storeConfiguration(); 77 } 78 else 79 { 80 reportStorage.remove(fileName); 81 persistency = false; 82 } 83 return true; 84 }, 85 [this](const auto&) { return persistency; }); 86 dbusIface.register_property_r( 87 "Readings", readings, 88 sdbusplus::vtable::property_::emits_change, 89 [this](const auto&) { return readings; }); 90 dbusIface.register_property_r( 91 "ReportingType", reportingType, 92 sdbusplus::vtable::property_::const_, 93 [this](const auto&) { return reportingType; }); 94 dbusIface.register_property_r( 95 "ReadingParameters", readingParameters, 96 sdbusplus::vtable::property_::const_, 97 [this](const auto&) { return readingParameters; }); 98 dbusIface.register_property_r( 99 "EmitsReadingsUpdate", emitsReadingsUpdate, 100 sdbusplus::vtable::property_::const_, 101 [this](const auto&) { return emitsReadingsUpdate; }); 102 dbusIface.register_property_r( 103 "LogToMetricReportsCollection", logToMetricReportsCollection, 104 sdbusplus::vtable::property_::const_, 105 [this](const auto&) { return logToMetricReportsCollection; }); 106 dbusIface.register_method("Update", [this] { 107 if (reportingType == "OnRequest") 108 { 109 updateReadings(); 110 } 111 }); 112 }); 113 114 if (reportingType == "Periodic") 115 { 116 scheduleTimer(interval); 117 } 118 } 119 120 void Report::timerProc(boost::system::error_code ec, Report& self) 121 { 122 if (ec) 123 { 124 return; 125 } 126 127 self.updateReadings(); 128 self.scheduleTimer(self.interval); 129 } 130 131 void Report::scheduleTimer(std::chrono::milliseconds timerInterval) 132 { 133 timer.expires_after(timerInterval); 134 timer.async_wait( 135 [this](boost::system::error_code ec) { timerProc(ec, *this); }); 136 } 137 138 void Report::updateReadings() 139 { 140 auto numElements = std::accumulate( 141 metrics.begin(), metrics.end(), 0u, [](auto sum, const auto& metric) { 142 return sum + metric->getReadings().size(); 143 }); 144 145 std::tuple_element_t<1, Readings> readingsCache(numElements); 146 147 auto it = readingsCache.begin(); 148 149 for (const auto& metric : metrics) 150 { 151 for (const auto& reading : metric->getReadings()) 152 { 153 *(it++) = std::make_tuple(reading.id, reading.metadata, 154 reading.value, reading.timestamp); 155 } 156 } 157 158 std::get<0>(readings) = std::time(0); 159 std::get<1>(readings) = std::move(readingsCache); 160 161 reportIface->signal_property("Readings"); 162 } 163 164 bool Report::storeConfiguration() const 165 { 166 try 167 { 168 nlohmann::json data; 169 170 data["Version"] = reportVersion; 171 data["Name"] = name; 172 data["ReportingType"] = reportingType; 173 data["EmitsReadingsUpdate"] = emitsReadingsUpdate; 174 data["LogToMetricReportsCollection"] = logToMetricReportsCollection; 175 data["Interval"] = interval.count(); 176 data["ReadingParameters"] = utils::transform( 177 metrics, [](const auto& metric) { return metric->to_json(); }); 178 179 reportStorage.store(fileName, data); 180 } 181 catch (const std::exception& e) 182 { 183 phosphor::logging::log<phosphor::logging::level::ERR>( 184 "Failed to store a report in storage", 185 phosphor::logging::entry("msg=", e.what())); 186 return false; 187 } 188 189 return true; 190 } 191