Skip to content

Commit 3af3d2d

Browse files
authored
Sending multiple metrics (values) in a single measurement (#15)
1 parent 2ad7a98 commit 3af3d2d

File tree

9 files changed

+124
-17
lines changed

9 files changed

+124
-17
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ set(EXAMPLES
164164
examples/5-Benchmark.cxx
165165
examples/6-DedicatedInstance.cxx
166166
examples/7-Latency.cxx
167+
examples/8-Multiple.cxx
167168
)
168169

169170
foreach (example ${EXAMPLES})

examples/5-Benchmark.cxx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ int main(int argc, char *argv[]) {
2525
("config", boost::program_options::value<std::string>()->required(), "Config file path")
2626
("id", boost::program_options::value<std::string>(), "Instance ID")
2727
("count", boost::program_options::value<int>(), "Number of metric bunches (x3)")
28+
("multiple", boost::program_options::bool_switch()->default_value(false), "Sends multiple metrics per measurement")
2829
;
2930

3031
boost::program_options::variables_map vm;
@@ -52,10 +53,21 @@ int main(int argc, char *argv[]) {
5253
add = 1;
5354
}
5455

55-
for (int i = 0; i <= count; i += add) {
56-
Monitoring::Get().send({"string" + std::to_string(intDist(mt)), "stringMetric"});
57-
Monitoring::Get().send({doubleDist(mt), "doubleMetric"});
58-
Monitoring::Get().send({intDist(mt), "intMetric"});
59-
std::this_thread::sleep_for(std::chrono::microseconds(sleep));
56+
if (!vm["multiple"].as<bool>()) {
57+
for (int i = 0; i <= count; i += add) {
58+
Monitoring::Get().send({"string" + std::to_string(intDist(mt)), "stringMetric"});
59+
Monitoring::Get().send({doubleDist(mt), "doubleMetric"});
60+
Monitoring::Get().send({intDist(mt), "intMetric"});
61+
std::this_thread::sleep_for(std::chrono::microseconds(sleep));
62+
}
63+
} else {
64+
for (int i = 0; i <= count; i += add) {
65+
Monitoring::Get().send("benchmarkMeasurement",{
66+
{"string" + std::to_string(intDist(mt)), "stringMetric"},
67+
{doubleDist(mt), "doubleMetric"},
68+
{intDist(mt), "intMetric"}
69+
});
70+
std::this_thread::sleep_for(std::chrono::microseconds(sleep));
71+
}
6072
}
6173
}

examples/8-Multiple.cxx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
///
2+
/// \file 8-Multiple.cxx
3+
/// \author Adam Wegrzynek <[email protected]>
4+
///
5+
6+
#include "ExampleBoilerplate.cxx"
7+
#include "Monitoring/MonitoringFactory.h"
8+
9+
using Monitoring = AliceO2::Monitoring::MonitoringFactory;
10+
11+
int main(int argc, char *argv[]) {
12+
13+
// configure monitoring (once per process), pass configuration path as parameter
14+
Monitoring::Configure("file://" + GetConfigFromCmdLine(argc, argv));
15+
16+
Monitoring::Get().send("measurementName", {{10, "myMetricInt"}, {10.10, "myMetricFloat"}});
17+
}

include/Monitoring/Collector.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,13 @@ class Collector
5656
/// Sends a metric to all avaliabes backends
5757
/// If metric has been added to DerivedMetric the derived metric is calculated (see addDerivedMetric method)
5858
/// \param metric r-value to metric object
59-
void send(Metric&& metric);
59+
void send(Metric&& metric, std::size_t skipBackend = -1);
60+
61+
/// Sends multiple metrics to as a single measurement
62+
/// If it's not supported by backend it fallbacks into sending multiple metrics
63+
/// \param name measurement name
64+
/// \param metrics list of metrics
65+
void send(std::string name, std::vector<Metric>&& metrics);
6066

6167
/// Sends a metric with tagset to all avaliabes backends
6268
/// If metric has been added to DerivedMetric the derived metric is calculated (see addDerivedMetric method)

include/Monitoring/Metric.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ class Metric
6161
/// \return metric name
6262
std::string getName() const;
6363

64+
/// Name setter
65+
/// \param new name of the metric
66+
void setName(std::string name);
67+
6468
/// Timestamp getter
6569
/// \return metric timestamp
6670
std::chrono::time_point<std::chrono::system_clock> getTimestamp() const;

src/Backends/InfluxDB.cxx

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,26 @@ void InfluxDB::escape(std::string& escaped)
4949
boost::replace_all(escaped, " ", "\\ ");
5050
}
5151

52+
void InfluxDB::sendMultiple(std::string name, std::vector<Metric>&& metrics)
53+
{
54+
escape(name);
55+
std::stringstream convert;
56+
convert << name << "," << tagSet << " ";
57+
58+
for (const auto& metric : metrics) {
59+
std::string value = boost::lexical_cast<std::string>(metric.getValue());
60+
prepareValue(value, metric.getType());
61+
convert << metric.getName() << "=" << value << ",";
62+
}
63+
convert.seekp(-1, std::ios_base::end);
64+
convert << " " << convertTimestamp(metrics.back().getTimestamp());
65+
66+
try {
67+
transport->send(convert.str());
68+
} catch (MonitoringInternalException&) {
69+
}
70+
}
71+
5272
void InfluxDB::send(const Metric& metric)
5373
{
5474
std::string metricTags{};
@@ -57,15 +77,7 @@ void InfluxDB::send(const Metric& metric)
5777
}
5878

5979
std::string value = boost::lexical_cast<std::string>(metric.getValue());
60-
if (metric.getType() == MetricType::STRING) {
61-
escape(value);
62-
value.insert(value.begin(), '"');
63-
value.insert(value.end(), '"');
64-
}
65-
66-
if (metric.getType() == MetricType::INT) {
67-
value.insert(value.end(), 'i');
68-
}
80+
prepareValue(value, metric.getType());
6981
std::string name = metric.getName();
7082
escape(name);
7183

@@ -78,6 +90,19 @@ void InfluxDB::send(const Metric& metric)
7890
}
7991
}
8092

