From 0c5efa0f83d4773f6faea5067cb75c8087f233e0 Mon Sep 17 00:00:00 2001 From: mohamedasifs123 <142201466+mohamedasifs123@users.noreply.github.com> Date: Tue, 4 Feb 2025 11:41:22 +0530 Subject: [PATCH] feat: demo doca app compiled with otel cpp Signed-off-by: Mohamed Asif <142201466+mohamedasifs123@users.noreply.github.com> feat: adding doca otel cpp demo Signed-off-by: Mohamed Asif <142201466+mohamedasifs123@users.noreply.github.com> Rename config/doca-demo/demo.png to config/doca-demo/images/demo.png Signed-off-by: Mohamed Asif <142201466+mohamedasifs123@users.noreply.github.com> Update README.md Signed-off-by: Mohamed Asif <142201466+mohamedasifs123@users.noreply.github.com> Rename Screenshot (31).png to demo.png Signed-off-by: Mohamed Asif <142201466+mohamedasifs123@users.noreply.github.com> Add files via upload Signed-off-by: Mohamed Asif <142201466+mohamedasifs123@users.noreply.github.com> Create README.md Signed-off-by: Mohamed Asif <142201466+mohamedasifs123@users.noreply.github.com> feat: adding meson build Signed-off-by: mohamedasifs123 <142201466+mohamedasifs123@users.noreply.github.com> feat: demo doca app compiled with otel cpp Signed-off-by: mohamedasifs123 <142201466+mohamedasifs123@users.noreply.github.com> --- doca-demo/README.md | 256 +++++++++++++++++++++++++++++ doca-demo/images/demo.png | Bin 0 -> 55455 bytes doca-demo/main.cc | 329 ++++++++++++++++++++++++++++++++++++++ doca-demo/meson.build | 68 ++++++++ 4 files changed, 653 insertions(+) create mode 100644 doca-demo/README.md create mode 100644 doca-demo/images/demo.png create mode 100644 doca-demo/main.cc create mode 100644 doca-demo/meson.build diff --git a/doca-demo/README.md b/doca-demo/README.md new file mode 100644 index 0000000..244fd14 --- /dev/null +++ b/doca-demo/README.md @@ -0,0 +1,256 @@ +# OpenTelemetry C++ Starter for DOCA + +## Prerequisites + +Ensure you have the following installed: + +- **Git** +- **C++ Compiler** +- **Make** +- **CMake** +- **Docker** (for running the OTLP collector and Jeager) + +### Create Project Directory + +Create a folder named otel-cpp-starter. + +move into the newly created folder. This will serve as your working directory. + +```bash +mkdir otel-cpp-starter +cd otel-cpp-starter +``` + +Next, install and build OpenTelemetry C++ locally using CMake, following these steps: + +In your terminal, navigate back to the otel-cpp-starter directory. Then, clone the OpenTelemetry C++ GitHub repository to your local machine. + +```bash +git clone https://github.com/open-telemetry/opentelemetry-cpp.git +``` + +Change your working directory to the OpenTelemetry C++ SDK directory. + +```bash +cd opentelemetry-cpp +``` + +Create a build directory and navigate into it. + +```bash +mkdir build +cd build +``` + +In the build directory run CMake, to configure and generate the build system without enabling tests: + +```bash +cmake -DBUILD_TESTING=OFF .. +Or, if the cmake --build fails, you can also try: + +cmake -DBUILD_TESTING=OFF -DWITH_ABSEIL=ON .. +Execute the build process: + +cmake --build . +Install OpenTelemetry C++ in otel-cpp-starter/otel-cpp: + +cmake --install . --prefix ../../otel-cpp +``` + +## Traces + +### Initialize tracing + +```bash +auto provider = opentelemetry::trace::Provider::GetTracerProvider(); +auto tracer = provider->GetTracer("foo_library", "1.0.0"); +``` + +The TracerProvider acquired in the first step is a singleton object that is usually provided by the OpenTelemetry C++ SDK. It is used to provide specific implementations for API interfaces. In case no SDK is used, the API provides a default no-op implementation of a TracerProvider. + +The Tracer acquired in the second step is needed to create and start Spans. + +#### Start a span + +```bash +auto span = tracer->StartSpan("HandleRequest"); +``` + +This creates a span, sets its name to "HandleRequest", and sets its start time to the current time. Refer to the API documentation for other operations that are available to enrich spans with additional data. + +#### Mark a span as active + +```bash +auto scope = tracer->WithActiveSpan(span); +``` + +This marks a span as active and returns a Scope object. The scope object controls how long a span is active. The span remains active for the lifetime of the scope object. + +The concept of an active span is important, as any span that is created without explicitly specifying a parent is parented to the currently active span. A span without a parent is called root span. + +## Exporters + +### Available exporters + +The registry contains a list of exporters for C++. + +Among exporters, OpenTelemetry Protocol (OTLP) exporters are designed with the OpenTelemetry data model in mind, emitting OTel data without any loss of information. Furthermore, many tools that operate on telemetry data support OTLP (such as Prometheus, Jaeger, and most vendors), providing you with a high degree of flexibility when you need it. To learn more about OTLP, see OTLP Specification. + +This page covers the main OpenTelemetry C++ exporters and how to set them up. + +## OTLP Exporter + +### Collector Setup + +In an empty directory, create a file called collector-config.yaml with the following content: + +```yaml +receivers: + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + http: + endpoint: 0.0.0.0:4318 +exporters: + debug: + verbosity: detailed +service: + pipelines: + traces: + receivers: [otlp] + exporters: [debug] + metrics: + receivers: [otlp] + exporters: [debug] + logs: + receivers: [otlp] + exporters: [debug] +``` + +Now run the collector in a docker container: + +```bash +docker run -p 4317:4317 -p 4318:4318 --rm -v $(pwd)/collector-config.yaml:/etc/otelcol/config.yaml otel/opentelemetry-collector +``` + +This collector is now able to accept telemetry via OTLP. Later you may want to configure the collector to send your telemetry to your observability backend. + +#### Dependencies + +If you want to send telemetry data to an OTLP endpoint (like the OpenTelemetry Collector, Jaeger or Prometheus), you can choose between two different protocols to transport your data: + +HTTP/protobuf +gRPC +Make sure that you have set the right cmake build variables while building OpenTelemetry C++ from source: + +```bash +-DWITH_OTLP_GRPC=ON: To enable building OTLP gRPC exporter. +-DWITH_OTLP_HTTP=ON: To enable building OTLP HTTP exporter. +``` + +In this tutorial, we use HTTP endpoint. + +## Usage + +```bash +#include "opentelemetry/exporters/otlp/otlp_http_exporter_factory.h" +#include "opentelemetry/exporters/otlp/otlp_http_exporter_options.h" +#include "opentelemetry/sdk/trace/processor.h" +#include "opentelemetry/sdk/trace/batch_span_processor_factory.h" +#include "opentelemetry/sdk/trace/batch_span_processor_options.h" +#include "opentelemetry/sdk/trace/tracer_provider_factory.h" +#include "opentelemetry/trace/provider.h" +#include "opentelemetry/sdk/trace/tracer_provider.h" + +#include "opentelemetry/exporters/otlp/otlp_http_metric_exporter_factory.h" +#include "opentelemetry/exporters/otlp/otlp_http_metric_exporter_options.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/export/periodic_exporting_metric_reader_factory.h" +#include "opentelemetry/sdk/metrics/meter_context_factory.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" +#include "opentelemetry/sdk/metrics/meter_provider_factory.h" + +#include "opentelemetry/exporters/otlp/otlp_http_log_record_exporter_factory.h" +#include "opentelemetry/exporters/otlp/otlp_http_log_record_exporter_options.h" +#include "opentelemetry/logs/provider.h" +#include "opentelemetry/sdk/logs/logger_provider_factory.h" +#include "opentelemetry/sdk/logs/processor.h" +#include "opentelemetry/sdk/logs/simple_log_record_processor_factory.h" + +namespace trace_api = opentelemetry::trace; +namespace trace_sdk = opentelemetry::sdk::trace; + +namespace metric_sdk = opentelemetry::sdk::metrics; +namespace metrics_api = opentelemetry::metrics; + +namespace otlp = opentelemetry::exporter::otlp; + +namespace logs_api = opentelemetry::logs; +namespace logs_sdk = opentelemetry::sdk::logs; + + + +void InitTracer() + { + // Create an OpenTelemetry Protocol (OTLP) exporter. + auto exporter = otlp::OtlpHttpExporterFactory::Create(opts); + auto processor = trace_sdk::SimpleSpanProcessorFactory::Create(std::move(exporter)); + + resource::ResourceAttributes attributes = { + {resource::SemanticConventions::kServiceName, "DOCA NVIDIA DEMO"}, // The application name. + {resource::SemanticConventions::kHostName, "$"} + }; + auto resource = opentelemetry::sdk::resource::Resource::Create(attributes); + + std::shared_ptr provider = + trace_sdk::TracerProviderFactory::Create(std::move(processor), std::move(resource)); + + // Set the trace provider. + trace::Provider::SetTracerProvider(provider); + } +void CleanupTracer() +{ + std::shared_ptr none; + trace::Provider::SetTracerProvider(none); +} +``` + +and then we define our function traces and we pass the service name and operation name on to it. + +```bash +void traces(std::string serviceName, std::string operationName) +{ + auto span = getTracer(serviceName)->StartSpan(operationName); + + span->SetAttribute("service.name", serviceName); + + span->End(); +} +``` + +we call it by using the traces and can pass the service and operation names respectively + +```bash + traces("doca", "doca prepare"); +``` + +The traces are called and it send the traces to otlp endpoint. + +After that, by using otlp the traces is sent to the jeager and it can be accessed on http... + +The Build steps are as follows, + +```bash +meson build +cd build +./doca_telemetry_export +``` + +make sure to run the docker containers for otel and jeager before executing above commands. + +the will display on browser on [Jeager](https://localhost:16686) + +![demo](images/demo.png) diff --git a/doca-demo/images/demo.png b/doca-demo/images/demo.png new file mode 100644 index 0000000000000000000000000000000000000000..ba6f5931c31ae67dded67286ce0519c5519c9e45 GIT binary patch literal 55455 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

