prometheus-cpp-lite-master/0000755000765700003170000000000014466227470015162 5ustar martinzdvprometheus-cpp-lite-master/.gitignore0000644000765700003170000000001514466227470017146 0ustar martinzdv.vs bin/ out/prometheus-cpp-lite-master/CMakeLists.txt0000644000765700003170000000146214466227470017725 0ustar martinzdvproject(prometheus-cpp-lite) cmake_minimum_required(VERSION 3.2) option(PROMETHEUS_BUILD_EXAMPLES "Build with examples" OFF) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) if(WIN32) # it prevent create Debug/ and Release folders in Visual Studio foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG ) set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${PROJECT_SOURCE_DIR}/bin ) endforeach() set (INSTALL_PATH_BIN "${PROJECT_SOURCE_DIR}/installed/bin/") else() # not WIN32 set (INSTALL_PATH_BIN "bin/") endif() add_subdirectory("./core") add_subdirectory("./simpleapi") add_subdirectory("./3rdpatry/http-client-lite") if(PROMETHEUS_BUILD_EXAMPLES) add_subdirectory("./examples") endif() prometheus-cpp-lite-master/LICENSE0000644000765700003170000000207214466227470016170 0ustar martinzdvMIT License Copyright (c) 2021 biaks (ianiskr@gmail.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. prometheus-cpp-lite-master/README.md0000644000765700003170000001706014466227470016445 0ustar martinzdv# C++ Header-only Prometheus client library [![Build examples](https://github.com/biaks/prometheus-cpp-lite/actions/workflows/cmake.yml/badge.svg)](https://github.com/biaks/prometheus-cpp-lite/actions/workflows/cmake.yml) It is a tool for quickly adding metrics (and profiling) functionality to C++ projects. ## Advantages: 1. Written in pure C++, 2. Header-only, 2. Cross-platform, 3. Compiles with C ++ 11, C ++ 14, C ++ 17 standards, 4. Has no third-party dependencies, 5. Several APIs for use in your projects, 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), 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), 8. Five types of metrics are supported: counter, gauge, summary, histogram and benchmark, 10. Has detailed examples of use (see examples folder) ## How it differs from the [jupp0r/prometheus-cpp](https://github.com/jupp0r/prometheus-cpp) project: 1. I need a simple header only wariant library without dependencies to write metrics to a .prom file, 2. I need the fastest possible work using integer values of counters (original project use only floating pointer values), 3. The origianl project have problems on compilers that do not know how to do LTO optimization, 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. ## How to use it: The library has two API: 1. Complex API for those who want to control everything, 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). ### Let's start with a simple API because it's simple: To add it to your C++ project add these lines to your CMakeLists.txt file: ``` add_subdirectory("prometheus-cpp-lite/core") add_subdirectory("prometheus-cpp-lite/3rdpatry/http-client-lite") add_subdirectory("prometheus-cpp-lite/simpleapi") target_link_libraries(your_target prometheus-cpp-simpleapi) ``` The simplest way to create a metric would be like this: ``` c++ prometheus::simpleapi::METRIC_metric_t metric1 { "metric1", "first simple metric without any tag" }; prometheus::simpleapi::METRIC_metric_t metric2 { "metric2", "second simple metric without any tag" }; ``` where ```METRIC``` can be ```counter```, ```gauge```, ```summary```, ```histogram``` or ```benchmark```. If you want to access an existing metric again elsewhere in the code, you can do this: ``` c++ prometheus::simpleapi::METRIC_metric_t metric2_yet_another_link { "metric2", "" }; ``` 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. You can create a family of metrics (metrics with tags) as follows: ``` c++ prometheus::simpleapi::METRIC_family_t family { "metric_family", "metric family" }; prometheus::simpleapi::METRIC_metric_t metric1 { family.Add({{"name", "metric1"}}) }; prometheus::simpleapi::METRIC_metric_t metric2 { family.Add({{"name", "metric2"}}) }; ``` where METRIC can be ```counter```, ```gauge```, ```summary```, ```histogram``` or ```benchmark```. Next, you can do the following things with metrics: ``` c++ metric++; // for increment it (only for counter and gauge metrics) metric += value; // for add value to metric (only for gauge metric) metric -= value; // for sub value from metric (only for gauge metric) metric = value; // save current value (only gauge metrics) metric.start(); // start calculate time (only for benchmark metric) metric.stop(); // stop calculate time (only for benchmark metric) ``` You can change the settings of save (or send) metrics data as follows: ``` c++ prometheus::simpleapi::saver.set_delay(period_in_seconds); // change the period of saving (or sending) metrics data in seconds (5 seconds by default) prometheus::simpleapi::saver.set_out_file(filename); // change the name of the output file (metrics.prom by default) prometheus::simpleapi::saver.set_server_url(url); // change the name of prometheus server (unset by default) ``` ### Simple API complex example 1 (examples/simpleapi_example.cpp): ``` c++ #include void main() { using namespace prometheus::simpleapi; counter_family_t family { "simple_family", "simple family example" }; counter_metric_t metric1 { family.Add({{"name", "counter1"}}) }; counter_metric_t metric2 { family.Add({{"name", "counter2"}}) }; counter_metric_t metric3 { "simple_counter_1", "simple counter 1 without labels example" }; counter_metric_t metric4 { "simple_counter_2", "simple counter 2 without labels example" }; for (;; ) { std::this_thread::sleep_for(std::chrono::seconds(1)); const int random_value = std::rand(); if (random_value & 1) metric1++; if (random_value & 2) metric2++; if (random_value & 4) metric3++; if (random_value & 8) metric4++; } } ``` Output in "metrics.prom" file (by default) will be: ``` # HELP simple_family simple family example # TYPE simple_family counter simple_family{name="counter1"} 10 simple_family{name="counter2"} 9 # HELP simple_counter_1 simple counter 1 without labels example # TYPE simple_counter_1 counter simple_counter_1 6 # HELP simple_counter_2 simple counter 2 without labels example # TYPE simple_counter_2 counter simple_counter_2 8 ``` ### Simple API complex example 2 (examples/simpleapi_use_in_class_example.cpp): ``` c++ #include using namespace prometheus::simpleapi; class MyClass { counter_family_t metric_family { "simple_family", "simple family example" }; counter_metric_t metric1 { metric_family.Add({{"name", "counter1"}}) }; counter_metric_t metric2 { metric_family.Add({{"name", "counter2"}}) }; counter_metric_t metric3 { "simple_counter_1", "simple counter 1 without labels example" }; counter_metric_t metric4 { "simple_counter_2", "simple counter 2 without labels example" }; benchmark_family_t benchmark_family { "simple_benchmark_family", "simple benchmark family example" }; benchmark_metric_t benchmark1 { benchmark_family.Add({{"benchmark", "1"}}) }; benchmark_metric_t benchmark2 { benchmark_family.Add({{"benchmark", "2"}}) }; public: MyClass() = default; void member_to_do_something() { benchmark1.start(); const int random_value = std::rand(); benchmark1.stop(); benchmark2.start(); if (random_value & 1) metric1++; if (random_value & 2) metric2++; if (random_value & 4) metric3++; if (random_value & 8) metric4++; benchmark2.stop(); } }; void main() { MyClass myClass; benchmark_metric_t benchmark { "simple_benchmark", "simple benchmark example" }; for (;; ) { benchmark.start(); std::this_thread::sleep_for(std::chrono::seconds(1)); benchmark.stop(); myClass.member_to_do_something(); } } ``` Output in "metrics.prom" file (by default) will be: ``` # HELP simple_family simple family example # TYPE simple_family counter simple_family{name="counter1"} 3 simple_family{name="counter2"} 2 # HELP simple_counter_1 simple counter 1 without labels example # TYPE simple_counter_1 counter simple_counter_1 3 # HELP simple_counter_2 simple counter 2 without labels example # TYPE simple_counter_2 counter simple_counter_2 3 # HELP simple_benchmark_family simple benchmark family example # TYPE simple_benchmark_family counter simple_benchmark_family{benchmark="1"} 0.0001088 simple_benchmark_family{benchmark="2"} 1.48e-05 # HELP simple_benchmark simple benchmark example # TYPE simple_benchmark counter simple_benchmark 6.0503248 ``` prometheus-cpp-lite-master/core/0000755000765700003170000000000014466227470016112 5ustar martinzdvprometheus-cpp-lite-master/core/CMakeLists.txt0000644000765700003170000000147714466227470020663 0ustar martinzdvproject(prometheus-cpp-lite-core) cmake_minimum_required(VERSION 3.2) file(GLOB_RECURSE PROMETHEUS_CPP_LITE_HEADERS *.h) # it is header only target add_library (${PROJECT_NAME} INTERFACE) target_sources (${PROJECT_NAME} INTERFACE ${PROMETHEUS_CPP_LITE_HEADERS}) target_include_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) add_custom_target (${PROJECT_NAME}-ide SOURCES ${PROMETHEUS_CPP_LITE_HEADERS}) target_link_libraries (${PROJECT_NAME} INTERFACE http-client-lite) set (${PROJECT_NAME}_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE) # it need for save_to_file_t if(NOT WIN32) find_package(Threads) target_link_libraries(${PROJECT_NAME} INTERFACE ${CMAKE_THREAD_LIBS_INIT}) endif() prometheus-cpp-lite-master/core/include/0000755000765700003170000000000014466227470017535 5ustar martinzdvprometheus-cpp-lite-master/core/include/prometheus/0000755000765700003170000000000014466227470021730 5ustar martinzdvprometheus-cpp-lite-master/core/include/prometheus/atomic_floating.h0000644000765700003170000000313114466227470025236 0ustar martinzdv#pragma once #include #include namespace prometheus { template inline std::atomic& atomic_add_for_floating_types(std::atomic& value, const FloatingType& add) { FloatingType desired; FloatingType expected = value.load(std::memory_order_relaxed); do { desired = expected + add; } while (!value.compare_exchange_weak(expected, desired)); return value; } template ::value, int>::type> inline std::atomic& operator++(std::atomic& value) { return atomic_add_for_floating_types(value, 1.0); } template ::value, int>::type> inline std::atomic& operator+=(std::atomic& value, const FloatingType& val) { return atomic_add_for_floating_types(value, val); } template ::value, int>::type> inline std::atomic& operator--(std::atomic& value) { return atomic_add_for_floating_types(value, -1.0); } template ::value, int>::type> inline std::atomic& operator-=(std::atomic& value, const FloatingType& val) { return atomic_add_for_floating_types(value, -val); } } prometheus-cpp-lite-master/core/include/prometheus/benchmark.h0000644000765700003170000000316614466227470024041 0ustar martinzdv#pragma once #include "prometheus/metric.h" #include "prometheus/family.h" #include namespace prometheus { class Benchmark : public Metric { #ifndef NDEBUG bool already_started = false; #endif std::chrono::time_point start_; std::chrono::time_point::duration elapsed = std::chrono::time_point::duration::zero(); // elapsed time public: using Value = double; using Family = CustomFamily; static const Metric::Type static_type = Metric::Type::Counter; Benchmark() : Metric(Metric::Type::Counter) {} void start() { #ifndef NDEBUG if (already_started) throw std::runtime_error("try to start already started counter"); else already_started = true; #endif start_ = std::chrono::high_resolution_clock::now(); } void stop() { #ifndef NDEBUG if (already_started == false) throw std::runtime_error("try to stop already stoped counter"); #endif std::chrono::time_point stop; stop = std::chrono::high_resolution_clock::now(); elapsed += stop - start_; #ifndef NDEBUG already_started = false; #endif } double Get() const { return std::chrono::duration_cast>(elapsed).count(); } virtual ClientMetric Collect() const { ClientMetric metric; metric.counter.value = Get(); return metric; } }; } // namespace prometheus prometheus-cpp-lite-master/core/include/prometheus/builder.h0000644000765700003170000000134214466227470023527 0ustar martinzdv#pragma once #include #include #include "registry.h" namespace prometheus { template class Builder { Family::Labels labels_; std::string name_; std::string help_; public: Builder& Labels(const std::map& labels) { labels_ = labels; return *this; } Builder& Name(const std::string& name) { name_ = name; return *this; } Builder& Help(const std::string& help) { help_ = help; return *this; } CustomFamily& Register(Registry& registry) { return registry.Add>(name_, help_, labels_); } }; }prometheus-cpp-lite-master/core/include/prometheus/ckms_quantiles.h0000644000765700003170000001046714466227470025133 0ustar martinzdv#pragma once #include #include #include #include namespace prometheus { namespace detail { class CKMSQuantiles { public: struct Quantile { double quantile; double error; double u; double v; Quantile(double quantile, double error) : quantile(quantile), error(error), u(2.0 * error / (1.0 - quantile)), v(2.0 * error / quantile) {} }; private: struct Item { double value; int g; int delta; Item(double value, int lower_delta, int delta) : value(value), g(lower_delta), delta(delta) {} }; public: explicit CKMSQuantiles(const std::vector& quantiles) : quantiles_(quantiles), count_(0), buffer_{}, buffer_count_(0) {} void insert(double value) { buffer_[buffer_count_] = value; ++buffer_count_; if (buffer_count_ == buffer_.size()) { insertBatch(); compress(); } } double get(double q) { insertBatch(); compress(); if (sample_.empty()) { return std::numeric_limits::quiet_NaN(); } int rankMin = 0; const auto desired = static_cast(q * static_cast(count_)); const auto bound = desired + (allowableError(desired) / 2); auto it = sample_.begin(); decltype(it) prev; auto cur = it++; while (it != sample_.end()) { prev = cur; cur = it++; rankMin += prev->g; if (rankMin + cur->g + cur->delta > bound) { return prev->value; } } return sample_.back().value; } void reset() { count_ = 0; sample_.clear(); buffer_count_ = 0; } private: double allowableError(int rank) { auto size = sample_.size(); double minError = static_cast(size + 1); for (const auto& q : quantiles_.get()) { double error; if (static_cast(rank) <= q.quantile * static_cast(size)) { error = q.u * static_cast(size - rank); } else { error = q.v * rank; } if (error < minError) { minError = error; } } return minError; } bool insertBatch() { if (buffer_count_ == 0) { return false; } std::sort(buffer_.begin(), buffer_.begin() + buffer_count_); std::size_t start = 0; if (sample_.empty()) { sample_.emplace_back(buffer_[0], 1, 0); ++start; ++count_; } std::size_t idx = 0; std::size_t item = idx++; for (std::size_t i = start; i < buffer_count_; ++i) { double v = buffer_[i]; while (idx < sample_.size() && sample_[item].value < v) { item = idx++; } if (sample_[item].value > v) { --idx; } int delta; if (idx - 1 == 0 || idx + 1 == sample_.size()) { delta = 0; } else { delta = static_cast(std::floor(allowableError(static_cast(idx + 1)))) + 1; } sample_.emplace(sample_.begin() + idx, v, 1, delta); count_++; item = idx++; } buffer_count_ = 0; return true; } void compress() { if (sample_.size() < 2) { return; } std::size_t idx = 0; std::size_t prev; std::size_t next = idx++; while (idx < sample_.size()) { prev = next; next = idx++; if (sample_[prev].g + sample_[next].g + sample_[next].delta <= allowableError(static_cast(idx - 1))) { sample_[next].g += sample_[prev].g; sample_.erase(sample_.begin() + prev); } } } private: const std::reference_wrapper> quantiles_; std::size_t count_; std::vector sample_; std::array buffer_; std::size_t buffer_count_; }; } // namespace detail } // namespace prometheus prometheus-cpp-lite-master/core/include/prometheus/client_metric.h0000644000765700003170000000307214466227470024724 0ustar martinzdv#pragma once #include #include #include #include #include namespace prometheus { struct ClientMetric { // Label struct Label { std::string name; std::string value; Label(std::string name_, std::string value_) : name(std::move(name_)), value(std::move(value_)) {} bool operator<(const Label& rhs) const { return std::tie(name, value) < std::tie(rhs.name, rhs.value); } bool operator==(const Label& rhs) const { return std::tie(name, value) == std::tie(rhs.name, rhs.value); } }; std::vector