93+
void InfluxDB::prepareValue(std::string& value, int type)
94+
{
95+
if (type == MetricType::STRING) {
96+
escape(value);
97+
value.insert(value.begin(), '"');
98+
value.insert(value.end(), '"');
99+
}
100+
101+
if (type == MetricType::INT) {
102+
value.insert(value.end(), 'i');
103+
}
104+
}
105+
81106
void InfluxDB::addGlobalTag(std::string name, std::string value)
82107
{
83108
escape(name); escape(value);

src/Backends/InfluxDB.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ class InfluxDB final : public Backend
5050
/// \param metric reference to metric object
5151
void send(const Metric& metric) override;
5252

53+
/// Sends multiple values in single measurement
54+
/// \param name measurement name
55+
/// \param metrics list of metrics
56+
void sendMultiple(std::string name, std::vector<Metric>&& metrics);
57+
5358
/// Adds tag
5459
/// \param name tag name
5560
/// \param value tag value
@@ -62,6 +67,11 @@ class InfluxDB final : public Backend
6267
/// Escapes " ", "," and "=" characters
6368
/// \param escaped string rerference to escape characters from
6469
void escape(std::string& escaped);
70+
71+
/// Modifies values to Influx Line Protocol format
72+
/// \param value reference to value
73+
/// \param type type of the metric
74+
void prepareValue(std::string& value, int type);
6575
};
6676

6777
} // namespace Backends

src/Collector.cxx

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ Collector::Collector(const std::string& configPath)
7979
MonLogger::Get() << "InfluxDB/HTTP backend disabled" << MonLogger::End();
8080
}
8181
#endif
82-
82+
8383
if (configFile->get<int>("Flume/enable").value_or(0) == 1) {
8484
mBackends.emplace_back(std::make_unique<Backends::Flume>(
8585
configFile->get<std::string>("Flume/hostname").value(),
@@ -154,9 +154,36 @@ void Collector::addDerivedMetric(std::string name, DerivedMetricMode mode) {
154154
mDerivedHandler->registerMetric(name, mode);
155155
}
156156

157-
void Collector::send(Metric&& metric)
157+
void Collector::send(std::string measurement, std::vector<Metric>&& metrics)
158+
{
159+
// find InfluxDB index
160+
size_t influxIndex = -1;
161+
for (auto& b: mBackends) {
162+
if (dynamic_cast<Backends::InfluxDB*>(b.get())) {
163+
influxIndex = &b-&mBackends[0];
164+
}
165+
}
166+
// send single metric to InfluxDB
167+
dynamic_cast<Backends::InfluxDB*>(
168+
mBackends[influxIndex].get())->sendMultiple(measurement, std::move(metrics)
169+
);
170+
171+
// send multiple metric to all other backends (prepend metric name with measurement name)
172+
for (auto& m : metrics) {
173+
std::string tempName = m.getName();
174+
m.setName(measurement + "-" + m.getName());
175+
send(std::move(m), influxIndex);
176+
m.setName(tempName);
177+
}
178+
}
179+
180+
void Collector::send(Metric&& metric, std::size_t skipBackend)
158181
{
182+
std::size_t index = 0;
159183
for (auto& b: mBackends) {
184+
if (index++ == skipBackend) {
185+
continue;
186+
}
160187
b->send(metric);
161188
}
162189
if (mDerivedHandler->isRegistered(metric.getName())) {

src/Metric.cxx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ std::string Metric::getName() const
3030
return mName;
3131
}
3232

33+
void Metric::setName(std::string name)
34+
{
35+
mName = name;
36+
}
37+
3338
Metric::Metric(int value, const std::string& name, std::chrono::time_point<std::chrono::system_clock> timestamp) :
3439
mValue(value), mName(name), mTimestamp(timestamp)
3540
{}

0 commit comments

Comments
 (0)