artdaq_utilities  v1_04_07
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 
8 #ifndef __METRIC_INTERFACE__
9 #define __METRIC_INTERFACE__
10 
11 #include <string>
12 #include <chrono>
13 #include <unordered_map>
14 #include "fhiclcpp/ParameterSet.h"
15 #include "fhiclcpp/types/Atom.h"
16 #if MESSAGEFACILITY_HEX_VERSION >= 0x20103
17 # include "fhiclcpp/types/ConfigurationTable.h"
18 #endif
19 
20 #include "artdaq-utilities/Plugins/MetricData.hh"
21 #include "cetlib/compiler_macros.h"
22 #ifndef FALLTHROUGH
23 #define FALLTHROUGH while(0)
24 #endif
25 
26 namespace artdaq
27 {
33  {
34  public:
38  struct Config
39  {
41  fhicl::Atom<std::string> metricPluginType{ fhicl::Name{"metricPluginType"}, fhicl::Comment{"The name of the metric plugin to load (may have additional configuration parameters"} };
43  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 };
45  fhicl::Atom<double> reporting_interval{ fhicl::Name{"reporting_interval"}, fhicl::Comment{"How often recorded metrics are sent to the underlying metric storage"}, 15.0 };
46  };
47 #if MESSAGEFACILITY_HEX_VERSION >= 0x20103
48  using Parameters = fhicl::WrappedTable<Config>;
49 #endif
50 
65  explicit MetricPlugin(fhicl::ParameterSet const& ps, std::string const& app_name) : pset(ps)
66  , app_name_(app_name)
67  , inhibit_(false)
68  {
69  runLevel_ = pset.get<int>("level", 0);
70  accumulationTime_ = pset.get<double>("reporting_interval", 15.0);
71  }
72 
76  virtual ~MetricPlugin() = default;
77 
79  //
80  // Interface Functions: These should be reimplemented in plugin classes!
81  //
83 
87  virtual std::string getLibName() const { return "ERROR"; }
88  protected:
97  virtual void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) = 0;
98 
107  virtual void sendMetric_(const std::string& name, const int& value, const std::string& unit) = 0;
108 
117  virtual void sendMetric_(const std::string& name, const double& value, const std::string& unit) = 0;
118 
127  virtual void sendMetric_(const std::string& name, const float& value, const std::string& unit) = 0;
128 
137  virtual void sendMetric_(const std::string& name, const long unsigned int& value, const std::string& unit) = 0;
138 
144  virtual void startMetrics_() = 0;
145 
151  virtual void stopMetrics_() = 0;
152 
154  //
155  // Implementation Functions: These should be called from ARTDAQ code!
156  //
158  public:
164  {
165  if (data.Type == MetricType::StringMetric)
166  {
167  sendMetric_(data.Name, data.StringValue, data.Unit);
168  }
169  else
170  {
171  if (!metricRegistry_.count(data.Name))
172  {
173  metricRegistry_[data.Name] = data;
174  }
175  metricData_[data.Name].push_back(data);
176  //sendMetrics();
177  }
178  }
179 
185  void sendMetrics(bool forceSend = false, std::chrono::steady_clock::time_point interval_end = std::chrono::steady_clock::now())
186  {
187  for (auto metric : metricData_)
188  {
189  auto metricName = metric.first;
190  if (readyToSend_(metricName) || forceSend)
191  {
192  if (metricData_[metricName].size() == 0 && metricRegistry_.count(metricName))
193  {
194  sendZero_(metricRegistry_[metricName]);
195  }
196  else if (metricData_[metricName].size() > 0)
197  {
198  auto metricMode = metricData_[metricName].back().Mode;
199  auto metricUnits = metricData_[metricName].back().Unit;
200  auto metricType = metricData_[metricName].back().Type;
201 
202  if (metricMode == MetricMode::LastPoint)
203  {
204  if (metricData_[metricName].size() > 1)
205  {
206  metricData_[metricName].erase(metricData_[metricName].begin(), std::prev(metricData_[metricName].end()));
207  }
208  sendMetric_(metricData_[metricName].back());
209  }
210  else
211  {
212  switch (metricType)
213  {
215  {
216  auto ds = 0.0;
217  for (auto& mv : metricData_[metricName]) { ds += mv.DoubleValue; }
218  switch (metricMode)
219  {
220  case MetricMode::Average: ds /= static_cast<double>(metricData_[metricName].size()); break;
221  case MetricMode::Rate: ds /= std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(); break;
222  case MetricMode::AccumulateAndRate: sendMetric_(metricName + " - Rate", ds / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s"); break;
223  default:
224  break;
225  }
226  sendMetric_(metricName, ds, metricUnits);
227  }
228  break;
230  {
231  auto fs = 0.0;
232  double ds = 0.0;
233  for (auto& mv : metricData_[metricName]) { fs += mv.FloatValue; }
234 
235  switch (metricMode)
236  {
237  case MetricMode::Average:
238  ds = fs / static_cast<double>(metricData_[metricName].size());
239  sendMetric_(metricName, ds, metricUnits);
240  break;
241  case MetricMode::Rate:
242  ds = fs / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
243  sendMetric_(metricName, ds, metricUnits);
244  break;
246  sendMetric_(metricName + " - Rate", fs / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
247  FALLTHROUGH;
249  default:
250  sendMetric_(metricName, fs, metricUnits);
251  break;
252  }
253  }
254  break;
256  {
257  auto is = 0;
258  double ds = 0.0;
259  for (auto& mv : metricData_[metricName]) { is += mv.IntValue; }
260 
261  switch (metricMode)
262  {
263  case MetricMode::Average:
264  ds = is / static_cast<double>(metricData_[metricName].size());
265  sendMetric_(metricName, ds, metricUnits);
266  break;
267  case MetricMode::Rate:
268  ds = is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
269  sendMetric_(metricName, ds, metricUnits);
270  break;
272  sendMetric_(metricName + " - Rate", is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
273  FALLTHROUGH;
275  default:
276  sendMetric_(metricName, is, metricUnits);
277  break;
278  }
279  }
280  break;
282  {
283  auto us = 0UL;
284  double ds = 0.0;
285  for (auto& mv : metricData_[metricName]) { us += mv.UnsignedValue; }
286 
287  switch (metricMode)
288  {
289  case MetricMode::Average:
290  ds = us / static_cast<double>(metricData_[metricName].size());
291  sendMetric_(metricName, ds, metricUnits);
292  break;
293  case MetricMode::Rate:
294  ds = us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
295  sendMetric_(metricName, ds, metricUnits);
296  break;
298  sendMetric_(metricName + " - Rate", us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
299  FALLTHROUGH;
301  default:
302  sendMetric_(metricName, us, metricUnits);
303  break;
304  }
305  }
306  break;
307  default:
308  break;
309  }
310  metricData_[metricName].clear();
311  }
312  }
313  interval_start_[metricName] = interval_end;
314  }
315  }
316  }
317 
322 
327  void stopMetrics()
328  {
329  inhibit_ = true;
330  sendMetrics(true);
331  for (auto metric : metricRegistry_)
332  {
333  sendZero_(metric.second);
334  }
335  stopMetrics_();
336  inhibit_ = false;
337  }
338 
343  void setRunLevel(int level) { runLevel_ = level; }
348  int getRunLevel() const { return runLevel_; }
349 
350  protected:
351  int runLevel_;
352  fhicl::ParameterSet pset;
354  std::string app_name_;
355  bool inhibit_;
356 
357  private:
358  std::unordered_map<std::string, std::list<MetricData>> metricData_;
359  std::unordered_map<std::string, MetricData> metricRegistry_;
360  std::unordered_map<std::string, std::chrono::steady_clock::time_point> lastSendTime_;
361  std::unordered_map<std::string, std::chrono::steady_clock::time_point> interval_start_;
362 
363  bool readyToSend_(std::string name)
364  {
365  auto now = std::chrono::steady_clock::now();
366  if (std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(now - lastSendTime_[name]).count() >= accumulationTime_)
367  {
368  lastSendTime_[name] = now;
369  return true;
370  }
371 
372  return false;
373  }
374 
375  void sendZero_(MetricData data)
376  {
377  switch (data.Type)
378  {
380  sendMetric_(data.Name, static_cast<double>(0.0), data.Unit);
381  break;
383  sendMetric_(data.Name, static_cast<float>(0.0), data.Unit);
384  break;
386  sendMetric_(data.Name, static_cast<int>(0), data.Unit);
387  break;
389  sendMetric_(data.Name, static_cast<unsigned long>(0), data.Unit);
390  break;
391  default:
392  break;
393  }
394 
396  {
397  sendMetric_(data.Name + " - Rate", static_cast<double>(0.0), data.Unit + "/s");
398  }
399  }
400 
401  void sendMetric_(MetricData data)
402  {
403  switch (data.Type)
404  {
406  sendMetric_(data.Name, data.DoubleValue, data.Unit);
407  break;
409  sendMetric_(data.Name, data.FloatValue, data.Unit);
410  break;
412  sendMetric_(data.Name, data.IntValue, data.Unit);
413  break;
415  sendMetric_(data.Name, data.UnsignedValue, data.Unit);
416  break;
417  default:
418  break;
419  }
420  }
421  };
422  } //End namespace artdaq
423 
424 #endif //End ifndef __METRIC_INTERFACE__
virtual void startMetrics_()=0
Perform any start-up actions necessary for the metric plugin.
std::string StringValue
Value of the metric, if it is a MetricType::StringMetric
Definition: MetricData.hh:77
The MetricPlugin class defines the interface that MetricManager uses to send metric data to the vario...
Definition: MetricPlugin.hh:32
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
The name of the metric plugin to load (may have additional configuration parameters.
Definition: MetricPlugin.hh:41
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:45
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 addMetricData(MetricData data)
Send a metric value to the MetricPlugin.
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:43
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:65
virtual std::string getLibName() const
Return the name of the current MetricPlugin instance.
Definition: MetricPlugin.hh:87
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
Report the sum of all values. Use for counters to report accurate results.
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 ...
Definition: MetricData.hh:42
The Config struct defines the accepted configuration parameters for this class.
Definition: MetricPlugin.hh:38
Report only the last value recorded. Useful for event counters, run numbers, etc. ...
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.
int runLevel_
The threshold for sending metrics to the underlying storage. Metrics with level &lt;= to runLevel_ will ...