diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 02e6b56cd9..c7aa81aa7f 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(plugin) add_subdirectory(simple) add_subdirectory(batch) add_subdirectory(metrics_simple) +add_subdirectory(prometheus_exporter) diff --git a/examples/prometheus_exporter/BUILD b/examples/prometheus_exporter/BUILD new file mode 100644 index 0000000000..fccb816963 --- /dev/null +++ b/examples/prometheus_exporter/BUILD @@ -0,0 +1,25 @@ +# Copyright 2020, OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cc_binary( + name = "prometheus_exporter_example", + srcs = [ + "main.cc", + ], + deps = [ + "//exporters/prometheus:prometheus_exporter", + "//exporters/prometheus:prometheus_collector", + "//exporters/prometheus:prometheus_utils", + ], +) \ No newline at end of file diff --git a/examples/prometheus_exporter/CMakeLists.txt b/examples/prometheus_exporter/CMakeLists.txt new file mode 100644 index 0000000000..907a1797cb --- /dev/null +++ b/examples/prometheus_exporter/CMakeLists.txt @@ -0,0 +1,6 @@ +include_directories(${CMAKE_SOURCE_DIR}/exporters/prometheus/include) +find_package(prometheus-cpp CONFIG REQUIRED) + +add_executable(prom_exp_example main.cc) +target_link_libraries(prom_exp_example ${CMAKE_THREAD_LIBS_INIT} + prometheus_exporter prometheus-cpp::pull) diff --git a/examples/prometheus_exporter/README.md b/examples/prometheus_exporter/README.md new file mode 100644 index 0000000000..f8a5a30be6 --- /dev/null +++ b/examples/prometheus_exporter/README.md @@ -0,0 +1,66 @@ +# Prometheus Exporter Example + +In this example, the application in `main.cc` initializes the Prometheus exporter and exports 6 different OTel Aggregator to Prometheus. +Here are more detailed explanations of it. + +## Start Prometheus Instance +Start a Prometheus instance with Docker: +```shell script +docker run prom/prometheus +``` +Add Prometheus Exporter job configuration to `~/docker/prometheus/prometheus.yml` +```yaml +scrape_configs: + # ... + # other jobs + # ... + - job_name: 'test_prom_exporter' + static_configs: + - targets: ['docker.for.mac.localhost:8080'] +``` +Restart Prometheus instance and specify configuration file +```shell script +docker run -d --expose 8080 \ + -p 9090:9090 \ + -v ~/docker/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml \ + prom/prometheus +``` + +## Run Example Program + +To run the program, you must provide a command line argument to specify which Aggregator Kind you want to run the demo. The six choices are: +``` +counter, gauge, mmsc, histogram, exact, sketch +``` + +Run with Bazel: +```shell +bazel build //examples/prometheus_exporter:prometheus_exporter_example +bazel-bin/examples/prometheus_exporter/prometheus_exporter_example histogram +``` +The `histogram` command line argument is the argument `agg` to specify. + +For example, if we choose Histogram, this is what it would look like to build and execute the example: +``` +$ bazel build //examples/prometheus_exporter:prometheus_exporter_example +$ bazel-bin/examples/prometheus_exporter/prometheus_exporter_example histogram +Prometheus Exporter example program running on localhost:8080... +Running histogram example program... +``` +The example program generates 4 metrics every second, and exports every 15 seconds. + +Wait for a while, and visit `localhost:9090`. Choose the name of metrics to view the graphs. + +Histogram Count: Each batch of metric data contains 60 metrics + +![IMG](./images/count.png) + +Histogram Sum: + +![IMG](./images/sum.png) + +Histogram Buckets: + +![IMG](./images/buckets.png) + +The process is similar for other OTel Aggregator. \ No newline at end of file diff --git a/examples/prometheus_exporter/images/buckets.png b/examples/prometheus_exporter/images/buckets.png new file mode 100644 index 0000000000..54a3ad2850 Binary files /dev/null and b/examples/prometheus_exporter/images/buckets.png differ diff --git a/examples/prometheus_exporter/images/count.png b/examples/prometheus_exporter/images/count.png new file mode 100644 index 0000000000..4b9c89856c Binary files /dev/null and b/examples/prometheus_exporter/images/count.png differ diff --git a/examples/prometheus_exporter/images/sum.png b/examples/prometheus_exporter/images/sum.png new file mode 100644 index 0000000000..dabdbb50fb Binary files /dev/null and b/examples/prometheus_exporter/images/sum.png differ diff --git a/examples/prometheus_exporter/main.cc b/examples/prometheus_exporter/main.cc new file mode 100644 index 0000000000..714e8933cf --- /dev/null +++ b/examples/prometheus_exporter/main.cc @@ -0,0 +1,173 @@ +#include "opentelemetry/exporters/prometheus/prometheus_collector.h" +#include "opentelemetry/exporters/prometheus/prometheus_exporter.h" +#include "opentelemetry/sdk/metrics/aggregator/counter_aggregator.h" +#include "opentelemetry/sdk/metrics/aggregator/exact_aggregator.h" +#include "opentelemetry/sdk/metrics/aggregator/gauge_aggregator.h" +#include "opentelemetry/sdk/metrics/aggregator/histogram_aggregator.h" +#include "opentelemetry/sdk/metrics/aggregator/min_max_sum_count_aggregator.h" +#include "opentelemetry/sdk/metrics/aggregator/sketch_aggregator.h" + +#include +#include +#include +#include +#include + +namespace prom_exp = opentelemetry::exporter::prometheus; +namespace metric_sdk = opentelemetry::sdk::metrics; +namespace metric_api = opentelemetry::metrics; + +namespace +{ + template + metric_sdk::Record get_record(const std::string &type, + int version, + const std::string &label, + std::shared_ptr> aggregator) + { + std::string name = "test-" + type + "-metric-record-v_" + std::to_string(version) + ".0"; + std::string desc = "this is a test " + type + " metric record"; + metric_sdk::Record record(name, desc, label, aggregator); + return record; + } + + template + void do_example(const std::shared_ptr> &aggregator, + std::vector collection, + const metric_sdk::Record &record, + prom_exp::PrometheusExporter &exporter) + { + int counter = 0; + while (true) + { + int val = (rand() % 100) + 1; + aggregator->update(val); + + counter++; + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + + if (counter % 60 == 0) + { + // add record to collection and export the collection + aggregator->checkpoint(); + collection.emplace_back(record); + exporter.Export(collection); + counter = 0; + } + } + } + + void counter_example(prom_exp::PrometheusExporter &exporter) + { + auto aggregator = std::shared_ptr>( + new metric_sdk::CounterAggregator(metric_api::InstrumentKind::Counter)); + + // collection of records to export + std::vector collection; + auto record = get_record("counter", 1, "{label-1:v1,label2:v2,}", aggregator); + do_example(aggregator, collection, record, exporter); + } + + void gauge_example(prom_exp::PrometheusExporter &exporter) + { + auto aggregator = std::shared_ptr>( + new metric_sdk::GaugeAggregator(metric_api::InstrumentKind::Counter)); + + // collection of records to export + std::vector collection; + auto record = get_record("gauge", 1, "{label-1:v1,label2:v2,}", aggregator); + do_example(aggregator, collection, record, exporter); + } + + void mmsc_example(prom_exp::PrometheusExporter &exporter) + { + auto aggregator = std::shared_ptr>( + new metric_sdk::MinMaxSumCountAggregator(metric_api::InstrumentKind::Counter)); + + // collection of records to export + std::vector collection; + auto record = get_record("mmsc", 1, "{label-1:v1,label2:v2,}", aggregator); + do_example(aggregator, collection, record, exporter); + } + + void histogram_example(prom_exp::PrometheusExporter &exporter) + { + std::vector boundaries{10, 20, 30, 40, 50}; + auto aggregator = std::shared_ptr>( + new metric_sdk::HistogramAggregator(metric_api::InstrumentKind::Counter, boundaries)); + + // collection of records to export + std::vector collection; + auto record = get_record("histogram", 1, "{label-1:v1,label2:v2,}", aggregator); + do_example(aggregator, collection, record, exporter); + } + + void exact_example(prom_exp::PrometheusExporter &exporter) + { + auto aggregator = std::shared_ptr>( + new metric_sdk::ExactAggregator(metric_api::InstrumentKind::Counter, true)); + + // collection of records to export + std::vector collection; + auto record = get_record("exact", 1, "{label-1:v1,label2:v2,}", aggregator); + do_example(aggregator, collection, record, exporter); + } + + void sketch_example(prom_exp::PrometheusExporter &exporter) + { + auto aggregator = std::shared_ptr>( + new metric_sdk::SketchAggregator(metric_api::InstrumentKind::Counter, true)); + + // collection of records to export + std::vector collection; + auto record = get_record("sketch", 1, "{label-1:v1,label2:v2,}", aggregator); + do_example(aggregator, collection, record, exporter); + } +} +int main(int argc, char** argv) +{ + if(argc != 2) { + std::cout << "invalid number of command line arguments\n"; + return 0; + } + + std::string agg(argv[1]); + + std::string address = "localhost:8080"; + prom_exp::PrometheusExporter exporter{address}; + + std::cout << "Prometheus Exporter example program running on " << address << "...\n"; + std::cout << "Running " << agg << " example program...\n"; + + if (agg == "counter") + { + counter_example(exporter); + } + else if (agg == "gauge") + { + gauge_example(exporter); + } + else if (agg == "mmsc") + { + mmsc_example(exporter); + } + else if (agg == "histogram") + { + histogram_example(exporter); + } + else if (agg == "exact") + { + exact_example(exporter); + } + else if (agg == "sketch") + { + sketch_example(exporter); + } + else + { + std::cout << "invalid aggregator kind given\n"; + } + + + return 0; +} \ No newline at end of file