7 #ifndef __METRIC_INTERFACE__
8 #define __METRIC_INTERFACE__
11 #pragma push_macro("TRACE_NAME")
13 #define TRACE_NAME "MetricPlugin"
14 #define TRACE_NAME_POP 1
16 #include "TRACE/trace.h"
18 #define METLOG(lvl) TLOG(lvl) << metric_name_ << ": "
19 #define METLOG_P(lvl) TLOG(lvl, "MetricPlugin") << metric_name_ << ": "
24 #include <unordered_map>
25 #include "fhiclcpp/ParameterSet.h"
26 #include "fhiclcpp/types/Atom.h"
27 #include "fhiclcpp/types/ConfigurationTable.h"
28 #include "fhiclcpp/types/Sequence.h"
30 #include "artdaq-utilities/Plugins/MetricData.hh"
31 #include "cetlib/compiler_macros.h"
33 #define FALLTHROUGH while (0)
50 fhicl::Atom<std::string>
metricPluginType{fhicl::Name{
"metricPluginType"}, fhicl::Comment{
"The name of the metric plugin to load (may have additional configuration parameters"}};
52 fhicl::Atom<size_t>
level{fhicl::Name{
"level"}, fhicl::Comment{
"The verbosity level threshold for this plugin. sendMetric calls with verbosity level greater than this will not be sent to the plugin. OPTIONAL"}, 0};
54 fhicl::Sequence<size_t>
metric_levels{fhicl::Name{
"metric_levels"}, fhicl::Comment{
"A list of levels that should be enabled for this plugin. OPTIONAL"}, std::vector<size_t>()};
56 fhicl::Atom<std::string>
level_string{fhicl::Name{
"level_string"}, fhicl::Comment{
"A string containing a comma-separated list of levels to enable. Ranges are supported. Example: \"1,2,4-10,11\" OPTIONAL"},
""};
58 fhicl::Atom<double>
reporting_interval{fhicl::Name{
"reporting_interval"}, fhicl::Comment{
"How often recorded metrics are sent to the underlying metric storage"}, 15.0};
60 fhicl::Atom<bool>
send_zeros{fhicl::Name{
"send_zeros"}, fhicl::Comment{
"Whether zeros should be sent to the metric back-end when metrics are not reported in an interval and during shutdown"},
true};
74 explicit MetricPlugin(fhicl::ParameterSet
const& ps, std::string
const& app_name, std::string
const& metric_name)
82 METLOG_P(TLVL_TRACE) <<
"MetricPlugin ctor start";
83 if (
pset.has_key(
"level"))
85 for (
size_t ii = 0; ii <=
pset.get<
size_t>(
"level"); ++ii)
90 if (
pset.has_key(
"metric_levels"))
92 auto levels =
pset.get<std::vector<size_t>>(
"metric_levels");
93 for (
auto& l : levels)
98 if (
pset.has_key(
"level_string"))
100 auto string =
pset.get<std::string>(
"level_string");
101 std::stringstream ss(
string);
103 while (std::getline(ss, token,
','))
105 auto it = token.find(
"-");
106 if (it == 0 || it == token.size() - 1)
continue;
108 if (it != std::string::npos)
110 auto minStr = token.substr(0, it);
111 auto maxStr = token.substr(it + 1);
112 auto min = std::stoi(minStr);
113 auto max = std::stoi(maxStr);
115 if (min > max) std::swap(min, max);
116 if (min > 63) min = 63;
117 if (max > 63) max = 63;
119 for (
int ii = min; ii <= max; ++ii)
126 auto level = std::stoi(token);
133 throw cet::exception(
"Configuration Error")
134 <<
"No levels were enabled for this plugin! Please specify at least one of the following Parameters: \"level\", \"metric_levels\", or \"level_string\"!";
165 virtual void sendMetric_(
const std::string& name,
const std::string& value,
const std::string& unit,
const std::chrono::system_clock::time_point& interval_end) = 0;
176 virtual void sendMetric_(
const std::string& name,
const int& value,
const std::string& unit,
const std::chrono::system_clock::time_point& interval_end) = 0;
187 virtual void sendMetric_(
const std::string& name,
const double& value,
const std::string& unit,
const std::chrono::system_clock::time_point& interval_end) = 0;
198 virtual void sendMetric_(
const std::string& name,
const float& value,
const std::string& unit,
const std::chrono::system_clock::time_point& interval_end) = 0;
209 virtual void sendMetric_(
const std::string& name,
const uint64_t& value,
const std::string& unit,
const std::chrono::system_clock::time_point& interval_end) = 0;
237 METLOG_P(22) <<
"Adding metric data for name " << data->Name;
240 sendMetric_(data->Name, data->StringValue, data->Unit, std::chrono::system_clock::now());
244 if (metricRegistry_.count(data->Name) == 0)
246 metricRegistry_[data->Name] = *data;
248 metricData_[data->Name].push_back(*data);
249 METLOG_P(22) <<
"Current list size: " << metricData_[data->Name].size();
263 std::chrono::steady_clock::time_point interval_end = std::chrono::steady_clock::now())
265 METLOG_P(23) <<
"sendMetrics called" << std::endl;
266 for (
auto& metric : metricData_)
268 if (readyToSend_(metric.first) || forceSend)
270 METLOG_P(24) <<
"Sending metric " << metric.first;
271 if (metric.second.empty() && metricRegistry_.count(metric.first))
273 METLOG_P(24) <<
"Sending zero";
274 sendZero_(metricRegistry_[metric.first]);
276 else if (!metric.second.empty())
278 METLOG_P(24) <<
"Aggregating " << metric.second.size() <<
" MetricData points";
280 if ((metric.second.front().Mode &
MetricMode::Persist) != MetricMode::None && metric.second.size() > 1)
282 TLOG(24) <<
"Metric is in Persist mode and multiple instances are present. Removing the first entry.";
283 metric.second.erase(metric.second.begin());
288 auto it = ++(metric.second.begin());
289 while (it != metric.second.end())
292 it = metric.second.erase(it);
295 std::bitset<32> modeSet(static_cast<uint32_t>(data.
Mode));
296 bool useSuffix =
true;
297 if (modeSet.count() <= 1 || (modeSet.count() <= 2 && (data.
Mode &
MetricMode::Persist) != MetricMode::None)) useSuffix =
false;
309 double average = 0.0;
327 sendMetric_(data.
Name + (useSuffix ?
" - Average" :
""), average, data.
Unit, to_system_clock(lastSendTime_[data.
Name]));
331 double duration = std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(
332 interval_end - interval_start_[metric.first])
338 rate = data.
Value.
d / duration;
341 rate = data.
Value.
f / duration;
344 rate = data.
Value.
i / duration;
347 rate = data.
Value.
u / duration;
352 sendMetric_(data.
Name + (useSuffix ?
" - Rate" :
""), rate, data.
Unit +
"/s", to_system_clock(lastSendTime_[data.
Name]));
365 METLOG_P(24) <<
"Clearing metric data list sz=" << metric.second.size();
366 metric.second.clear();
367 METLOG_P(24) <<
"Cleared metric data list sz=" << metricData_[metric.first].size();
371 TLOG(24) <<
"Metric is Persisted, leaving " << metricData_[metric.first].size() <<
" entries (should be 1)";
374 interval_start_[metric.first] = interval_end;
377 METLOG_P(23) <<
"sendMetrics done" << std::endl;
393 for (
auto const& metric : metricRegistry_)
395 sendZero_(metric.second);
408 if (level > 63) level = 63;
409 if (level < 0)
return true;
419 for (
auto& metric : metricData_)
421 if (!metric.second.empty())
423 METLOG_P(TLVL_TRACE) <<
"Metric " << metric.first <<
" has " << metric.second.size() <<
" pending MetricData instances" << std::endl;
446 std::unordered_map<std::string, std::list<MetricData>> metricData_;
447 std::unordered_map<std::string, MetricData> metricRegistry_;
448 std::unordered_map<std::string, std::chrono::steady_clock::time_point> lastSendTime_;
449 std::unordered_map<std::string, std::chrono::steady_clock::time_point> interval_start_;
451 std::chrono::system_clock::time_point to_system_clock(std::chrono::steady_clock::time_point
const& t)
453 auto pt = std::chrono::system_clock::now() + (t - std::chrono::steady_clock::now());
454 return std::chrono::system_clock::time_point(std::chrono::duration_cast<std::chrono::system_clock::duration>(pt.time_since_epoch()));
457 bool readyToSend_(std::string
const& name)
459 auto now = std::chrono::steady_clock::now();
460 if (std::chrono::duration_cast<std::chrono::duration<
double, std::ratio<1>>>(now - lastSendTime_[name]).count() >=
accumulationTime_)
462 lastSendTime_[name] = now;
469 void sendZero_(MetricData data)
473 std::bitset<32> modeSet(static_cast<uint32_t>(data.Mode));
474 bool useSuffix =
true;
475 if (modeSet.count() <= 1) useSuffix =
false;
477 MetricData::MetricDataValue zero;
498 sendMetric_(data.Name + (useSuffix ?
" - Last" :
""), zero, data.Unit, data.Type, std::chrono::system_clock::now());
502 sendMetric_(data.Name + (useSuffix ?
" - Total" :
""), zero, data.Unit, data.Type, std::chrono::system_clock::now());
506 sendMetric_(data.Name + (useSuffix ?
" - Average" :
""), 0.0, data.Unit, std::chrono::system_clock::now());
510 sendMetric_(data.Name + (useSuffix ?
" - Rate" :
""), 0.0, data.Unit +
"/s", std::chrono::system_clock::now());
514 sendMetric_(data.Name + (useSuffix ?
" - Min" :
""), zero, data.Unit, data.Type, std::chrono::system_clock::now());
518 sendMetric_(data.Name + (useSuffix ?
" - Max" :
""), zero, data.Unit, data.Type, std::chrono::system_clock::now());
523 void sendMetric_(std::string
const& name, MetricData::MetricDataValue data, std::string
const& unit,
MetricType type, std::chrono::system_clock::time_point
const& interval_end)
546 #ifdef TRACE_NAME_POP
547 #pragma pop_macro("TRACE_NAME")
548 #undef TRACE_NAME_POP
550 #endif //End ifndef __METRIC_INTERFACE__
bool IsLevelEnabled(int level)
Determine if the given level is enabled for this MetricPlugin instance.
virtual void startMetrics_()=0
Perform any start-up actions necessary for the metric plugin.
The MetricPlugin class defines the interface that MetricManager uses to send metric data to the vario...
void startMetrics()
Perform startup actions. Simply calls the virtual startMetrics_ function.
size_t DataPointCount
Number of data points accumulated in this MetricData
Report the sum of all values. Use for counters to report accurate results.
fhicl::ParameterSet pset
The ParameterSet used to configure the MetricPlugin.
fhicl::Atom< std::string > metricPluginType
The name of the metric plugin to load (may have additional configuration parameters.
std::string Unit
Units of the metric
float f
Value of the metric, if it is a MetricType::FloatMetric.
Metric is a std::string (not in union)
std::string Name
Name of the metric
std::string metric_name_
Name of this MetricPlugin instance.
fhicl::Atom< double > reporting_interval
"reporting_interval" (Default: 15.0): The interval, in seconds, which the metric plugin will accumula...
MetricPlugin(fhicl::ParameterSet const &ps, std::string const &app_name, std::string const &metric_name)
MetricPlugin Constructor.
MetricMode Mode
Accumulation mode of the metric
bool Add(MetricData other)
Add two MetricData instances together
MetricType
This enumeration is used to identify the type of the metric instance (which value should be extraced ...
MetricDataValue Max
Maximum recorded vaule of this MetricData.
void stopMetrics()
Perform shutdown actions. Zeroes out all accumulators, and sends zeros for each metric. Calls stopMetrics_() for any plugin-defined shutdown actions.
Reports the minimum value recorded.
std::string app_name_
Name of the application which is sending metrics to this plugin.
Metric is a long unsigned int.
void sendMetrics(bool forceSend=false, std::chrono::steady_clock::time_point interval_end=std::chrono::steady_clock::now())
For each known metric, determine whether the reporting interval has elapsed, and if so...
over. Use to create rates from counters.
Report only the last value recorded. Useful for event counters, run numbers, etc. ...
Repots the maximum value recorded.
std::bitset< 64 > level_mask_
Bitset indicating for each possible metric level, whether this plugin will receive those metrics...
bool metricsPending()
Determine if metrics are waiting to be sent.
virtual std::string getLibName() const
Return the name of the current MetricPlugin instance.
virtual void sendMetric_(const std::string &name, const std::string &value, const std::string &unit, const std::chrono::system_clock::time_point &interval_end)=0
Send a metric to the underlying metric storage (file, Graphite, Ganglia, etc.)
MetricDataValue Value
Accumulated value of this MetricData
virtual void stopMetrics_()=0
Perform any shutdown actions necessary for the metric plugin.
int i
Value of the metric, if it is a MetricType::IntMetric.
Keep previous metric value in memory.
MetricType Type
Type of the metric
fhicl::Atom< std::string > level_string
"level_string" (OPTIONAL): A string containing a comma-separated list of levels to enable...
fhicl::Atom< bool > send_zeros
"send_zeros" (Default: true): Whether zeros should be sent to the metric back-end when metrics are no...
fhicl::WrappedTable< Config > Parameters
Used for ParameterSet validation (if desired)
MetricDataValue Last
Last value of this MetricData.
fhicl::Atom< size_t > level
"level" (OPTIONAL): The verbosity level threshold for this plugin. sendMetric calls with verbosity le...
double accumulationTime_
The amount of time to average metric values; except for accumulate=false metrics, will be the interva...
Small structure used to hold a metric data point before sending to the metric plugins ...
The Config struct defines the accepted configuration parameters for this class.
uint64_t u
Value of the metric, if it is a MetricType::UnsignedMetric.
Report the average of all values. Use for rates to report accurate results.
MetricDataValue Min
Minimum recorded value of this MetricData.
fhicl::Sequence< size_t > metric_levels
"metric_levels" (OPTIONAL): A list of levels that should be enabled for this plugin.
void addMetricData(std::unique_ptr< MetricData > const &data)
Send a metric value to the MetricPlugin.
bool sendZeros_
Whether zeros should be sent to this metric backend when metric instances are missing or at the end o...
virtual ~MetricPlugin()=default
Default virtual Desctructor.
double d
Value of the metric, if it is a MetricType::DoubleMetric.
bool inhibit_
Flag to indicate that the MetricPlugin is being stopped, and any metric back-ends which do not have a...