• Home
  • Extend Dynatrace
  • Send data to Dynatrace with OpenTelemetry
  • OpenTelemetry metrics
  • Instrument for metrics
  • Instrument C++ applications with OpenTelemetry Metrics

Instrument C++ applications with OpenTelemetry Metrics

This guide shows how to instrument your C++ application with OpenTelemetry and export the metrics to Dynatrace.

  • To learn more about how Dynatrace works with OpenTelemetry, see Send data to Dynatrace with OpenTelemetry.

OpenTelemetry-cpp prerequisites

  • A supported development platform.
  • A compatible C++ compiler.
  • Git for fetching opentelemetry-cpp source code from repository. For details, see how to set up git.
  • CMake for building opentelemetry-cpp API and SDK. For details, see how to install CMake.
  • GoogleTest framework to build and run the OpenTelemetry unit tests. For details, see how to install GoogleTest.
  • Google benchmark, a library to benchmark code snippets. For details, see how to install benchmark.

OpenTelemetry-cpp OTLP exporter prerequisites

  • Protobuf library to serialize structured data. For details, see how to install Protobuf.
  • libcurl the multiprotocol file transfer library. For details, see (libcurl documentation).
  • nlohmann/json the JSON for Modern C++ (you can use cmake to build and install nlohmann/json from its github repository).

Build and install the OpenTelemetry-cpp

Now that you have all the dependencies, let's build the opentelemetry-cpp using CMake.
We will follow the steps from OpenTelemetry, with some adjustments to also build the OTLP_HTTP exporter.

  1. Get the opentelemetry-cpp source in the directory where you want to create the code repository:
shell
git clone --recursive https://github.com/open-telemetry/opentelemetry-cpp
  1. Navigate to the cloned repository and create the CMake build configuration:
shell
cd opentelemetry-cpp mkdir build && cd build cmake -DBUILD_TESTING=OFF -DWITH_OTLP=ON -DWITH_OTLP_HTTP=ON ..
  1. Once the build configuration is created, build the CMake targets. This step includes building SDKs and the unit tests for API and SDK. Note that, since the API is a header-only library, no separate build is triggered for it.
shell
cmake --build . --target all
  1. To validate your build, run the tests:
shell
ctest
  1. Install the header files for the API, and the generated targets and header files for the SDK. You can also define the install location by adding --prefix /<install_root>/ to the command below, or execute it as is to use the default one.
shell
cmake --install .

Overview

To monitor your C++ application with OpenTelemetry

Instrument your application

Send the data to Dynatrace

Restart your application and verify that the metrics are ingested into Dynatrace

Instrument your application

C++ instrumentation requires some manual steps. Add the following to your CMakeLists.txt file and add the code snippet below to any C++ method you want to monitor.

  • Set names for the meter and the instrument.
  • Add a description and attributes to the instrument as you see fit.
cpp
find_package(CURL REQUIRED) find_package(nlohmann_json REQUIRED) find_package(opentelemetry-cpp CONFIG REQUIRED) find_package(Protobuf REQUIRED) find_package(gRPC CONFIG REQUIRED) target_include_directories(app PRIVATE ${OPENTELEMETRY_CPP_INCLUDE_DIRS}) target_link_libraries(app ${OPENTELEMETRY_CPP_LIBRARIES} opentelemetry_trace opentelemetry_http_client_curl opentelemetry_metrics opentelemetry_exporter_otlp_http_client opentelemetry_exporter_otlp_http opentelemetry_exporter_otlp_http_metric opentelemetry_resources gRPC::grpc++)

Send data to Dynatrace

Dynatrace version 1.254+

You can create a new header file to take care of all metrics-related configurations.

Simply include it in on the top of your application's files and call its method.

cpp
#include "meter_common.h" initMeter();

This is the code for the header file meter_common.h:

