Skip to content

Commit f0cb0e5

Browse files
authored
Support multiple values per metric (#189)
1 parent 8c37f47 commit f0cb0e5

29 files changed

+314
-522
lines changed

CMakeLists.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ message(STATUS " Compiling InfluxDB backend with Unix socket and UDP transport"
9292
add_library(Monitoring SHARED
9393
src/Monitoring.cxx
9494
src/Metric.cxx
95-
src/ComplexMetric.cxx
9695
src/Backends/InfluxDB.cxx
9796
src/Backends/StdOut.cxx
9897
src/DerivedMetrics.cxx
@@ -174,8 +173,6 @@ set(EXAMPLES
174173
examples/5-Benchmark.cxx
175174
examples/6-Increment.cxx
176175
examples/7-InternalBenchamrk.cxx
177-
examples/8-Multiple.cxx
178-
examples/9-AutoUpdate.cxx
179176
examples/10-Buffering.cxx
180177
)
181178

README.md

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -43,77 +43,75 @@ See the table below to find `URI`s for supported backends:
4343
4444
| Backend name | Transport | URI backend[-protocol] | URI query | Default verbosity |
4545
| ------------ |:-----------:|:----------------------:|:-----------:| -----------------:|
46-
| No-op | - | `no-op` | | - |
46+
| No-op | - | `no-op` | - | - |
4747
| InfluxDB | UDP | `influxdb-udp` | - | `info` |
4848
| InfluxDB | Unix socket | `influxdb-unix` | - | `info` |
4949
| InfluxDB | StdOut | `influxdb-stdout` | - | `info` |
5050
| InfluxDB | Kafka | `influxdb-kafka` | Kafka topic | `info` |
5151
| ApMon | UDP | `apmon` | - | `info` |
5252
| StdOut | - | `stdout`, `infologger` | [Prefix] | `debug` |
5353
54-
##### StdCout output format
55-
```
56-
[METRIC] <name>,<type> <value> <timestamp> <tags>
57-
```
58-
The prefix (`[METRIC]`) can be changed using query component.
59-
6054
### Metrics
61-
A metric consist of 5 parameters: name, value, timestamp, verbosity and tags.
55+
A metric consist of 5 parameters:
56+
- name - metric name
57+
- values - vector of value and value name pairs
58+
- timestamp - time of creation
59+
- verbosity - metric "severity"
60+
- tags - metric metadata represented as map
6261
6362
| Parameter name | Type | Required | Default |
6463
| -------------- |:--------------------------------:|:--------:| -----------------------:|
6564
| name | string | yes | - |
66-
| value | int / double / string / uint64_t | yes | - |
65+
| values | map&lt;string, int/double/string/uint64_t&gt; | no/1 | - |
6766
| timestamp | time_point&lt;system_clock&gt; | no | current time |
6867
| verbosity | Enum (Debug/Info/Prod) | no | Verbosity::Info |
69-
| tags | vector<unsigned int> | no | host and process names |
68+
| tags | map | no | host and process names |
7069
71-
A metric can be constructed by providing required parameters (value and name):
70+
A metric can be constructed by providing required parameters (value and metric name, value name is set to `value`):
7271
```cpp
7372
Metric{10, "name"}
7473
```
75-
76-
#### Verbosity
77-
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)`.
78-
To overwrite verbosity on per metric basis use third, optional parameter to metric constructor:
74+
#### Values
75+
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:
7976
```cpp
80-
Metric{10, "name", Verbosity::Prod}
77+
Metric{10, "name"}
78+
Metric{"name"}.addValue(10, "value")
8179
```
8280
83-
Metrics need to match backends verbosity in order to be sent, eg. backend with `/info` verbosity will accept `Info` and `Prod` metrics only.
84-
8581
#### Tags
8682
Each metric can be tagged with any number of [predefined tags](include/Monitoring/Tags.h).
8783
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.
8884
85+
```cpp
86+
Metric{10, "name"}.addTag(tags::Key::Subsystem, tags::Value::QC)
87+
```
88+
8989
See the example: [examples/2-TaggedMetrics.cxx](examples/2-TaggedMetrics.cxx).
9090

9191
### Sending metric
92-
Pass metric object to send method and l-value reference:
92+
Pass metric object to `send` method as l-value reference:
9393
```cpp
9494
send({10, "name"})
95+
send(Metric{20, "name"}.addTag(tags::Key::CRU, 123))
96+
send(Metric{"throughput"}.addValue(100, "tx").addValue(200, "rx"))
9597
```
9698
9799
See how it works in the example: [examples/1-Basic.cxx](examples/1-Basic.cxx).
98100
99101
## Advanced features
100102
101-
### Sending more than one metric
102-
In order to send more than one metric in a packet group them into vector:
103-
```cpp
104-
monitoring->send(std::vector<Metric>&& metrics);
105-
```
106-
107-
It's also possible to send multiple, grouped values (`InfluxDB` backends are supported); For example `cpu` metric can be composed of `cpuUser`, `cpuSystem` values.
103+
### Metric verbosity
104+
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)`.
105+
To overwrite verbosity on per metric basis use third, optional parameter to metric constructor:
108106
```cpp
109-
void sendGroupped(std::string name, std::vector<Metric>&& metrics)
107+
Metric{10, "name", Verbosity::Prod}
110108
```
111109

112-
See how it works in the example: [examples/8-Multiple.cxx](examples/8-Multiple.cxx)
110+
Metrics need to match backends verbosity in order to be sent, eg. backend with `/info` verbosity will accept `Info` and `Prod` metrics only.
113111

114112
### Buffering metrics
115113
In order to avoid sending each metric separately, metrics can be temporary stored in the buffer and flushed at the most convenient moment.
116-
This feature can be operated with following two methods:
114+
This feature can be controlled with following two methods:
117115
```cpp
118116
monitoring->enableBuffering(const std::size_t maxSize)
119117
...
@@ -124,27 +122,29 @@ monitoring->flushBuffer();
124122
125123
See how it works in the example: [examples/10-Buffering.cxx](examples/10-Buffering.cxx).
126124
127-
### Calculating derived metrics
128-
The module can calculate derived metrics. To do so, use optional `DerivedMetricMode mode` parameter of `send` method:
125+
### Calculating derived values
126+
This feature can calculate derived values. To do so, use optional `DerivedMetricMode mode` parameter of `send` method:
129127
```
130128
send(Metric&& metric, [DerivedMetricMode mode])
131129
```
132130
133-
Three modes are available:
134-
+ `DerivedMetricMode::NONE` - no action,
135-
+ `DerivedMetricMode::RATE` - rate between two following metrics,
136-
+ `DerivedMetricMode::AVERAGE` - average value of all metrics stored in cache.
131+
Two modes are available:
132+
+ `DerivedMetricMode::RATE` - rate between two following values,
133+
+ `DerivedMetricMode::INCREMENT` - sum of all passed values.
137134
138-
Derived metrics are generated each time as new value is passed to the module. Their names are suffixed with derived mode name.
135+
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.
139136
140137
See how it works in the example: [examples/4-RateDerivedMetric.cxx](examples/4-RateDerivedMetric.cxx).
141138
142139
### Global tags
143-
Global tags are added to each metric. Two tags: `hostname` and `name` (process name) are set as global by the library.
140+
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.
144141
145142
You can add your own global tag by calling `addGlobalTag(std::string_view key, std::string_view value)` or `addGlobalTag(tags::Key, tags::Value)`.
146143
147144
### Process monitoring
145+
146+
This feature provides basic performance status of the process. Note that is runs in separate thread (without mutex).
147+
148148
```cpp
149149
enableProcessMonitoring([interval in seconds]);
150150
```
@@ -153,16 +153,14 @@ The following metrics are generated every interval:
153153
+ **involuntaryContextSwitches** - involuntary context switches over time interval
154154
+ **memoryUsagePercentage** - ratio of the process's resident set size to the physical memory on the machine, expressed as a percentage (Linux only)
155155

156-
### Automatic metric updates
157-
Sometimes it's necessary to provide value every exact interval of time (even though value does not change). This can be done using `AutoPushMetric`.
158-
```cpp
159-
ComplexMetric& metric = monitoring->getAutoPushMetric("exampleMetric");
160-
metric = 10;
156+
### StdOut backend output format
157+
```
158+
[METRIC] <name>,<type> <values> <timestamp> <tags>
161159
```
162-
See how it works in the example: [examples/11-AutoUpdate.cxx](examples/11-AutoUpdate.cxx).
160+
The prefix (`[METRIC]`) can be changed using query component.
163161

164162
### Regex verbosity policy
165-
Overwrite metric verbosities using regex expression:
163+
Overwrite metric verbosity using regex expression:
166164
```
167165
Metric::setVerbosityPolicy(Verbosity verbosity, const std::regex& regex)
168166
```

examples/1-Basic.cxx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,15 @@ int main()
1111
{
1212
// Configure monitoring
1313
// Pass string with list of URLs as parameter
14-
auto monitoring = MonitoringFactory::Get("stdout://");
14+
auto monitoring = MonitoringFactory::Get("influxdb-stdout://");
1515

16-
// now send an application specific metric
16+
// send a metric using one of two equivalent methods
1717
// 10 is the value
1818
// myMetric is the name of the metric by creating and moving Metric object
19-
monitoring->send({10, "myMetricInt"});
20-
monitoring->send({10.10, "myMetricFloat"});
19+
monitoring->send({10, "myMetricInt"}); // default name is "value"
20+
monitoring->send(Metric{"myMetricInt"}.addValue(10, "value"));
21+
22+
// now send a metric with multiple values
23+
monitoring->send(Metric{10, "myMetricInt"}.addValue(10.10, "value_float"));
24+
monitoring->send(Metric{"myMetricInt"}.addValue(10, "value").addValue(10.10, "value_float"));
2125
}

examples/3-Verbosity.cxx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ int main()
1919
monitoring->send({10, "myMetricInt", Verbosity::Debug}, DerivedMetricMode::INCREMENT);
2020
monitoring->send({10.10, "myMetricFloat", Verbosity::Prod}, DerivedMetricMode::INCREMENT);
2121

22-
monitoring->sendGrouped("measurementName", {{20, "myMetricIntMultiple"}, {20.30, "myMetricFloatMultple"}}, Verbosity::Debug);
23-
monitoring->sendGrouped("measurementName", {{20, "myMetricIntMultiple"}, {20.30, "myMetricFloatMultple"}}, Verbosity::Prod);
22+
//monitoring->sendGrouped("measurementName", {{20, "myMetricIntMultiple"}, {20.30, "myMetricFloatMultple"}}, Verbosity::Debug);
23+
//monitoring->sendGrouped("measurementName", {{20, "myMetricIntMultiple"}, {20.30, "myMetricFloatMultple"}}, Verbosity::Prod);
2424

2525
monitoring->send({10, "myMetricInt", Verbosity::Debug}, DerivedMetricMode::INCREMENT);
2626
monitoring->send({10.10, "myMetricFloat", Verbosity::Prod}, DerivedMetricMode::INCREMENT);

examples/5-Benchmark.cxx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,11 @@ int main(int argc, char* argv[])
5555
if (vm["multiple"].as<bool>()) {
5656
for (int j = 1; j <= count; j++) {
5757
for (int i = 1; i <= measurements; i++) {
58-
monitoring->sendGrouped("measurement" + std::to_string(i), {{doubleDist(mt), "doubleMetric" + std::to_string(i)},
59-
{intDist(mt), "intMetric" + std::to_string(i)},
60-
{std::rand() % 2, "onOffMetric" + std::to_string(i)}});
58+
monitoring->send(Metric{"measurement" + std::to_string(i)}
59+
.addValue(doubleDist(mt), "doubleMetric")
60+
.addValue(intDist(mt), "intMetric")
61+
.addValue(std::rand() % 2, "onOffMetric")
62+
);
6163
std::this_thread::sleep_for(std::chrono::microseconds(sleep));
6264
}
6365
if (!vm.count("count"))

examples/7-InternalBenchamrk.cxx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,17 @@ using namespace std::chrono;
1212
void test(std::unique_ptr<Monitoring>& monitoring)
1313
{
1414
for (int i = 0; i < 100000; i++) {
15-
monitoring->send({10, "myMetricInt"});
16-
monitoring->send({10.10, "myMetricFloat"});
15+
monitoring->send(Metric{"myMetricInt"}.addValue(10, "value"));
16+
monitoring->send(Metric{"myMetricFloat"}.addValue(10.10, "value"));
1717
}
1818
}
1919

2020
void testWithTags(std::unique_ptr<Monitoring>& monitoring)
2121
{
2222
monitoring->addGlobalTag("name", "benchmark");
2323
for (int i = 0; i < 100000; i++) {
24-
monitoring->send(Metric{10, "myMetricInt"}.addTag(tags::Key::Detector, tags::Value::TPC));
25-
monitoring->send(Metric{10.10, "myMetricFloat"}.addTag(tags::Key::Subsystem, tags::Value::QC));
24+
monitoring->send(Metric{"myMetricInt"}.addValue(10, "value").addTag(tags::Key::Detector, tags::Value::TPC));
25+
monitoring->send(Metric{"myMetricFloat"}.addValue(10.10, "value").addTag(tags::Key::Subsystem, tags::Value::QC));
2626
}
2727
}
2828

examples/8-Multiple.cxx

Lines changed: 0 additions & 17 deletions
This file was deleted.

examples/9-AutoUpdate.cxx

Lines changed: 0 additions & 23 deletions
This file was deleted.

include/Monitoring/Backend.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,6 @@ class Backend
5555
/// Sends multiple metrics not related to each other
5656
virtual void send(std::vector<Metric>&& metrics) = 0;
5757

58-
/// Sends multiple related to each other metrics under a common name
59-
/// If not supported by backend, falls back into sending single metrics
60-
virtual void sendMultiple(std::string measurement, std::vector<Metric>&& metrics) = 0;
61-
6258
/// Sets a tag
6359
virtual void addGlobalTag(std::string_view name, std::string_view value) = 0;
6460
};

include/Monitoring/ComplexMetric.h

Lines changed: 0 additions & 70 deletions
This file was deleted.

0 commit comments

Comments
 (0)