1 #include "report_manager.hpp" 2 3 #include "report.hpp" 4 5 #include <phosphor-logging/log.hpp> 6 #include <sdbusplus/exception.hpp> 7 8 #include <stdexcept> 9 #include <system_error> 10 11 ReportManager::ReportManager( 12 std::unique_ptr<interfaces::ReportFactory> reportFactoryIn, 13 std::unique_ptr<interfaces::JsonStorage> reportStorageIn, 14 const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) : 15 reportFactory(std::move(reportFactoryIn)), 16 reportStorage(std::move(reportStorageIn)), objServer(objServerIn) 17 { 18 reports.reserve(maxReports); 19 loadFromPersistent(); 20 21 reportManagerIface = objServer->add_unique_interface( 22 reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) { 23 dbusIface.register_property_r( 24 "MaxReports", uint32_t{}, sdbusplus::vtable::property_::const_, 25 [](const auto&) { return maxReports; }); 26 dbusIface.register_property_r( 27 "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_, 28 [](const auto&) -> uint64_t { return minInterval.count(); }); 29 30 dbusIface.register_method( 31 "AddReport", [this](boost::asio::yield_context& yield, 32 const std::string& reportName, 33 const std::string& reportingType, 34 const bool emitsReadingsUpdate, 35 const bool logToMetricReportsCollection, 36 const uint64_t interval, 37 const ReadingParameters& metricParams) { 38 return addReport(yield, reportName, reportingType, 39 emitsReadingsUpdate, 40 logToMetricReportsCollection, 41 std::chrono::milliseconds(interval), 42 metricParams) 43 ->getPath(); 44 }); 45 }); 46 } 47 48 void ReportManager::removeReport(const interfaces::Report* report) 49 { 50 reports.erase( 51 std::remove_if(reports.begin(), reports.end(), 52 [report](const auto& x) { return report == x.get(); }), 53 reports.end()); 54 } 55 56 std::unique_ptr<interfaces::Report>& ReportManager::addReport( 57 std::optional<std::reference_wrapper<boost::asio::yield_context>> yield, 58 const std::string& reportName, const std::string& reportingType, 59 const bool emitsReadingsUpdate, const bool logToMetricReportsCollection, 60 std::chrono::milliseconds interval, const ReadingParameters& metricParams) 61 { 62 if (reports.size() >= maxReports) 63 { 64 throw sdbusplus::exception::SdBusError( 65 static_cast<int>(std::errc::too_many_files_open), 66 "Reached maximal report count"); 67 } 68 69 for (const auto& report : reports) 70 { 71 if (report->getName() == reportName) 72 { 73 throw sdbusplus::exception::SdBusError( 74 static_cast<int>(std::errc::file_exists), "Duplicate report"); 75 } 76 } 77 78 if (interval < minInterval) 79 { 80 throw sdbusplus::exception::SdBusError( 81 static_cast<int>(std::errc::invalid_argument), "Invalid interval"); 82 } 83 84 reports.emplace_back( 85 reportFactory->make(yield, reportName, reportingType, 86 emitsReadingsUpdate, logToMetricReportsCollection, 87 interval, metricParams, *this, *reportStorage)); 88 return reports.back(); 89 } 90 91 void ReportManager::loadFromPersistent() 92 { 93 std::vector<interfaces::JsonStorage::FilePath> paths = 94 reportStorage->list(); 95 96 for (const auto& path : paths) 97 { 98 std::optional<nlohmann::json> data = reportStorage->load(path); 99 try 100 { 101 size_t version = data->at("Version").get<size_t>(); 102 if (version != Report::reportVersion) 103 { 104 throw std::logic_error("Invalid version"); 105 } 106 std::string& name = data->at("Name").get_ref<std::string&>(); 107 std::string& reportingType = 108 data->at("ReportingType").get_ref<std::string&>(); 109 bool emitsReadingsSignal = 110 data->at("EmitsReadingsUpdate").get<bool>(); 111 bool logToMetricReportsCollection = 112 data->at("LogToMetricReportsCollection").get<bool>(); 113 uint64_t interval = data->at("Interval").get<uint64_t>(); 114 ReadingParameters readingParameters; 115 for (auto& item : data->at("ReadingParameters")) 116 { 117 readingParameters.emplace_back( 118 LabeledReadingParameter::from_json(item)); 119 } 120 121 addReport(std::nullopt, name, reportingType, emitsReadingsSignal, 122 logToMetricReportsCollection, 123 std::chrono::milliseconds(interval), readingParameters); 124 } 125 catch (const std::exception& e) 126 { 127 phosphor::logging::log<phosphor::logging::level::ERR>( 128 "Failed to load report from storage", 129 phosphor::logging::entry( 130 "filename=", 131 static_cast<std::filesystem::path>(path).c_str()), 132 phosphor::logging::entry("msg=", e.what())); 133 reportStorage->remove(path); 134 } 135 } 136 } 137