Skip to content

Commit 47907b3

Browse files
authored
[OMON-501] Add suppress mode to avoid sending same value over again (#270)
1 parent 80b28f0 commit 47907b3

File tree

6 files changed

+112
-12
lines changed

6 files changed

+112
-12
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ send(Metric&& metric, [DerivedMetricMode mode])
142142
Two modes are available:
143143
+ `DerivedMetricMode::RATE` - rate between two following values,
144144
+ `DerivedMetricMode::INCREMENT` - sum of all passed values.
145+
+ `DerivedMetricMode::SUPPRESS` - suppresses forthcoming metric with same value, this happens until timeout is reached (configurable using `DerivedMetrics::mSuppressTimeout`)
145146
146147
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.
147148

examples/4-RateDerivedMetric.cxx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,17 @@ int main()
1414
auto monitoring = MonitoringFactory::Get("stdout://");
1515

1616
// now send at least two metrics to see the result
17-
for (int i = 0; i < 101; i += 10) {
17+
for (int i = 0; i < 41; i += 10) {
1818
monitoring->send(Metric{i, "myMetric"}.addTag(tags::Key::Subsystem, tags::Value::Readout), DerivedMetricMode::RATE);
1919
std::this_thread::sleep_for(std::chrono::milliseconds(100));
2020
}
21+
22+
// present "suppress" mode
23+
for (int i = 0; i < 10; i++) {
24+
monitoring->send(Metric{1, "slowMetric"}, DerivedMetricMode::SUPPRESS); // only 1 should be displayed
25+
}
26+
DerivedMetrics::mSuppressTimeout = std::chrono::seconds(1); // change timeout to 1 s
27+
monitoring->send(Metric{2, "slowMetric"}, DerivedMetricMode::SUPPRESS); // value changes
28+
std::this_thread::sleep_for(std::chrono::seconds(1));
29+
monitoring->send(Metric{2, "slowMetric"}, DerivedMetricMode::SUPPRESS); // timeout reached !
2130
}

include/Monitoring/DerivedMetrics.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#ifndef ALICEO2_MONITORING_CORE_DERIVED_METRICS_H
1818
#define ALICEO2_MONITORING_CORE_DERIVED_METRICS_H
1919

20+
#include <chrono>
2021
#include <unordered_map>
2122
#include <memory>
2223
#include <string>
@@ -33,7 +34,8 @@ namespace monitoring
3334
/// Available derived metric modes
3435
enum class DerivedMetricMode { RATE,
3536
INCREMENT,
36-
NONE };
37+
NONE,
38+
SUPPRESS };
3739

3840
/// \brief Enables Calculation of derived metrics
3941
///
@@ -48,12 +50,14 @@ class DerivedMetrics
4850
/// Default destructor
4951
~DerivedMetrics() = default;
5052

51-
/// Metrics store necessary for derived metrics
52-
std::unordered_map<std::string, Metric> mStorage;
53-
5453
/// Entry method to DerivedMetrics
5554
/// Switches over processing modes: rate and increment
56-
void process(Metric& metric, DerivedMetricMode mode);
55+
bool process(Metric& metric, DerivedMetricMode mode);
56+
57+
static std::chrono::seconds mSuppressTimeout;
58+
private:
59+
/// Metrics store necessary for derived metrics
60+
std::unordered_map<std::string, Metric> mStorage;
5761
};
5862

5963
} // namespace monitoring

src/DerivedMetrics.cxx

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ namespace o2
3737
namespace monitoring
3838
{
3939

40-
void DerivedMetrics::process(Metric& metric, DerivedMetricMode mode)
40+
bool DerivedMetrics::process(Metric& metric, DerivedMetricMode mode)
4141
{
42-
const std::map<DerivedMetricMode, std::function<void(Metric&)>> map = {
42+
const std::map<DerivedMetricMode, std::function<bool(Metric&)>> map = {
4343
{DerivedMetricMode::INCREMENT, [this](Metric& metric) {
4444
auto tags = metric.getTags();
4545
std::string key = metric.getName();
@@ -57,6 +57,7 @@ void DerivedMetrics::process(Metric& metric, DerivedMetricMode mode)
5757
metric.addValue(metric.getFirstValue().second, metric.getFirstValue().first + "_increment");
5858
}
5959
mStorage.insert(std::make_pair(key, metric));
60+
return true;
6061
}},
6162
{DerivedMetricMode::RATE, [this](Metric& metric) {
6263
/// create pseudo unique key
@@ -71,7 +72,7 @@ void DerivedMetrics::process(Metric& metric, DerivedMetricMode mode)
7172
if (search == mStorage.end()) {
7273
mStorage.insert(std::make_pair(key, metric));
7374
metric.addValue((double)0.0, metric.getFirstValue().first + "_rate");
74-
return;
75+
return true;
7576
}
7677

7778
auto timestampDifference = std::chrono::duration_cast<std::chrono::milliseconds>(
@@ -100,13 +101,41 @@ void DerivedMetrics::process(Metric& metric, DerivedMetricMode mode)
100101
mStorage.insert(std::make_pair(key, metric));
101102
// add rate field
102103
metric.addValue(rate, metric.getFirstValue().first + "_rate");
103-
}}};
104+
return true;
105+
}},
106+
{DerivedMetricMode::SUPPRESS, [this](Metric& metric) {
107+
auto tags = metric.getTags();
108+
std::string key = metric.getName();
109+
std::for_each(tags.begin(), tags.end(), [&key](auto const& pair) {
110+
key += pair.second;
111+
});
112+
113+
// if no previous values -> store and send
114+
auto search = mStorage.find(key);
115+
if (search == mStorage.end()) {
116+
mStorage.insert(std::make_pair(key, metric));
117+
return true;
118+
}
119+
// if same values and timeout not reached -> skip
120+
if (metric.getFirstValue().second == search->second.getFirstValue().second
121+
&& std::chrono::duration_cast<std::chrono::seconds>(
122+
metric.getTimestamp() - search->second.getTimestamp()
123+
) < std::chrono::seconds(DerivedMetrics::mSuppressTimeout)) {
124+
return false;
125+
}
126+
mStorage.erase(key);
127+
mStorage.insert(std::make_pair(key, metric));
128+
return true;
129+
}}
130+
};
104131
auto iterator = map.find(mode);
105132
if (iterator == map.end()) {
106133
throw MonitoringException("DerivedMetrics", "Unknown mode");
107134
}
108-
iterator->second(metric);
135+
return iterator->second(metric);
109136
}
110137

