00001
00002
00003
00004
00005
00006
00007
00008 #ifndef __METRIC_INTERFACE__
00009 #define __METRIC_INTERFACE__
00010
00011 #include <string>
00012 #include <chrono>
00013 #include <unordered_map>
00014 #include "fhiclcpp/ParameterSet.h"
00015 #include "artdaq-utilities/Plugins/MetricData.hh"
00016 #include "cetlib/compiler_macros.h"
00017 #ifndef FALLTHROUGH
00018 #define FALLTHROUGH while(0)
00019 #endif
00020
00021 namespace artdaq
00022 {
00027 class MetricPlugin
00028 {
00029 public:
00043 explicit MetricPlugin(fhicl::ParameterSet const& ps) : pset(ps)
00044 , inhibit_(false)
00045 {
00046 runLevel_ = pset.get<int>("level", 0);
00047 accumulationTime_ = pset.get<double>("reporting_interval", 15.0);
00048 }
00049
00053 virtual ~MetricPlugin() = default;
00054
00056
00057
00058
00060
00064 virtual std::string getLibName() const { return "ERROR"; }
00065 protected:
00074 virtual void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) = 0;
00075
00084 virtual void sendMetric_(const std::string& name, const int& value, const std::string& unit) = 0;
00085
00094 virtual void sendMetric_(const std::string& name, const double& value, const std::string& unit) = 0;
00095
00104 virtual void sendMetric_(const std::string& name, const float& value, const std::string& unit) = 0;
00105
00114 virtual void sendMetric_(const std::string& name, const long unsigned int& value, const std::string& unit) = 0;
00115
00121 virtual void startMetrics_() = 0;
00122
00128 virtual void stopMetrics_() = 0;
00129
00131
00132
00133
00135 public:
00140 void addMetricData(MetricData data)
00141 {
00142 if (data.Type == MetricType::StringMetric)
00143 {
00144 sendMetric_(data.Name, data.StringValue, data.Unit);
00145 }
00146 else
00147 {
00148 if (!metricRegistry_.count(data.Name))
00149 {
00150 metricRegistry_[data.Name] = data;
00151 }
00152 metricData_[data.Name].push_back(data);
00153
00154 }
00155 }
00156
00161 void sendMetrics(bool forceSend = false, std::chrono::steady_clock::time_point interval_end = std::chrono::steady_clock::now())
00162 {
00163 for (auto metric : metricData_)
00164 {
00165 auto metricName = metric.first;
00166 if (readyToSend_(metricName) || forceSend)
00167 {
00168 if (metricData_[metricName].size() == 0 && metricRegistry_.count(metricName))
00169 {
00170 sendZero_(metricRegistry_[metricName]);
00171 }
00172 else if (metricData_[metricName].size() > 0)
00173 {
00174 auto metricMode = metricData_[metricName].back().Mode;
00175 auto metricUnits = metricData_[metricName].back().Unit;
00176 auto metricType = metricData_[metricName].back().Type;
00177
00178 if (metricMode == MetricMode::LastPoint)
00179 {
00180 if (metricData_[metricName].size() > 1)
00181 {
00182 metricData_[metricName].erase(metricData_[metricName].begin(), std::prev(metricData_[metricName].end()));
00183 }
00184 sendMetric_(metricData_[metricName].back());
00185 }
00186 else
00187 {
00188 switch (metricType)
00189 {
00190 case MetricType::DoubleMetric:
00191 {
00192 auto ds = 0.0;
00193 for (auto& mv : metricData_[metricName]) { ds += mv.DoubleValue; }
00194 switch (metricMode)
00195 {
00196 case MetricMode::Average: ds /= static_cast<double>(metricData_[metricName].size()); break;
00197 case MetricMode::Rate: ds /= std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(); break;
00198 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;
00199 default:
00200 break;
00201 }
00202 sendMetric_(metricName, ds, metricUnits);
00203 }
00204 break;
00205 case MetricType::FloatMetric:
00206 {
00207 auto fs = 0.0;
00208 double ds = 0.0;
00209 for (auto& mv : metricData_[metricName]) { fs += mv.FloatValue; }
00210
00211 switch (metricMode)
00212 {
00213 case MetricMode::Average:
00214 ds = fs / static_cast<double>(metricData_[metricName].size());
00215 sendMetric_(metricName, ds, metricUnits);
00216 break;
00217 case MetricMode::Rate:
00218 ds = fs / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
00219 sendMetric_(metricName, ds, metricUnits);
00220 break;
00221 case MetricMode::AccumulateAndRate:
00222 sendMetric_(metricName + " - Rate", fs / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
00223 FALLTHROUGH;
00224 case MetricMode::Accumulate:
00225 default:
00226 sendMetric_(metricName, fs, metricUnits);
00227 break;
00228 }
00229 }
00230 break;
00231 case MetricType::IntMetric:
00232 {
00233 auto is = 0;
00234 double ds = 0.0;
00235 for (auto& mv : metricData_[metricName]) { is += mv.IntValue; }
00236
00237 switch (metricMode)
00238 {
00239 case MetricMode::Average:
00240 ds = is / static_cast<double>(metricData_[metricName].size());
00241 sendMetric_(metricName, ds, metricUnits);
00242 break;
00243 case MetricMode::Rate:
00244 ds = is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
00245 sendMetric_(metricName, ds, metricUnits);
00246 break;
00247 case MetricMode::AccumulateAndRate:
00248 sendMetric_(metricName + " - Rate", is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
00249 FALLTHROUGH;
00250 case MetricMode::Accumulate:
00251 default:
00252 sendMetric_(metricName, is, metricUnits);
00253 break;
00254 }
00255 }
00256 break;
00257 case MetricType::UnsignedMetric:
00258 {
00259 auto us = 0UL;
00260 double ds = 0.0;
00261 for (auto& mv : metricData_[metricName]) { us += mv.UnsignedValue; }
00262
00263 switch (metricMode)
00264 {
00265 case MetricMode::Average:
00266 ds = us / static_cast<double>(metricData_[metricName].size());
00267 sendMetric_(metricName, ds, metricUnits);
00268 break;
00269 case MetricMode::Rate:
00270 ds = us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
00271 sendMetric_(metricName, ds, metricUnits);
00272 break;
00273 case MetricMode::AccumulateAndRate:
00274 sendMetric_(metricName + " - Rate", us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
00275 FALLTHROUGH;
00276 case MetricMode::Accumulate:
00277 default:
00278 sendMetric_(metricName, us, metricUnits);
00279 break;
00280 }
00281 }
00282 break;
00283 default:
00284 break;
00285 }
00286 metricData_[metricName].clear();
00287 }
00288 }
00289 interval_start_[metricName] = interval_end;
00290 }
00291 }
00292 }
00293
00297 void startMetrics() { startMetrics_(); }
00298
00303 void stopMetrics()
00304 {
00305 inhibit_ = true;
00306 sendMetrics(true);
00307 for (auto metric : metricRegistry_)
00308 {
00309 sendZero_(metric.second);
00310 }
00311 stopMetrics_();
00312 inhibit_ = false;
00313 }
00314
00319 void setRunLevel(int level) { runLevel_ = level; }
00324 int getRunLevel() const { return runLevel_; }
00325
00326 protected:
00327 int runLevel_;
00328 fhicl::ParameterSet pset;
00329 double accumulationTime_;
00330 bool inhibit_;
00331
00332 private:
00333 std::unordered_map<std::string, std::list<MetricData>> metricData_;
00334 std::unordered_map<std::string, MetricData> metricRegistry_;
00335 std::unordered_map<std::string, std::chrono::steady_clock::time_point> lastSendTime_;
00336 std::unordered_map<std::string, std::chrono::steady_clock::time_point> interval_start_;
00337
00338 bool readyToSend_(std::string name)
00339 {
00340 auto now = std::chrono::steady_clock::now();
00341 if (std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(now - lastSendTime_[name]).count() >= accumulationTime_)
00342 {
00343 lastSendTime_[name] = now;
00344 return true;
00345 }
00346
00347 return false;
00348 }
00349
00350 void sendZero_(MetricData data)
00351 {
00352 switch (data.Type)
00353 {
00354 case MetricType::DoubleMetric:
00355 sendMetric_(data.Name, static_cast<double>(0.0), data.Unit);
00356 break;
00357 case MetricType::FloatMetric:
00358 sendMetric_(data.Name, static_cast<float>(0.0), data.Unit);
00359 break;
00360 case MetricType::IntMetric:
00361 sendMetric_(data.Name, static_cast<int>(0), data.Unit);
00362 break;
00363 case MetricType::UnsignedMetric:
00364 sendMetric_(data.Name, static_cast<unsigned long>(0), data.Unit);
00365 break;
00366 default:
00367 break;
00368 }
00369
00370 if (data.Mode == MetricMode::AccumulateAndRate)
00371 {
00372 sendMetric_(data.Name + " - Rate", static_cast<double>(0.0), data.Unit + "/s");
00373 }
00374 }
00375
00376 void sendMetric_(MetricData data)
00377 {
00378 switch (data.Type)
00379 {
00380 case MetricType::DoubleMetric:
00381 sendMetric_(data.Name, data.DoubleValue, data.Unit);
00382 break;
00383 case MetricType::FloatMetric:
00384 sendMetric_(data.Name, data.FloatValue, data.Unit);
00385 break;
00386 case MetricType::IntMetric:
00387 sendMetric_(data.Name, data.IntValue, data.Unit);
00388 break;
00389 case MetricType::UnsignedMetric:
00390 sendMetric_(data.Name, data.UnsignedValue, data.Unit);
00391 break;
00392 default:
00393 break;
00394 }
00395 }
00396 };
00397 }
00398
00399 #endif //End ifndef __METRIC_INTERFACE__