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:
00035 struct Config
00036 {
00037 fhicl::Atom<std::string> metricPluginType{ fhicl::Name{"metricPluginType"}, fhicl::Comment{"The name of the metric plugin to load (may have additional configuration parameters"} };
00038 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 };
00039 fhicl::Atom<double> reporting_interval{ fhicl::Name{"reporting_interval"}, fhicl::Comment{"How often recorded metrics are sent to the underlying metric storage"}, 15.0 };
00040 };
00041 #if MESSAGEFACILITY_HEX_VERSION >= 0x20103
00042 using Parameters = fhicl::WrappedTable<Config>;
00043 #endif
00044
00058 explicit MetricPlugin(fhicl::ParameterSet const& ps, std::string const& app_name) : pset(ps)
00059 , app_name_(app_name)
00060 , inhibit_(false)
00061 {
00062 runLevel_ = pset.get<int>("level", 0);
00063 accumulationTime_ = pset.get<double>("reporting_interval", 15.0);
00064 }
00065
00069 virtual ~MetricPlugin() = default;
00070
00072
00073
00074
00076
00080 virtual std::string getLibName() const { return "ERROR"; }
00081 protected:
00090 virtual void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) = 0;
00091
00100 virtual void sendMetric_(const std::string& name, const int& value, const std::string& unit) = 0;
00101
00110 virtual void sendMetric_(const std::string& name, const double& value, const std::string& unit) = 0;
00111
00120 virtual void sendMetric_(const std::string& name, const float& value, const std::string& unit) = 0;
00121
00130 virtual void sendMetric_(const std::string& name, const long unsigned int& value, const std::string& unit) = 0;
00131
00137 virtual void startMetrics_() = 0;
00138
00144 virtual void stopMetrics_() = 0;
00145
00147
00148
00149
00151 public:
00156 void addMetricData(MetricData data)
00157 {
00158 if (data.Type == MetricType::StringMetric)
00159 {
00160 sendMetric_(data.Name, data.StringValue, data.Unit);
00161 }
00162 else
00163 {
00164 if (!metricRegistry_.count(data.Name))
00165 {
00166 metricRegistry_[data.Name] = data;
00167 }
00168 metricData_[data.Name].push_back(data);
00169
00170 }
00171 }
00172
00177 void sendMetrics(bool forceSend = false, std::chrono::steady_clock::time_point interval_end = std::chrono::steady_clock::now())
00178 {
00179 for (auto metric : metricData_)
00180 {
00181 auto metricName = metric.first;
00182 if (readyToSend_(metricName) || forceSend)
00183 {
00184 if (metricData_[metricName].size() == 0 && metricRegistry_.count(metricName))
00185 {
00186 sendZero_(metricRegistry_[metricName]);
00187 }
00188 else if (metricData_[metricName].size() > 0)
00189 {
00190 auto metricMode = metricData_[metricName].back().Mode;
00191 auto metricUnits = metricData_[metricName].back().Unit;
00192 auto metricType = metricData_[metricName].back().Type;
00193
00194 if (metricMode == MetricMode::LastPoint)
00195 {
00196 if (metricData_[metricName].size() > 1)
00197 {
00198 metricData_[metricName].erase(metricData_[metricName].begin(), std::prev(metricData_[metricName].end()));
00199 }
00200 sendMetric_(metricData_[metricName].back());
00201 }
00202 else
00203 {
00204 switch (metricType)
00205 {
00206 case MetricType::DoubleMetric:
00207 {
00208 auto ds = 0.0;
00209 for (auto& mv : metricData_[metricName]) { ds += mv.DoubleValue; }
00210 switch (metricMode)
00211 {
00212 case MetricMode::Average: ds /= static_cast<double>(metricData_[metricName].size()); break;
00213 case MetricMode::Rate: ds /= std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(); break;
00214 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;
00215 default:
00216 break;
00217 }
00218 sendMetric_(metricName, ds, metricUnits);
00219 }
00220 break;
00221 case MetricType::FloatMetric:
00222 {
00223 auto fs = 0.0;
00224 double ds = 0.0;
00225 for (auto& mv : metricData_[metricName]) { fs += mv.FloatValue; }
00226
00227 switch (metricMode)
00228 {
00229 case MetricMode::Average:
00230 ds = fs / static_cast<double>(metricData_[metricName].size());
00231 sendMetric_(metricName, ds, metricUnits);
00232 break;
00233 case MetricMode::Rate:
00234 ds = fs / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
00235 sendMetric_(metricName, ds, metricUnits);
00236 break;
00237 case MetricMode::AccumulateAndRate:
00238 sendMetric_(metricName + " - Rate", fs / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
00239 FALLTHROUGH;
00240 case MetricMode::Accumulate:
00241 default:
00242 sendMetric_(metricName, fs, metricUnits);
00243 break;
00244 }
00245 }
00246 break;
00247 case MetricType::IntMetric:
00248 {
00249 auto is = 0;
00250 double ds = 0.0;
00251 for (auto& mv : metricData_[metricName]) { is += mv.IntValue; }
00252
00253 switch (metricMode)
00254 {
00255 case MetricMode::Average:
00256 ds = is / static_cast<double>(metricData_[metricName].size());
00257 sendMetric_(metricName, ds, metricUnits);
00258 break;
00259 case MetricMode::Rate:
00260 ds = is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
00261 sendMetric_(metricName, ds, metricUnits);
00262 break;
00263 case MetricMode::AccumulateAndRate:
00264 sendMetric_(metricName + " - Rate", is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
00265 FALLTHROUGH;
00266 case MetricMode::Accumulate:
00267 default:
00268 sendMetric_(metricName, is, metricUnits);
00269 break;
00270 }
00271 }
00272 break;
00273 case MetricType::UnsignedMetric:
00274 {
00275 auto us = 0UL;
00276 double ds = 0.0;
00277 for (auto& mv : metricData_[metricName]) { us += mv.UnsignedValue; }
00278
00279 switch (metricMode)
00280 {
00281 case MetricMode::Average:
00282 ds = us / static_cast<double>(metricData_[metricName].size());
00283 sendMetric_(metricName, ds, metricUnits);
00284 break;
00285 case MetricMode::Rate:
00286 ds = us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count();
00287 sendMetric_(metricName, ds, metricUnits);
00288 break;
00289 case MetricMode::AccumulateAndRate:
00290 sendMetric_(metricName + " - Rate", us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(interval_end - interval_start_[metricName]).count(), metricUnits + "/s");
00291 FALLTHROUGH;
00292 case MetricMode::Accumulate:
00293 default:
00294 sendMetric_(metricName, us, metricUnits);
00295 break;
00296 }
00297 }
00298 break;
00299 default:
00300 break;
00301 }
00302 metricData_[metricName].clear();
00303 }
00304 }
00305 interval_start_[metricName] = interval_end;
00306 }
00307 }
00308 }
00309
00313 void startMetrics() { startMetrics_(); }
00314
00319 void stopMetrics()
00320 {
00321 inhibit_ = true;
00322 sendMetrics(true);
00323 for (auto metric : metricRegistry_)
00324 {
00325 sendZero_(metric.second);
00326 }
00327 stopMetrics_();
00328 inhibit_ = false;
00329 }
00330
00335 void setRunLevel(int level) { runLevel_ = level; }
00340 int getRunLevel() const { return runLevel_; }
00341
00342 protected:
00343 int runLevel_;
00344 fhicl::ParameterSet pset;
00345 double accumulationTime_;
00346 std::string app_name_;
00347 bool inhibit_;
00348
00349 private:
00350 std::unordered_map<std::string, std::list<MetricData>> metricData_;
00351 std::unordered_map<std::string, MetricData> metricRegistry_;
00352 std::unordered_map<std::string, std::chrono::steady_clock::time_point> lastSendTime_;
00353 std::unordered_map<std::string, std::chrono::steady_clock::time_point> interval_start_;
00354
00355 bool readyToSend_(std::string name)
00356 {
00357 auto now = std::chrono::steady_clock::now();
00358 if (std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(now - lastSendTime_[name]).count() >= accumulationTime_)
00359 {
00360 lastSendTime_[name] = now;
00361 return true;
00362 }
00363
00364 return false;
00365 }
00366
00367 void sendZero_(MetricData data)
00368 {
00369 switch (data.Type)
00370 {
00371 case MetricType::DoubleMetric:
00372 sendMetric_(data.Name, static_cast<double>(0.0), data.Unit);
00373 break;
00374 case MetricType::FloatMetric:
00375 sendMetric_(data.Name, static_cast<float>(0.0), data.Unit);
00376 break;
00377 case MetricType::IntMetric:
00378 sendMetric_(data.Name, static_cast<int>(0), data.Unit);
00379 break;
00380 case MetricType::UnsignedMetric:
00381 sendMetric_(data.Name, static_cast<unsigned long>(0), data.Unit);
00382 break;
00383 default:
00384 break;
00385 }
00386
00387 if (data.Mode == MetricMode::AccumulateAndRate)
00388 {
00389 sendMetric_(data.Name + " - Rate", static_cast<double>(0.0), data.Unit + "/s");
00390 }
00391 }
00392
00393 void sendMetric_(MetricData data)
00394 {
00395 switch (data.Type)
00396 {
00397 case MetricType::DoubleMetric:
00398 sendMetric_(data.Name, data.DoubleValue, data.Unit);
00399 break;
00400 case MetricType::FloatMetric:
00401 sendMetric_(data.Name, data.FloatValue, data.Unit);
00402 break;
00403 case MetricType::IntMetric:
00404 sendMetric_(data.Name, data.IntValue, data.Unit);
00405 break;
00406 case MetricType::UnsignedMetric:
00407 sendMetric_(data.Name, data.UnsignedValue, data.Unit);
00408 break;
00409 default:
00410 break;
00411 }
00412 }
00413 };
00414 }
00415
00416 #endif //End ifndef __METRIC_INTERFACE__