cpp
//meter_common.h //Add dependencies #include "opentelemetry/exporters/otlp/otlp_grpc_metric_exporter_factory.h" #include "opentelemetry/exporters/otlp/otlp_http_metric_exporter_factory.h" #include "opentelemetry/exporters/otlp/otlp_http_metric_exporter.h" #include "opentelemetry/ext/http/client/http_client_factory.h" #include "opentelemetry/metrics/provider.h" #include "opentelemetry/sdk/metrics/aggregation/default_aggregation.h" #include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h" #include "opentelemetry/sdk/metrics/meter.h" #include "opentelemetry/sdk/metrics/meter_provider.h" #include <memory> #include <thread> //namespaces namespace metric_sdk = opentelemetry::sdk::metrics; namespace metrics_api = opentelemetry::metrics; namespace otlp_exporter = opentelemetry::exporter::otlp; namespace { otlp_exporter::OtlpHttpMetricExporterOptions options; std::string version{ "1.0.1" }; //TODO Replace with the version of your application std::string name{ "cpp-quickstart" }; //TODO Replace with the name of your application std::string schema{ "https://opentelemetry.io/schemas/1.2.0" }; void initMeter() { //These are the options that are passed to the exporter, like authorization, endpoint, etc. otlp_exporter::OtlpHttpMetricExporterOptions otlpOptions; otlpOptions.url = "<URL>"; //TODO Replace <URL> to your SaaS/Managed-URL as mentioned in the next step otlpOptions.aggregation_temporality = opentelemetry::sdk::metrics::AggregationTemporality::kDelta; otlpOptions.content_type = otlp_exporter::HttpRequestContentType::kBinary; otlpOptions.http_headers.insert( std::make_pair<const std::string, std::string>("Authorization", "Api-Token <TOKEN>")); //TODO Replace <TOKEN> with your API Token as mentioned in the next step //This creates the exporter with the options we have defined above. auto exporter = otlp_exporter::OtlpHttpMetricExporterFactory::Create(otlpOptions); //This builds a MeterProvider and a Reader metric_sdk::PeriodicExportingMetricReaderOptions options; options.export_interval_millis = std::chrono::milliseconds(1000); options.export_timeout_millis = std::chrono::milliseconds(500); std::unique_ptr<metric_sdk::MetricReader> reader{ new metric_sdk::PeriodicExportingMetricReader(std::move(exporter), options) }; auto provider = std::shared_ptr<metrics_api::MeterProvider>(new metric_sdk::MeterProvider()); auto p = std::static_pointer_cast<metric_sdk::MeterProvider>(provider); p->AddMetricReader(std::move(reader)); //This builds a Meter for your instruments std::unique_ptr<metric_sdk::InstrumentSelector> instrument_selector{ new metric_sdk::InstrumentSelector(metric_sdk::InstrumentType::kCounter, name) }; std::unique_ptr<metric_sdk::MeterSelector> meter_selector{ new metric_sdk::MeterSelector(name, version, schema) }; std::unique_ptr<metric_sdk::View> sum_view{ new metric_sdk::View{name, "description", metric_sdk::AggregationType::kSum} }; p->AddView(std::move(instrument_selector), std::move(meter_selector), std::move(sum_view)); //This builds your instrument, in this case: a counter auto meter = provider->GetMeter(name, "0.0.0"); //TODO Replace with the version of your meter auto double_counter = meter->CreateDoubleCounter("cpp-double-counter"); //TODO Replace with the name of your instrument } }

In this case, we used a Counter instrument. To find the instrument that fits your needs, see the official OpenTelemetry documentation. The code below creates the instrument with attributes and calls the Add method on it.

cpp
//This creates a label set which annotates metric values std::map<std::string, std::string> labels = { {"key", "value"} }; //TODO Add attributes auto labelkv = opentelemetry::common::KeyValueIterableView<decltype(labels)>{ labels }; //This will add to the counter double_counter->Add(1.0, labelkv);

If no OneAgent is available locally, you need to define the correct endpoint and token to make sure your data arrives where it should be.

  • To set the endpoint
    1. Use your Environment ID to set the endpoint to which your app will send traces as follows:
      • Dynatrace SaaS https://{your-environment-id}.live.dynatrace.com/api/v2/metrics/ingest
      • Dynatrace Managed https://{your-domain}/e/{your-environment-id}/api/v2/metrics/ingest
      • Dynatrace ActiveGate https://{your-activegate-endpoint}/e/{your-environment-id}/api/v2/metrics/ingest
        • You may need to include the port to your ActiveGate endpoint. For example:
          • https://{your-activegate-endpoint}:9999/e/{your-environment-id}/api/v2/metrics/ingest
        • If you are running a containerized ActiveGate, you need to use the FQDN of it. For example:
          • https://{your-activegate-service-name}.dynatrace.svc.cluster.local/e/{your-environment-id}/api/v2/metrics/ingest
    2. Replace <URL> in the code snippet above with your endpoint.
  • To create an authentication token
    1. In the Dynatrace menu, go to Access tokens and select Generate new token.
    2. Provide a Token name.
    3. In the Search scopes box, search for Ingest metrics (under API v2 scopes), and select the checkbox.
    4. Select Generate token.
    5. Select Copy to copy the token to your clipboard.
    6. Save the token in a safe place; you can't display it again.
    7. Replace <TOKEN> in the code snippet above with your token.

Verify that the metrics are ingested into Dynatrace

A few minutes after restarting your app, look for your metrics:

  • In the Dynatrace menu, go to Metrics and filter for your metrics (by the names you have given them).
  • To get more detailed information, or to filter for different criteria, expand Details for a metric and select Create chart.

If your application doesn't receive any traffic, no metrics are generated, consequently Dynatrace won't ingest any metrics.