artdaq_utilities  v1_04_06
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:
35  struct Config
36  {
37  fhicl::Atom<std::string> metricPluginType{ fhicl::Name{"metricPluginType"}, fhicl::Comment{"The name of the metric plugin to load (may have additional configuration parameters"} };
38  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 };
39  fhicl::Atom<double> reporting_interval{ fhicl::Name{"reporting_interval"}, fhicl::Comment{"How often recorded metrics are sent to the underlying metric storage"}, 15.0 };
40  };
41 #if MESSAGEFACILITY_HEX_VERSION >= 0x20103
42  using Parameters = fhicl::WrappedTable<Config>;
43 #endif
44 
58  explicit MetricPlugin(fhicl::ParameterSet const& ps, std::string const& app_name) : pset(ps)
59  , app_name_(app_name)
60  , inhibit_(false)
61  {
62  runLevel_ = pset.get<int>("level", 0);
63  accumulationTime_ = pset.get<double>("reporting_interval", 15.0);
64  }
65 
69  virtual ~MetricPlugin() = default;
70 
72  //
73  // Interface Functions: These should be reimplemented in plugin classes!
74  //
76 
80  virtual std::string getLibName() const { return "ERROR"; }
81  protected:
90  virtual void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) = 0;
91 
100  virtual void sendMetric_(const std::string& name, const int& value, const std::string& unit) = 0;
101 
110  virtual void sendMetric_(const std::string& name, const double& value, const std::string& unit) = 0;
111 
120  virtual void sendMetric_(const std::string& name, const float& value, const std::string& unit) = 0;
121 
130  virtual void sendMetric_(const std::string& name, const long unsigned int& value, const std::string& unit) = 0;
131 
137  virtual void startMetrics_() = 0;
138 
144  virtual void stopMetrics_() = 0;
145 
147  //
148  // Implementation Functions: These should be called from ARTDAQ code!
149  //
151  public:
157  {
158  if (data.Type == MetricType::StringMetric)
159  {
160  sendMetric_(data.Name, data.StringValue, data.Unit);
161  }
162  else
163  {
164  if (!metricRegistry_.count(data.Name))
165  {
166  metricRegistry_[data.Name] = data;
167  }
168  metricData_[data.Name].push_back(data);
169  //sendMetrics();
170  }
171  }
172 
177  void sendMetrics(bool forceSend = false, std::chrono::steady_clock::time_point interval_end = std::chrono::steady_clock::now())
178  {
179  for (auto metric : metricData_)
180  {
181  auto metricName = metric.first;
182  if (readyToSend_(metricName) || forceSend)
183  {
184  if (metricData_[metricName].size() == 0 && metricRegistry_.count(metricName))
185  {
186  sendZero_(metricRegistry_[metricName]);
187  }
188  else if (metricData_[metricName].size() > 0)
189  {
190  auto metricMode = metricData_[metricName].back().Mode;
191  auto metricUnits = metricData_[metricName].back().Unit;
192  auto metricType = metricData_[metricName].back().Type;
193 
194  if (metricMode == MetricMode::LastPoint)
195  {
196  if (metricData_[metricName].size() > 1)
197  {
198  metricData_[metricName].erase(metricData_[metricName].begin(), std::prev(metricData_[metricName].end()));
199  }
200  sendMetric_(metricData_[metricName].back());
201  }
202  else
203  {
204  switch (metricType)
205  {
207  {
208  auto ds = 0.0;
209  for (auto& mv : metricData_[metricName]) { ds += mv.DoubleValue; }
210  switch (metricMode)
211  {
212  case MetricMode::Average: ds /= static_cast<double>(metricData_[metricName].size()); break;
213  case MetricMode::Rate: ds /= std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(); break;
214  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;
215  default:
216  break;
217  }
218  sendMetric_(metricName, ds, metricUnits);
219  }
220  break;
222  {
223  auto fs = 0.0;
224  double ds = 0.0;
225  for (auto& mv : metricData_[metricName]) { fs += mv.FloatValue; }
226 
227  switch (metricMode)
228  {
229  case MetricMode::Average:
230  ds = fs / static_cast<double>(metricData_[metricName].size());
231  sendMetric_(metricName, ds, metricUnits);
232  break;
233  case MetricMode::Rate:
234  ds = fs / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
235  sendMetric_(metricName, ds, metricUnits);
236  break;
238  sendMetric_(metricName + " - Rate", fs / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
239  FALLTHROUGH;
241  default:
242  sendMetric_(metricName, fs, metricUnits);
243  break;
244  }
245  }
246  break;
248  {
249  auto is = 0;
250  double ds = 0.0;
251  for (auto& mv : metricData_[metricName]) { is += mv.IntValue; }
252 
253  switch (metricMode)
254  {
255  case MetricMode::Average:
256  ds = is / static_cast<double>(metricData_[metricName].size());
257  sendMetric_(metricName, ds, metricUnits);
258  break;
259  case MetricMode::Rate:
260  ds = is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
261  sendMetric_(metricName, ds, metricUnits);
262  break;
264  sendMetric_(metricName + " - Rate", is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
265  FALLTHROUGH;
267  default:
268  sendMetric_(metricName, is, metricUnits);
269  break;
270  }
271  }
272  break;
274  {
275  auto us = 0UL;
276  double ds = 0.0;
277  for (auto& mv : metricData_[metricName]) { us += mv.UnsignedValue; }
278 
279  switch (metricMode)
280  {
281  case MetricMode::Average:
282  ds = us / static_cast<double>(metricData_[metricName].size());
283  sendMetric_(metricName, ds, metricUnits);
284  break;
285  case MetricMode::Rate:
286  ds = us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
287  sendMetric_(metricName, ds, metricUnits);
288  break;
290  sendMetric_(metricName + " - Rate", us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
291  FALLTHROUGH;
293  default:
294  sendMetric_(metricName, us, metricUnits);
295  break;
296  }
297  }
298  break;
299  default:
300  break;
301  }
302  metricData_[metricName].clear();
303  }
304  }
305  interval_start_[metricName] = interval_end;
306  }
307  }
308  }
309 
314 
319  void stopMetrics()
320  {
321  inhibit_ = true;
322  sendMetrics(true);
323  for (auto metric : metricRegistry_)
324  {
325  sendZero_(metric.second);
326  }
327  stopMetrics_();
328  inhibit_ = false;
329  }
330 
335  void setRunLevel(int level) { runLevel_ = level; }
340  int getRunLevel() const { return runLevel_; }
341 
342  protected:
343  int runLevel_;
344  fhicl::ParameterSet pset;
346  std::string app_name_;
347  bool inhibit_;
348 
349  private:
350  std::unordered_map<std::string, std::list<MetricData>> metricData_;
351  std::unordered_map<std::string, MetricData> metricRegistry_;
352  std::unordered_map<std::string, std::chrono::steady_clock::time_point> lastSendTime_;
353  std::unordered_map<std::string, std::chrono::steady_clock::time_point> interval_start_;
354 
355  bool readyToSend_(std::string name)
356  {
357  auto now = std::chrono::steady_clock::now();
358  if (std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(now - lastSendTime_[name]).count() >= accumulationTime_)
359  {
360  lastSendTime_[name] = now;
361  return true;
362  }
363 
364  return false;
365  }
366 
367  void sendZero_(MetricData data)
368  {
369  switch (data.Type)
370  {
372  sendMetric_(data.Name, static_cast<double>(0.0), data.Unit);
373  break;
375  sendMetric_(data.Name, static_cast<float>(0.0), data.Unit);
376  break;
378  sendMetric_(data.Name, static_cast<int>(0), data.Unit);
379  break;
381  sendMetric_(data.Name, static_cast<unsigned long>(0), data.Unit);
382  break;
383  default:
384  break;
385  }
386 
388  {
389  sendMetric_(data.Name + " - Rate", static_cast<double>(0.0), data.Unit + "/s");
390  }
391  }
392 
393  void sendMetric_(MetricData data)
394  {
395  switch (data.Type)
396  {
398  sendMetric_(data.Name, data.DoubleValue, data.Unit);
399  break;
401  sendMetric_(data.Name, data.FloatValue, data.Unit);
402  break;
404  sendMetric_(data.Name, data.IntValue, data.Unit);
405  break;
407  sendMetric_(data.Name, data.UnsignedValue, data.Unit);
408  break;
409  default:
410  break;
411  }
412  }
413  };
414  } //End namespace artdaq
415 
416 #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.
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
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.
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:58
virtual std::string getLibName() const
Return the name of the current MetricPlugin instance.
Definition: MetricPlugin.hh:80
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
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 ...