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 "fhiclcpp/types/Atom.h"
00016 #if MESSAGEFACILITY_HEX_VERSION >= 0x20103
00017 # include "fhiclcpp/types/ConfigurationTable.h"
00018 #endif
00019
00020 #include "artdaq-utilities/Plugins/MetricData.hh"
00021 #include "cetlib/compiler_macros.h"
00022 #ifndef FALLTHROUGH
00023 #define FALLTHROUGH while(0)
00024 #endif
00025
00026 namespace artdaq
00027 {
00032 class MetricPlugin
00033 {
00034 public:
00038 struct Config
00039 {
00041 fhicl::Atom<std::string> metricPluginType{ fhicl::Name{"metricPluginType"}, fhicl::Comment{"The name of the metric plugin to load (may have additional configuration parameters"} };
00043 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 };
00045 fhicl::Atom<double> reporting_interval{ fhicl::Name{"reporting_interval"}, fhicl::Comment{"How often recorded metrics are sent to the underlying metric storage"}, 15.0 };
00046 };
00047 #if MESSAGEFACILITY_HEX_VERSION >= 0x20103
00048 using Parameters = fhicl::WrappedTable<Config>;
00049 #endif
00050
00065 explicit MetricPlugin(fhicl::ParameterSet const& ps, std::string const& app_name) : pset(ps)
00066 , app_name_(app_name)
00067 , inhibit_(false)
00068 {
00069 runLevel_ = pset.get<int>("level", 0);
00070 accumulationTime_ = pset.get<double>("reporting_interval", 15.0);
00071 }
00072
00076 virtual ~MetricPlugin() = default;
00077
00079
00080
00081
00083
00087 virtual std::string getLibName() const { return "ERROR"; }
00088 protected:
00097 virtual void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) = 0;
00098
00107 virtual void sendMetric_(const std::string& name, const int& value, const std::string& unit) = 0;
00108
00117 virtual void sendMetric_(const std::string& name, const double& value, const std::string& unit) = 0;
00118
00127 virtual void sendMetric_(const std::string& name, const float& value, const std::string& unit) = 0;
00128
00137 virtual void sendMetric_(const std::string& name, const long unsigned int& value, const std::string& unit) = 0;
00138
00144 virtual void startMetrics_() = 0;
00145
00151 virtual void stopMetrics_() = 0;
00152
00154
00155
00156
00158 public:
00163 void addMetricData(MetricData data)
00164 {
00165 if (data.Type == MetricType::StringMetric)
00166 {
00167 sendMetric_(data.Name, data.StringValue, data.Unit);
00168 }
00169 else
00170 {
00171 if (!metricRegistry_.count(data.Name))
00172 {
00173 metricRegistry_[data.Name] = data;
00174 }
00175 metricData_[data.Name].push_back(data);
00176
00177 }
00178 }
00179
00185 void sendMetrics(bool forceSend = false, std::chrono::steady_clock::time_point interval_end = std::chrono::steady_clock::now())
00186 {
00187 for (auto metric : metricData_)
00188 {
00189 auto metricName = metric.first;
00190 if (readyToSend_(metricName) || forceSend)
00191 {
00192 if (metricData_[metricName].size() == 0 && metricRegistry_.count(metricName))
00193 {
00194 sendZero_(metricRegistry_[metricName]);
00195 }
00196 else if (metricData_[metricName].size() > 0)
00197 {
00198 auto metricMode = metricData_[metricName].back().Mode;
00199 auto metricUnits = metricData_[metricName].back().Unit;
00200 auto metricType = metricData_[metricName].back().Type;
00201
00202 if (metricMode == MetricMode::LastPoint)
00203 {
00204 if (metricData_[metricName].size() > 1)
00205 {
00206 metricData_[metricName].erase(metricData_[metricName].begin(), std::prev(metricData_[metricName].end()));
00207 }
00208 sendMetric_(metricData_[metricName].back());
00209 }
00210 else
00211 {
00212 switch (metricType)
00213 {
00214 case MetricType::DoubleMetric:
00215 {
00216 auto ds = 0.0;
00217 for (auto& mv : metricData_[metricName]) { ds += mv.DoubleValue; }
00218 switch (metricMode)
00219 {
00220 case MetricMode::Average: ds /= static_cast<double>(metricData_[metricName].size()); break;
00221 case MetricMode::Rate: ds /= std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(); break;
00222 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;
00223 default:
00224 break;
00225 }
00226 sendMetric_(metricName, ds, metricUnits);
00227 }
00228 break;
00229 case MetricType::FloatMetric:
00230 {
00231 auto fs = 0.0;
00232 double ds = 0.0;
00233 for (auto& mv : metricData_[metricName]) { fs += mv.FloatValue; }
00234
00235 switch (metricMode)
00236 {
00237 case MetricMode::Average:
00238 ds = fs / static_cast<double>(metricData_[metricName].size());
00239 sendMetric_(metricName, ds, metricUnits);
00240 break;
00241 case MetricMode::Rate:
00242 ds = fs / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
00243 sendMetric_(metricName, ds, metricUnits);
00244 break;
00245 case MetricMode::AccumulateAndRate:
00246 sendMetric_(metricName + " - Rate", fs / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
00247 FALLTHROUGH;
00248 case MetricMode::Accumulate:
00249 default:
00250 sendMetric_(metricName, fs, metricUnits);
00251 break;
00252 }
00253 }
00254 break;
00255 case MetricType::IntMetric:
00256 {
00257 auto is = 0;
00258 double ds = 0.0;
00259 for (auto& mv : metricData_[metricName]) { is += mv.IntValue; }
00260
00261 switch (metricMode)
00262 {
00263 case MetricMode::Average:
00264 ds = is / static_cast<double>(metricData_[metricName].size());
00265 sendMetric_(metricName, ds, metricUnits);
00266 break;
00267 case MetricMode::Rate:
00268 ds = is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
00269 sendMetric_(metricName, ds, metricUnits);
00270 break;
00271 case MetricMode::AccumulateAndRate:
00272 sendMetric_(metricName + " - Rate", is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
00273 FALLTHROUGH;
00274 case MetricMode::Accumulate:
00275 default:
00276 sendMetric_(metricName, is, metricUnits);
00277 break;
00278 }
00279 }
00280 break;
00281 case MetricType::UnsignedMetric:
00282 {
00283 auto us = 0UL;
00284 double ds = 0.0;
00285 for (auto& mv : metricData_[metricName]) { us += mv.UnsignedValue; }
00286
00287 switch (metricMode)
00288 {
00289 case MetricMode::Average:
00290 ds = us / static_cast<double>(metricData_[metricName].size());
00291 sendMetric_(metricName, ds, metricUnits);
00292 break;
00293 case MetricMode::Rate:
00294 ds = us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
00295 sendMetric_(metricName, ds, metricUnits);
00296 break;
00297 case MetricMode::AccumulateAndRate:
00298 sendMetric_(metricName + " - Rate", us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
00299 FALLTHROUGH;
00300 case MetricMode::Accumulate:
00301 default:
00302 sendMetric_(metricName, us, metricUnits);
00303 break;
00304 }
00305 }
00306 break;
00307 default:
00308 break;
00309 }
00310 metricData_[metricName].clear();
00311 }
00312 }
00313 interval_start_[metricName] = interval_end;
00314 }
00315 }
00316 }
00317
00321 void startMetrics() { startMetrics_(); }
00322
00327 void stopMetrics()
00328 {
00329 inhibit_ = true;
00330 sendMetrics(true);
00331 for (auto metric : metricRegistry_)
00332 {
00333 sendZero_(metric.second);
00334 }
00335 stopMetrics_();
00336 inhibit_ = false;
00337 }
00338
00343 void setRunLevel(int level) { runLevel_ = level; }
00348 int getRunLevel() const { return runLevel_; }
00349
00350 protected:
00351 int runLevel_;
00352 fhicl::ParameterSet pset;
00353 double accumulationTime_;
00354 std::string app_name_;
00355 bool inhibit_;
00356
00357 private:
00358 std::unordered_map<std::string, std::list<MetricData>> metricData_;
00359 std::unordered_map<std::string, MetricData> metricRegistry_;
00360 std::unordered_map<std::string, std::chrono::steady_clock::time_point> lastSendTime_;
00361 std::unordered_map<std::string, std::chrono::steady_clock::time_point> interval_start_;
00362
00363 bool readyToSend_(std::string name)
00364 {
00365 auto now = std::chrono::steady_clock::now();
00366 if (std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(now - lastSendTime_[name]).count() >= accumulationTime_)
00367 {
00368 lastSendTime_[name] = now;
00369 return true;
00370 }
00371
00372 return false;
00373 }
00374
00375 void sendZero_(MetricData data)
00376 {
00377 switch (data.Type)
00378 {
00379 case MetricType::DoubleMetric:
00380 sendMetric_(data.Name, static_cast<double>(0.0), data.Unit);
00381 break;
00382 case MetricType::FloatMetric:
00383 sendMetric_(data.Name, static_cast<float>(0.0), data.Unit);
00384 break;
00385 case MetricType::IntMetric:
00386 sendMetric_(data.Name, static_cast<int>(0), data.Unit);
00387 break;
00388 case MetricType::UnsignedMetric:
00389 sendMetric_(data.Name, static_cast<unsigned long>(0), data.Unit);
00390 break;
00391 default:
00392 break;
00393 }
00394
00395 if (data.Mode == MetricMode::AccumulateAndRate)
00396 {
00397 sendMetric_(data.Name + " - Rate", static_cast<double>(0.0), data.Unit + "/s");
00398 }
00399 }
00400
00401 void sendMetric_(MetricData data)
00402 {
00403 switch (data.Type)
00404 {
00405 case MetricType::DoubleMetric:
00406 sendMetric_(data.Name, data.DoubleValue, data.Unit);
00407 break;
00408 case MetricType::FloatMetric:
00409 sendMetric_(data.Name, data.FloatValue, data.Unit);
00410 break;
00411 case MetricType::IntMetric:
00412 sendMetric_(data.Name, data.IntValue, data.Unit);
00413 break;
00414 case MetricType::UnsignedMetric:
00415 sendMetric_(data.Name, data.UnsignedValue, data.Unit);
00416 break;
00417 default:
00418 break;
00419 }
00420 }
00421 };
00422 }
00423
00424 #endif //End ifndef __METRIC_INTERFACE__