$treeview $search $mathjax $extrastylesheet
artdaq_utilities
v1_04_10
$projectbrief
|
$projectbrief
|
$searchbox |
00001 // MetricPlugin.hh: Metric Plugin Interface 00002 // Author: Eric Flumerfelt 00003 // Last Modified: 11/05/2014 (Created) 00004 // 00005 // Defines the interface that any ARTDAQ metric plugin must implement 00006 00007 #ifndef __METRIC_INTERFACE__ 00008 #define __METRIC_INTERFACE__ 00009 00010 #include <chrono> 00011 #include <string> 00012 #include <unordered_map> 00013 #include "fhiclcpp/ParameterSet.h" 00014 #include "fhiclcpp/types/Atom.h" 00015 # include "fhiclcpp/types/ConfigurationTable.h" 00016 00017 #include "artdaq-utilities/Plugins/MetricData.hh" 00018 #include "cetlib/compiler_macros.h" 00019 #ifndef FALLTHROUGH 00020 #define FALLTHROUGH while(0) 00021 #endif 00022 00023 namespace artdaq 00024 { 00025 /* 00026 * \brief The MetricPlugin class defines the interface that MetricManager uses to send metric data 00027 * to the various metric plugins. 00028 */ 00029 class MetricPlugin 00030 { 00031 public: 00032 /* 00033 * \brief The Config struct defines the accepted configuration parameters for this class 00034 */ 00035 struct Config 00036 { 00038 fhicl::Atom<std::string> metricPluginType{ fhicl::Name{"metricPluginType"}, fhicl::Comment{"The name of the metric plugin to load (may have additional configuration parameters"} }; 00040 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 }; 00042 fhicl::Atom<double> reporting_interval{ fhicl::Name{"reporting_interval"}, fhicl::Comment{"How often recorded metrics are sent to the underlying metric storage"}, 15.0 }; 00043 }; 00044 using Parameters = fhicl::WrappedTable<Config>; 00045 00046 /* 00047 * \brief MetricPlugin Constructor 00048 * \param ps The ParameterSet used to configure this MetricPlugin instance 00049 * \param app_name The Application name which can be used by the Metric Plugin for identification 00050 * 00051 * \verbatim 00052 * MetricPlugin accepts the following parameters: 00053 * "metricPluginType": The name of the plugin to load 00054 * "level" (Default: 0): The verbosity level of the metric plugin. Higher number = fewer metrics sent to the metric storage 00055 * "reporting_interval" (Default: 15.0): The interval, in seconds, which the metric plugin will accumulate values for. 00056 * Calling sendMetric with the accumulate parameter set to false will bypass this accumulation and directly send the 00057 * metric. String metrics cannot be accumulated. 00058 * \endverbatim 00059 */ 00060 explicit MetricPlugin(fhicl::ParameterSet const& ps, std::string const& app_name) : pset(ps) 00061 , app_name_(app_name) 00062 , inhibit_(false) 00063 { 00064 runLevel_ = pset.get<int>("level", 0); 00065 accumulationTime_ = pset.get<double>("reporting_interval", 15.0); 00066 } 00067 00068 /* 00069 * \brief Default virtual Desctructor 00070 */ 00071 virtual ~MetricPlugin() = default; 00072 00074 // 00075 // Interface Functions: These should be reimplemented in plugin classes! 00076 // 00078 00079 /* 00080 * \brief Return the name of the current MetricPlugin instance 00081 */ 00082 virtual std::string getLibName() const { return "ERROR"; } 00083 00084 protected: 00085 /* 00086 * \brief Send a metric to the underlying metric storage (file, Graphite, Ganglia, etc.) 00087 * \param name Name of the metric 00088 * \param value Value of the metric 00089 * \param unit Units for the metric 00090 * 00091 * Note this is a pure virtual function, it should be overridden by implementation plugins 00092 */ 00093 virtual void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) = 0; 00094 00095 /* 00096 * \brief Send a metric to the underlying metric storage (file, Graphite, Ganglia, etc.) 00097 * \param name Name of the metric 00098 * \param value Value of the metric 00099 * \param unit Units for the metric 00100 * 00101 * Note this is a pure virtual function, it should be overridden by implementation plugins 00102 */ 00103 virtual void sendMetric_(const std::string& name, const int& value, const std::string& unit) = 0; 00104 00105 /* 00106 * \brief Send a metric to the underlying metric storage (file, Graphite, Ganglia, etc.) 00107 * \param name Name of the metric 00108 * \param value Value of the metric 00109 * \param unit Units for the metric 00110 * 00111 * Note this is a pure virtual function, it should be overridden by implementation plugins 00112 */ 00113 virtual void sendMetric_(const std::string& name, const double& value, const std::string& unit) = 0; 00114 00115 /* 00116 * \brief Send a metric to the underlying metric storage (file, Graphite, Ganglia, etc.) 00117 * \param name Name of the metric 00118 * \param value Value of the metric 00119 * \param unit Units for the metric 00120 * 00121 * Note this is a pure virtual function, it should be overridden by implementation plugins 00122 */ 00123 virtual void sendMetric_(const std::string& name, const float& value, const std::string& unit) = 0; 00124 00125 /* 00126 * \brief Send a metric to the underlying metric storage (file, Graphite, Ganglia, etc.) 00127 * \param name Name of the metric 00128 * \param value Value of the metric 00129 * \param unit Units for the metric 00130 * 00131 * Note this is a pure virtual function, it should be overridden by implementation plugins 00132 */ 00133 virtual void sendMetric_(const std::string& name, const long unsigned int& value, const std::string& unit) = 0; 00134 00135 /* 00136 * \brief Perform any start-up actions necessary for the metric plugin 00137 * 00138 * This is a pure virtual function, it should be overridden by implementation plugins 00139 */ 00140 virtual void startMetrics_() = 0; 00141 00142 /* 00143 * \brief Perform any shutdown actions necessary for the metric plugin 00144 * 00145 * This is a pure virtual function, it should be overridden by implementation plugins 00146 */ 00147 virtual void stopMetrics_() = 0; 00148 00150 // 00151 // Implementation Functions: These should be called from ARTDAQ code! 00152 // 00154 public: 00155 /* 00156 * \brief Send a metric value to the MetricPlugin 00157 * \param data A MetricData struct containing the metric value 00158 */ 00159 void addMetricData(std::unique_ptr<MetricData> const& 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 //sendMetrics(); 00173 } 00174 } 00175 00176 /* 00177 * \brief For each known metric, determine whether the reporting interval has elapsed, and if so, report a value to 00178 * the underlying metric storage 00179 * \param forceSend (Default = false): Force sending metrics, even if reporting interval 00180 * has not elapsed 00181 * \param interval_end (Default = now): For calculating rates, when the current reporting interval 00182 * ended (interval began at last value of interval_end) 00183 */ 00184 void sendMetrics(bool forceSend = false, 00185 std::chrono::steady_clock::time_point interval_end = std::chrono::steady_clock::now()) { 00186 double ds; 00187 float fs; 00188 int is; 00189 unsigned long us; 00190 size_t count; 00191 00192 for (auto metric : metricData_) { 00193 auto *metricName = &metric.first; 00194 count = 0; 00195 if (readyToSend_(*metricName) || forceSend) { 00196 if (metricData_[*metricName].size() == 0 && metricRegistry_.count(*metricName)) { 00197 sendZero_(metricRegistry_[*metricName]); 00198 } else if (metricData_[*metricName].size() > 0) { 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 if (metricData_[*metricName].size() > 1) { 00205 metricData_[*metricName].erase(metricData_[*metricName].begin(), 00206 std::prev(metricData_[*metricName].end())); 00207 } 00208 sendMetric_(metricData_[*metricName].back()); 00209 } else { 00210 switch (*metricType) { 00211 case MetricType::DoubleMetric: { 00212 ds = 0.0; 00213 for (auto& mv : metricData_[*metricName]) { 00214 ds += mv.DoubleValue; 00215 count += mv.DataPointCount; 00216 } 00217 switch (*metricMode) { 00218 case MetricMode::Average: 00219 ds /= static_cast<double>(count); 00220 break; 00221 case MetricMode::Rate: 00222 ds /= std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>( 00223 interval_end - interval_start_[*metricName]) 00224 .count(); 00225 break; 00226 case MetricMode::AccumulateAndRate: 00227 sendMetric_(*metricName + " - Rate", 00228 ds / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>( 00229 interval_end - interval_start_[*metricName]) 00230 .count(), 00231 *metricUnits + "/s"); 00232 break; 00233 default: 00234 break; 00235 } 00236 sendMetric_(*metricName, ds, *metricUnits); 00237 } break; 00238 case MetricType::FloatMetric: { 00239 fs = 0.0; 00240 for (auto& mv : metricData_[*metricName]) { 00241 fs += mv.FloatValue; 00242 count += mv.DataPointCount; 00243 } 00244 00245 switch (*metricMode) { 00246 case MetricMode::Average: 00247 ds = fs / static_cast<double>(count); 00248 sendMetric_(*metricName, ds, *metricUnits); 00249 break; 00250 case MetricMode::Rate: 00251 ds = fs / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>( 00252 interval_end - interval_start_[*metricName]) 00253 .count(); 00254 sendMetric_(*metricName, ds, *metricUnits); 00255 break; 00256 case MetricMode::AccumulateAndRate: 00257 sendMetric_(*metricName + " - Rate", 00258 fs / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>( 00259 interval_end - interval_start_[*metricName]) 00260 .count(), 00261 *metricUnits + "/s"); 00262 FALLTHROUGH; 00263 case MetricMode::Accumulate: 00264 default: 00265 sendMetric_(*metricName, fs, *metricUnits); 00266 break; 00267 } 00268 } break; 00269 case MetricType::IntMetric: { 00270 is = 0; 00271 for (auto& mv : metricData_[*metricName]) { 00272 is += mv.IntValue; 00273 count += mv.DataPointCount; 00274 } 00275 00276 switch (*metricMode) { 00277 case MetricMode::Average: 00278 ds = is / static_cast<double>(count); 00279 sendMetric_(*metricName, ds, *metricUnits); 00280 break; 00281 case MetricMode::Rate: 00282 ds = is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>( 00283 interval_end - interval_start_[*metricName]) 00284 .count(); 00285 sendMetric_(*metricName, ds, *metricUnits); 00286 break; 00287 case MetricMode::AccumulateAndRate: 00288 sendMetric_(*metricName + " - Rate", 00289 is / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>( 00290 interval_end - interval_start_[*metricName]) 00291 .count(), 00292 *metricUnits + "/s"); 00293 FALLTHROUGH; 00294 case MetricMode::Accumulate: 00295 default: 00296 sendMetric_(*metricName, is, *metricUnits); 00297 break; 00298 } 00299 } break; 00300 case MetricType::UnsignedMetric: { 00301 us = 0UL; 00302 for (auto& mv : metricData_[*metricName]) { 00303 us += mv.UnsignedValue; 00304 count += mv.DataPointCount; 00305 } 00306 00307 switch (*metricMode) { 00308 case MetricMode::Average: 00309 ds = us / static_cast<double>(count); 00310 sendMetric_(*metricName, ds, *metricUnits); 00311 break; 00312 case MetricMode::Rate: 00313 ds = us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>( 00314 interval_end - interval_start_[*metricName]) 00315 .count(); 00316 sendMetric_(*metricName, ds, *metricUnits); 00317 break; 00318 case MetricMode::AccumulateAndRate: 00319 sendMetric_(*metricName + " - Rate", 00320 us / std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>( 00321 interval_end - interval_start_[*metricName]) 00322 .count(), 00323 *metricUnits + "/s"); 00324 FALLTHROUGH; 00325 case MetricMode::Accumulate: 00326 default: 00327 sendMetric_(*metricName, us, *metricUnits); 00328 break; 00329 } 00330 } break; 00331 default: 00332 break; 00333 } 00334 metricData_[*metricName].clear(); 00335 } 00336 } 00337 interval_start_[*metricName] = interval_end; 00338 } 00339 } 00340 } 00341 00342 /* 00343 * \brief Perform startup actions. Simply calls the virtual startMetrics_ function 00344 */ 00345 void startMetrics() { startMetrics_(); } 00346 00347 /* 00348 * \brief Perform shutdown actions. Zeroes out all accumulators, and sends zeros for each metric. 00349 * Calls stopMetrics_() for any plugin-defined shutdown actions. 00350 */ 00351 void stopMetrics() { 00352 inhibit_ = true; 00353 sendMetrics(true); 00354 for (auto metric : metricRegistry_) { 00355 sendZero_(metric.second); 00356 } 00357 stopMetrics_(); 00358 inhibit_ = false; 00359 } 00360 00361 /* 00362 * \brief Set the threshold for sending metrics to the underlying storage. 00363 * \param level The new threshold for sending metrics to the underlying storage. Metrics with level <= to runLevel_ 00364 * will be sent. 00365 */ 00366 void setRunLevel(int level) { runLevel_ = level; } 00367 /* 00368 * \brief Get the threshold for sending metrics to the underlying storage. 00369 * \return The threshold for sending metrics to the underlying storage. Metrics with level <= to runLevel_ will be 00370 * sent. 00371 */ 00372 int getRunLevel() const { return runLevel_; } 00373 00374 protected: 00375 int runLevel_; 00376 00377 fhicl::ParameterSet pset; 00378 double accumulationTime_; 00379 00380 std::string app_name_; 00381 bool inhibit_; 00382 00383 private: 00384 std::unordered_map<std::string, std::list<MetricData>> metricData_; 00385 std::unordered_map<std::string, MetricData> metricRegistry_; 00386 std::unordered_map<std::string, std::chrono::steady_clock::time_point> lastSendTime_; 00387 std::unordered_map<std::string, std::chrono::steady_clock::time_point> interval_start_; 00388 00389 bool readyToSend_(std::string name) { 00390 auto now = std::chrono::steady_clock::now(); 00391 if (std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(now - lastSendTime_[name]).count() >= 00392 accumulationTime_) { 00393 lastSendTime_[name] = now; 00394 return true; 00395 } 00396 00397 return false; 00398 } 00399 00400 void sendZero_(MetricData data) { 00401 switch (data.Type) { 00402 case MetricType::DoubleMetric: 00403 sendMetric_(data.Name, static_cast<double>(0.0), data.Unit); 00404 break; 00405 case MetricType::FloatMetric: 00406 sendMetric_(data.Name, static_cast<float>(0.0), data.Unit); 00407 break; 00408 case MetricType::IntMetric: 00409 sendMetric_(data.Name, static_cast<int>(0), data.Unit); 00410 break; 00411 case MetricType::UnsignedMetric: 00412 sendMetric_(data.Name, static_cast<unsigned long>(0), data.Unit); 00413 break; 00414 default: 00415 break; 00416 } 00417 00418 if (data.Mode == MetricMode::AccumulateAndRate) { 00419 sendMetric_(data.Name + " - Rate", static_cast<double>(0.0), data.Unit + "/s"); 00420 } 00421 } 00422 00423 void sendMetric_(MetricData data) { 00424 switch (data.Type) { 00425 case MetricType::DoubleMetric: 00426 sendMetric_(data.Name, data.DoubleValue, data.Unit); 00427 break; 00428 case MetricType::FloatMetric: 00429 sendMetric_(data.Name, data.FloatValue, data.Unit); 00430 break; 00431 case MetricType::IntMetric: 00432 sendMetric_(data.Name, data.IntValue, data.Unit); 00433 break; 00434 case MetricType::UnsignedMetric: 00435 sendMetric_(data.Name, data.UnsignedValue, data.Unit); 00436 break; 00437 default: 00438 break; 00439 } 00440 } 00441 }; 00442 } //End namespace artdaq 00443 00444 #endif //End ifndef __METRIC_INTERFACE__