From f0cb0e5f8f24dd0ff41d9e4d16f50f1e54a7f93d Mon Sep 17 00:00:00 2001 From: Adam Wegrzynek Date: Tue, 31 Mar 2020 18:15:50 +0200 Subject: [PATCH] Support multiple values per metric (#189) --- CMakeLists.txt | 3 - README.md | 86 +++++++++++---------- examples/1-Basic.cxx | 12 ++- examples/3-Verbosity.cxx | 4 +- examples/5-Benchmark.cxx | 8 +- examples/7-InternalBenchamrk.cxx | 8 +- examples/8-Multiple.cxx | 17 ----- examples/9-AutoUpdate.cxx | 23 ------ include/Monitoring/Backend.h | 4 - include/Monitoring/ComplexMetric.h | 70 ----------------- include/Monitoring/DerivedMetrics.h | 2 +- include/Monitoring/Metric.h | 57 ++++++++++---- include/Monitoring/Monitoring.h | 14 +--- include/Monitoring/ProcessMonitor.h | 2 - src/Backends/ApMonBackend.cxx | 113 +++++++++++----------------- src/Backends/ApMonBackend.h | 7 +- src/Backends/InfluxDB.cxx | 47 +++--------- src/Backends/InfluxDB.h | 5 -- src/Backends/Noop.h | 4 - src/Backends/StdOut.cxx | 41 ++++------ src/Backends/StdOut.h | 5 -- src/ComplexMetric.cxx | 60 --------------- src/DerivedMetrics.cxx | 38 +++++----- src/Metric.cxx | 77 ++++++++++++------- src/Monitoring.cxx | 22 ++---- test/testApMon.cxx | 1 + test/testDerived.cxx | 50 ++++++------ test/testMetric.cxx | 45 ++++++++--- test/testMonitoring.cxx | 11 --- 29 files changed, 314 insertions(+), 522 deletions(-) delete mode 100644 examples/8-Multiple.cxx delete mode 100644 examples/9-AutoUpdate.cxx delete mode 100644 include/Monitoring/ComplexMetric.h delete mode 100644 src/ComplexMetric.cxx diff --git a/CMakeLists.txt b/CMakeLists.txt index d7654c6c3..b56fee8d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,7 +92,6 @@ message(STATUS " Compiling InfluxDB backend with Unix socket and UDP transport" add_library(Monitoring SHARED src/Monitoring.cxx src/Metric.cxx - src/ComplexMetric.cxx src/Backends/InfluxDB.cxx src/Backends/StdOut.cxx src/DerivedMetrics.cxx @@ -174,8 +173,6 @@ set(EXAMPLES examples/5-Benchmark.cxx examples/6-Increment.cxx examples/7-InternalBenchamrk.cxx - examples/8-Multiple.cxx - examples/9-AutoUpdate.cxx examples/10-Buffering.cxx ) diff --git a/README.md b/README.md index 8931edf50..0267821e1 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ See the table below to find `URI`s for supported backends: | Backend name | Transport | URI backend[-protocol] | URI query | Default verbosity | | ------------ |:-----------:|:----------------------:|:-----------:| -----------------:| -| No-op | - | `no-op` | | - | +| No-op | - | `no-op` | - | - | | InfluxDB | UDP | `influxdb-udp` | - | `info` | | InfluxDB | Unix socket | `influxdb-unix` | - | `info` | | InfluxDB | StdOut | `influxdb-stdout` | - | `info` | @@ -51,69 +51,67 @@ See the table below to find `URI`s for supported backends: | ApMon | UDP | `apmon` | - | `info` | | StdOut | - | `stdout`, `infologger` | [Prefix] | `debug` | -##### StdCout output format -``` -[METRIC] , -``` -The prefix (`[METRIC]`) can be changed using query component. - ### Metrics -A metric consist of 5 parameters: name, value, timestamp, verbosity and tags. +A metric consist of 5 parameters: +- name - metric name +- values - vector of value and value name pairs +- timestamp - time of creation +- verbosity - metric "severity" +- tags - metric metadata represented as map | Parameter name | Type | Required | Default | | -------------- |:--------------------------------:|:--------:| -----------------------:| | name | string | yes | - | -| value | int / double / string / uint64_t | yes | - | +| values | map<string, int/double/string/uint64_t> | no/1 | - | | timestamp | time_point<system_clock> | no | current time | | verbosity | Enum (Debug/Info/Prod) | no | Verbosity::Info | -| tags | vector | no | host and process names | +| tags | map | no | host and process names | -A metric can be constructed by providing required parameters (value and name): +A metric can be constructed by providing required parameters (value and metric name, value name is set to `value`): ```cpp Metric{10, "name"} ``` - -#### Verbosity -There are 3 verbosity levels (the same as for backends): Debug, Info, Prod. By default it is set to `Verbosity::Info`. The default value can be overwritten using: `Metric::setDefaultVerbosity(verbosity)`. -To overwrite verbosity on per metric basis use third, optional parameter to metric constructor: +#### Values +By default metric can be created with zero or one value (in such case value name is set to `value`). Any additional value may be added using `.addValue` method, therefore the following two metrics are identical: ```cpp -Metric{10, "name", Verbosity::Prod} +Metric{10, "name"} +Metric{"name"}.addValue(10, "value") ``` -Metrics need to match backends verbosity in order to be sent, eg. backend with `/info` verbosity will accept `Info` and `Prod` metrics only. - #### Tags Each metric can be tagged with any number of [predefined tags](include/Monitoring/Tags.h). In order to do so use `addTag(tags::Key, tags::Value)` or `addTag(tags::Key, unsigned short)` methods. The latter method allows assigning numeric value to a tag. +```cpp +Metric{10, "name"}.addTag(tags::Key::Subsystem, tags::Value::QC) +``` + See the example: [examples/2-TaggedMetrics.cxx](examples/2-TaggedMetrics.cxx). ### Sending metric -Pass metric object to send method and l-value reference: +Pass metric object to `send` method as l-value reference: ```cpp send({10, "name"}) +send(Metric{20, "name"}.addTag(tags::Key::CRU, 123)) +send(Metric{"throughput"}.addValue(100, "tx").addValue(200, "rx")) ``` See how it works in the example: [examples/1-Basic.cxx](examples/1-Basic.cxx). ## Advanced features -### Sending more than one metric -In order to send more than one metric in a packet group them into vector: -```cpp -monitoring->send(std::vector&& metrics); -``` - -It's also possible to send multiple, grouped values (`InfluxDB` backends are supported); For example `cpu` metric can be composed of `cpuUser`, `cpuSystem` values. +### Metric verbosity +There are 3 verbosity levels (the same as for backends): Debug, Info, Prod. By default it is set to `Verbosity::Info`. The default value can be overwritten using: `Metric::setDefaultVerbosity(verbosity)`. +To overwrite verbosity on per metric basis use third, optional parameter to metric constructor: ```cpp -void sendGroupped(std::string name, std::vector&& metrics) +Metric{10, "name", Verbosity::Prod} ``` -See how it works in the example: [examples/8-Multiple.cxx](examples/8-Multiple.cxx) +Metrics need to match backends verbosity in order to be sent, eg. backend with `/info` verbosity will accept `Info` and `Prod` metrics only. ### Buffering metrics In order to avoid sending each metric separately, metrics can be temporary stored in the buffer and flushed at the most convenient moment. -This feature can be operated with following two methods: +This feature can be controlled with following two methods: ```cpp monitoring->enableBuffering(const std::size_t maxSize) ... @@ -124,27 +122,29 @@ monitoring->flushBuffer(); See how it works in the example: [examples/10-Buffering.cxx](examples/10-Buffering.cxx). -### Calculating derived metrics -The module can calculate derived metrics. To do so, use optional `DerivedMetricMode mode` parameter of `send` method: +### Calculating derived values +This feature can calculate derived values. To do so, use optional `DerivedMetricMode mode` parameter of `send` method: ``` send(Metric&& metric, [DerivedMetricMode mode]) ``` -Three modes are available: - + `DerivedMetricMode::NONE` - no action, - + `DerivedMetricMode::RATE` - rate between two following metrics, - + `DerivedMetricMode::AVERAGE` - average value of all metrics stored in cache. +Two modes are available: + + `DerivedMetricMode::RATE` - rate between two following values, + + `DerivedMetricMode::INCREMENT` - sum of all passed values. -Derived metrics are generated each time as new value is passed to the module. Their names are suffixed with derived mode name. +The derived value is generated only from the first value of the metric and it is added to the same metric with the value name suffixed with `_rate`, `_increment` accordingly. See how it works in the example: [examples/4-RateDerivedMetric.cxx](examples/4-RateDerivedMetric.cxx). ### Global tags -Global tags are added to each metric. Two tags: `hostname` and `name` (process name) are set as global by the library. +Global tags are added to each metric sent using given monitoring instance. Two tags: `hostname` and `name` (process name) are set as global by default. You can add your own global tag by calling `addGlobalTag(std::string_view key, std::string_view value)` or `addGlobalTag(tags::Key, tags::Value)`. ### Process monitoring + +This feature provides basic performance status of the process. Note that is runs in separate thread (without mutex). + ```cpp enableProcessMonitoring([interval in seconds]); ``` @@ -153,16 +153,14 @@ The following metrics are generated every interval: + **involuntaryContextSwitches** - involuntary context switches over time interval + **memoryUsagePercentage** - ratio of the process's resident set size to the physical memory on the machine, expressed as a percentage (Linux only) -### Automatic metric updates -Sometimes it's necessary to provide value every exact interval of time (even though value does not change). This can be done using `AutoPushMetric`. -```cpp -ComplexMetric& metric = monitoring->getAutoPushMetric("exampleMetric"); -metric = 10; +### StdOut backend output format +``` +[METRIC] , ``` -See how it works in the example: [examples/11-AutoUpdate.cxx](examples/11-AutoUpdate.cxx). +The prefix (`[METRIC]`) can be changed using query component. ### Regex verbosity policy -Overwrite metric verbosities using regex expression: +Overwrite metric verbosity using regex expression: ``` Metric::setVerbosityPolicy(Verbosity verbosity, const std::regex& regex) ``` diff --git a/examples/1-Basic.cxx b/examples/1-Basic.cxx index 18e95e59e..40a7ae950 100644 --- a/examples/1-Basic.cxx +++ b/examples/1-Basic.cxx @@ -11,11 +11,15 @@ int main() { // Configure monitoring // Pass string with list of URLs as parameter - auto monitoring = MonitoringFactory::Get("stdout://"); + auto monitoring = MonitoringFactory::Get("influxdb-stdout://"); - // now send an application specific metric + // send a metric using one of two equivalent methods // 10 is the value // myMetric is the name of the metric by creating and moving Metric object - monitoring->send({10, "myMetricInt"}); - monitoring->send({10.10, "myMetricFloat"}); + monitoring->send({10, "myMetricInt"}); // default name is "value" + monitoring->send(Metric{"myMetricInt"}.addValue(10, "value")); + + // now send a metric with multiple values + monitoring->send(Metric{10, "myMetricInt"}.addValue(10.10, "value_float")); + monitoring->send(Metric{"myMetricInt"}.addValue(10, "value").addValue(10.10, "value_float")); } diff --git a/examples/3-Verbosity.cxx b/examples/3-Verbosity.cxx index 8e37e7b0f..db61b65a3 100644 --- a/examples/3-Verbosity.cxx +++ b/examples/3-Verbosity.cxx @@ -19,8 +19,8 @@ int main() monitoring->send({10, "myMetricInt", Verbosity::Debug}, DerivedMetricMode::INCREMENT); monitoring->send({10.10, "myMetricFloat", Verbosity::Prod}, DerivedMetricMode::INCREMENT); - monitoring->sendGrouped("measurementName", {{20, "myMetricIntMultiple"}, {20.30, "myMetricFloatMultple"}}, Verbosity::Debug); - monitoring->sendGrouped("measurementName", {{20, "myMetricIntMultiple"}, {20.30, "myMetricFloatMultple"}}, Verbosity::Prod); + //monitoring->sendGrouped("measurementName", {{20, "myMetricIntMultiple"}, {20.30, "myMetricFloatMultple"}}, Verbosity::Debug); + //monitoring->sendGrouped("measurementName", {{20, "myMetricIntMultiple"}, {20.30, "myMetricFloatMultple"}}, Verbosity::Prod); monitoring->send({10, "myMetricInt", Verbosity::Debug}, DerivedMetricMode::INCREMENT); monitoring->send({10.10, "myMetricFloat", Verbosity::Prod}, DerivedMetricMode::INCREMENT); diff --git a/examples/5-Benchmark.cxx b/examples/5-Benchmark.cxx index fc9d791ff..274504803 100644 --- a/examples/5-Benchmark.cxx +++ b/examples/5-Benchmark.cxx @@ -55,9 +55,11 @@ int main(int argc, char* argv[]) if (vm["multiple"].as()) { for (int j = 1; j <= count; j++) { for (int i = 1; i <= measurements; i++) { - monitoring->sendGrouped("measurement" + std::to_string(i), {{doubleDist(mt), "doubleMetric" + std::to_string(i)}, - {intDist(mt), "intMetric" + std::to_string(i)}, - {std::rand() % 2, "onOffMetric" + std::to_string(i)}}); + monitoring->send(Metric{"measurement" + std::to_string(i)} + .addValue(doubleDist(mt), "doubleMetric") + .addValue(intDist(mt), "intMetric") + .addValue(std::rand() % 2, "onOffMetric") + ); std::this_thread::sleep_for(std::chrono::microseconds(sleep)); } if (!vm.count("count")) diff --git a/examples/7-InternalBenchamrk.cxx b/examples/7-InternalBenchamrk.cxx index 0bb2c97d9..9d0701cd1 100644 --- a/examples/7-InternalBenchamrk.cxx +++ b/examples/7-InternalBenchamrk.cxx @@ -12,8 +12,8 @@ using namespace std::chrono; void test(std::unique_ptr& monitoring) { for (int i = 0; i < 100000; i++) { - monitoring->send({10, "myMetricInt"}); - monitoring->send({10.10, "myMetricFloat"}); + monitoring->send(Metric{"myMetricInt"}.addValue(10, "value")); + monitoring->send(Metric{"myMetricFloat"}.addValue(10.10, "value")); } } @@ -21,8 +21,8 @@ void testWithTags(std::unique_ptr& monitoring) { monitoring->addGlobalTag("name", "benchmark"); for (int i = 0; i < 100000; i++) { - monitoring->send(Metric{10, "myMetricInt"}.addTag(tags::Key::Detector, tags::Value::TPC)); - monitoring->send(Metric{10.10, "myMetricFloat"}.addTag(tags::Key::Subsystem, tags::Value::QC)); + monitoring->send(Metric{"myMetricInt"}.addValue(10, "value").addTag(tags::Key::Detector, tags::Value::TPC)); + monitoring->send(Metric{"myMetricFloat"}.addValue(10.10, "value").addTag(tags::Key::Subsystem, tags::Value::QC)); } } diff --git a/examples/8-Multiple.cxx b/examples/8-Multiple.cxx deleted file mode 100644 index 0997a0b64..000000000 --- a/examples/8-Multiple.cxx +++ /dev/null @@ -1,17 +0,0 @@ -/// -/// \file 8-Multiple.cxx -/// \author Adam Wegrzynek -/// - -#include "Monitoring/MonitoringFactory.h" - -using Monitoring = o2::monitoring::MonitoringFactory; - -int main() -{ - // Configure monitoring - // Pass string with list of URLs as parameter - auto monitoring = Monitoring::Get("stdout://"); - - monitoring->sendGrouped("measurementName", {{20, "myMetricIntMultiple"}, {20.30, "myMetricFloatMultple"}}); -} diff --git a/examples/9-AutoUpdate.cxx b/examples/9-AutoUpdate.cxx deleted file mode 100644 index afda350ff..000000000 --- a/examples/9-AutoUpdate.cxx +++ /dev/null @@ -1,23 +0,0 @@ -/// -/// \file 11-AutoUpdate.cxx -/// \author Adam Wegrzynek -/// - -#include "Monitoring/MonitoringFactory.h" - -using namespace o2::monitoring; - -int main() -{ - auto monitoring = MonitoringFactory::Get("stdout://"); - - // Get reference to metrics - auto& qcMetric = monitoring->getAutoPushMetric("qcMetric"); - auto& qcMetric2 = monitoring->getAutoPushMetric("qcMetric2"); - std::this_thread::sleep_for(std::chrono::milliseconds(2000)); - - // Update values - qcMetric = 123; - qcMetric2 = 321; - std::this_thread::sleep_for(std::chrono::milliseconds(2000)); -} diff --git a/include/Monitoring/Backend.h b/include/Monitoring/Backend.h index 471975326..672af955d 100644 --- a/include/Monitoring/Backend.h +++ b/include/Monitoring/Backend.h @@ -55,10 +55,6 @@ class Backend /// Sends multiple metrics not related to each other virtual void send(std::vector&& metrics) = 0; - /// Sends multiple related to each other metrics under a common name - /// If not supported by backend, falls back into sending single metrics - virtual void sendMultiple(std::string measurement, std::vector&& metrics) = 0; - /// Sets a tag virtual void addGlobalTag(std::string_view name, std::string_view value) = 0; }; diff --git a/include/Monitoring/ComplexMetric.h b/include/Monitoring/ComplexMetric.h deleted file mode 100644 index efd45b2ba..000000000 --- a/include/Monitoring/ComplexMetric.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file ComplexMetric.h -/// \author Adam Wegrzynek -/// - -#ifndef ALICEO2_MONITORING_CORE_COMPLEXMETRIC_H -#define ALICEO2_MONITORING_CORE_COMPLEXMETRIC_H - -#include "Metric.h" -#include - -namespace o2 -{ -/// ALICE O2 Monitoring system -namespace monitoring -{ - -// \brief Extends metric to value setter -class ComplexMetric : public o2::monitoring::Metric -{ - public: - /// Integer metric construtor - /// \param value metric value (int) - /// \param name metric name - ComplexMetric(int value, const std::string& name); - - /// String metric construtor - /// \param value metric value (string) - /// \param name the metric name - ComplexMetric(std::string value, const std::string& name); - - /// Double metric constructor - /// \param value metric value (double) - /// \param name metric name - ComplexMetric(double value, const std::string& name); - - /// uint64_t metric constructor - /// \param value metric value (uint64_t) - /// \param name metric name - ComplexMetric(uint64_t value, const std::string& name); - - /// boost variant metric constructor, required by derived metrics logic - /// \param value metric value (boost variant) - /// \param name metric name - ComplexMetric(std::variant, const std::string& name); - - /// Default destructor - ~ComplexMetric() = default; - - // Resets metric's timestamp - void resetTimestamp(); - - /// Assign operator overload, assignes new values to the metric object - ComplexMetric& operator=(const std::variant& value); -}; - -} // namespace monitoring -} // namespace o2 - -#endif // ALICEO2_MONITORING_CORE_COMPLEXMETRIC_H diff --git a/include/Monitoring/DerivedMetrics.h b/include/Monitoring/DerivedMetrics.h index 70c1062e1..27c234120 100644 --- a/include/Monitoring/DerivedMetrics.h +++ b/include/Monitoring/DerivedMetrics.h @@ -52,7 +52,7 @@ class DerivedMetrics /// Entry method to DerivedMetrics /// Switches over processing modes: rate and increment - Metric process(Metric& metric, DerivedMetricMode mode); + void process(Metric& metric, DerivedMetricMode mode); }; } // namespace monitoring diff --git a/include/Monitoring/Metric.h b/include/Monitoring/Metric.h index 89a517708..5979edd90 100644 --- a/include/Monitoring/Metric.h +++ b/include/Monitoring/Metric.h @@ -9,9 +9,9 @@ #include #include #include -#include #include #include +#include #include "Tags.h" namespace o2 @@ -57,17 +57,38 @@ class Metric /// \param name metric name Metric(uint64_t value, const std::string& name, Verbosity verbosity = Metric::DefaultVerbosity); - /// boost variant metric constructor, required by derived metrics logic - /// \param value metric value (boost variant) + /// Constructor that does not require any value to be specified, .addValue needs to be used /// \param name metric name - Metric(std::variant, const std::string& name, Verbosity verbosity = Metric::DefaultVerbosity); + Metric(const std::string& name, Verbosity verbosity = Metric::DefaultVerbosity); + + /// Adds additional int value to metric + /// \param value + /// \param name + Metric&& addValue(int value, const std::string& name); + + /// Adds additional double value to metric + /// \param value + /// \param name + Metric&& addValue(double value, const std::string& name); + + /// Adds additional uint64_t value to metric + /// \param value + /// \param name + Metric&& addValue(uint64_t value, const std::string& name); + + /// Adds additional string value to metric + /// \param value + /// \param name + Metric&& addValue(std::string value, const std::string& name); + + /// Adds additional variant value to metric + /// \param value + /// \param name + Metric&& addValue(const std::variant& value, const std::string& name); /// Default destructor ~Metric() = default; - /// Assign operator overload, assignes new values to the metric object - Metric& operator=(const std::variant& value); - /// Name getter /// \return metric name const std::string& getName() const; @@ -76,13 +97,16 @@ class Metric /// \return metric timestamp std::chrono::time_point getTimestamp() const; - /// Value getter - /// \return metric value - std::variant getValue() const; + /// Values getter + /// \return vector of values + const std::vector>>& getValues() const; - /// Value type getter - /// \return type of value stores inside metric : 0 - int, 1 - std::string, 2 - double - int getType() const; + /// First value getter + /// \return first value as pair + const std::pair>& getFirstValue() const; + + /// Values vector size getter + std::size_t getValuesSize() const noexcept; /// Tag list getter /// \return tags @@ -126,8 +150,8 @@ class Metric /// Set full vector of tags Metric&& setTags(std::vector>&& tags); - /// Metric value - std::variant mValue; + /// Metric values + std::vector>> mValues; /// Metric name std::string mName; @@ -146,6 +170,9 @@ class Metric /// Overwirte verbosity using regex policy void overwriteVerbosity(); + + /// Default value name + static constexpr char mDefaultValueName[] = "value"; }; } // namespace monitoring diff --git a/include/Monitoring/Monitoring.h b/include/Monitoring/Monitoring.h index fb8705931..4079d9266 100644 --- a/include/Monitoring/Monitoring.h +++ b/include/Monitoring/Monitoring.h @@ -27,7 +27,6 @@ #include #include -#include "Monitoring/ComplexMetric.h" #include "Monitoring/Backend.h" #include "Monitoring/DerivedMetrics.h" #include "Monitoring/ProcessMonitor.h" @@ -68,13 +67,6 @@ class Monitoring /// \param mode Derived metric mode void send(Metric&& metric, DerivedMetricMode mode = DerivedMetricMode::NONE); - /// Sends multiple realated to each other metric values under a common measurement name - /// You can imagine it as a data point with multiple values - /// If it's not supported by a backend it fallbacks into sending one by one - /// \param name measurement name - /// \param metrics list of metrics - void sendGrouped(std::string name, std::vector&& metrics, Verbosity verbosity = Metric::DefaultVerbosity); - /// Enables process monitoring /// \param interval refresh interval void enableProcessMonitoring(const unsigned int interval = 5); @@ -99,7 +91,7 @@ class Monitoring /// Returns a metric which will be periodically sent to backends /// \param name metric name /// \return periodically send metric - ComplexMetric& getAutoPushMetric(std::string name, unsigned int interval = 1); + //ComplexMetric& getAutoPushMetric(std::string name, unsigned int interval = 1); private: /// Sends multiple (not related to each other) metrics @@ -144,13 +136,13 @@ class Monitoring std::size_t mBufferSize; /// Store for automatically pushed metrics - std::deque mPushStore; + //std::deque mPushStore; /// Process monitor interval std::atomic mProcessMonitoringInterval; /// Automatic metric push interval - std::atomic mAutoPushInterval; + //std::atomic mAutoPushInterval; }; } // namespace monitoring diff --git a/include/Monitoring/ProcessMonitor.h b/include/Monitoring/ProcessMonitor.h index ff78aa2b1..19e1521e2 100644 --- a/include/Monitoring/ProcessMonitor.h +++ b/include/Monitoring/ProcessMonitor.h @@ -18,10 +18,8 @@ #include #include -#include #include #include -#include #include #include diff --git a/src/Backends/ApMonBackend.cxx b/src/Backends/ApMonBackend.cxx index 12a113062..8af374ae0 100644 --- a/src/Backends/ApMonBackend.cxx +++ b/src/Backends/ApMonBackend.cxx @@ -52,94 +52,73 @@ inline int ApMonBackend::convertTimestamp(const std::chrono::time_point&& metrics) +void ApMonBackend::send(const Metric& metric) { - int noMetrics = metrics.size(); + std::string name = metric.getName(); + std::string entity = mEntity; + for (const auto& [key, value] : metric.getTags()) { + entity += ','; + entity += tags::GetValue(value); + } + + int valueSize = metric.getValuesSize(); char **paramNames, **paramValues; int* valueTypes; - paramNames = (char**)std::malloc(noMetrics * sizeof(char*)); - paramValues = (char**)std::malloc(noMetrics * sizeof(char*)); - valueTypes = (int*)std::malloc(noMetrics * sizeof(int)); + paramNames = (char**)std::malloc(valueSize * sizeof(char*)); + paramValues = (char**)std::malloc(valueSize * sizeof(char*)); + valueTypes = (int*)std::malloc(valueSize * sizeof(int)); // the scope of values must be the same as sendTimedParameters method int intValue; double doubleValue; std::string stringValue; - for (int i = 0; i < noMetrics; i++) { - paramNames[i] = const_cast(metrics[i].getName().c_str()); + auto& values = metric.getValues(); + + for (int i = 0; i < valueSize; i++) { + paramNames[i] = const_cast(values[i].first.c_str()); std::visit(overloaded{ - [&](int value) { - valueTypes[i] = XDR_INT32; - intValue = value; - paramValues[i] = reinterpret_cast(&intValue); - }, - [&](double value) { - valueTypes[i] = XDR_REAL64; - doubleValue = value; - paramValues[i] = reinterpret_cast(&doubleValue); - }, - [&](const std::string& value) { - valueTypes[i] = XDR_STRING; - stringValue = value; - paramValues[i] = const_cast(stringValue.c_str()); - }, - [&](uint64_t value) { - valueTypes[i] = XDR_REAL64; - doubleValue = static_cast(value); - paramValues[i] = reinterpret_cast(&doubleValue); - }, - }, - metrics[i].getValue()); + [&](int value) { + valueTypes[i] = XDR_INT32; + intValue = value; + paramValues[i] = reinterpret_cast(&intValue); + }, + [&](double value) { + valueTypes[i] = XDR_REAL64; + doubleValue = value; + paramValues[i] = reinterpret_cast(&doubleValue); + }, + [&](const std::string& value) { + valueTypes[i] = XDR_STRING; + stringValue = value; + paramValues[i] = const_cast(stringValue.c_str()); + }, + [&](uint64_t value) { + valueTypes[i] = XDR_REAL64; + doubleValue = static_cast(value); + paramValues[i] = reinterpret_cast(&doubleValue); + }, + }, values[i].second); } - mApMon->sendTimedParameters(const_cast(entity.c_str()), const_cast(entity.c_str()), - noMetrics, paramNames, valueTypes, paramValues, convertTimestamp(metrics[0].getTimestamp())); + mApMon->sendTimedParameters(const_cast(name.c_str()), const_cast(entity.c_str()), + valueSize, paramNames, valueTypes, paramValues, convertTimestamp(metric.getTimestamp())); std::free(paramNames); std::free(paramValues); std::free(valueTypes); } -void ApMonBackend::sendMultiple(std::string, std::vector&& metrics) -{ - send(std::move(metrics)); -} - -void ApMonBackend::send(const Metric& metric) +void ApMonBackend::send(std::vector&& metrics) { - std::string name = metric.getName(); - - for (const auto& [key, value] : metric.getTags()) { - name += ','; - name += tags::TAG_KEY[key]; - name += "="; - name += tags::GetValue(value); + for (auto& metric : metrics) { + send(metric); } - - std::visit(overloaded{ - [this, &metric](int value) { - mApMon->sendTimedParameter(const_cast(entity.c_str()), const_cast(entity.c_str()), - const_cast(metric.getName().c_str()), XDR_INT32, reinterpret_cast(&value), convertTimestamp(metric.getTimestamp())); - }, - [this, &metric](double value) { - mApMon->sendTimedParameter(const_cast(entity.c_str()), const_cast(entity.c_str()), - const_cast(metric.getName().c_str()), XDR_REAL64, reinterpret_cast(&value), convertTimestamp(metric.getTimestamp())); - }, - [this, &metric](const std::string& value) { - mApMon->sendTimedParameter(const_cast(entity.c_str()), const_cast(entity.c_str()), - const_cast(metric.getName().c_str()), XDR_STRING, const_cast(value.c_str()), convertTimestamp(metric.getTimestamp())); - }, - [this, &metric](uint64_t value) { - mApMon->sendTimedParameter(const_cast(entity.c_str()), const_cast(entity.c_str()), - const_cast(metric.getName().c_str()), XDR_REAL64, reinterpret_cast(&value), convertTimestamp(metric.getTimestamp())); - }, - }, - metric.getValue()); } } // namespace backends diff --git a/src/Backends/ApMonBackend.h b/src/Backends/ApMonBackend.h index 302125670..7dc8e9208 100644 --- a/src/Backends/ApMonBackend.h +++ b/src/Backends/ApMonBackend.h @@ -56,11 +56,6 @@ class ApMonBackend final : public Backend /// \param metric reference to metric object: void send(const Metric& metric) override; - /// Sends grouped metrics under common measuremet name - /// \param measurement measurement name - /// \param metrics list of metrics - void sendMultiple(std::string measurement, std::vector&& metrics) override; - /// Extends entity value /// \param name tag name (unused) /// \param value tag value that is concatenated to entity string @@ -73,7 +68,7 @@ class ApMonBackend final : public Backend int convertTimestamp(const std::chrono::time_point& timestamp); std::unique_ptr mApMon; ///< ApMon object - std::string entity; ///< MonALISA entity, created out of global tags + std::string mEntity; ///< MonALISA entity, created out of global tags }; } // namespace backends diff --git a/src/Backends/InfluxDB.cxx b/src/Backends/InfluxDB.cxx index 2adccdf34..14f19583d 100644 --- a/src/Backends/InfluxDB.cxx +++ b/src/Backends/InfluxDB.cxx @@ -56,38 +56,6 @@ void InfluxDB::escape(std::string& escaped) boost::replace_all(escaped, " ", "\\ "); } -void InfluxDB::sendMultiple(std::string measurement, std::vector&& metrics) -{ - escape(measurement); - std::stringstream convert; - convert << measurement << "," << tagSet; - for (const auto& [key, value] : metrics.front().getTags()) { - convert << "," << tags::TAG_KEY[key] << "=" << tags::GetValue(value); - } - convert << " "; - - for (const auto& metric : metrics) { - convert << metric.getName() << "="; - std::visit(overloaded{ - [&convert](uint64_t value) { convert << value << 'i'; }, - [&convert](int value) { convert << value << 'i'; }, - [&convert](double value) { convert << value; }, - [&convert](const std::string& value) { convert << '"' << value << '"'; }, - }, - metric.getValue()); - convert << ","; - } - convert.seekp(-1, std::ios_base::end); - if (Metric::includeTimestamp) { - convert << " " << convertTimestamp(metrics.back().getTimestamp()); - } - - try { - mTransport->send(convert.str()); - } catch (MonitoringException&) { - } -} - void InfluxDB::send(std::vector&& metrics) { std::string influxMetrics = ""; @@ -120,16 +88,19 @@ std::string InfluxDB::toInfluxLineProtocol(const Metric& metric) for (const auto& [key, value] : metric.getTags()) { convert << "," << tags::TAG_KEY[key] << "=" << tags::GetValue(value); } - - convert << " value="; - - std::visit(overloaded{ + convert << ' '; + for (const auto& [name, value] : metric.getValues()) { + convert << name << '='; + std::visit(overloaded{ [&convert](uint64_t value) { convert << value << 'i'; }, [&convert](int value) { convert << value << 'i'; }, [&convert](double value) { convert << value; }, [&convert](const std::string& value) { convert << '"' << value << '"'; }, - }, - metric.getValue()); + }, + value); + convert << ','; + } + convert.seekp(-1, std::ios_base::end); if (Metric::includeTimestamp) { convert << " " << convertTimestamp(metric.getTimestamp()); } diff --git a/src/Backends/InfluxDB.h b/src/Backends/InfluxDB.h index 14a1cd586..67150f3cb 100644 --- a/src/Backends/InfluxDB.h +++ b/src/Backends/InfluxDB.h @@ -57,11 +57,6 @@ class InfluxDB final : public Backend /// \@param metrics vector of metrics void send(std::vector&& metrics) override; - /// Sends multiple values in single measurement - /// \param measurement measurement name - /// \param metrics list of metrics - void sendMultiple(std::string measurement, std::vector&& metrics) override; - /// Adds tag /// \param name tag name /// \param value tag value diff --git a/src/Backends/Noop.h b/src/Backends/Noop.h index 57089db93..bf8187760 100644 --- a/src/Backends/Noop.h +++ b/src/Backends/Noop.h @@ -45,10 +45,6 @@ class Noop final : public Backend /// \param metric reference to metric object: void send(const Metric& /*metric*/) final {} - /// \param measurement measurement name - /// \param metrics list of metrics - void sendMultiple(std::string /*measurement*/, std::vector&& /*metrics*/) final {} - /// \param name tag name /// \param value tag value that is concatenated to entity string void addGlobalTag(std::string_view /*name*/, std::string_view /*value*/) final {} diff --git a/src/Backends/StdOut.cxx b/src/Backends/StdOut.cxx index 24a423c7f..b61793608 100644 --- a/src/Backends/StdOut.cxx +++ b/src/Backends/StdOut.cxx @@ -63,36 +63,21 @@ void StdOut::send(std::vector&& metrics) } } -void StdOut::sendMultiple(std::string measurement, std::vector&& metrics) -{ - std::string metricTags{}; - for (const auto& [key, value] : metrics.front().getTags()) { - metricTags += ','; - metricTags += tags::TAG_KEY[key]; - metricTags += "="; - metricTags += tags::GetValue(value); - } - for (auto& metric : metrics) { - auto value = std::visit(overloaded{ - [](const std::string& value) -> std::string { return value; }, - [](auto value) -> std::string { return std::to_string(value); }}, - metric.getValue()); - - mStream << "[" << mPrefix << "] " << measurement << '/' << metric.getName() << ',' << metric.getType() << ' ' - << value << ' ' << convertTimestamp(metric.getTimestamp()) << ' ' << tagString - << metricTags << '\n'; - } -} - void StdOut::send(const Metric& metric) { - auto value = std::visit(overloaded{ - [](const std::string& value) -> std::string { return value; }, - [](auto value) -> std::string { return std::to_string(value); }}, - metric.getValue()); - - mStream << "[" << mPrefix << "] " << metric.getName() << ',' << metric.getType() << " " << value - << ' ' << convertTimestamp(metric.getTimestamp()) << ' ' << tagString; + mStream << "[" << mPrefix << "] " << metric.getName(); + for (auto& value : metric.getValues()) { + auto stringValue = std::visit(overloaded{ + [](const std::string& value) -> std::string { return value; }, + [](auto value) -> std::string { return std::to_string(value); } + }, value.second); + if (metric.getValuesSize() == 1) { + mStream << ",0 " << stringValue; + } else { + mStream << ' ' << value.first << '=' << stringValue; + } + } + mStream << ' ' << convertTimestamp(metric.getTimestamp()) << ' ' << tagString; for (const auto& [key, value] : metric.getTags()) { mStream << ',' << tags::TAG_KEY[key] << "=" << tags::GetValue(value); diff --git a/src/Backends/StdOut.h b/src/Backends/StdOut.h index 5ab68dfdc..417c2a0ad 100644 --- a/src/Backends/StdOut.h +++ b/src/Backends/StdOut.h @@ -46,11 +46,6 @@ class StdOut final : public Backend /// \@param metrics vector of metrics void send(std::vector&& metrics) override; - /// Prints a metric with multiple values (names are prefixed with measurement) - /// \param measurement measurement name - /// \param metrics list of metrics - void sendMultiple(std::string measurement, std::vector&& metrics) override; - /// Adds tag /// \param name tag name /// \param value tag value diff --git a/src/ComplexMetric.cxx b/src/ComplexMetric.cxx deleted file mode 100644 index 448de2e2d..000000000 --- a/src/ComplexMetric.cxx +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file ComplexMetric.cxx -/// \author Adam Wegrzynek -/// - -#include "Monitoring/ComplexMetric.h" - -#include -#include -#include - -namespace o2 -{ -/// ALICE O2 Monitoring system -namespace monitoring -{ - -ComplexMetric::ComplexMetric(int value, const std::string& name) : Metric(value, name) -{ -} - -ComplexMetric::ComplexMetric(std::string value, const std::string& name) : Metric(value, name) -{ -} - -ComplexMetric::ComplexMetric(double value, const std::string& name) : Metric(value, name) -{ -} - -ComplexMetric::ComplexMetric(uint64_t value, const std::string& name) : Metric(value, name) -{ -} - -ComplexMetric::ComplexMetric(std::variant value, const std::string& name) : Metric(value, name) -{ -} - -void ComplexMetric::resetTimestamp() -{ - mTimestamp = Metric::getCurrentTimestamp(); -} - -ComplexMetric& ComplexMetric::operator=(const std::variant& value) -{ - mValue = value; - return *this; -} - -} // namespace monitoring -} // namespace o2 diff --git a/src/DerivedMetrics.cxx b/src/DerivedMetrics.cxx index f4b61c738..b76e3e9d2 100644 --- a/src/DerivedMetrics.cxx +++ b/src/DerivedMetrics.cxx @@ -36,9 +36,9 @@ namespace o2 namespace monitoring { -Metric DerivedMetrics::process(Metric& metric, DerivedMetricMode mode) +void DerivedMetrics::process(Metric& metric, DerivedMetricMode mode) { - const std::map> map = { + const std::map> map = { {DerivedMetricMode::INCREMENT, [this](Metric& metric) { auto tags = metric.getTags(); std::string key = metric.getName(); @@ -47,33 +47,30 @@ Metric DerivedMetrics::process(Metric& metric, DerivedMetricMode mode) }); auto search = mStorage.find(key); if (search != mStorage.end()) { - auto currentValue = metric.getValue(); - auto storedValue = search->second.getValue(); + auto currentValue = metric.getFirstValue().second; + auto storedValue = search->second.getValues().back().second; auto value = std::visit(VariantVisitorAdd{}, currentValue, storedValue); mStorage.erase(search); - Metric result = Metric{value, metric.getName() + "Increment", metric.getVerbosity()}.setTags(std::move(tags)); - mStorage.insert(std::make_pair(key, result)); - return result; + metric.addValue(value, metric.getFirstValue().first + "_increment"); + } else { + metric.addValue(metric.getFirstValue().second, metric.getFirstValue().first + "_increment"); } mStorage.insert(std::make_pair(key, metric)); - return metric; }}, {DerivedMetricMode::RATE, [this](Metric& metric) { - // disallow string + /// create pseudo unique key auto tags = metric.getTags(); std::string key = metric.getName(); std::for_each(tags.begin(), tags.end(), [&key](auto const& pair) { key += pair.second; }); - if (metric.getType() == MetricType::STRING) { - throw MonitoringException("DerivedMetrics", "Not able to process string values"); - } // search for previous value auto search = mStorage.find(key); if (search == mStorage.end()) { mStorage.insert(std::make_pair(key, metric)); - return Metric{(double)0.0, metric.getName() + "Rate", metric.getVerbosity()}.setTags(std::move(tags)); + metric.addValue((double)0.0, metric.getFirstValue().first + "_rate"); + return; } auto timestampDifference = std::chrono::duration_cast( @@ -84,15 +81,15 @@ Metric DerivedMetrics::process(Metric& metric, DerivedMetricMode mode) throw MonitoringException("DerivedMetrics", "Division by 0"); } - auto current = metric.getValue(); - auto previous = search->second.getValue(); + auto current = metric.getFirstValue().second; + auto previous = search->second.getFirstValue().second; auto rate = std::visit(VariantVisitorRate(timestampCount), current, previous); // handle situation when a new run starts auto isZero = std::visit(overloaded{ - [](auto arg) { return arg == 0; }, - [](const std::string& arg) { return arg == ""; }}, - current); + [](auto arg) { return arg == 0; }, + [](const std::string& arg) { return arg == ""; } + }, current); if (rate < 0 && isZero) { rate = 0; } @@ -100,13 +97,14 @@ Metric DerivedMetrics::process(Metric& metric, DerivedMetricMode mode) // swap metrics mStorage.erase(key); mStorage.insert(std::make_pair(key, metric)); - return Metric{rate, metric.getName() + "Rate", metric.getVerbosity()}.setTags(std::move(tags)); + // add rate field + metric.addValue(rate, metric.getFirstValue().first + "_rate"); }}}; auto iterator = map.find(mode); if (iterator == map.end()) { throw MonitoringException("DerivedMetrics", "Unknown mode"); } - return iterator->second(metric); + iterator->second(metric); } } // namespace monitoring diff --git a/src/Metric.cxx b/src/Metric.cxx index 5565652ec..3775881ac 100644 --- a/src/Metric.cxx +++ b/src/Metric.cxx @@ -30,52 +30,66 @@ std::chrono::time_point Metric::getTimestamp() const return mTimestamp; } -/// This is required for backward compability with boost::variant -int Metric::getType() const -{ - if (std::holds_alternative(mValue)) - return 0; - else if (std::holds_alternative(mValue)) - return 1; - else if (std::holds_alternative(mValue)) - return 2; - else - return 3; -} - const std::string& Metric::getName() const { return mName; } -Metric::Metric(int value, const std::string& name, Verbosity verbosity) : mValue(value), mName(name), mTimestamp(Metric::getCurrentTimestamp()), mVerbosity(verbosity) +Metric::Metric(int value, const std::string& name, Verbosity verbosity) : mName(name), mTimestamp(Metric::getCurrentTimestamp()), mVerbosity(verbosity) { overwriteVerbosity(); + addValue(value, Metric::mDefaultValueName); } -Metric::Metric(std::string value, const std::string& name, Verbosity verbosity) : mValue(value), mName(name), mTimestamp(Metric::getCurrentTimestamp()), mVerbosity(verbosity) +Metric::Metric(std::string value, const std::string& name, Verbosity verbosity) : mName(name), mTimestamp(Metric::getCurrentTimestamp()), mVerbosity(verbosity) { overwriteVerbosity(); + addValue(value, Metric::mDefaultValueName); } -Metric::Metric(double value, const std::string& name, Verbosity verbosity) : mValue(value), mName(name), mTimestamp(Metric::getCurrentTimestamp()), mVerbosity(verbosity) +Metric::Metric(double value, const std::string& name, Verbosity verbosity) : mName(name), mTimestamp(Metric::getCurrentTimestamp()), mVerbosity(verbosity) { overwriteVerbosity(); + addValue(value, Metric::mDefaultValueName); } -Metric::Metric(uint64_t value, const std::string& name, Verbosity verbosity) : mValue(value), mName(name), mTimestamp(Metric::getCurrentTimestamp()), mVerbosity(verbosity) +Metric::Metric(uint64_t value, const std::string& name, Verbosity verbosity) : mName(name), mTimestamp(Metric::getCurrentTimestamp()), mVerbosity(verbosity) { overwriteVerbosity(); + addValue(value, Metric::mDefaultValueName); } -Metric::Metric(std::variant value, const std::string& name, Verbosity verbosity) : mValue(value), mName(name), mTimestamp(Metric::getCurrentTimestamp()), mVerbosity(verbosity) +Metric&& Metric::addValue(int value, const std::string& name) { - overwriteVerbosity(); + mValues.push_back({name, value}); + return std::move(*this); +} +Metric&& Metric::addValue(double value, const std::string& name) +{ + mValues.push_back({name, value}); + return std::move(*this); +} +Metric&& Metric::addValue(uint64_t value, const std::string& name) +{ + mValues.push_back({name, value}); + return std::move(*this); +} + +Metric&& Metric::addValue(std::string value, const std::string& name) +{ + mValues.push_back({name, value}); + return std::move(*this); +} + +Metric&& Metric::addValue(const std::variant& value, const std::string& name) +{ + mValues.push_back({name, value}); + return std::move(*this); } -std::variant Metric::getValue() const +Metric::Metric(const std::string& name, Verbosity verbosity) : mName(name), mTimestamp(Metric::getCurrentTimestamp()), mVerbosity(verbosity) { - return mValue; + overwriteVerbosity(); } Verbosity Metric::getVerbosity() @@ -97,12 +111,6 @@ void Metric::overwriteVerbosity() } } -Metric& Metric::operator=(const std::variant& value) -{ - mValue = value; - return *this; -} - Metric&& Metric::addTag(tags::Key key, tags::Value value) { mTags.push_back({static_cast::type>(key), static_cast::type>(value)}); @@ -136,6 +144,21 @@ void Metric::setDefaultVerbosity(Verbosity verbosity) Metric::DefaultVerbosity = verbosity; } +const std::vector>>& Metric::getValues() const +{ + return mValues; +} + +const std::pair>& Metric::getFirstValue() const +{ + return mValues.front(); +} + +std::size_t Metric::getValuesSize() const noexcept +{ + return mValues.size(); +} + bool Metric::includeTimestamp = true; Verbosity Metric::DefaultVerbosity = Verbosity::Info; std::map::type, std::regex> Metric::mRegexPolicy; diff --git a/src/Monitoring.cxx b/src/Monitoring.cxx index cce8ea082..d6dc7bc50 100644 --- a/src/Monitoring.cxx +++ b/src/Monitoring.cxx @@ -39,7 +39,7 @@ Monitoring::Monitoring() mDerivedHandler = std::make_unique(); mBuffering = false; mProcessMonitoringInterval = 0; - mAutoPushInterval = 0; + //mAutoPushInterval = 0; mMonitorRunning = false; } @@ -140,20 +140,20 @@ void Monitoring::pushLoop() #endif } - if (mAutoPushInterval != 0 && (loopCount % (mAutoPushInterval * 10)) == 0) { + /*if (mAutoPushInterval != 0 && (loopCount % (mAutoPushInterval * 10)) == 0) { std::vector metrics; for (auto metric : mPushStore) { metric.resetTimestamp(); metrics.push_back(metric); } transmit(std::move(metrics)); - } + }*/ std::this_thread::sleep_for(std::chrono::milliseconds(100)); (loopCount >= 600) ? loopCount = 0 : loopCount++; } } -ComplexMetric& Monitoring::getAutoPushMetric(std::string name, unsigned int interval) +/*ComplexMetric& Monitoring::getAutoPushMetric(std::string name, unsigned int interval) { if (!mMonitorRunning) { mMonitorRunning = true; @@ -162,16 +162,7 @@ ComplexMetric& Monitoring::getAutoPushMetric(std::string name, unsigned int inte } mPushStore.emplace_back(std::variant{}, name); return mPushStore.back(); -} - -void Monitoring::sendGrouped(std::string measurement, std::vector&& metrics, Verbosity verbosity) -{ - for (auto& backend : mBackends) { - if (matchVerbosity(backend->getVerbosity(), verbosity)) { - backend->sendMultiple(measurement, std::move(metrics)); - } - } -} +}*/ void Monitoring::transmit(std::vector&& metrics) { @@ -201,7 +192,8 @@ void Monitoring::send(Metric&& metric, DerivedMetricMode mode) { if (mode != DerivedMetricMode::NONE) { try { - transmit(mDerivedHandler->process(metric, mode)); + mDerivedHandler->process(metric, mode); + transmit(std::move(metric)); } catch (MonitoringException& e) { MonLogger::Get() << e.what() << MonLogger::End(); } diff --git a/test/testApMon.cxx b/test/testApMon.cxx index 577a6488d..d81d3bc25 100644 --- a/test/testApMon.cxx +++ b/test/testApMon.cxx @@ -32,6 +32,7 @@ BOOST_AUTO_TEST_CASE(simplySendMetric) boost::filesystem::path configPath = boost::filesystem::canonical("."); auto monitoring = MonitoringFactory::Get("apmon://" + configPath.string() + "/ApMon.conf"); monitoring->send({10, "myCrazyMetric"}); + monitoring->send(Metric{20, "myCrazyMetric"}.addValue(6, "another_value")); } } // namespace Test diff --git a/test/testDerived.cxx b/test/testDerived.cxx index fca73a867..beee4b35c 100644 --- a/test/testDerived.cxx +++ b/test/testDerived.cxx @@ -42,9 +42,10 @@ BOOST_AUTO_TEST_CASE(derivedRateInt) try { std::this_thread::sleep_for(std::chrono::milliseconds(100)); o2::monitoring::Metric metric(result.value, name); - o2::monitoring::Metric derived = derivedHandler.process(metric, DerivedMetricMode::RATE); - BOOST_CHECK_EQUAL(derived.getName(), "metricIntRate"); - BOOST_WARN_CLOSE(std::get(derived.getValue()), result.rate, 1.0); + derivedHandler.process(metric, DerivedMetricMode::RATE); + BOOST_CHECK_EQUAL(metric.getName(), "metricInt"); + BOOST_CHECK_EQUAL(metric.getValues().back().first, "value_rate"); + BOOST_WARN_CLOSE(std::get(metric.getValues().back().second), result.rate, 1.0); } catch (MonitoringException& e) { BOOST_CHECK_EQUAL(e.what(), std::string("Not enough values")); } @@ -65,9 +66,10 @@ BOOST_AUTO_TEST_CASE(derivedRateInt_newRun) try { std::this_thread::sleep_for(std::chrono::milliseconds(100)); o2::monitoring::Metric metric(result.value, name); - o2::monitoring::Metric derived = derivedHandler.process(metric, DerivedMetricMode::RATE); - BOOST_CHECK_EQUAL(derived.getName(), "metricIntRate"); - BOOST_WARN_CLOSE(std::get(derived.getValue()), result.rate, 1.0); + derivedHandler.process(metric, DerivedMetricMode::RATE); + BOOST_CHECK_EQUAL(metric.getName(), "metricInt"); + BOOST_CHECK_EQUAL(metric.getValues().back().first, "value_rate"); + BOOST_WARN_CLOSE(std::get(metric.getValues().back().second), result.rate, 1.0); } catch (MonitoringException& e) { BOOST_CHECK_EQUAL(e.what(), std::string("Not enough values")); } @@ -89,11 +91,13 @@ BOOST_AUTO_TEST_CASE(derivedRateDouble) std::this_thread::sleep_for(std::chrono::milliseconds(100)); o2::monitoring::Metric metric(results[i].value, name); o2::monitoring::Metric metricTagged = Metric{resultsTagged[i].value, name}.addTag(o2::monitoring::tags::Key::Subsystem, o2::monitoring::tags::Value::Readout); - o2::monitoring::Metric derived = derivedHandler.process(metric, DerivedMetricMode::RATE); - o2::monitoring::Metric derivedTagged = derivedHandler.process(metricTagged, DerivedMetricMode::RATE); - BOOST_CHECK_EQUAL(derived.getName(), "metricDoubleRate"); - BOOST_WARN_CLOSE(std::get(derived.getValue()), results[i].rate, 1.0); - BOOST_WARN_CLOSE(std::get(derivedTagged.getValue()), resultsTagged[i].rate, 1.0); + derivedHandler.process(metric, DerivedMetricMode::RATE); + derivedHandler.process(metricTagged, DerivedMetricMode::RATE); + BOOST_CHECK_EQUAL(metric.getName(), "metricDouble"); + BOOST_WARN_CLOSE(std::get(metric.getValues().back().second), results[i].rate, 1.0); + BOOST_CHECK_EQUAL(metric.getValues().back().first, "value_rate"); + BOOST_WARN_CLOSE(std::get(metricTagged.getValues().back().second), resultsTagged[i].rate, 1.0); + BOOST_CHECK_EQUAL(metricTagged.getValues().back().first, "value_rate"); } catch (MonitoringException& e) { BOOST_CHECK_EQUAL(e.what(), std::string("Not enough values")); } @@ -114,9 +118,10 @@ BOOST_AUTO_TEST_CASE(derivedRateUint64_t) try { std::this_thread::sleep_for(std::chrono::milliseconds(100)); o2::monitoring::Metric metric(result.value, name); - o2::monitoring::Metric derived = derivedHandler.process(metric, DerivedMetricMode::RATE); - BOOST_CHECK_EQUAL(derived.getName(), "metricUint64_tRate"); - BOOST_WARN_CLOSE(std::get(derived.getValue()), result.rate, 1.0); + derivedHandler.process(metric, DerivedMetricMode::RATE); + BOOST_CHECK_EQUAL(metric.getName(), "metricUint64_t"); + BOOST_CHECK_EQUAL(metric.getValues().back().first, "value_rate"); + BOOST_WARN_CLOSE(std::get(metric.getValues().back().second), result.rate, 1.0); } catch (MonitoringException& e) { BOOST_CHECK_EQUAL(e.what(), std::string("Not enough values")); } @@ -146,15 +151,16 @@ BOOST_AUTO_TEST_CASE(derivedIncrementInt) { struct IncrementResults { int value; - int rate; + int increment; }; std::vector results = {{10, 10}, {20, 30}, {30, 60}, {50, 110}, {60, 170}, {65, 235}, {70, 305}, {80, 385}, {90, 475}, {100, 575}}; o2::monitoring::DerivedMetrics derivedHandler; std::string name("metricInt"); for (auto const result : results) { o2::monitoring::Metric metric(result.value, name); - o2::monitoring::Metric derived = derivedHandler.process(metric, DerivedMetricMode::INCREMENT); - BOOST_CHECK_EQUAL(std::get(derived.getValue()), result.rate); + derivedHandler.process(metric, DerivedMetricMode::INCREMENT); + BOOST_CHECK_EQUAL(std::get(metric.getValues().back().second), result.increment); + BOOST_CHECK_EQUAL(metric.getValues().back().first, "value_increment"); } } @@ -169,8 +175,9 @@ BOOST_AUTO_TEST_CASE(derivedIncrementUint64_t) std::string name("metricUint64_t"); for (auto const result : results) { o2::monitoring::Metric metric(result.value, name); - o2::monitoring::Metric derived = derivedHandler.process(metric, DerivedMetricMode::INCREMENT); - BOOST_CHECK_EQUAL(std::get(derived.getValue()), result.rate); + derivedHandler.process(metric, DerivedMetricMode::INCREMENT); + BOOST_CHECK_EQUAL(std::get(metric.getValues().back().second), result.rate); + BOOST_CHECK_EQUAL(metric.getValues().back().first, "value_increment"); } } @@ -185,8 +192,9 @@ BOOST_AUTO_TEST_CASE(derivedIncrementDouble) std::string name("metricDouble"); for (auto const result : results) { o2::monitoring::Metric metric(result.value, name); - o2::monitoring::Metric derived = derivedHandler.process(metric, DerivedMetricMode::INCREMENT); - BOOST_CHECK_CLOSE(std::get(derived.getValue()), result.rate, 0.01); + derivedHandler.process(metric, DerivedMetricMode::INCREMENT); + BOOST_CHECK_CLOSE(std::get(metric.getValues().back().second), result.rate, 0.01); + BOOST_CHECK_EQUAL(metric.getValues().back().first, "value_increment"); } } diff --git a/test/testMetric.cxx b/test/testMetric.cxx index a734b95db..2b94107db 100644 --- a/test/testMetric.cxx +++ b/test/testMetric.cxx @@ -19,7 +19,6 @@ BOOST_AUTO_TEST_CASE(retrieveOtherParams) { int value = 10; Metric metricInstance(value, "metric name"); - BOOST_CHECK_EQUAL(metricInstance.getName(), "metric name"); } @@ -28,6 +27,11 @@ BOOST_AUTO_TEST_CASE(constCharName) const char* name = "a name"; Metric metricInstance(10, name); BOOST_CHECK_EQUAL(metricInstance.getName(), "a name"); + BOOST_CHECK_EQUAL(metricInstance.getFirstValue().first, "value"); + Metric metricInstance2("metric name"); + metricInstance2.addValue(10, name); + BOOST_CHECK_EQUAL(metricInstance2.getName(), "metric name"); + BOOST_CHECK_EQUAL(metricInstance2.getFirstValue().first, "a name"); } BOOST_AUTO_TEST_CASE(retrieveInt) @@ -36,38 +40,55 @@ BOOST_AUTO_TEST_CASE(retrieveInt) std::string name("metric name"); Metric metricInstance(value, name); - BOOST_CHECK_EQUAL(std::get(metricInstance.getValue()), 10); - BOOST_CHECK_EQUAL(metricInstance.getType(), 0); + BOOST_CHECK_EQUAL(std::get(metricInstance.getFirstValue().second), 10); + BOOST_CHECK_EQUAL(metricInstance.getFirstValue().first, "value"); + BOOST_CHECK(std::holds_alternative(metricInstance.getFirstValue().second)); } BOOST_AUTO_TEST_CASE(retrieveDouble) { double value = 1.11; + double value2 = 2.22; std::string name("metric name"); Metric metricInstance(value, name); - - BOOST_CHECK_EQUAL(std::get(metricInstance.getValue()), 1.11); - BOOST_CHECK_EQUAL(metricInstance.getType(), 2); + BOOST_CHECK_EQUAL(std::get(metricInstance.getFirstValue().second), 1.11); + BOOST_CHECK_EQUAL(metricInstance.getFirstValue().first, "value"); + BOOST_CHECK(std::holds_alternative(metricInstance.getFirstValue().second)); + metricInstance.addValue(value2, "double"); + BOOST_CHECK_EQUAL(metricInstance.getValues().back().first, "double"); + BOOST_CHECK(std::holds_alternative(metricInstance.getValues().back().second)); + BOOST_CHECK_EQUAL(std::get(metricInstance.getValues().back().second), 2.22); } BOOST_AUTO_TEST_CASE(retrieveString) { std::string value = "testString"; + std::string value2 = "testString2"; std::string name("metric name"); Metric metricInstance(value, name); - BOOST_CHECK_EQUAL(std::get(metricInstance.getValue()), "testString"); - BOOST_CHECK_EQUAL(metricInstance.getType(), 1); + BOOST_CHECK_EQUAL(std::get(metricInstance.getFirstValue().second), "testString"); + BOOST_CHECK_EQUAL(metricInstance.getFirstValue().first, "value"); + BOOST_CHECK(std::holds_alternative(metricInstance.getFirstValue().second)); + metricInstance.addValue(value2, "string"); + BOOST_CHECK_EQUAL(metricInstance.getValues().back().first, "string"); + BOOST_CHECK(std::holds_alternative(metricInstance.getValues().back().second)); + BOOST_CHECK_EQUAL(std::get(metricInstance.getValues().back().second), "testString2"); } BOOST_AUTO_TEST_CASE(retrieveUnsignedLongLong) { uint64_t value = 10000000000000LL; + uint64_t value2 = 10000000000001LL; std::string name("metric name"); Metric metricInstance(value, name); - - BOOST_CHECK_EQUAL(std::get(metricInstance.getValue()), 10000000000000LL); - BOOST_CHECK_EQUAL(metricInstance.getType(), 3); + BOOST_CHECK_EQUAL(std::get(metricInstance.getFirstValue().second), 10000000000000LL); + BOOST_CHECK_EQUAL(metricInstance.getFirstValue().first, "value"); + BOOST_CHECK(std::holds_alternative(metricInstance.getFirstValue().second)); + metricInstance.addValue(value2, "uint64_t"); + BOOST_CHECK_EQUAL(metricInstance.getValues().back().first, "uint64_t"); + BOOST_CHECK(std::holds_alternative(metricInstance.getValues().back().second)); + BOOST_CHECK_EQUAL(std::get(metricInstance.getValues().back().second), 10000000000001LL); } bool is_critical(const std::bad_variant_access&) { return true; } @@ -77,7 +98,7 @@ BOOST_AUTO_TEST_CASE(retrieveWrongType) double value = 1.11; std::string name("metric name"); o2::monitoring::Metric metricInstance(value, name); - BOOST_CHECK_EXCEPTION(std::get(metricInstance.getValue()), std::bad_variant_access, is_critical); + BOOST_CHECK_EXCEPTION(std::get(metricInstance.getFirstValue().second), std::bad_variant_access, is_critical); } BOOST_AUTO_TEST_CASE(tags) diff --git a/test/testMonitoring.cxx b/test/testMonitoring.cxx index 01f8bebbf..1960a5d48 100644 --- a/test/testMonitoring.cxx +++ b/test/testMonitoring.cxx @@ -53,17 +53,6 @@ BOOST_AUTO_TEST_CASE(buffering) monitoring->flushBuffer(); } -BOOST_AUTO_TEST_CASE(testPush) -{ - auto monitoring = Monitoring::Get("stdout://"); - auto& qcMetric = monitoring->getAutoPushMetric("qcMetric"); - auto& qcMetric2 = monitoring->getAutoPushMetric("qcMetric2"); - std::this_thread::sleep_for(std::chrono::milliseconds(1500)); - qcMetric = 133 + 11 + 2.2; - qcMetric2 = 133 - 11 - 2.2; - std::this_thread::sleep_for(std::chrono::milliseconds(1500)); -} - BOOST_AUTO_TEST_CASE(testSymbols) { BOOST_WARN_MESSAGE(!BOOST_IS_DEFINED(O2_MONITORING_WITH_APPMON), "ApMon Backend disabled");