artdaq_utilities  v1_04_05
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 "artdaq-utilities/Plugins/MetricData.hh"
16 #include "cetlib/compiler_macros.h"
17 #ifndef FALLTHROUGH
18 #define FALLTHROUGH while(0)
19 #endif
20 
21 namespace artdaq
22 {
28  {
29  public:
43  explicit MetricPlugin(fhicl::ParameterSet const& ps) : pset(ps)
44  , inhibit_(false)
45  {
46  runLevel_ = pset.get<int>("level", 0);
47  accumulationTime_ = pset.get<double>("reporting_interval", 15.0);
48  }
49 
53  virtual ~MetricPlugin() = default;
54 
56  //
57  // Interface Functions: These should be reimplemented in plugin classes!
58  //
60 
64  virtual std::string getLibName() const { return "ERROR"; }
65  protected:
74  virtual void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) = 0;
75 
84  virtual void sendMetric_(const std::string& name, const int& value, const std::string& unit) = 0;
85 
94  virtual void sendMetric_(const std::string& name, const double& value, const std::string& unit) = 0;
95 
104  virtual void sendMetric_(const std::string& name, const float& value, const std::string& unit) = 0;
105 
114  virtual void sendMetric_(const std::string& name, const long unsigned int& value, const std::string& unit) = 0;
115 
121  virtual void startMetrics_() = 0;
122 
128  virtual void stopMetrics_() = 0;
129 
131  //
132  // Implementation Functions: These should be called from ARTDAQ code!
133  //
135  public:
141  {
142  if (data.Type == MetricType::StringMetric)
143  {
144  sendMetric_(data.Name, data.StringValue, data.Unit);
145  }
146  else
147  {
148  if (!metricRegistry_.count(data.Name))
149  {
150  metricRegistry_[data.Name] = data;
151  }
152  metricData_[data.Name].push_back(data);
153  //sendMetrics();
154  }
155  }
156 
161  void sendMetrics(bool forceSend = false, std::chrono::steady_clock::time_point interval_end = std::chrono::steady_clock::now())
162  {
163  for (auto metric : metricData_)
164  {
165  auto metricName = metric.first;
166  if (readyToSend_(metricName) || forceSend)
167  {
168  if (metricData_[metricName].size() == 0 && metricRegistry_.count(metricName))
169  {
170  sendZero_(metricRegistry_[metricName]);
171  }
172  else if (metricData_[metricName].size() > 0)
173  {
174  auto metricMode = metricData_[metricName].back().Mode;
175  auto metricUnits = metricData_[metricName].back().Unit;
176  auto metricType = metricData_[metricName].back().Type;
177 
178  if (metricMode == MetricMode::LastPoint)
179  {
180  if (metricData_[metricName].size() > 1)
181  {
182  metricData_[metricName].erase(metricData_[metricName].begin(), std::prev(metricData_[metricName].end()));
183  }
184  sendMetric_(metricData_[metricName].back());
185  }
186  else
187  {
188  switch (metricType)
189  {
191  {
192  auto ds = 0.0;
193  for (auto& mv : metricData_[metricName]) { ds += mv.DoubleValue; }
194  switch (metricMode)
195  {
196  case MetricMode::Average: ds /= static_cast<double>(metricData_[metricName].size()); break;
197  case MetricMode::Rate: ds /= std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(); break;
198  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;
199  default:
200  break;
201  }
202  sendMetric_(metricName, ds, metricUnits);
203  }
204  break;
206  {
207  auto fs = 0.0;
208  double ds = 0.0;
209  for (auto& mv : metricData_[metricName]) { fs += mv.FloatValue; }
210 
211  switch (metricMode)
212  {
213  case MetricMode::Average:
214  ds = fs / static_cast<double>(metricData_[metricName].size());
215  sendMetric_(metricName, ds, metricUnits);
216  break;
217  case MetricMode::Rate:
218  ds = fs / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
219  sendMetric_(metricName, ds, metricUnits);
220  break;
222  sendMetric_(metricName + " - Rate", fs / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
223  FALLTHROUGH;
225  default:
226  sendMetric_(metricName, fs, metricUnits);
227  break;
228  }
229  }
230  break;
232  {
233  auto is = 0;
234  double ds = 0.0;
235  for (auto& mv : metricData_[metricName]) { is += mv.IntValue; }
236 
237  switch (metricMode)
238  {
239  case MetricMode::Average:
240  ds = is / static_cast<double>(metricData_[metricName].size());
241  sendMetric_(metricName, ds, metricUnits);
242  break;
243  case MetricMode::Rate:
244  ds = is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
245  sendMetric_(metricName, ds, metricUnits);
246  break;
248  sendMetric_(metricName + " - Rate", is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
249  FALLTHROUGH;
251  default:
252  sendMetric_(metricName, is, metricUnits);
253  break;
254  }
255  }
256  break;
258  {
259  auto us = 0UL;
260  double ds = 0.0;
261  for (auto& mv : metricData_[metricName]) { us += mv.UnsignedValue; }
262 
263  switch (metricMode)
264  {
265  case MetricMode::Average:
266  ds = us / static_cast<double>(metricData_[metricName].size());
267  sendMetric_(metricName, ds, metricUnits);
268  break;
269  case MetricMode::Rate:
270  ds = us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
271  sendMetric_(metricName, ds, metricUnits);
272  break;
274  sendMetric_(metricName + " - Rate", us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
275  FALLTHROUGH;
277  default:
278  sendMetric_(metricName, us, metricUnits);
279  break;
280  }
281  }
282  break;
283  default:
284  break;
285  }
286  metricData_[metricName].clear();
287  }
288  }
289  interval_start_[metricName] = interval_end;
290  }
291  }
292  }
293 
298 
303  void stopMetrics()
304  {
305  inhibit_ = true;
306  sendMetrics(true);
307  for (auto metric : metricRegistry_)
308  {
309  sendZero_(metric.second);
310  }
311  stopMetrics_();
312  inhibit_ = false;
313  }
314 
319  void setRunLevel(int level) { runLevel_ = level; }
324  int getRunLevel() const { return runLevel_; }
325 
326  protected:
327  int runLevel_;
328  fhicl::ParameterSet pset;
330  bool inhibit_;
331 
332  private:
333  std::unordered_map<std::string, std::list<MetricData>> metricData_;
334  std::unordered_map<std::string, MetricData> metricRegistry_;
335  std::unordered_map<std::string, std::chrono::steady_clock::time_point> lastSendTime_;
336  std::unordered_map<std::string, std::chrono::steady_clock::time_point> interval_start_;
337 
338  bool readyToSend_(std::string name)
339  {
340  auto now = std::chrono::steady_clock::now();
341  if (std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(now - lastSendTime_[name]).count() >= accumulationTime_)
342  {
343  lastSendTime_[name] = now;
344  return true;
345  }
346 
347  return false;
348  }
349 
350  void sendZero_(MetricData data)
351  {
352  switch (data.Type)
353  {
355  sendMetric_(data.Name, static_cast<double>(0.0), data.Unit);
356  break;
358  sendMetric_(data.Name, static_cast<float>(0.0), data.Unit);
359  break;
361  sendMetric_(data.Name, static_cast<int>(0), data.Unit);
362  break;
364  sendMetric_(data.Name, static_cast<unsigned long>(0), data.Unit);
365  break;
366  default:
367  break;
368  }
369 
371  {
372  sendMetric_(data.Name + " - Rate", static_cast<double>(0.0), data.Unit + "/s");
373  }
374  }
375 
376  void sendMetric_(MetricData data)
377  {
378  switch (data.Type)
379  {
381  sendMetric_(data.Name, data.DoubleValue, data.Unit);
382  break;
384  sendMetric_(data.Name, data.FloatValue, data.Unit);
385  break;
387  sendMetric_(data.Name, data.IntValue, data.Unit);
388  break;
390  sendMetric_(data.Name, data.UnsignedValue, data.Unit);
391  break;
392  default:
393  break;
394  }
395  }
396  };
397 } //End namespace artdaq
398 
399 #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:27
void startMetrics()
Perform startup actions. Simply calls the virtual startMetrics_ function.
MetricPlugin(fhicl::ParameterSet const &ps)
MetricPlugin Constructor.
Definition: MetricPlugin.hh:43
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.
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.
virtual std::string getLibName() const
Return the name of the current MetricPlugin instance.
Definition: MetricPlugin.hh:64
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 ...