|
1 | | -# Prometheus C++ header-only client library |
| 1 | +# C++ Header-only Prometheus client library |
2 | 2 |
|
3 | | -This is a lite, C++ header-only client library for prometheus based on [jupp0r/prometheus-cpp](https://github.com/jupp0r/prometheus-cpp) project. |
| 3 | +It is a tool for quickly adding metrics (and profiling) functionality to C++ projects. |
4 | 4 |
|
5 | | -To see how this can be used see the examples folders. |
| 5 | +## Advantages: |
6 | 6 |
|
7 | | -## Why I decided to do this deep refactoring of an original project prometheus-cpp: |
| 7 | +1. Written in pure C++, |
| 8 | +2. Header-only, |
| 9 | +2. Cross-platform, |
| 10 | +3. Compiles with C ++ 11, C ++ 14, C ++ 17 standards, |
| 11 | +4. Has no third-party dependencies, |
| 12 | +5. Several APIs for use in your projects, |
| 13 | +6. Saving metrics to a file (and then works with node_exporter) or sending via http (uses built-in header-only http-client-lite library), |
| 14 | +7. Possiblity to use different types for storing metrics data (default is uint32_t, but you can use double or uint64_t types if you want), |
| 15 | +8. Five types of metrics are supported: counter, gauge, summary, histogram and benchmark, |
| 16 | +10. Has detailed examples of use (see examples folder) |
| 17 | + |
| 18 | +## How it differs from the [jupp0r/prometheus-cpp](https://github.com/jupp0r/prometheus-cpp) project: |
8 | 19 | 1. I need a simple header only wariant library without dependencies to write metrics to a .prom file, |
9 | 20 | 2. I need the fastest possible work using integer values of counters (original project use only floating pointer values), |
10 | 21 | 3. The origianl project have problems on compilers that do not know how to do LTO optimization, |
11 | 22 | 4. I did not like the python style of the original project and the large amount of extra code in it and I wanted to make it lighter and more c++ classic. |
12 | 23 |
|
13 | | -## Now the core of the library has been rewritten: |
14 | | -- The amount of code in core is greatly reduced, |
15 | | -- All the kernel code has been moved to the header files (due to this, the problem with LTO optimization is also solved), |
16 | | -- It is possible to set the type of value that will be used in the counter (you can even use several counters with different value types at the same time). |
| 24 | +## How to use it: |
| 25 | +The library has two API: |
| 26 | +1. Complex API for those who want to control everything, |
| 27 | +2. Simple API for those who want to quickly add metrics to their C ++ (and it is actually just a wrapper around the complex API). |
| 28 | + |
| 29 | + |
| 30 | +### Let's start with a simple API because it's simple: |
| 31 | + |
| 32 | +To add it to your C++ project add these lines to your CMakeLists.txt file: |
| 33 | +``` |
| 34 | +add_subdirectory("prometheus-cpp-lite/core") |
| 35 | +add_subdirectory("prometheus-cpp-lite/3rdpatry/http-client-lite") |
| 36 | +add_subdirectory("prometheus-cpp-lite/simpleapi") |
| 37 | +target_link_libraries(your_target prometheus-cpp-simpleapi) |
| 38 | +``` |
| 39 | + |
| 40 | +The simplest way to create a metric would be like this: |
| 41 | +``` c++ |
| 42 | +prometheus::simpleapi::METRIC_metric_t metric1 { "metric1", "first simple metric without any tag" }; |
| 43 | +prometheus::simpleapi::METRIC_metric_t metric2 { "metric2", "second simple metric without any tag" }; |
| 44 | +``` |
| 45 | +where ```METRIC``` can be ```counter```, ```gauge```, ```summary```, ```histogram``` or ```benchmark```. |
| 46 | +
|
| 47 | +If you want to access an existing metric again elsewhere in the code, you can do this: |
| 48 | +``` c++ |
| 49 | +prometheus::simpleapi::METRIC_metric_t metric2_yet_another_link { "metric2", "" }; |
| 50 | +``` |
| 51 | +this works because when adding a metric, it checks whether there is already a metric with the same name and, if there is one, a link to it is returned. |
| 52 | + |
| 53 | +You can create a family of metrics (metrics with tags) as follows: |
| 54 | +``` c++ |
| 55 | +prometheus::simpleapi::METRIC_family_t family { "metric_family", "metric family" }; |
| 56 | +prometheus::simpleapi::METRIC_metric_t metric1 { family.Add({{"name", "metric1"}}) }; |
| 57 | +prometheus::simpleapi::METRIC_metric_t metric2 { family.Add({{"name", "metric2"}}) }; |
| 58 | +``` |
| 59 | +where METRIC can be ```counter```, ```gauge```, ```summary```, ```histogram``` or ```benchmark```. |
| 60 | +
|
| 61 | +Next, you can do the following things with metrics: |
| 62 | +``` c++ |
| 63 | +metric++; // for increment it (only for counter and gauge metrics) |
| 64 | +metric += value; // for add value to metric (only for gauge metric) |
| 65 | +metric -= value; // for sub value from metric (only for gauge metric) |
| 66 | +metric = value; // save current value (only gauge metrics) |
| 67 | +metric.start(); // start calculate time (only for benchmark metric) |
| 68 | +metric.stop(); // stop calculate time (only for benchmark metric) |
| 69 | +``` |
| 70 | + |
| 71 | +You can change the settings of save (or send) metrics data as follows: |
| 72 | +``` c++ |
| 73 | +prometheus::simpleapi::saver.set_delay(period_in_seconds); // change the period of saving (or sending) metrics data in seconds (5 seconds by default) |
| 74 | +prometheus::simpleapi::saver.set_out_file(filename); // change the name of the output file (metrics.prom by default) |
| 75 | +prometheus::simpleapi::saver.set_server_url(url); // change the name of prometheus server (unset by default) |
| 76 | +``` |
| 77 | + |
| 78 | +### Simple API complex example 1 (examples/simpleapi_example.cpp): |
| 79 | + |
| 80 | +``` c++ |
| 81 | +#include <prometheus/simpleapi.h> |
| 82 | + |
| 83 | +void main() { |
| 84 | + |
| 85 | + using namespace prometheus::simpleapi; |
| 86 | + |
| 87 | + counter_family_t family { "simple_family", "simple family example" }; |
| 88 | + counter_metric_t metric1 { family.Add({{"name", "counter1"}}) }; |
| 89 | + counter_metric_t metric2 { family.Add({{"name", "counter2"}}) }; |
| 90 | + |
| 91 | + counter_metric_t metric3 { "simple_counter_1", "simple counter 1 without labels example" }; |
| 92 | + counter_metric_t metric4 { "simple_counter_2", "simple counter 2 without labels example" }; |
| 93 | + |
| 94 | + for (;; ) { |
| 95 | + std::this_thread::sleep_for(std::chrono::seconds(1)); |
| 96 | + const int random_value = std::rand(); |
| 97 | + if (random_value & 1) metric1++; |
| 98 | + if (random_value & 2) metric2++; |
| 99 | + if (random_value & 4) metric3++; |
| 100 | + if (random_value & 8) metric4++; |
| 101 | + } |
| 102 | + |
| 103 | +} |
| 104 | +``` |
| 105 | + |
| 106 | +Output in "metrics.prom" file (by default) will be: |
| 107 | + |
| 108 | +``` |
| 109 | +# HELP simple_family simple family example |
| 110 | +# TYPE simple_family counter |
| 111 | +simple_family{name="counter1"} 10 |
| 112 | +simple_family{name="counter2"} 9 |
| 113 | +# HELP simple_counter_1 simple counter 1 without labels example |
| 114 | +# TYPE simple_counter_1 counter |
| 115 | +simple_counter_1 6 |
| 116 | +# HELP simple_counter_2 simple counter 2 without labels example |
| 117 | +# TYPE simple_counter_2 counter |
| 118 | +simple_counter_2 8 |
| 119 | +``` |
| 120 | + |
| 121 | +### Simple API complex example 2 (examples/simpleapi_use_in_class_example.cpp): |
| 122 | + |
| 123 | +``` c++ |
| 124 | +#include <prometheus/simpleapi.h> |
| 125 | + |
| 126 | +using namespace prometheus::simpleapi; |
| 127 | + |
| 128 | +class MyClass { |
| 129 | + |
| 130 | + counter_family_t metric_family { "simple_family", "simple family example" }; |
| 131 | + counter_metric_t metric1 { metric_family.Add({{"name", "counter1"}}) }; |
| 132 | + counter_metric_t metric2 { metric_family.Add({{"name", "counter2"}}) }; |
| 133 | + |
| 134 | + counter_metric_t metric3 { "simple_counter_1", "simple counter 1 without labels example" }; |
| 135 | + counter_metric_t metric4 { "simple_counter_2", "simple counter 2 without labels example" }; |
| 136 | + |
| 137 | + benchmark_family_t benchmark_family { "simple_benchmark_family", "simple benchmark family example" }; |
| 138 | + benchmark_metric_t benchmark1 { benchmark_family.Add({{"benchmark", "1"}}) }; |
| 139 | + benchmark_metric_t benchmark2 { benchmark_family.Add({{"benchmark", "2"}}) }; |
| 140 | + |
| 141 | +public: |
| 142 | + |
| 143 | + MyClass() = default; |
| 144 | + |
| 145 | + void member_to_do_something() { |
| 146 | + |
| 147 | + benchmark1.start(); |
| 148 | + const int random_value = std::rand(); |
| 149 | + benchmark1.stop(); |
| 150 | + |
| 151 | + benchmark2.start(); |
| 152 | + if (random_value & 1) metric1++; |
| 153 | + if (random_value & 2) metric2++; |
| 154 | + if (random_value & 4) metric3++; |
| 155 | + if (random_value & 8) metric4++; |
| 156 | + benchmark2.stop(); |
| 157 | + |
| 158 | + } |
| 159 | + |
| 160 | +}; |
| 161 | + |
| 162 | +void main() { |
| 163 | + |
| 164 | + MyClass myClass; |
| 165 | + benchmark_metric_t benchmark { "simple_benchmark", "simple benchmark example" }; |
| 166 | + |
| 167 | + for (;; ) { |
| 168 | + |
| 169 | + benchmark.start(); |
| 170 | + std::this_thread::sleep_for(std::chrono::seconds(1)); |
| 171 | + benchmark.stop(); |
| 172 | + |
| 173 | + myClass.member_to_do_something(); |
| 174 | + |
| 175 | + } |
| 176 | + |
| 177 | +} |
| 178 | +``` |
17 | 179 |
|
18 | | -## What am I going to do next: |
19 | | -- Write a couple of examples how to using the existing core functionality, |
20 | | -- Check and debug this refactored code for Linux mashine (now I worked only in Visual Studio), |
21 | | -- Move from the original project a part of the code responsible for sending metrics through libcurl to the prometheus server, refactoring it and write some examples for it too. |
| 180 | +Output in "metrics.prom" file (by default) will be: |
22 | 181 |
|
| 182 | +``` |
| 183 | +# HELP simple_family simple family example |
| 184 | +# TYPE simple_family counter |
| 185 | +simple_family{name="counter1"} 3 |
| 186 | +simple_family{name="counter2"} 2 |
| 187 | +# HELP simple_counter_1 simple counter 1 without labels example |
| 188 | +# TYPE simple_counter_1 counter |
| 189 | +simple_counter_1 3 |
| 190 | +# HELP simple_counter_2 simple counter 2 without labels example |
| 191 | +# TYPE simple_counter_2 counter |
| 192 | +simple_counter_2 3 |
| 193 | +# HELP simple_benchmark_family simple benchmark family example |
| 194 | +# TYPE simple_benchmark_family counter |
| 195 | +simple_benchmark_family{benchmark="1"} 0.0001088 |
| 196 | +simple_benchmark_family{benchmark="2"} 1.48e-05 |
| 197 | +# HELP simple_benchmark simple benchmark example |
| 198 | +# TYPE simple_benchmark counter |
| 199 | +simple_benchmark 6.0503248 |
| 200 | +``` |
23 | 201 |
|
0 commit comments