Review fixes for 'Created metric class'
- Changed metric to_json to dumpConfiguration returning LabeledTuple
- LabeledTuple can be created and assigned directly to json
- LabeledTuple can be readed from json using json.get<LabeledTuple>
- Added PrintTo for LabeledMetricParams, LabeledSensorParams
- Added helper method expectMake to ReportFactoryMock
- sensorPaths are serialized to tuple<service, path> instead of single
field with service and path separated via ':'
- Changed configuration version from 1 to 2
Change-Id: I7c45fb584687172f88fd549a93329264793b0b8e
Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
diff --git a/src/interfaces/metric.hpp b/src/interfaces/metric.hpp
index d63c979..5a960a4 100644
--- a/src/interfaces/metric.hpp
+++ b/src/interfaces/metric.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include "interfaces/types.hpp"
#include "metric_value.hpp"
#include <nlohmann/json.hpp>
@@ -16,7 +17,7 @@
virtual void initialize() = 0;
virtual const std::vector<MetricValue>& getReadings() const = 0;
- virtual nlohmann::json to_json() const = 0;
+ virtual LabeledMetricParameters dumpConfiguration() const = 0;
};
} // namespace interfaces
diff --git a/src/interfaces/report_factory.hpp b/src/interfaces/report_factory.hpp
index 056c9e0..237ae7b 100644
--- a/src/interfaces/report_factory.hpp
+++ b/src/interfaces/report_factory.hpp
@@ -20,11 +20,17 @@
virtual ~ReportFactory() = default;
virtual std::unique_ptr<interfaces::Report> make(
- std::optional<std::reference_wrapper<boost::asio::yield_context>> yield,
+ boost::asio::yield_context& yield, const std::string& name,
+ const std::string& reportingType, bool emitsReadingsSignal,
+ bool logToMetricReportsCollection, std::chrono::milliseconds period,
+ const ReadingParameters& metricParams, ReportManager& reportManager,
+ JsonStorage& reportStorage) const = 0;
+ virtual std::unique_ptr<interfaces::Report> make(
const std::string& name, const std::string& reportingType,
bool emitsReadingsSignal, bool logToMetricReportsCollection,
std::chrono::milliseconds period, const ReadingParameters& metricParams,
- ReportManager& reportManager, JsonStorage& reportStorage) const = 0;
+ ReportManager& reportManager, JsonStorage& reportStorage,
+ std::vector<LabeledMetricParameters> labeledMetricParams) const = 0;
};
} // namespace interfaces
diff --git a/src/interfaces/types.hpp b/src/interfaces/types.hpp
index 1eca51a..de97353 100644
--- a/src/interfaces/types.hpp
+++ b/src/interfaces/types.hpp
@@ -13,8 +13,13 @@
std::vector<std::tuple<std::vector<sdbusplus::message::object_path>,
std::string, std::string, std::string>>;
-using LabeledReadingParameter =
- utils::LabeledTuple<ReadingParameters::value_type,
+using LabeledSensorParameters =
+ utils::LabeledTuple<std::tuple<std::string, std::string>,
+ utils::tstring::Service, utils::tstring::Path>;
+
+using LabeledMetricParameters =
+ utils::LabeledTuple<std::tuple<std::vector<LabeledSensorParameters>,
+ std::string, std::string, std::string>,
utils::tstring::SensorPaths,
utils::tstring::OperationType, utils::tstring::Id,
utils::tstring::MetricMetadata>;
diff --git a/src/metric.cpp b/src/metric.cpp
index 8d9f19b..b12f3a6 100644
--- a/src/metric.cpp
+++ b/src/metric.cpp
@@ -52,13 +52,11 @@
return readings.at(index);
}
-nlohmann::json Metric::to_json() const
+LabeledMetricParameters Metric::dumpConfiguration() const
{
- auto sensorPaths = utils::transform(
- sensors, [](const auto& sensor) -> sdbusplus::message::object_path {
- return sdbusplus::message::object_path(sensor->id().service + ":" +
- sensor->id().path);
- });
- return LabeledReadingParameter::to_json(ReadingParameters::value_type(
- std::move(sensorPaths), operationType, id, metadata));
+ auto sensorPaths = utils::transform(sensors, [](const auto& sensor) {
+ return LabeledSensorParameters(sensor->id().service, sensor->id().path);
+ });
+ return LabeledMetricParameters(std::move(sensorPaths), operationType, id,
+ metadata);
}
diff --git a/src/metric.hpp b/src/metric.hpp
index 6e27446..39f525c 100644
--- a/src/metric.hpp
+++ b/src/metric.hpp
@@ -17,7 +17,7 @@
const std::vector<MetricValue>& getReadings() const override;
void sensorUpdated(interfaces::Sensor&, uint64_t) override;
void sensorUpdated(interfaces::Sensor&, uint64_t, double value) override;
- nlohmann::json to_json() const override;
+ LabeledMetricParameters dumpConfiguration() const override;
private:
MetricValue& findMetric(interfaces::Sensor&);
diff --git a/src/report.cpp b/src/report.cpp
index 4d91787..dc8f37b 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -28,11 +28,6 @@
fileName(std::to_string(std::hash<std::string>{}(name))),
reportStorage(reportStorageIn)
{
- for (auto& metric : this->metrics)
- {
- metric->initialize();
- }
-
deleteIface = objServer->add_unique_interface(
path, deleteIfaceName, [this, &ioc, &reportManager](auto& dbusIface) {
dbusIface.register_method("Delete", [this, &ioc, &reportManager] {
@@ -121,6 +116,11 @@
{
scheduleTimer(interval);
}
+
+ for (auto& metric : this->metrics)
+ {
+ metric->initialize();
+ }
}
void Report::timerProc(boost::system::error_code ec, Report& self)
@@ -179,8 +179,10 @@
data["EmitsReadingsUpdate"] = emitsReadingsUpdate;
data["LogToMetricReportsCollection"] = logToMetricReportsCollection;
data["Interval"] = interval.count();
- data["ReadingParameters"] = utils::transform(
- metrics, [](const auto& metric) { return metric->to_json(); });
+ data["ReadingParameters"] =
+ utils::transform(metrics, [](const auto& metric) {
+ return metric->dumpConfiguration();
+ });
reportStorage.store(fileName, data);
}
diff --git a/src/report.hpp b/src/report.hpp
index b227392..c58d38b 100644
--- a/src/report.hpp
+++ b/src/report.hpp
@@ -75,5 +75,5 @@
"/xyz/openbmc_project/Telemetry/Reports/";
static constexpr const char* deleteIfaceName =
"xyz.openbmc_project.Object.Delete";
- static constexpr size_t reportVersion = 1;
+ static constexpr size_t reportVersion = 2;
};
diff --git a/src/report_factory.cpp b/src/report_factory.cpp
index e4689aa..b8b5518 100644
--- a/src/report_factory.cpp
+++ b/src/report_factory.cpp
@@ -13,31 +13,35 @@
{}
std::unique_ptr<interfaces::Report> ReportFactory::make(
- std::optional<std::reference_wrapper<boost::asio::yield_context>> yield,
+ boost::asio::yield_context& yield, const std::string& name,
+ const std::string& reportingType, bool emitsReadingsSignal,
+ bool logToMetricReportsCollection, std::chrono::milliseconds period,
+ const ReadingParameters& metricParams,
+ interfaces::ReportManager& reportManager,
+ interfaces::JsonStorage& reportStorage) const
+{
+ return make(name, reportingType, emitsReadingsSignal,
+ logToMetricReportsCollection, period, metricParams,
+ reportManager, reportStorage,
+ convertMetricParams(yield, metricParams));
+}
+
+std::unique_ptr<interfaces::Report> ReportFactory::make(
const std::string& name, const std::string& reportingType,
bool emitsReadingsSignal, bool logToMetricReportsCollection,
std::chrono::milliseconds period, const ReadingParameters& metricParams,
interfaces::ReportManager& reportManager,
- interfaces::JsonStorage& reportStorage) const
+ interfaces::JsonStorage& reportStorage,
+ std::vector<LabeledMetricParameters> labeledMetricParams) const
{
- std::optional<std::vector<ReportFactory::SensorTree>> sensorTree;
-
- std::vector<std::shared_ptr<interfaces::Metric>> metrics;
- metrics.reserve(metricParams.size());
-
- for (const auto& [sensorPaths, op, id, metadata] : metricParams)
- {
- if (!sensorTree && yield && sensorPaths.size() > 0)
- {
- sensorTree = getSensorTree(*yield);
- }
-
- std::vector<std::shared_ptr<interfaces::Sensor>> sensors =
- getSensors(sensorTree, sensorPaths);
-
- metrics.emplace_back(
- std::make_shared<Metric>(std::move(sensors), op, id, metadata));
- }
+ std::vector<std::shared_ptr<interfaces::Metric>> metrics = utils::transform(
+ labeledMetricParams,
+ [this](const LabeledMetricParameters& param)
+ -> std::shared_ptr<interfaces::Metric> {
+ return std::make_shared<Metric>(
+ getSensors(param.at_index<0>()), param.at_index<1>(),
+ param.at_index<2>(), param.at_index<3>());
+ });
return std::make_unique<Report>(
bus->get_io_context(), objServer, name, reportingType,
@@ -46,58 +50,57 @@
}
std::vector<std::shared_ptr<interfaces::Sensor>> ReportFactory::getSensors(
- const std::optional<std::vector<ReportFactory::SensorTree>>& tree,
- const std::vector<sdbusplus::message::object_path>& sensorPaths) const
+ const std::vector<LabeledSensorParameters>& sensorPaths) const
{
- if (tree)
- {
- std::vector<std::shared_ptr<interfaces::Sensor>> sensors;
+ return utils::transform(sensorPaths,
+ [this](const LabeledSensorParameters& param)
+ -> std::shared_ptr<interfaces::Sensor> {
+ using namespace utils::tstring;
- for (const auto& [sensor, ifacesMap] : *tree)
- {
- auto it = std::find(sensorPaths.begin(), sensorPaths.end(), sensor);
- if (it != sensorPaths.end())
- {
- for (const auto& [service, ifaces] : ifacesMap)
- {
- sensors.emplace_back(sensorCache.makeSensor<Sensor>(
- service, sensor, bus->get_io_context(), bus));
- }
- }
- }
-
- return sensors;
- }
- else
- {
- return utils::transform(
- sensorPaths,
- [this](const std::string& sensor)
- -> std::shared_ptr<interfaces::Sensor> {
- std::string::size_type pos = sensor.find_first_of(":");
- auto service = sensor.substr(0, pos);
- auto path = sensor.substr(pos + 1);
- return sensorCache.makeSensor<Sensor>(
- service, path, bus->get_io_context(), bus);
- });
- }
+ return sensorCache.makeSensor<Sensor>(
+ param.at_label<Service>(),
+ param.at_label<Path>(),
+ bus->get_io_context(), bus);
+ });
}
-std::vector<ReportFactory::SensorTree>
- ReportFactory::getSensorTree(boost::asio::yield_context& yield) const
+std::vector<LabeledMetricParameters> ReportFactory::convertMetricParams(
+ boost::asio::yield_context& yield,
+ const ReadingParameters& metricParams) const
{
std::array<const char*, 1> interfaces = {
"xyz.openbmc_project.Sensor.Value"};
boost::system::error_code ec;
- auto result = bus->yield_method_call<std::vector<SensorTree>>(
+ auto tree = bus->yield_method_call<std::vector<SensorTree>>(
yield, ec, "xyz.openbmc_project.ObjectMapper",
"/xyz/openbmc_project/object_mapper",
"xyz.openbmc_project.ObjectMapper", "GetSubTree",
"/xyz/openbmc_project/sensors", 2, interfaces);
if (ec)
{
- throw std::runtime_error("failed");
+ throw std::runtime_error("Failed to query ObjectMapper!");
}
- return result;
+
+ return utils::transform(metricParams, [&tree](const auto& item) {
+ std::vector<LabeledSensorParameters> sensors;
+
+ for (const auto& sensorPath : std::get<0>(item))
+ {
+ auto it = std::find_if(
+ tree.begin(), tree.end(),
+ [&sensorPath](const auto& v) { return v.first == sensorPath; });
+
+ if (it != tree.end())
+ {
+ for (const auto& [service, ifaces] : it->second)
+ {
+ sensors.emplace_back(service, sensorPath);
+ }
+ }
+ }
+
+ return LabeledMetricParameters(std::move(sensors), std::get<1>(item),
+ std::get<2>(item), std::get<3>(item));
+ });
}
diff --git a/src/report_factory.hpp b/src/report_factory.hpp
index 0346441..de2bc02 100644
--- a/src/report_factory.hpp
+++ b/src/report_factory.hpp
@@ -14,13 +14,23 @@
std::shared_ptr<sdbusplus::asio::connection> bus,
const std::shared_ptr<sdbusplus::asio::object_server>& objServer);
- std::unique_ptr<interfaces::Report> make(
- std::optional<std::reference_wrapper<boost::asio::yield_context>> yield,
- const std::string& name, const std::string& reportingType,
- bool emitsReadingsSignal, bool logToMetricReportsCollection,
- std::chrono::milliseconds period, const ReadingParameters& metricParams,
- interfaces::ReportManager& reportManager,
- interfaces::JsonStorage& reportStorage) const override;
+ std::unique_ptr<interfaces::Report>
+ make(boost::asio::yield_context& yield, const std::string& name,
+ const std::string& reportingType, bool emitsReadingsSignal,
+ bool logToMetricReportsCollection,
+ std::chrono::milliseconds period,
+ const ReadingParameters& metricParams,
+ interfaces::ReportManager& reportManager,
+ interfaces::JsonStorage& reportStorage) const override;
+ std::unique_ptr<interfaces::Report>
+ make(const std::string& name, const std::string& reportingType,
+ bool emitsReadingsSignal, bool logToMetricReportsCollection,
+ std::chrono::milliseconds period,
+ const ReadingParameters& metricParams,
+ interfaces::ReportManager& reportManager,
+ interfaces::JsonStorage& reportStorage,
+ std::vector<LabeledMetricParameters> labeledMetricParams)
+ const override;
private:
using SensorPath = std::string;
@@ -30,10 +40,10 @@
using SensorTree = std::pair<SensorPath, SensorIfaces>;
std::vector<std::shared_ptr<interfaces::Sensor>> getSensors(
- const std::optional<std::vector<SensorTree>>& tree,
- const std::vector<sdbusplus::message::object_path>& sensorPaths) const;
- std::vector<SensorTree>
- getSensorTree(boost::asio::yield_context& yield) const;
+ const std::vector<LabeledSensorParameters>& sensorPaths) const;
+ std::vector<LabeledMetricParameters>
+ convertMetricParams(boost::asio::yield_context& yield,
+ const ReadingParameters& metricParams) const;
std::shared_ptr<sdbusplus::asio::connection> bus;
std::shared_ptr<sdbusplus::asio::object_server> objServer;
diff --git a/src/report_manager.cpp b/src/report_manager.cpp
index eb2d767..f9840d3 100644
--- a/src/report_manager.cpp
+++ b/src/report_manager.cpp
@@ -1,6 +1,8 @@
#include "report_manager.hpp"
+#include "interfaces/types.hpp"
#include "report.hpp"
+#include "utils/transform.hpp"
#include <phosphor-logging/log.hpp>
#include <sdbusplus/exception.hpp>
@@ -35,13 +37,13 @@
const bool emitsReadingsUpdate,
const bool logToMetricReportsCollection,
const uint64_t interval,
- const ReadingParameters& metricParams) {
+ ReadingParameters metricParams) {
return addReport(yield, reportName, reportingType,
emitsReadingsUpdate,
logToMetricReportsCollection,
std::chrono::milliseconds(interval),
- metricParams)
- ->getPath();
+ std::move(metricParams))
+ .getPath();
});
});
}
@@ -54,11 +56,8 @@
reports.end());
}
-std::unique_ptr<interfaces::Report>& ReportManager::addReport(
- std::optional<std::reference_wrapper<boost::asio::yield_context>> yield,
- const std::string& reportName, const std::string& reportingType,
- const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
- std::chrono::milliseconds interval, const ReadingParameters& metricParams)
+void ReportManager::verifyAddReport(const std::string& reportName,
+ std::chrono::milliseconds interval)
{
if (reports.size() >= maxReports)
{
@@ -81,12 +80,49 @@
throw sdbusplus::exception::SdBusError(
static_cast<int>(std::errc::invalid_argument), "Invalid interval");
}
+}
- reports.emplace_back(
- reportFactory->make(yield, reportName, reportingType,
- emitsReadingsUpdate, logToMetricReportsCollection,
- interval, metricParams, *this, *reportStorage));
- return reports.back();
+interfaces::Report& ReportManager::addReport(
+ boost::asio::yield_context& yield, const std::string& reportName,
+ const std::string& reportingType, const bool emitsReadingsUpdate,
+ const bool logToMetricReportsCollection, std::chrono::milliseconds interval,
+ ReadingParameters metricParams)
+{
+ verifyAddReport(reportName, interval);
+
+ reports.emplace_back(reportFactory->make(
+ yield, reportName, reportingType, emitsReadingsUpdate,
+ logToMetricReportsCollection, interval, std::move(metricParams), *this,
+ *reportStorage));
+ return *reports.back();
+}
+
+interfaces::Report& ReportManager::addReport(
+ const std::string& reportName, const std::string& reportingType,
+ const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
+ std::chrono::milliseconds interval,
+ std::vector<LabeledMetricParameters> labeledMetricParams)
+{
+ verifyAddReport(reportName, interval);
+
+ auto metricParams = utils::transform(
+ labeledMetricParams, [](const LabeledMetricParameters& param) {
+ using namespace utils::tstring;
+
+ return ReadingParameters::value_type(
+ utils::transform(param.at_index<0>(),
+ [](const LabeledSensorParameters& p) {
+ return sdbusplus::message::object_path(
+ p.at_label<Path>());
+ }),
+ param.at_index<1>(), param.at_index<2>(), param.at_index<3>());
+ });
+
+ reports.emplace_back(reportFactory->make(
+ reportName, reportingType, emitsReadingsUpdate,
+ logToMetricReportsCollection, interval, std::move(metricParams), *this,
+ *reportStorage, labeledMetricParams));
+ return *reports.back();
}
void ReportManager::loadFromPersistent()
@@ -112,16 +148,14 @@
bool logToMetricReportsCollection =
data->at("LogToMetricReportsCollection").get<bool>();
uint64_t interval = data->at("Interval").get<uint64_t>();
- ReadingParameters readingParameters;
- for (auto& item : data->at("ReadingParameters"))
- {
- readingParameters.emplace_back(
- LabeledReadingParameter::from_json(item));
- }
+ auto readingParameters =
+ data->at("ReadingParameters")
+ .get<std::vector<LabeledMetricParameters>>();
- addReport(std::nullopt, name, reportingType, emitsReadingsSignal,
+ addReport(name, reportingType, emitsReadingsSignal,
logToMetricReportsCollection,
- std::chrono::milliseconds(interval), readingParameters);
+ std::chrono::milliseconds(interval),
+ std::move(readingParameters));
}
catch (const std::exception& e)
{
diff --git a/src/report_manager.hpp b/src/report_manager.hpp
index a26b59e..0e37144 100644
--- a/src/report_manager.hpp
+++ b/src/report_manager.hpp
@@ -35,12 +35,20 @@
std::unique_ptr<sdbusplus::asio::dbus_interface> reportManagerIface;
std::vector<std::unique_ptr<interfaces::Report>> reports;
- std::unique_ptr<interfaces::Report>& addReport(
- std::optional<std::reference_wrapper<boost::asio::yield_context>> yield,
+ void verifyAddReport(const std::string& reportName,
+ std::chrono::milliseconds interval);
+ interfaces::Report& addReport(boost::asio::yield_context& yield,
+ const std::string& reportName,
+ const std::string& reportingType,
+ const bool emitsReadingsUpdate,
+ const bool logToMetricReportsCollection,
+ std::chrono::milliseconds interval,
+ ReadingParameters metricParams);
+ interfaces::Report& addReport(
const std::string& reportName, const std::string& reportingType,
const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
std::chrono::milliseconds interval,
- const ReadingParameters& metricParams);
+ std::vector<LabeledMetricParameters> metricParams);
void loadFromPersistent();
public:
diff --git a/src/sensor.cpp b/src/sensor.cpp
index c4973cd..8a6f673 100644
--- a/src/sensor.cpp
+++ b/src/sensor.cpp
@@ -53,6 +53,11 @@
void Sensor::registerForUpdates(
const std::weak_ptr<interfaces::SensorListener>& weakListener)
{
+ listeners.erase(
+ std::remove_if(listeners.begin(), listeners.end(),
+ [](const auto& listener) { return listener.expired(); }),
+ listeners.end());
+
if (auto listener = weakListener.lock())
{
listeners.emplace_back(weakListener);
diff --git a/src/utils/labeled_tuple.hpp b/src/utils/labeled_tuple.hpp
index 7e75322..795f37f 100644
--- a/src/utils/labeled_tuple.hpp
+++ b/src/utils/labeled_tuple.hpp
@@ -53,54 +53,93 @@
template <class... Args, class... Labels>
struct LabeledTuple<std::tuple<Args...>, Labels...>
{
- LabeledTuple() = delete;
-
static_assert(sizeof...(Args) == sizeof...(Labels));
- static nlohmann::json to_json(const std::tuple<Args...>& tuple)
+ using tuple_type = std::tuple<Args...>;
+
+ LabeledTuple() = default;
+ LabeledTuple(const LabeledTuple&) = default;
+ LabeledTuple(LabeledTuple&&) = default;
+
+ LabeledTuple(tuple_type v) : value(std::move(v))
+ {}
+ LabeledTuple(Args... args) : value(std::move(args)...)
+ {}
+
+ LabeledTuple& operator=(const LabeledTuple&) = default;
+ LabeledTuple& operator=(LabeledTuple&&) = default;
+
+ nlohmann::json to_json() const
{
nlohmann::json j;
- to_json_all(j, tuple, std::make_index_sequence<sizeof...(Args)>());
+ to_json_all(j, std::make_index_sequence<sizeof...(Args)>());
return j;
}
- static std::tuple<Args...> from_json(const nlohmann::json& j)
+ void from_json(const nlohmann::json& j)
{
- std::tuple<Args...> value;
- from_json_all(j, value, std::make_index_sequence<sizeof...(Args)>());
- return value;
+ from_json_all(j, std::make_index_sequence<sizeof...(Args)>());
+ }
+
+ template <size_t Idx>
+ const auto& at_index() const
+ {
+ return std::get<Idx>(value);
+ }
+
+ template <size_t Idx>
+ auto& at_index()
+ {
+ return std::get<Idx>(value);
+ }
+
+ template <class Label>
+ const auto& at_label() const
+ {
+ return find_item<0, Label>(*this);
+ }
+
+ template <class Label>
+ auto& at_label()
+ {
+ return find_item<0, Label>(*this);
+ }
+
+ bool operator==(const LabeledTuple& other) const
+ {
+ return value == other.value;
+ }
+
+ bool operator<(const LabeledTuple& other) const
+ {
+ return value < other.value;
}
private:
template <size_t... Idx>
- static void to_json_all(nlohmann::json& j, const std::tuple<Args...>& tuple,
- std::index_sequence<Idx...>)
+ void to_json_all(nlohmann::json& j, std::index_sequence<Idx...>) const
{
- (to_json_item<Idx>(j, tuple), ...);
+ (to_json_item<Idx>(j), ...);
}
template <size_t Idx>
- static void to_json_item(nlohmann::json& j,
- const std::tuple<Args...>& tuple)
+ void to_json_item(nlohmann::json& j) const
{
using Label = std::tuple_element_t<Idx, std::tuple<Labels...>>;
- j[Label::str()] = std::get<Idx>(tuple);
+ j[Label::str()] = std::get<Idx>(value);
}
template <size_t... Idx>
- static void from_json_all(const nlohmann::json& j,
- std::tuple<Args...>& value,
- std::index_sequence<Idx...>)
+ void from_json_all(const nlohmann::json& j, std::index_sequence<Idx...>)
{
- (from_json_item<Idx>(j, value), ...);
+ (from_json_item<Idx>(j), ...);
}
template <size_t Idx>
- static void from_json_item(const nlohmann::json& j,
- std::tuple<Args...>& value)
+ void from_json_item(const nlohmann::json& j)
{
using Label = std::tuple_element_t<Idx, std::tuple<Labels...>>;
- using T = std::tuple_element_t<Idx, std::tuple<Args...>>;
+ using T = std::tuple_element_t<Idx, tuple_type>;
const nlohmann::json& item = j.at(Label::str());
if constexpr (detail::has_utils_from_json_v<T>)
{
@@ -112,6 +151,36 @@
std::get<Idx>(value) = item.get<T>();
}
}
+
+ template <size_t Idx, class Label, class Self>
+ static auto& find_item(Self& self)
+ {
+ if constexpr (std::is_same_v<Label, std::tuple_element_t<
+ Idx, std::tuple<Labels...>>>)
+ {
+ return std::get<Idx>(self.value);
+ }
+ else
+ {
+ return find_item<Idx + 1, Label>(self);
+ }
+ }
+
+ tuple_type value;
};
+template <class... Args, class... Labels>
+void to_json(nlohmann::json& json,
+ const LabeledTuple<std::tuple<Args...>, Labels...>& tuple)
+{
+ json = tuple.to_json();
+}
+
+template <class... Args, class... Labels>
+void from_json(const nlohmann::json& json,
+ LabeledTuple<std::tuple<Args...>, Labels...>& tuple)
+{
+ tuple.from_json(json);
+}
+
} // namespace utils
diff --git a/src/utils/tstring.hpp b/src/utils/tstring.hpp
index 7fcddb3..f0a401f 100644
--- a/src/utils/tstring.hpp
+++ b/src/utils/tstring.hpp
@@ -5,32 +5,56 @@
namespace utils
{
-namespace literals
-{
-
-constexpr char id[] = "id";
-constexpr char sensorPaths[] = "sensorPaths";
-constexpr char operationType[] = "operationType";
-constexpr char metricMetadata[] = "metricMetadata";
-
-} // namespace literals
-
-template <const char* const V>
-struct Label
-{
- static std::string str()
- {
- return V;
- }
-};
-
namespace tstring
{
-using Id = utils::Label<utils::literals::id>;
-using SensorPaths = utils::Label<utils::literals::sensorPaths>;
-using OperationType = utils::Label<utils::literals::operationType>;
-using MetricMetadata = utils::Label<utils::literals::metricMetadata>;
+struct Id
+{
+ static std::string str()
+ {
+ return "id";
+ }
+};
+
+struct SensorPaths
+{
+ static std::string str()
+ {
+ return "sensorPaths";
+ }
+};
+
+struct OperationType
+{
+ static std::string str()
+ {
+ return "operationType";
+ }
+};
+
+struct MetricMetadata
+{
+ static std::string str()
+ {
+ return "metricMetadata";
+ }
+};
+
+struct Service
+{
+ static std::string str()
+ {
+ return "service";
+ }
+};
+
+struct Path
+{
+ static std::string str()
+ {
+ return "path";
+ }
+};
} // namespace tstring
} // namespace utils