138+
std::chrono::seconds DerivedMetrics::mSuppressTimeout{300};
139+
111140
} // namespace monitoring
112141
} // namespace o2

src/Monitoring.cxx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,9 @@ void Monitoring::send(Metric&& metric, DerivedMetricMode mode)
180180
{
181181
if (mode != DerivedMetricMode::NONE) {
182182
try {
183-
mDerivedHandler->process(metric, mode);
183+
if (!mDerivedHandler->process(metric, mode)) {
184+
return;
185+
}
184186
} catch (MonitoringException& e) {
185187
MonLogger::Get() << e.what() << MonLogger::End();
186188
}

test/testDerived.cxx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,61 @@ BOOST_AUTO_TEST_CASE(derivedIncrementDouble)
220220
}
221221
}
222222

223+
BOOST_AUTO_TEST_CASE(suppressSimple)
224+
{
225+
DerivedMetrics derivedHandler;
226+
Metric m1{3, "metricInt"};
227+
BOOST_CHECK(derivedHandler.process(m1, DerivedMetricMode::SUPPRESS));
228+
Metric m2{3, "metricInt"};
229+
BOOST_CHECK(!derivedHandler.process(m2, DerivedMetricMode::SUPPRESS));
230+
Metric m3{4, "metricInt"};
231+
BOOST_CHECK(derivedHandler.process(m3, DerivedMetricMode::SUPPRESS));
232+
Metric m4{4, "metricInt"};
233+
BOOST_CHECK(!derivedHandler.process(m4, DerivedMetricMode::SUPPRESS));
234+
}
235+
236+
BOOST_AUTO_TEST_CASE(suppressTag)
237+
{
238+
DerivedMetrics derivedHandler;
239+
Metric metric{3, "metricInt"};
240+
metric.addTag(o2::monitoring::tags::Key::Subsystem, o2::monitoring::tags::Value::Readout);
241+
Metric metric2{3, "metricInt"};
242+
metric2.addTag(o2::monitoring::tags::Key::Subsystem, o2::monitoring::tags::Value::DPL);
243+
BOOST_CHECK(derivedHandler.process(metric, DerivedMetricMode::SUPPRESS));
244+
BOOST_CHECK(derivedHandler.process(metric2, DerivedMetricMode::SUPPRESS));
245+
BOOST_CHECK(!derivedHandler.process(metric, DerivedMetricMode::SUPPRESS));
246+
BOOST_CHECK(!derivedHandler.process(metric, DerivedMetricMode::SUPPRESS));
247+
}
248+
249+
BOOST_AUTO_TEST_CASE(suppressTimeout)
250+
{
251+
252+
DerivedMetrics::mSuppressTimeout = std::chrono::seconds(200);
253+
DerivedMetrics derivedHandler;
254+
Metric m1{3, "metricInt"};
255+
BOOST_CHECK(derivedHandler.process(m1, DerivedMetricMode::SUPPRESS));
256+
257+
auto timestamp = std::chrono::system_clock::now();
258+
timestamp += std::chrono::seconds(150);
259+
Metric m2("metricInt", Metric::DefaultVerbosity, timestamp);
260+
m2.addValue(3, "value");
261+
BOOST_CHECK(!derivedHandler.process(m2, DerivedMetricMode::SUPPRESS));
262+
263+
timestamp += std::chrono::seconds(60);
264+
Metric m3("metricInt", Metric::DefaultVerbosity, timestamp);
265+
m3.addValue(3, "value");
266+
BOOST_CHECK(derivedHandler.process(m3, DerivedMetricMode::SUPPRESS));
267+
268+
timestamp += std::chrono::seconds(60);
269+
Metric m4("metricInt", Metric::DefaultVerbosity, timestamp);
270+
m4.addValue(3, "value");
271+
BOOST_CHECK(!derivedHandler.process(m4, DerivedMetricMode::SUPPRESS));
272+
273+
Metric m5("metricInt", Metric::DefaultVerbosity, timestamp);
274+
m5.addValue(4, "value");
275+
BOOST_CHECK(derivedHandler.process(m5, DerivedMetricMode::SUPPRESS));
276+
}
277+
223278
BOOST_AUTO_TEST_CASE(testBoostVisitor)
224279
{
225280
{

0 commit comments

Comments
 (0)