7 #ifndef __PCPMMV_METRIC__
8 #define __PCPMMV_METRIC__ 1
10 #define TRACE_NAME "PCPMMVMetric"
13 #include "artdaq-utilities/Plugins/MetricMacros.hh"
14 #include "fhiclcpp/fwd.h"
17 #include <pcp/pmapi.h>
19 #include <pcp/mmv_stats.h>
37 std::unordered_map<std::string, int> registered_metric_types_;
38 std::vector<mmv_metric_t> registered_metrics_;
43 size_t initial_metric_collection_time_;
44 std::chrono::steady_clock::time_point metric_start_time_;
46 void copy_string(
char* dest,
size_t dstsize,
const std::string& src)
48 if (src.size() <= dstsize - 1)
50 dstsize = src.size() + 1;
52 memcpy(dest, src.c_str(), dstsize);
57 if (!registered_metrics_.empty())
59 mmv_stats_flags_t flags{};
60 TLOG(TLVL_INFO) <<
"Going to initialize mmv metric with name " << normalize_name_(app_name_) <<
", metric count " << registered_metrics_.size();
61 TLOG(TLVL_INFO) <<
"First metric name: " << registered_metrics_[0].name <<
", type " << registered_metrics_[0].type <<
", item " << registered_metrics_[0].item;
62 mmvAddr_ = mmv_stats_init(normalize_name_(app_name_).c_str(), domain_, flags, ®istered_metrics_[0], registered_metrics_.size(),
nullptr, 0);
68 if (mmvAddr_ !=
nullptr)
70 mmv_stats_stop(normalize_name_(app_name_).c_str(), mmvAddr_);
75 std::string normalize_name_(std::string name)
77 auto nameTemp(std::move(name));
79 auto pos = nameTemp.find(
'%');
80 while (pos != std::string::npos)
82 nameTemp = nameTemp.replace(pos, 1,
"Percent");
83 pos = nameTemp.find(
'%');
85 std::replace(nameTemp.begin(), nameTemp.end(),
' ',
'_');
87 if (nameTemp.size() > MMV_NAMEMAX - 1)
89 nameTemp = nameTemp.substr(0, MMV_NAMEMAX - 1);
96 auto dur = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - metric_start_time_).count();
97 TLOG(TLVL_INFO) <<
"Duration since start: " << dur <<
" seconds. (initial = " << initial_metric_collection_time_ <<
" seconds)";
102 return static_cast<size_t>(dur) > initial_metric_collection_time_;
105 pmUnits infer_units_(std::string unitString)
108 output.scaleCount = PM_COUNT_ONE;
109 output.scaleSpace = PM_SPACE_BYTE;
110 output.scaleTime = PM_TIME_SEC;
115 std::transform(unitString.begin(), unitString.end(), unitString.begin(), ::tolower);
116 std::string before = unitString;
119 if (
auto pos = unitString.find(
'/') != std::string::npos)
121 before = unitString.substr(0, static_cast<int>(pos) - 1);
122 after = unitString.substr(pos);
124 std::istringstream iss(before);
125 std::vector<std::string> before_tokens{std::istream_iterator<std::string>{iss},
126 std::istream_iterator<std::string>{}};
129 std::vector<std::string> after_tokens{std::istream_iterator<std::string>{iss},
130 std::istream_iterator<std::string>{}};
132 for (
const auto& token : before_tokens)
138 if (token ==
"s" || token.find(
"sec") == 0)
142 else if (token ==
"b" || token.find(
"byte") == 0)
152 for (
const auto& token : after_tokens)
158 if (token ==
"s" || token.find(
"sec") == 0)
162 else if (token ==
"b" || token.find(
"byte") == 0)
189 explicit PCPMMVMetric(fhicl::ParameterSet
const& pset, std::string
const& app_name)
190 : MetricPlugin(pset, app_name)
192 , domain_(pset.get<int>(
"pcp_domain_number", 0))
193 , initial_metric_collection_time_(pset.get<size_t>(
"seconds_before_init", 30))
196 ~
PCPMMVMetric()
override { MetricPlugin::stopMetrics(); }
212 void startMetrics_()
override { metric_start_time_ = std::chrono::steady_clock::now(); }
220 void sendMetric_(
const std::string& name,
const std::string& value,
const std::string& unit,
const std::chrono::system_clock::time_point&)
override
222 auto nname = normalize_name_(name);
223 if (registered_metric_types_.count(nname) == 0u)
225 TLOG(TLVL_INFO) <<
"Adding string metric named " << nname;
226 mmv_metric_t newMetric;
227 copy_string(newMetric.name, MMV_NAMEMAX, nname);
228 newMetric.item = registered_metrics_.size();
229 newMetric.type = MMV_TYPE_STRING;
230 newMetric.semantics = MMV_SEM_INSTANT;
231 newMetric.dimension = infer_units_(unit);
233 newMetric.helptext =
nullptr;
234 newMetric.shorttext =
nullptr;
236 registered_metrics_.push_back(newMetric);
237 registered_metric_types_[nname] = MMV_TYPE_STRING;
241 if (registered_metric_types_[nname] != MMV_TYPE_STRING)
243 TLOG(TLVL_ERROR) <<
"PCP-MMV Metric: Metric instance has wrong type! Expected " << registered_metric_types_[nname]
244 <<
", got std::string";
248 if ((mmvAddr_ ==
nullptr) && check_time_())
253 if (mmvAddr_ !=
nullptr)
255 auto base = mmv_lookup_value_desc(mmvAddr_, nname.c_str(),
nullptr);
257 if (val.size() > MMV_STRINGMAX - 1)
259 val = val.substr(0, MMV_STRINGMAX - 1);
262 mmv_set_string(mmvAddr_, base, value.c_str(), value.size());
272 void sendMetric_(
const std::string& name,
const int& value,
const std::string& unit,
const std::chrono::system_clock::time_point&)
override
274 auto nname = normalize_name_(name);
275 if (registered_metric_types_.count(nname) == 0u)
277 TLOG(TLVL_INFO) <<
"Adding int metric named " << nname;
278 mmv_metric_t newMetric;
279 copy_string(newMetric.name, MMV_NAMEMAX, nname);
280 newMetric.item = registered_metrics_.size();
281 newMetric.type = MMV_TYPE_I64;
282 newMetric.semantics = MMV_SEM_INSTANT;
283 newMetric.dimension = infer_units_(unit);
285 newMetric.helptext =
nullptr;
286 newMetric.shorttext =
nullptr;
288 registered_metrics_.push_back(newMetric);
289 registered_metric_types_[nname] = MMV_TYPE_I64;
293 if (registered_metric_types_[nname] != MMV_TYPE_I64)
295 TLOG(TLVL_ERROR) <<
"PCP-MMV Metric: Metric instance has wrong type! Expected " << registered_metric_types_[nname]
300 if ((mmvAddr_ ==
nullptr) && check_time_())
305 if (mmvAddr_ !=
nullptr)
307 auto base = mmv_lookup_value_desc(mmvAddr_, nname.c_str(),
nullptr);
308 mmv_set_value(mmvAddr_, base, value);
318 void sendMetric_(
const std::string& name,
const double& value,
const std::string& unit,
const std::chrono::system_clock::time_point&)
override
320 auto nname = normalize_name_(name);
321 if (registered_metric_types_.count(nname) == 0u)
323 TLOG(TLVL_INFO) <<
"Adding double metric named " << nname;
324 mmv_metric_t newMetric;
325 copy_string(newMetric.name, MMV_NAMEMAX, nname);
326 newMetric.item = registered_metrics_.size();
327 newMetric.type = MMV_TYPE_DOUBLE;
328 newMetric.semantics = MMV_SEM_INSTANT;
329 newMetric.dimension = infer_units_(unit);
331 newMetric.helptext =
nullptr;
332 newMetric.shorttext =
nullptr;
334 registered_metrics_.push_back(newMetric);
335 registered_metric_types_[nname] = MMV_TYPE_DOUBLE;
339 if (registered_metric_types_[nname] != MMV_TYPE_DOUBLE)
341 TLOG(TLVL_ERROR) <<
"PCP-MMV Metric: Metric instance has wrong type! Expected " << registered_metric_types_[nname]
346 if ((mmvAddr_ ==
nullptr) && check_time_())
351 if (mmvAddr_ !=
nullptr)
353 auto base = mmv_lookup_value_desc(mmvAddr_, nname.c_str(),
nullptr);
354 mmv_set_value(mmvAddr_, base, value);
364 void sendMetric_(
const std::string& name,
const float& value,
const std::string& unit,
const std::chrono::system_clock::time_point&)
override
366 auto nname = normalize_name_(name);
367 if (registered_metric_types_.count(nname) == 0u)
369 TLOG(TLVL_INFO) <<
"Adding float metric named " << nname;
370 mmv_metric_t newMetric;
371 copy_string(newMetric.name, MMV_NAMEMAX, nname);
372 newMetric.item = registered_metrics_.size();
373 newMetric.type = MMV_TYPE_FLOAT;
374 newMetric.semantics = MMV_SEM_INSTANT;
375 newMetric.dimension = infer_units_(unit);
377 newMetric.helptext =
nullptr;
378 newMetric.shorttext =
nullptr;
380 registered_metrics_.push_back(newMetric);
381 registered_metric_types_[nname] = MMV_TYPE_FLOAT;
385 if (registered_metric_types_[nname] != MMV_TYPE_FLOAT)
387 TLOG(TLVL_ERROR) <<
"PCP-MMV Metric: Metric instance has wrong type! Expected " << registered_metric_types_[nname]
392 if ((mmvAddr_ ==
nullptr) && check_time_())
397 if (mmvAddr_ !=
nullptr)
399 auto base = mmv_lookup_value_desc(mmvAddr_, nname.c_str(),
nullptr);
400 mmv_set_value(mmvAddr_, base, value);
410 void sendMetric_(
const std::string& name,
const uint64_t& value,
const std::string& unit,
const std::chrono::system_clock::time_point&)
override
412 auto nname = normalize_name_(name);
413 if (registered_metric_types_.count(nname) == 0u)
415 TLOG(TLVL_INFO) <<
"Adding unsigned metric named " << nname;
416 mmv_metric_t newMetric;
417 copy_string(newMetric.name, MMV_NAMEMAX, nname);
418 newMetric.item = registered_metrics_.size();
419 newMetric.type = MMV_TYPE_U64;
420 newMetric.semantics = MMV_SEM_INSTANT;
421 newMetric.dimension = infer_units_(unit);
423 newMetric.helptext =
nullptr;
424 newMetric.shorttext =
nullptr;
426 registered_metrics_.push_back(newMetric);
427 registered_metric_types_[nname] = MMV_TYPE_U64;
431 if (registered_metric_types_[nname] != MMV_TYPE_U64)
433 TLOG(TLVL_ERROR) <<
"PCP-MMV Metric: Metric instance has wrong type! Expected " << registered_metric_types_[nname]
434 <<
", got unsigned int";
438 if ((mmvAddr_ ==
nullptr) && check_time_())
443 if (mmvAddr_ !=
nullptr)
445 auto base = mmv_lookup_value_desc(mmvAddr_, nname.c_str(),
nullptr);
446 mmv_set_value(mmvAddr_, base, value);
454 #endif // End ifndef __PCPMMV_METRIC__
void sendMetric_(const std::string &name, const float &value, const std::string &unit, const std::chrono::system_clock::time_point &) override
Send a float metric to PCPMMV.
void sendMetric_(const std::string &name, const int &value, const std::string &unit, const std::chrono::system_clock::time_point &) override
Send a integer metric to PCPMMV.
PCPMMVMetric(fhicl::ParameterSet const &pset, std::string const &app_name)
Construct an instance of the PCPMMV metric.
std::string getLibName() const override
Gets the unique library name of this plugin.
void sendMetric_(const std::string &name, const std::string &value, const std::string &unit, const std::chrono::system_clock::time_point &) override
Send a string metric to PCPMMV.
void stopMetrics_() override
PCPMMV does not need any specific action on stop.
void startMetrics_() override
PCPMMV does not need any specific action on start.
void sendMetric_(const std::string &name, const uint64_t &value, const std::string &unit, const std::chrono::system_clock::time_point &) override
Send an unsigned long metric to PCPMMV.
An instance of the MetricPlugin class that sends metric data to PCPMMV.
void sendMetric_(const std::string &name, const double &value, const std::string &unit, const std::chrono::system_clock::time_point &) override
Send a double metric to PCPMMV.