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 # include "fhiclcpp/types/ConfigurationTable.h"
00017
00018 #include "artdaq-utilities/Plugins/MetricData.hh"
00019 #include "cetlib/compiler_macros.h"
00020 #ifndef FALLTHROUGH
00021 #define FALLTHROUGH while(0)
00022 #endif
00023
00024 namespace artdaq
00025 {
00026
00027
00028
00029
00030 class MetricPlugin
00031 {
00032 public:
00033
00034
00035
00036 struct Config
00037 {
00039 fhicl::Atom<std::string> metricPluginType{ fhicl::Name{"metricPluginType"}, fhicl::Comment{"The name of the metric plugin to load (may have additional configuration parameters"} };
00041 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 };
00043 fhicl::Atom<double> reporting_interval{ fhicl::Name{"reporting_interval"}, fhicl::Comment{"How often recorded metrics are sent to the underlying metric storage"}, 15.0 };
00044 };
00045 using Parameters = fhicl::WrappedTable<Config>;
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 explicit MetricPlugin(fhicl::ParameterSet const& ps, std::string const& app_name) : pset(ps)
00062 , app_name_(app_name)
00063 , inhibit_(false)
00064 {
00065 runLevel_ = pset.get<int>("level", 0);
00066 accumulationTime_ = pset.get<double>("reporting_interval", 15.0);
00067 }
00068
00069
00070
00071
00072 virtual ~MetricPlugin() = default;
00073
00075
00076
00077
00079
00080
00081
00082
00083 virtual std::string getLibName() const { return "ERROR"; }
00084 protected:
00085
00086
00087
00088
00089
00090
00091
00092
00093 virtual void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) = 0;
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 virtual void sendMetric_(const std::string& name, const int& value, const std::string& unit) = 0;
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 virtual void sendMetric_(const std::string& name, const double& value, const std::string& unit) = 0;
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 virtual void sendMetric_(const std::string& name, const float& value, const std::string& unit) = 0;
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 virtual void sendMetric_(const std::string& name, const long unsigned int& value, const std::string& unit) = 0;
00134
00135
00136
00137
00138
00139
00140 virtual void startMetrics_() = 0;
00141
00142
00143
00144
00145
00146
00147 virtual void stopMetrics_() = 0;
00148
00150
00151
00152
00154 public:
00155
00156
00157
00158
00159 void addMetricData(MetricData data)
00160 {
00161 if (data.Type == MetricType::StringMetric)
00162 {
00163 sendMetric_(data.Name, data.StringValue, data.Unit);
00164 }
00165 else
00166 {
00167 if (!metricRegistry_.count(data.Name))
00168 {
00169 metricRegistry_[data.Name] = data;
00170 }
00171 metricData_[data.Name].push_back(data);
00172
00173 }
00174 }
00175
00176
00177
00178
00179
00180
00181 void sendMetrics(bool forceSend = false, std::chrono::steady_clock::time_point interval_end = std::chrono::steady_clock::now())
00182 {
00183 double ds;
00184 float fs;
00185 int is;
00186 unsigned long us;
00187
00188 for (auto metric : metricData_)
00189 {
00190 auto *metricName = &metric.first;
00191 if (readyToSend_(*metricName) || forceSend)
00192 {
00193 if (metricData_[*metricName].size() == 0 && metricRegistry_.count(*metricName))
00194 {
00195 sendZero_(metricRegistry_[*metricName]);
00196 }
00197 else if (metricData_[*metricName].size() > 0)
00198 {
00199 auto metricMode = &metricData_[*metricName].back().Mode;
00200 auto metricUnits = &metricData_[*metricName].back().Unit;
00201 auto metricType = &metricData_[*metricName].back().Type;
00202
00203 if (*metricMode == MetricMode::LastPoint)
00204 {
00205 if (metricData_[*metricName].size() > 1)
00206 {
00207 metricData_[*metricName].erase(metricData_[*metricName].begin(), std::prev(metricData_[*metricName].end()));
00208 }
00209 sendMetric_(metricData_[*metricName].back());
00210 }
00211 else
00212 {
00213 switch (*metricType)
00214 {
00215 case MetricType::DoubleMetric:
00216 {
00217 ds = 0.0;
00218 for (auto& mv : metricData_[*metricName]) { ds += mv.DoubleValue; }
00219 switch (*metricMode)
00220 {
00221 case MetricMode::Average: ds /= static_cast<double>(metricData_[*metricName].size()); break;
00222 case MetricMode::Rate: ds /= std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[*metricName]).count(); break;
00223 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;
00224 default:
00225 break;
00226 }
00227 sendMetric_(*metricName, ds, *metricUnits);
00228 }
00229 break;
00230 case MetricType::FloatMetric:
00231 {
00232 fs = 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 is = 0;
00258 for (auto& mv : metricData_[*metricName]) { is += mv.IntValue; }
00259
00260 switch (*metricMode)
00261 {
00262 case MetricMode::Average:
00263 ds = is / static_cast<double>(metricData_[*metricName].size());
00264 sendMetric_(*metricName, ds, *metricUnits);
00265 break;
00266 case MetricMode::Rate:
00267 ds = is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[*metricName]).count();
00268 sendMetric_(*metricName, ds, *metricUnits);
00269 break;
00270 case MetricMode::AccumulateAndRate:
00271 sendMetric_(*metricName + " - Rate", is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[*metricName]).count(), *metricUnits + "/s");
00272 FALLTHROUGH;
00273 case MetricMode::Accumulate:
00274 default:
00275 sendMetric_(*metricName, is, *metricUnits);
00276 break;
00277 }
00278 }
00279 break;
00280 case MetricType::UnsignedMetric:
00281 {
00282 us = 0UL;
00283 for (auto& mv : metricData_[*metricName]) { us += mv.UnsignedValue; }
00284
00285 switch (*metricMode)
00286 {
00287 case MetricMode::Average:
00288 ds = us / static_cast<double>(metricData_[*metricName].size());
00289 sendMetric_(*metricName, ds, *metricUnits);
00290 break;
00291 case MetricMode::Rate:
00292 ds = us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[*metricName]).count();
00293 sendMetric_(*metricName, ds, *metricUnits);
00294 break;
00295 case MetricMode::AccumulateAndRate:
00296 sendMetric_(*metricName + " - Rate", us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[*metricName]).count(), *metricUnits + "/s");
00297 FALLTHROUGH;
00298 case MetricMode::Accumulate:
00299 default:
00300 sendMetric_(*metricName, us, *metricUnits);
00301 break;
00302 }
00303 }
00304 break;
00305 default:
00306 break;
00307 }
00308 metricData_[*metricName].clear();
00309 }
00310 }
00311 interval_start_[*metricName] = interval_end;
00312 }
00313 }
00314 }
00315
00316
00317
00318
00319 void startMetrics() { startMetrics_(); }
00320
00321
00322
00323
00324
00325 void stopMetrics()
00326 {
00327 inhibit_ = true;
00328 sendMetrics(true);
00329 for (auto metric : metricRegistry_)
00330 {
00331 sendZero_(metric.second);
00332 }
00333 stopMetrics_();
00334 inhibit_ = false;
00335 }
00336
00337
00338
00339
00340
00341 void setRunLevel(int level) { runLevel_ = level; }
00342
00343
00344
00345
00346 int getRunLevel() const { return runLevel_; }
00347
00348 protected:
00349 int runLevel_;
00350 fhicl::ParameterSet pset;
00351 double accumulationTime_;
00352 std::string app_name_;
00353 bool inhibit_;
00354
00355 private:
00356 std::unordered_map<std::string, std::list<MetricData>> metricData_;
00357 std::unordered_map<std::string, MetricData> metricRegistry_;
00358 std::unordered_map<std::string, std::chrono::steady_clock::time_point> lastSendTime_;
00359 std::unordered_map<std::string, std::chrono::steady_clock::time_point> interval_start_;
00360
00361 bool readyToSend_(std::string name)
00362 {
00363 auto now = std::chrono::steady_clock::now();
00364 if (std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(now - lastSendTime_[name]).count() >= accumulationTime_)
00365 {
00366 lastSendTime_[name] = now;
00367 return true;
00368 }
00369
00370 return false;
00371 }
00372
00373 void sendZero_(MetricData data)
00374 {
00375 switch (data.Type)
00376 {
00377 case MetricType::DoubleMetric:
00378 sendMetric_(data.Name, static_cast<double>(0.0), data.Unit);
00379 break;
00380 case MetricType::FloatMetric:
00381 sendMetric_(data.Name, static_cast<float>(0.0), data.Unit);
00382 break;
00383 case MetricType::IntMetric:
00384 sendMetric_(data.Name, static_cast<int>(0), data.Unit);
00385 break;
00386 case MetricType::UnsignedMetric:
00387 sendMetric_(data.Name, static_cast<unsigned long>(0), data.Unit);
00388 break;
00389 default:
00390 break;
00391 }
00392
00393 if (data.Mode == MetricMode::AccumulateAndRate)
00394 {
00395 sendMetric_(data.Name + " - Rate", static_cast<double>(0.0), data.Unit + "/s");
00396 }
00397 }
00398
00399 void sendMetric_(MetricData data)
00400 {
00401 switch (data.Type)
00402 {
00403 case MetricType::DoubleMetric:
00404 sendMetric_(data.Name, data.DoubleValue, data.Unit);
00405 break;
00406 case MetricType::FloatMetric:
00407 sendMetric_(data.Name, data.FloatValue, data.Unit);
00408 break;
00409 case MetricType::IntMetric:
00410 sendMetric_(data.Name, data.IntValue, data.Unit);
00411 break;
00412 case MetricType::UnsignedMetric:
00413 sendMetric_(data.Name, data.UnsignedValue, data.Unit);
00414 break;
00415 default:
00416 break;
00417 }
00418 }
00419 };
00420 }
00421
00422 #endif //End ifndef __METRIC_INTERFACE__