artdaq_utilities  v1_04_11
MetricPlugin.hh
1 // MetricPlugin.hh: Metric Plugin Interface
2 // Author: Eric Flumerfelt
3 // Last Modified: 11/05/2014 (Created)
4 //
5 // Defines the interface that any ARTDAQ metric plugin must implement
6 
7 #ifndef __METRIC_INTERFACE__
8 #define __METRIC_INTERFACE__
9 
10 #include <chrono>
11 #include <string>
12 #include <unordered_map>
13 #include "fhiclcpp/ParameterSet.h"
14 #include "fhiclcpp/types/Atom.h"
15 # include "fhiclcpp/types/ConfigurationTable.h"
16 
17 #include "artdaq-utilities/Plugins/MetricData.hh"
18 #include "cetlib/compiler_macros.h"
19 #ifndef FALLTHROUGH
20 #define FALLTHROUGH while(0)
21 #endif
22 
23 namespace artdaq
24 {
30  {
31  public:
35  struct Config
36  {
38  fhicl::Atom<std::string> metricPluginType{ fhicl::Name{"metricPluginType"}, fhicl::Comment{"The name of the metric plugin to load (may have additional configuration parameters)"} };
40  fhicl::Atom<int> level{ fhicl::Name{"level"}, fhicl::Comment{"The verbosity level threshold for this plugin. Metrics with verbosity level greater than this will not be sent to the plugin"}, 0 };
42  fhicl::Atom<double> reporting_interval{ fhicl::Name{"reporting_interval"}, fhicl::Comment{"How often recorded metrics are sent to the underlying metric storage"}, 15.0 };
43  };
45  using Parameters = fhicl::WrappedTable<Config>;
46 
61  explicit MetricPlugin(fhicl::ParameterSet const& ps, std::string const& app_name) : pset(ps)
62  , app_name_(app_name)
63  , inhibit_(false)
64  {
65  runLevel_ = pset.get<int>("level", 0);
66  accumulationTime_ = pset.get<double>("reporting_interval", 15.0);
67  }
68 
72  virtual ~MetricPlugin() = default;
73 
75  //
76  // Interface Functions: These should be reimplemented in plugin classes!
77  //
79 
83  virtual std::string getLibName() const { return "ERROR"; }
84 
85  protected:
94  virtual void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) = 0;
95 
104  virtual void sendMetric_(const std::string& name, const int& value, const std::string& unit) = 0;
105 
114  virtual void sendMetric_(const std::string& name, const double& value, const std::string& unit) = 0;
115 
124  virtual void sendMetric_(const std::string& name, const float& value, const std::string& unit) = 0;
125 
134  virtual void sendMetric_(const std::string& name, const long unsigned int& value, const std::string& unit) = 0;
135 
141  virtual void startMetrics_() = 0;
142 
148  virtual void stopMetrics_() = 0;
149 
151  //
152  // Implementation Functions: These should be called from ARTDAQ code!
153  //
155  public:
160  void addMetricData(std::unique_ptr<MetricData> const& data)
161  {
162  if (data->Type == MetricType::StringMetric)
163  {
164  sendMetric_(data->Name, data->StringValue, data->Unit);
165  }
166  else
167  {
168  if (!metricRegistry_.count(data->Name))
169  {
170  metricRegistry_[data->Name] = *data;
171  }
172  metricData_[data->Name].push_back(*data);
173  //sendMetrics();
174  }
175  }
176 
185  void sendMetrics(bool forceSend = false,
186  std::chrono::steady_clock::time_point interval_end = std::chrono::steady_clock::now()) {
187  double ds;
188  float fs;
189  int is;
190  unsigned long us;
191  size_t count;
192 
193  for (auto metric : metricData_) {
194  auto *metricName = &metric.first;
195  count = 0;
196  if (readyToSend_(*metricName) || forceSend) {
197  if (metricData_[*metricName].size() == 0 && metricRegistry_.count(*metricName)) {
198  sendZero_(metricRegistry_[*metricName]);
199  } else if (metricData_[*metricName].size() > 0) {
200  auto metricMode = &metricData_[*metricName].back().Mode;
201  auto metricUnits = &metricData_[*metricName].back().Unit;
202  auto metricType = &metricData_[*metricName].back().Type;
203 
204  if (*metricMode == MetricMode::LastPoint) {
205  if (metricData_[*metricName].size() > 1) {
206  metricData_[*metricName].erase(metricData_[*metricName].begin(),
207  std::prev(metricData_[*metricName].end()));
208  }
209  sendMetric_(metricData_[*metricName].back());
210  } else {
211  switch (*metricType) {
213  ds = 0.0;
214  for (auto& mv : metricData_[*metricName]) {
215  ds += mv.DoubleValue;
216  count += mv.DataPointCount;
217  }
218  switch (*metricMode) {
219  case MetricMode::Average:
220  ds /= static_cast<double>(count);
221  break;
222  case MetricMode::Rate:
223  ds /= std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(
224  interval_end - interval_start_[*metricName])
225  .count();
226  break;
228  sendMetric_(*metricName + " - Rate",
229  ds / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(
230  interval_end - interval_start_[*metricName])
231  .count(),
232  *metricUnits + "/s");
233  break;
234  default:
235  break;
236  }
237  sendMetric_(*metricName, ds, *metricUnits);
238  } break;
240  fs = 0.0;
241  for (auto& mv : metricData_[*metricName]) {
242  fs += mv.FloatValue;
243  count += mv.DataPointCount;
244  }
245 
246  switch (*metricMode) {
247  case MetricMode::Average:
248  ds = fs / static_cast<double>(count);
249  sendMetric_(*metricName, ds, *metricUnits);
250  break;
251  case MetricMode::Rate:
252  ds = fs / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(
253  interval_end - interval_start_[*metricName])
254  .count();
255  sendMetric_(*metricName, ds, *metricUnits);
256  break;
258  sendMetric_(*metricName + " - Rate",
259  fs / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(
260  interval_end - interval_start_[*metricName])
261  .count(),
262  *metricUnits + "/s");
263  FALLTHROUGH;
265  default:
266  sendMetric_(*metricName, fs, *metricUnits);
267  break;
268  }
269  } break;
270  case MetricType::IntMetric: {
271  is = 0;
272  for (auto& mv : metricData_[*metricName]) {
273  is += mv.IntValue;
274  count += mv.DataPointCount;
275  }
276 
277  switch (*metricMode) {
278  case MetricMode::Average:
279  ds = is / static_cast<double>(count);
280  sendMetric_(*metricName, ds, *metricUnits);
281  break;
282  case MetricMode::Rate:
283  ds = is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(
284  interval_end - interval_start_[*metricName])
285  .count();
286  sendMetric_(*metricName, ds, *metricUnits);
287  break;
289  sendMetric_(*metricName + " - Rate",
290  is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(
291  interval_end - interval_start_[*metricName])
292  .count(),
293  *metricUnits + "/s");
294  FALLTHROUGH;
296  default:
297  sendMetric_(*metricName, is, *metricUnits);
298  break;
299  }
300  } break;
302  us = 0UL;
303  for (auto& mv : metricData_[*metricName]) {
304  us += mv.UnsignedValue;
305  count += mv.DataPointCount;
306  }
307 
308  switch (*metricMode) {
309  case MetricMode::Average:
310  ds = us / static_cast<double>(count);
311  sendMetric_(*metricName, ds, *metricUnits);
312  break;
313  case MetricMode::Rate:
314  ds = us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(
315  interval_end - interval_start_[*metricName])
316  .count();
317  sendMetric_(*metricName, ds, *metricUnits);
318  break;
320  sendMetric_(*metricName + " - Rate",
321  us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(
322  interval_end - interval_start_[*metricName])
323  .count(),
324  *metricUnits + "/s");
325  FALLTHROUGH;
327  default:
328  sendMetric_(*metricName, us, *metricUnits);
329  break;
330  }
331  } break;
332  default:
333  break;
334  }
335  metricData_[*metricName].clear();
336  }
337  }
338  interval_start_[*metricName] = interval_end;
339  }
340  }
341  }
342 
347 
352  void stopMetrics() {
353  inhibit_ = true;
354  sendMetrics(true);
355  for (auto metric : metricRegistry_) {
356  sendZero_(metric.second);
357  }
358  stopMetrics_();
359  inhibit_ = false;
360  }
361 
367  void setRunLevel(int level) { runLevel_ = level; }
368 
374  int getRunLevel() const { return runLevel_; }
375 
376  protected:
377  int runLevel_;
378  fhicl::ParameterSet pset;
381  std::string app_name_;
383  bool inhibit_;
384 
385  private:
386  std::unordered_map<std::string, std::list<MetricData>> metricData_;
387  std::unordered_map<std::string, MetricData> metricRegistry_;
388  std::unordered_map<std::string, std::chrono::steady_clock::time_point> lastSendTime_;
389  std::unordered_map<std::string, std::chrono::steady_clock::time_point> interval_start_;
390 
391  bool readyToSend_(std::string name) {
392  auto now = std::chrono::steady_clock::now();
393  if (std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(now - lastSendTime_[name]).count() >=
395  lastSendTime_[name] = now;
396  return true;
397  }
398 
399  return false;
400  }
401 
402  void sendZero_(MetricData data) {
403  switch (data.Type) {
405  sendMetric_(data.Name, static_cast<double>(0.0), data.Unit);
406  break;
408  sendMetric_(data.Name, static_cast<float>(0.0), data.Unit);
409  break;
411  sendMetric_(data.Name, static_cast<int>(0), data.Unit);
412  break;
414  sendMetric_(data.Name, static_cast<unsigned long>(0), data.Unit);
415  break;
416  default:
417  break;
418  }
419 
420  if (data.Mode == MetricMode::AccumulateAndRate) {
421  sendMetric_(data.Name + " - Rate", static_cast<double>(0.0), data.Unit + "/s");
422  }
423  }
424 
425  void sendMetric_(MetricData data) {
426  switch (data.Type) {
428  sendMetric_(data.Name, data.DoubleValue, data.Unit);
429  break;
431  sendMetric_(data.Name, data.FloatValue, data.Unit);
432  break;
434  sendMetric_(data.Name, data.IntValue, data.Unit);
435  break;
437  sendMetric_(data.Name, data.UnsignedValue, data.Unit);
438  break;
439  default:
440  break;
441  }
442  }
443  };
444  } //End namespace artdaq
445 
446 #endif //End ifndef __METRIC_INTERFACE__
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...
Definition: MetricPlugin.hh:29
void startMetrics()
Perform startup actions. Simply calls the virtual startMetrics_ function.
Report the average of all values. Use for rates to report accurate results.
fhicl::ParameterSet pset
The ParameterSet used to configure the MetricPlugin.
fhicl::Atom< std::string > metricPluginType
&quot;metricPluginType&quot;: The name of the metric plugin to load (may have additional configuration paramete...
Definition: MetricPlugin.hh:38
virtual void sendMetric_(const std::string &name, const std::string &value, const std::string &unit)=0
Send a metric to the underlying metric storage (file, Graphite, Ganglia, etc.)
std::string Unit
Units of the metric
Definition: MetricData.hh:97
Metric is a std::string (not in union)
std::string Name
Name of the metric
Definition: MetricData.hh:73
fhicl::Atom< double > reporting_interval
&quot;reporting_interval&quot; (Default: 15.0): The interval, in seconds, which the metric plugin will accumula...
Definition: MetricPlugin.hh:42
Reports the sum of all values, divided by the length of the time interval they were accumulated over...
MetricMode Mode
Accumulation mode of the metric
Definition: MetricData.hh:105
void stopMetrics()
Perform shutdown actions. Zeroes out all accumulators, and sends zeros for each metric. Calls stopMetrics_() for any plugin-defined shutdown actions.
fhicl::Atom< int > level
&quot;level&quot; (Default: 0): The verbosity level of the metric plugin. Higher number = fewer metrics sent to...
Definition: MetricPlugin.hh:40
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...
int getRunLevel() const
Get the threshold for sending metrics to the underlying storage.
MetricPlugin(fhicl::ParameterSet const &ps, std::string const &app_name)
MetricPlugin Constructor.
Definition: MetricPlugin.hh:61
virtual std::string getLibName() const
Return the name of the current MetricPlugin instance.
Definition: MetricPlugin.hh:83
virtual void stopMetrics_()=0
Perform any shutdown actions necessary for the metric plugin.
Sends both the Accumulate mode and Rate mode metric. (Rate mode metric will append &quot;/s&quot; to metric uni...
MetricType Type
Type of the metric
Definition: MetricData.hh:93
fhicl::WrappedTable< Config > Parameters
Used for ParameterSet validation (if desired)
Definition: MetricPlugin.hh:45
Report the sum of all values. Use for counters to report accurate results.
Small structure used to hold a metric data point before sending to the metric plugins ...
Definition: MetricData.hh:42
The Config struct defines the accepted configuration parameters for this class.
Definition: MetricPlugin.hh:35
Report only the last value recorded. Useful for event counters, run numbers, etc. ...
void addMetricData(std::unique_ptr< MetricData > const &data)
Send a metric value to the MetricPlugin.
virtual ~MetricPlugin()=default
Default virtual Desctructor.
void setRunLevel(int level)
Set the threshold for sending metrics to the underlying storage.
bool inhibit_
Whether to inhibit all metric sending.