{O@wS1zYveZxe#9EPA=b2V(#L%xBQ@n)A(M9j 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 literal 0 HcmV?d00001 diff --git a/doca-demo/main.cc b/doca-demo/main.cc new file mode 100644 index 0000000..0ce69ce --- /dev/null +++ b/doca-demo/main.cc @@ -0,0 +1,329 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "opentelemetry/exporters/otlp/otlp_http_exporter_factory.h" +#include "opentelemetry/exporters/otlp/otlp_http_exporter_options.h" +#include "opentelemetry/context/propagation/global_propagator.h" +#include "opentelemetry/context/propagation/text_map_propagator.h" +#include "opentelemetry/exporters/ostream/span_exporter_factory.h" +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/sdk/trace/simple_processor_factory.h" +#include "opentelemetry/sdk/trace/tracer_context.h" +#include "opentelemetry/sdk/trace/tracer_context_factory.h" +#include "opentelemetry/sdk/trace/tracer_provider_factory.h" +#include "opentelemetry/trace/propagation/http_trace_context.h" +#include "opentelemetry/trace/provider.h" +#include "opentelemetry/ext/http/client/http_client_factory.h" +#include "opentelemetry/sdk/resource/semantic_conventions.h" +#include "opentelemetry/sdk/common/global_log_handler.h" + +#define NB_EXAMPLE_STRINGS 5 /* Amount of example strings */ +#define MAX_EXAMPLE_STRING_SIZE 256 /* Indicates the max length of string */ +#define SINGLE_FIELD_VALUE 1 /* Indicates the field contains one value */ +namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; +namespace trace_sdk = opentelemetry::sdk::trace; +namespace otlp = opentelemetry::exporter::otlp; +namespace internal_log = opentelemetry::sdk::common::internal_log; +namespace resource = opentelemetry::sdk::resource; + +opentelemetry::nostd::shared_ptr getTracer( + std::string serviceName) +{ + auto provider = opentelemetry::trace::Provider::GetTracerProvider(); + return provider->GetTracer(serviceName); +} + opentelemetry::exporter::otlp::OtlpHttpExporterOptions opts; + + +void traces(std::string serviceName, std::string operationName) +{ + auto span = getTracer(serviceName)->StartSpan(operationName); + + span->SetAttribute("service.name", serviceName); + + span->End(); +} + +void InitTracer() + { + // Create an OpenTelemetry Protocol (OTLP) exporter. + auto exporter = otlp::OtlpHttpExporterFactory::Create(opts); + auto processor = trace_sdk::SimpleSpanProcessorFactory::Create(std::move(exporter)); + + resource::ResourceAttributes attributes = { + {resource::SemanticConventions::kServiceName, "DOCA NVIDIA DEMO"}, // The application name. + {resource::SemanticConventions::kHostName, "$"} + }; + auto resource = opentelemetry::sdk::resource::Resource::Create(attributes); + + std::shared_ptr provider = + trace_sdk::TracerProviderFactory::Create(std::move(processor), std::move(resource)); + + // Set the trace provider. + trace::Provider::SetTracerProvider(provider); + } + + void CleanupTracer() + { + std::shared_ptr none; + trace::Provider::SetTracerProvider(none); + } + + nostd::shared_ptr get_tracer() + { + auto provider = trace::Provider::GetTracerProvider(); + return provider->GetTracer("library name to trace", OPENTELEMETRY_SDK_VERSION); + } +DOCA_LOG_REGISTER(TELEMETRY); + +static std::vector example_strings = { + "example_str_1", "example_str_2", "example_str_3", "example_str_4", "example_str_5" +}; + +/* Event struct from which report will be serialized */ +struct TestEventType { + doca_telemetry_timestamp_t timestamp; + int32_t event_number; + int32_t iter_number; + uint64_t string_number; + char example_string[MAX_EXAMPLE_STRING_SIZE]; +} __attribute__((packed)); + +/* + * This function fills up event buffer with the example string of specified number. + * It also saves number of iteration, number of string and overall number of events. + */ +static doca_error_t prepare_example_event(int32_t iter_number, uint64_t string_number, TestEventType &event) { + static int collected_example_events_count = 0; + doca_telemetry_timestamp_t timestamp; + doca_error_t result = DOCA_SUCCESS; + traces("doca", "doca prepare"); +result = doca_telemetry_get_timestamp(×tamp); + + if (result != DOCA_SUCCESS) + return result; + + event.timestamp = timestamp; + event.event_number = collected_example_events_count++; + event.iter_number = iter_number; + event.string_number = string_number; + + if (example_strings[string_number].length() >= MAX_EXAMPLE_STRING_SIZE) + return DOCA_ERROR_INVALID_VALUE; + + strncpy(event.example_string, example_strings[string_number].c_str(), MAX_EXAMPLE_STRING_SIZE); + return DOCA_SUCCESS; +} + +/* + * Registers the example fields to the doca_telemetry_type. + */ +static doca_error_t telemetry_register_fields(doca_telemetry_type *type) { + doca_error_t result; + doca_telemetry_field *field; + const int nb_fields = 5; + + struct { + const char *name; + const char *desc; + const char *type_name; + uint16_t len; + } fields_info[] = { + {"timestamp", "Event timestamp", DOCA_TELEMETRY_FIELD_TYPE_TIMESTAMP, SINGLE_FIELD_VALUE}, + {"event_number", "Event number", DOCA_TELEMETRY_FIELD_TYPE_INT32, SINGLE_FIELD_VALUE}, + {"iter_num", "Iteration number", DOCA_TELEMETRY_FIELD_TYPE_INT32, SINGLE_FIELD_VALUE}, + {"string_number", "String number", DOCA_TELEMETRY_FIELD_TYPE_UINT64, SINGLE_FIELD_VALUE}, + {"example_string", "String example", DOCA_TELEMETRY_FIELD_TYPE_CHAR, MAX_EXAMPLE_STRING_SIZE}, + }; + + for (int i = 0; i < nb_fields; i++) { + result = doca_telemetry_field_create(&field); + if (result != DOCA_SUCCESS) + return result; + traces("register fields", fields_info[i].name); + + doca_telemetry_field_set_name(field, fields_info[i].name); + doca_telemetry_field_set_description(field, fields_info[i].desc); + doca_telemetry_field_set_type_name(field, fields_info[i].type_name); + doca_telemetry_field_set_array_len(field, fields_info[i].len); + + result = doca_telemetry_type_add_field(type, field); + if (result != DOCA_SUCCESS) + return result; + } + + return result; +} + +doca_error_t telemetry_export() { + bool file_write_enable = true; + bool ipc_enabled = true; + int repetition = 10; + doca_error_t result; + int32_t iteration = 0; + uint64_t string_number = 0; + doca_telemetry_schema *doca_schema = nullptr; + doca_telemetry_source *doca_source = nullptr; + TestEventType test_event; + doca_telemetry_type_index_t example_index; + doca_telemetry_type *example_type; + + result = doca_telemetry_schema_init("example_doca_schema_name", &doca_schema); + if (result != DOCA_SUCCESS) { + DOCA_LOG_ERR("Cannot init doca schema"); + return result; + } + + doca_telemetry_schema_set_buf_size(doca_schema, sizeof(test_event) * 5); + + result = doca_telemetry_type_create(&example_type); + if (result != DOCA_SUCCESS) { + DOCA_LOG_ERR("Cannot create type"); + goto err_schema; + } + + result = telemetry_register_fields(example_type); + if (result != DOCA_SUCCESS) { + DOCA_LOG_ERR("Cannot register fields"); + doca_telemetry_type_destroy(example_type); + goto err_schema; + } + + if (file_write_enable) + doca_telemetry_schema_set_file_write_enabled(doca_schema); + + if (ipc_enabled) + doca_telemetry_schema_set_ipc_enabled(doca_schema); + + result = doca_telemetry_schema_add_type(doca_schema, "example_event", example_type, &example_index); + if (result != DOCA_SUCCESS) { + DOCA_LOG_ERR("Cannot add type to doca_schema!"); + goto err_schema; + } + + result = doca_telemetry_schema_start(doca_schema); + if (result != DOCA_SUCCESS) { + DOCA_LOG_ERR("Cannot start doca_schema!"); + goto err_schema; + } + + result = doca_telemetry_source_create(doca_schema, &doca_source); + if (result != DOCA_SUCCESS) { + DOCA_LOG_ERR("Cannot create doca_source!"); + goto err_schema; + } + + doca_telemetry_source_set_id(doca_source, "source_1"); + doca_telemetry_source_set_tag(doca_source, "source_1_tag"); + + result = doca_telemetry_source_start(doca_source); + if (result != DOCA_SUCCESS) { + DOCA_LOG_ERR("Cannot start doca_source!"); + goto err_source; + } + + for (iteration = 0; iteration < repetition; iteration++) { + for (string_number = 0; string_number < NB_EXAMPLE_STRINGS; string_number++) { + result = prepare_example_event(iteration, string_number, test_event); + if (result != DOCA_SUCCESS) { + DOCA_LOG_ERR("Failed to create event"); + goto err_source; + } + + result = doca_telemetry_source_report(doca_source, example_index, &test_event, 1); + if (result != DOCA_SUCCESS) { + DOCA_LOG_ERR("Cannot report to doca_source!"); + goto err_source; + + } + + if (iteration % 2 == 0) { + /* + * Optionally force DOCA Telemetry source buffer to flush. + * Handy for bursty events or specific event types. + */ + result = doca_telemetry_source_flush(doca_source); + if (result != DOCA_SUCCESS) { + DOCA_LOG_ERR("Cannot flush doca_source!"); + goto err_source; + } + } + } + + } + + doca_telemetry_source_destroy(doca_source); + doca_telemetry_schema_destroy(doca_schema); + return DOCA_SUCCESS; + +err_source: + doca_telemetry_source_destroy(doca_source); +err_schema: + doca_telemetry_schema_destroy(doca_schema); + return result; +} + +int main(int argc, char *argv[]) { + InitTracer(); + + doca_error_t result; + struct doca_log_backend *sdk_log; + int exit_status = EXIT_FAILURE; + + /* Register a logger backend */ + result = doca_log_backend_create_standard(); + if (result != DOCA_SUCCESS) + goto sample_exit; + + /* Register a logger backend for internal SDK errors and warnings */ + result = doca_log_backend_create_with_file_sdk(stderr, &sdk_log); + if (result != DOCA_SUCCESS) + goto sample_exit; + result = doca_log_backend_set_sdk_level(sdk_log, DOCA_LOG_LEVEL_WARNING); + if (result != DOCA_SUCCESS) + goto sample_exit; + + DOCA_LOG_INFO("Starting the sample"); + + /* Parse cmdline/json arguments */ + result = doca_argp_init("doca_telemetry_export", NULL); + if (result != DOCA_SUCCESS) { + DOCA_LOG_ERR("Failed to init ARGP resources: %s", doca_error_get_descr(result)); + goto sample_exit; + } + result = doca_argp_start(argc, argv); + if (result != DOCA_SUCCESS) { + DOCA_LOG_ERR("Failed to parse sample input: %s", doca_error_get_descr(result)); + goto argp_cleanup; + } + result = telemetry_export(); + if (result != DOCA_SUCCESS) { + DOCA_LOG_ERR("telemetry_export() encountered an error: %s", doca_error_get_descr(result)); + goto argp_cleanup; + } + + exit_status = EXIT_SUCCESS; + +argp_cleanup: + doca_argp_destroy(); +sample_exit: + if (exit_status == EXIT_SUCCESS) + DOCA_LOG_INFO("Sample finished successfully"); + else + DOCA_LOG_INFO("Sample finished with errors"); + CleanupTracer(); + + return exit_status; + +} diff --git a/doca-demo/meson.build b/doca-demo/meson.build new file mode 100644 index 0000000..28bce76 --- /dev/null +++ b/doca-demo/meson.build @@ -0,0 +1,68 @@ +# +# Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES, ALL RIGHTS RESERVED. +# +# This software product is a proprietary product of NVIDIA CORPORATION & +# AFFILIATES (the "Company") and all right, title, and interest in and to the +# software product, including all associated intellectual property rights, are +# and shall remain exclusively with the Company. +# +# This software product is governed by the End User License Agreement +# provided with the software product +# + +project('DOCA_SAMPLE', 'C', 'CPP', + # Get version number from file. + version: run_command(find_program('cat'), + files('/opt/mellanox/doca/applications/VERSION'), check: true).stdout().strip(), + license: 'Proprietary', + default_options: ['buildtype=debug'], + meson_version: '>= 0.61.2' +) + +SAMPLE_NAME = 'telemetry_export' + +# Comment this line to restore warnings of experimental DOCA features +add_project_arguments('-D DOCA_ALLOW_EXPERIMENTAL_API', language: ['c', 'cpp']) + +sample_dependencies = [] +# Required for all DOCA programs +sample_dependencies += dependency('doca-common') +# The DOCA library of the sample itself +sample_dependencies += dependency('doca-telemetry') +# Utility DOCA library for executables +sample_dependencies += dependency('doca-argp') +sample_dependencies += dependency('libcurl') + sample_dependencies +=dependency('opentelemetry-cpp', modules: [ + 'opentelemetry-cpp::proto', + 'opentelemetry-cpp::api', + 'opentelemetry-cpp::sdk', + 'opentelemetry-cpp::common', + 'opentelemetry-cpp::trace', + 'opentelemetry-cpp::metrics', + 'opentelemetry-cpp::logs', + 'opentelemetry-cpp::version', + 'opentelemetry-cpp::resources', + 'opentelemetry-cpp::ext', + 'opentelemetry-cpp::http_client_curl', + 'opentelemetry-cpp::otlp_recordable', + 'opentelemetry-cpp::otlp_http_client', + 'opentelemetry-cpp::otlp_http_exporter', + 'opentelemetry-cpp::otlp_http_log_record_exporter', + 'opentelemetry-cpp::otlp_http_metric_exporter', + 'opentelemetry-cpp::ostream_span_exporter', + 'opentelemetry-cpp::ostream_metrics_exporter', + 'opentelemetry-cpp::ostream_log_record_exporter', + 'opentelemetry-cpp::in_memory_span_exporter', + 'opentelemetry-cpp::in_memory_metric_exporter' + ]) +sample_srcs = [ + # Main function for the executable + 'main.cc', +] + +sample_inc_dirs = [] + +executable('doca_' + SAMPLE_NAME, sample_srcs, + dependencies : sample_dependencies, + include_directories: sample_inc_dirs, + install: false)