artdaq_utilities  v1_02_02
 All Classes
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 <cstdint>
13 #include <chrono>
14 #include <unordered_map>
15 #include "fhiclcpp/ParameterSet.h"
16 
17 namespace artdaq
18 {
20  {
21  public:
22  MetricPlugin(fhicl::ParameterSet const& ps) : pset(ps)
23  , inhibit_(false)
24  {
25  runLevel_ = pset.get<int>("level", 0);
26  accumulationTime_ = pset.get<double>("reporting_interval", 15.0);
27  }
28 
29  virtual ~MetricPlugin() = default;
30 
32  //
33  // Interface Functions: These should be reimplemented in plugin classes!
34  //
36  public:
37  virtual std::string getLibName() const { return "ERROR"; }
38  protected:
39  // These methods dispatch the metric to the metric storage (file, Graphite, Ganglia, etc.)
40  // Metric plugins should override them
41  virtual void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) = 0;
42 
43  virtual void sendMetric_(const std::string& name, const int& value, const std::string& unit) = 0;
44 
45  virtual void sendMetric_(const std::string& name, const double& value, const std::string& unit) = 0;
46 
47  virtual void sendMetric_(const std::string& name, const float& value, const std::string& unit) = 0;
48 
49  virtual void sendMetric_(const std::string& name, const long unsigned int& value, const std::string& unit) = 0;
50 
51  //Run Control -> Clean-up and start-up methods for metric plugins
52  virtual void startMetrics_() = 0;
53 
54  virtual void stopMetrics_() = 0;
55 
57  //
58  // Implementation Functions: These should be called from ARTDAQ code!
59  //
61  public:
62  // Methods for aggregating metrics. These methods should be called from ARTDAQ and derived code.
63  virtual void sendMetric(const std::string& name, const std::string& value, const std::string& unit, bool accumulate = true)
64  {
65  if (accumulate)
66  {
67  // There's no sensible way to accumulate string values, just pass them through...
68  sendMetric_(name, value, unit);
69  }
70  else
71  {
72  sendMetric_(name, value, unit);
73  }
74  }
75 
76  virtual void sendMetric(const std::string& name, const int& value, const std::string& unit, bool accumulate = true)
77  {
78  // 22-Jul-2015, KAB - moved push_back here so that we always get the name
79  // added to the map, even if accumulate is false. This helps ensure that a
80  // zero is sent at stop time.
81  intAccumulator_[name].push_back(value);
82 
83  if (!accumulate)
84  {
85  sendMetric_(name, value, unit);
86  intAccumulator_[name].clear();
87  lastSendTime_[name] = std::chrono::steady_clock::now();
88  return;
89  }
90 
91  if (readyToSend_(name))
92  {
93  double sendValue = 0;
94  for (auto val : intAccumulator_[name])
95  {
96  sendValue += val / (double)intAccumulator_[name].size();
97  }
98 
99  sendMetric_(name, sendValue, unit);
100 
101  intAccumulator_[name].clear();
102  }
103  }
104 
105  virtual void sendMetric(const std::string& name, const double& value, const std::string& unit, bool accumulate = true)
106  {
107  // 22-Jul-2015, KAB - moved push_back here so that we always get the name
108  // added to the map, even if accumulate is false. This helps ensure that a
109  // zero is sent at stop time.
110  doubleAccumulator_[name].push_back(value);
111 
112  if (!accumulate)
113  {
114  sendMetric_(name, value, unit);
115  doubleAccumulator_[name].clear();
116  lastSendTime_[name] = std::chrono::steady_clock::now();
117  return;
118  }
119 
120  if (readyToSend_(name))
121  {
122  double sendValue = 0;
123  for (auto val : doubleAccumulator_[name])
124  {
125  sendValue += val / doubleAccumulator_[name].size();
126  }
127 
128  sendMetric_(name, sendValue, unit);
129 
130  doubleAccumulator_[name].clear();
131  }
132  }
133 
134  virtual void sendMetric(const std::string& name, const float& value, const std::string& unit, bool accumulate = true)
135  {
136  // 22-Jul-2015, KAB - moved push_back here so that we always get the name
137  // added to the map, even if accumulate is false. This helps ensure that a
138  // zero is sent at stop time.
139  floatAccumulator_[name].push_back(value);
140 
141  if (!accumulate)
142  {
143  sendMetric_(name, value, unit);
144  floatAccumulator_[name].clear();
145  lastSendTime_[name] = std::chrono::steady_clock::now();
146  return;
147  }
148 
149  if (readyToSend_(name))
150  {
151  float sendValue = 0;
152  for (auto val : floatAccumulator_[name])
153  {
154  sendValue += val / floatAccumulator_[name].size();
155  }
156 
157  sendMetric_(name, sendValue, unit);
158 
159  floatAccumulator_[name].clear();
160  }
161  }
162 
163  virtual void sendMetric(const std::string& name, const long unsigned int& value, const std::string& unit, bool accumulate = true)
164  {
165  // 22-Jul-2015, KAB - moved push_back here so that we always get the name
166  // added to the map, even if accumulate is false. This helps ensure that a
167  // zero is sent at stop time.
168  uint32_t uvalue = static_cast<uint32_t>(value);
169  uintAccumulator_[name].push_back(uvalue);
170 
171  if (!accumulate)
172  {
173  sendMetric_(name, value, unit);
174  uintAccumulator_[name].clear();
175  lastSendTime_[name] = std::chrono::steady_clock::now();
176  return;
177  }
178 
179  if (readyToSend_(name))
180  {
181  double sendValue = 0;
182  for (auto val : uintAccumulator_[name])
183  {
184  sendValue += val / (double)uintAccumulator_[name].size();
185  }
186 
187  sendMetric_(name, sendValue, unit);
188 
189  uintAccumulator_[name].clear();
190  }
191  }
192 
193 
194  //Run Control
195  virtual void startMetrics() { startMetrics_(); }
196 
197  virtual void stopMetrics()
198  {
199  inhibit_ = true;
200  for (auto dv : doubleAccumulator_)
201  {
202  static_cast<std::vector<double>>(dv.second).clear();
203  // 22-Jul-2015, KAB - added cast to get correct call and false to get immediate zero
204  sendMetric(dv.first, (double)0.0, "", false);
205  }
206  for (auto iv : intAccumulator_)
207  {
208  static_cast<std::vector<int>>(iv.second).clear();
209  // 22-Jul-2015, KAB - added cast to get correct call and false to get immediate zero
210  sendMetric(iv.first, (int)0, "", false);
211  }
212  for (auto fv : floatAccumulator_)
213  {
214  static_cast<std::vector<float>>(fv.second).clear();
215  // 22-Jul-2015, KAB - added cast to get correct call and false to get immediate zero
216  sendMetric(fv.first, (float)0.0, "", false);
217  }
218  for (auto uv : uintAccumulator_)
219  {
220  static_cast<std::vector<uint32_t>>(uv.second).clear();
221  // 22-Jul-2015, KAB - added cast to get correct call and false to get immediate zero
222  sendMetric(uv.first, (long unsigned int)0, "", false);
223  }
224  stopMetrics_();
225  inhibit_ = false;
226  }
227 
228  void setRunLevel(int level) { runLevel_ = level; }
229  int getRunLevel() { return runLevel_; }
230 
231  protected:
232  int runLevel_;
233  fhicl::ParameterSet pset;
234  double accumulationTime_;
235  bool inhibit_;
236 
237  private:
238  std::unordered_map<std::string, std::vector<double>> doubleAccumulator_;
239  std::unordered_map<std::string, std::vector<int>> intAccumulator_;
240  std::unordered_map<std::string, std::vector<float>> floatAccumulator_;
241  std::unordered_map<std::string, std::vector<uint32_t>> uintAccumulator_;
242  std::unordered_map<std::string, std::chrono::steady_clock::time_point> lastSendTime_;
243 
244  bool readyToSend_(std::string name)
245  {
246  auto now = std::chrono::steady_clock::now();
247  if (std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(now - lastSendTime_[name]).count() >= accumulationTime_)
248  {
249  lastSendTime_[name] = now;
250  return true;
251  }
252 
253  return false;
254  }
255  };
256 } //End namespace artdaq
257 
258 #endif //End ifndef __METRIC_INTERFACE__