Skip to content

Commit dee48df

Browse files
authored
Introduce metric severity (#107)
* Drop debug API * Make send vector method private * Rename methods passing values to backend to transmit * Fix influxdb http backend * Added metric verbosity * Fix - remove unintended code * Match metric and backend verbosities * Add verbosity example * Fix buffering * Derived metric should have the same verbosity * Add verbosity example * Adapt README
1 parent 975f0d3 commit dee48df

18 files changed

+196
-145
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ target_compile_features(Monitoring PUBLIC cxx_std_17)
141141
set(EXAMPLES
142142
examples/1-Basic.cxx
143143
examples/2-TaggedMetrics.cxx
144+
examples/3-Verbosity.cxx
144145
examples/4-RateDerivedMetric.cxx
145146
examples/5-Benchmark.cxx
146147
examples/6-Increment.cxx

README.md

Lines changed: 38 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ make install
5656

5757
## Getting started
5858
### Monitoring instance
59-
The recommended way of getting (`unique_ptr` to) monitoring instance is `Get`ing it from `MonitoringFactory` by passing backend URI(s) as a parameter (comma seperated if more than one).
60-
The library is accessible from `o2::monitoring` namespace.
59+
The recommended way of getting monitoring instance is `Get`ing it from `MonitoringFactory` by passing backend's URI(s) as a parameter (comma separated if more than one).
60+
The factory is accessible from `o2::monitoring` namespace.
6161

6262
```cpp
6363
#include <MonitoringFactory.h>
@@ -67,53 +67,62 @@ std::unique_ptr<Monitoring> monitoring = MonitoringFactory::Get("backend[-protoc
6767
6868
See table below to find out how to create `URI` for each backend:
6969
70-
| Backend name | Transport | URI backend[-protocol] | URI query | Default verbosity |
71-
| ------------ |:---------:|:----------------------:|:----------------:| -----------------:|
72-
| InfluxDB | HTTP | `influxdb-http` | `/write?db=<db>` | `prod` |
73-
| InfluxDB | UDP | `influxdb-udp` | - | `prod` |
74-
| ApMon | UDP | `apmon` | - | `prod` |
75-
| StdOut | - | `stdout`, `infologger` | - | `debug` |
76-
| Flume | UDP | `flume` | - | `prod` |
70+
| Backend name | Transport | URI backend[-protocol] | URI query | Default verbosity |
71+
| ------------ |:---------:|:----------------------:|:----------:| -----------------:|
72+
| InfluxDB | HTTP | `influxdb-http` | `?db=<db>` | `info` |
73+
| InfluxDB | UDP | `influxdb-udp` | - | `info` |
74+
| ApMon | UDP | `apmon` | - | `info` |
75+
| StdOut | - | `stdout`, `infologger` | - | `debug` |
76+
| Flume | UDP | `flume` | - | `info` |
7777
78-
Multiple backends may be used at the same time, URLs should be separated by `,` (comma).
79-
80-
#### StdCout output format
78+
##### StdCout output format
8179
```
8280
[METRIC] <name>,<type> <value> <timestamp> <tags>
8381
```
8482

85-
### Sending metric
83+
### Metrics
84+
A metric consist of 5 parameters: name, value, timestamp, verbosity and tags.
8685

86+
| Parameter name | Type | Required | Default |
87+
| -------------- |:---------------------------------------------:|:--------:| --------------:|
88+
| name | string | yes | - |
89+
| value | int / double / string / uint64_t | yes | - |
90+
| timestamp | chrono::time_point&lt;std::chrono::system_clock&gt; | no | current timestamp |
91+
| verbosity | DEBUG / INFO / PROD | no | INFO |
92+
| tags | vector<unsigned int> | no | - |
93+
94+
A metric can be constructed by providing required parameters:
8795
```cpp
88-
send(Metric&& metric, [DerivedMetricMode mode])
96+
Metric{10, "name"}
8997
```
90-
Where metric constructor receives following parameters:
91-
- `T value`
92-
- `std::string& name`
9398
94-
See how it works in the example: [examples/1-Basic.cxx](examples/1-Basic.cxx).
99+
#### Verbosity
100+
There are 3 verbosity levels (the same as for backends): DEBUG, INFO, PROD. The default verbosity is set using: `Metric::setDefaultVerbosity(verbosity)`.
101+
To overwrite verbosity on per metric basis use third, optional parameter to metric constructor:
102+
```cpp
103+
Metric{10, "name", Verbosity::PROD}
104+
```
105+
106+
Metrics need to match backends verbosity in order to be sent, eg. backend with `/info` verbosity will accept `INFO` and `PROD` metrics only.
95107

96-
The `DerivedMetricMode` is optional and described in [Calculating derived metrics](#calculating-derived-metrics) section.
97108

98-
### Taging metric
109+
#### Tags
99110
Each metric can be tagged with any number of [predefined tags](include/Monitoring/Tags.h).
100111
In order to do so use `addTags(std::initializer_list<unsigned int>&& tags)` method.
101112

102113
See the example: [examples/2-TaggedMetrics.cxx](examples/2-TaggedMetrics.cxx).
103114

104-
### Debug metrics
105-
Debug metrics can be send by a similar method to above's `send`:
115+
### Sending metric
116+
106117
```cpp
107-
debug(Metric&& metric)
118+
send(Metric&& metric, [DerivedMetricMode mode])
108119
```
109120
110-
The difference is that debug metrics are only passed to backends which verbosity level is set to `debug`.
121+
See how it works in the example: [examples/1-Basic.cxx](examples/1-Basic.cxx).
111122
112-
Each backend has its default verbosity (see backend in [Monitoring instance](#monitoring-instance) section). This can be changed by defining path of a backend URL:
113-
- `/prod` - only `send` metrics are passed to the backend
114-
- `/debug` - all the metrics are passed to the backend
123+
The `DerivedMetricMode` is optional and described in [Calculating derived metrics](#calculating-derived-metrics) section.
115124
116-
## Features and additional information
125+
## Advanced features
117126
118127
### Sending more than one metric
119128
In order to send more than one metric in a packet group them into vector:
@@ -141,20 +150,6 @@ monitoring->flushBuffer();
141150

142151
See how it works in the example: [examples/10-Buffering.cxx](examples/10-Buffering.cxx).
143152

144-
### Metrics
145-
Metrics consist of 4 parameters: name, value, timestamp and tags.
146-
147-
| Parameter name | Type | Required | Default |
148-
| -------------- |:---------------------------------------------:|:--------:| ----------------:|
149-
| name | string | yes | - |
150-
| value | int / double / string / uint64_t | yes | - |
151-
| timestamp | chrono::time_point&lt;std::chrono::system_clock&gt; | no | current timestamp |
152-
| tags | vector<unsigned int> | no | -** |
153-
154-
**Default tag set is process specific and included in each metric:
155-
+ hostname
156-
+ process name
157-
158153
### Calculating derived metrics
159154
The module can calculate derived metrics. To do so, use optional `DerivedMetricMode mode` parameter of `send` method:
160155
+ `DerivedMetricMode::NONE` - no action,
@@ -172,7 +167,7 @@ Glabal tags are tags that are added to each metric. The following tags are set t
172167

173168
You can add your own global tag by calling `addGlobalTag(std::string name, std::string value)`.
174169

175-
### Monitoring process
170+
### Process monitoring
176171
```cpp
177172
enableProcessMonitoring([interval in seconds]);
178173
```

examples/3-Verbosity.cxx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
///
2+
/// \file 1-Basic.cxx
3+
/// \author Adam Wegrzynek <[email protected]>
4+
///
5+
6+
#include "Monitoring/MonitoringFactory.h"
7+
8+
using namespace o2::monitoring;
9+
10+
int main() {
11+
// Configure monitoring
12+
// Pass string with list of URLs as parameter
13+
auto monitoring = MonitoringFactory::Get("stdout:///info");
14+
15+
// now send an application specific metric
16+
// 10 is the value
17+
// myMetric is the name of the metric by creating and moving Metric object
18+
monitoring->send({10, "myMetricInt", Verbosity::DEBUG}, DerivedMetricMode::INCREMENT);
19+
monitoring->send({10.10, "myMetricFloat", Verbosity::PROD}, DerivedMetricMode::INCREMENT);
20+
21+
monitoring->sendGrouped("measurementName", {{20, "myMetricIntMultiple"}, {20.30, "myMetricFloatMultple"}}, Verbosity::DEBUG);
22+
monitoring->sendGrouped("measurementName", {{20, "myMetricIntMultiple"}, {20.30, "myMetricFloatMultple"}}, Verbosity::PROD);
23+
24+
monitoring->send({10, "myMetricInt", Verbosity::DEBUG}, DerivedMetricMode::INCREMENT);
25+
monitoring->send({10.10, "myMetricFloat", Verbosity::PROD}, DerivedMetricMode::INCREMENT);
26+
27+
monitoring->enableBuffering();
28+
monitoring->send({10, "myMetricInt", Verbosity::DEBUG});
29+
monitoring->send({10.10, "myMetricFloat", Verbosity::PROD});
30+
}

examples/5-Benchmark.cxx

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ int main(int argc, char *argv[]) {
2727
("id", boost::program_options::value<std::string>(), "Instance ID")
2828
("count", boost::program_options::value<int>(), "Number of loop cycles")
2929
("multiple", boost::program_options::bool_switch()->default_value(false), "Sends multiple metrics per measurement")
30-
("vector", boost::program_options::bool_switch()->default_value(false), "Sends vector of metrics")
3130
("monitor", boost::program_options::bool_switch()->default_value(false), "Enabled process monitor")
3231
("buffer", boost::program_options::value<int>(), "Creates buffr of given size")
3332
("measurements", boost::program_options::value<int>(), "Number of different measurements")
@@ -64,17 +63,6 @@ int main(int argc, char *argv[]) {
6463
}
6564
if (!vm.count("count")) j--;
6665
}
67-
} else if (vm["vector"].as<bool>()) {
68-
for (int j = 1; j <= count; j++) {
69-
for (int i = 1; i <= measurements; i++) {
70-
monitoring->send({
71-
{doubleDist(mt), "doubleMetric" + std::to_string(i)},
72-
{intDist(mt), "intMetricDebug" + std::to_string(i)}
73-
});
74-
std::this_thread::sleep_for(std::chrono::microseconds(sleep));
75-
}
76-
if (!vm.count("count")) j--;
77-
}
7866
} else {
7967
if (vm.count("buffer")) {
8068
monitoring->enableBuffering(vm["buffer"].as<int>());
@@ -83,7 +71,6 @@ int main(int argc, char *argv[]) {
8371
for (int i = 1; i <= measurements; i++) {
8472
monitoring->send({doubleDist(mt), "doubleMetric" + std::to_string(i)});
8573
monitoring->send({intDist(mt), "intMetric" + std::to_string(i)});
86-
monitoring->debug({intDist(mt), "intMetricDebug" + std::to_string(i)});
8774
std::this_thread::sleep_for(std::chrono::microseconds(sleep));
8875
}
8976
if (!vm.count("count")) j--;

examples/8-Multiple.cxx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,4 @@ int main() {
1313
auto monitoring = Monitoring::Get("stdout://");
1414

1515
monitoring->sendGrouped("measurementName", {{20, "myMetricIntMultiple"}, {20.30, "myMetricFloatMultple"}});
16-
monitoring->send({{201, "myMetricIntMultiple"}, {2.34, "myMetricFloatMultple"}});
1716
}

include/Monitoring/Backend.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ namespace o2
1616
namespace monitoring
1717
{
1818

19-
namespace backend
20-
{
21-
enum class Verbosity { Prod, Debug };
22-
}
2319
/// \brief Backend pure virtual interface
2420
///
2521
/// Interface that allows to send a metric to remote backend.
@@ -28,20 +24,20 @@ class Backend
2824
{
2925
private:
3026
/// Verbosity level
31-
backend::Verbosity verbosityLevel;
27+
Verbosity verbosityLevel;
3228

3329
public:
3430
/// Default constructor
35-
Backend() { verbosityLevel = backend::Verbosity::Prod; }
31+
Backend() { verbosityLevel = Verbosity::PROD; }
3632

3733
/// Default destructor
3834
virtual ~Backend() = default;
3935

4036
/// Set verbosity level
41-
void setVerbosisty(backend::Verbosity level) { verbosityLevel = level; }
37+
void setVerbosisty(Verbosity level) { verbosityLevel = level; }
4238

4339
/// Get verbosity level
44-
backend::Verbosity getVerbosity() { return verbosityLevel; }
40+
Verbosity getVerbosity() { return verbosityLevel; }
4541

4642
/// Sends metric via backend
4743
virtual void send(const Metric& metric) = 0;

include/Monitoring/Metric.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ namespace o2
1818
namespace monitoring
1919
{
2020

21+
enum class Verbosity : short { PROD, INFO, DEBUG };
22+
2123
enum MetricType { INT = 0, STRING = 1, DOUBLE = 2, UINT64_T = 3 };
2224

2325
/// \brief Represents a metric including value, type of the value, name, timestamp and tags
@@ -27,27 +29,27 @@ class Metric
2729
/// Integer metric construtor
2830
/// \param value metric value (int)
2931
/// \param name metric name
30-
Metric(int value, const std::string& name);
32+
Metric(int value, const std::string& name, Verbosity verbosity = Metric::DEFAULT_VERBOSITY);
3133

3234
/// String metric construtor
3335
/// \param value metric value (string)
3436
/// \param name the metric name
35-
Metric(std::string value, const std::string& name);
37+
Metric(std::string value, const std::string& name, Verbosity verbosity = Metric::DEFAULT_VERBOSITY);
3638

3739
/// Double metric constructor
3840
/// \param value metric value (double)
3941
/// \param name metric name
40-
Metric(double value, const std::string& name);
42+
Metric(double value, const std::string& name, Verbosity verbosity = Metric::DEFAULT_VERBOSITY);
4143

4244
/// uint64_t metric constructor
4345
/// \param value metric value (uint64_t)
4446
/// \param name metric name
45-
Metric(uint64_t value, const std::string& name);
47+
Metric(uint64_t value, const std::string& name, Verbosity verbosity = Metric::DEFAULT_VERBOSITY);
4648

4749
/// boost variant metric constructor, required by derived metrics logic
4850
/// \param value metric value (boost variant)
4951
/// \param name metric name
50-
Metric(boost::variant< int, std::string, double, uint64_t >, const std::string& name);
52+
Metric(boost::variant< int, std::string, double, uint64_t >, const std::string& name, Verbosity verbosity = Metric::DEFAULT_VERBOSITY);
5153

5254
/// Default destructor
5355
~Metric() = default;
@@ -77,10 +79,18 @@ class Metric
7779
/// \return r-value to "this" - to be able to chain methods
7880
Metric&& addTags(std::vector<unsigned int>&& tags);
7981

82+
/// Verbosity getter
83+
Verbosity getVerbosity();
84+
8085
/// Generetes current timestamp
8186
/// return timestamp as std::chrono::system_clock
8287
static auto getCurrentTimestamp() -> decltype(std::chrono::system_clock::now());
8388

89+
/// Sets default verbosity of metrics
90+
static void setDefaultVerbosity(Verbosity verbosity);
91+
92+
/// Default metric verbosity
93+
static Verbosity DEFAULT_VERBOSITY;
8494
protected:
8595
/// Metric value
8696
boost::variant< int, std::string, double, uint64_t > mValue;
@@ -93,6 +103,9 @@ class Metric
93103

94104
/// Metric tags
95105
std::vector<unsigned int> mTags;
106+
107+
/// Metric verbosity
108+
Verbosity mVerbosity;
96109
};
97110

98111
} // namespace monitoring

include/Monitoring/Monitoring.h

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,12 @@ class Monitoring
5858
/// \param mode Derived metric mode
5959
void send(Metric&& metric, DerivedMetricMode mode = DerivedMetricMode::NONE);
6060

61-
/// Send metrics to debug backends only
62-
/// \param metric r-value to metric object
63-
void debug(Metric&& metric);
64-
65-
/// Sends multiple (not related to each other) metrics
66-
/// \param metrics vector of metrics
67-
void send(std::vector<Metric>&& metrics);
68-
6961
/// Sends multiple realated to each other metric values under a common measurement name
7062
/// You can imagine it as a data point with multiple values
7163
/// If it's not supported by a backend it fallbacks into sending one by one
7264
/// \param name measurement name
7365
/// \param metrics list of metrics
74-
void sendGrouped(std::string name, std::vector<Metric>&& metrics);
66+
void sendGrouped(std::string name, std::vector<Metric>&& metrics, Verbosity verbosity = Metric::DEFAULT_VERBOSITY);
7567

7668
/// Enables process monitoring
7769
/// \param interval refresh interval
@@ -99,6 +91,16 @@ class Monitoring
9991
ComplexMetric& getAutoPushMetric(std::string name, unsigned int interval = 1);
10092

10193
private:
94+
/// Sends multiple (not related to each other) metrics
95+
/// \param metrics vector of metrics
96+
void transmit(std::vector<Metric>&& metrics);
97+
98+
/// Flush buffer of desired verbosity
99+
void flushBuffer(short index);
100+
101+
/// Matches verbosity of a backend and a metric in order to decide whether metric should be send to the backend
102+
bool matchVerbosity(Verbosity backend, Verbosity metric);
103+
102104
/// Derived metrics handler
103105
/// \see class DerivedMetrics
104106
std::unique_ptr<DerivedMetrics> mDerivedHandler;
@@ -122,7 +124,7 @@ class Monitoring
122124
void pushLoop();
123125

124126
/// Metric buffer
125-
std::vector<Metric> mStorage;
127+
std::unordered_map<std::underlying_type<Verbosity>::type, std::vector<Metric>> mStorage;
126128

127129
/// Flag stating whether metric buffering is enabled
128130
bool mBuffering;

src/Backends/InfluxDB.cxx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ InfluxDB::InfluxDB(const std::string& host, unsigned int port)
2626
<< " ("<< host << ":" << port << ")" << MonLogger::End();
2727
}
2828

29-
InfluxDB::InfluxDB(const std::string& host, unsigned int port, const std::string& path)
29+
InfluxDB::InfluxDB(const std::string& host, unsigned int port, const std::string& search)
3030
{
3131
transport = std::make_unique<transports::HTTP>(
32-
"http://" + host + ":" + std::to_string(port) + "/?" + path
32+
"http://" + host + ":" + std::to_string(port) + "/write?" + search
3333
);
3434
MonLogger::Get() << "InfluxDB/HTTP backend initialized" << " (" << "http://" << host
35-
<< ":" << std::to_string(port) << "/?" << path << ")" << MonLogger::End();
35+
<< ":" << std::to_string(port) << "/write?" << search << ")" << MonLogger::End();
3636
}
3737

3838
inline unsigned long InfluxDB::convertTimestamp(const std::chrono::time_point<std::chrono::system_clock>& timestamp)

src/Backends/InfluxDB.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ class InfluxDB final : public Backend
3535
/// Constructor for HTTP transport
3636
/// \param host InfluxDB HTTP endpoint hostname
3737
/// \param port InfluxDB HTTP endpoint port number
38-
/// \param path Query path
39-
InfluxDB(const std::string& host, unsigned int port, const std::string& path);
38+
/// \param path Query search providing database name
39+
InfluxDB(const std::string& host, unsigned int port, const std::string& search);
4040

4141
/// Default destructor
4242
~InfluxDB() = default;

0 commit comments

Comments
 (0)