From f1b3d18b6290e8e862ba1751579f3a6c91801107 Mon Sep 17 00:00:00 2001 From: Azal Khaled <56312360+Akhaled19@users.noreply.github.com> Date: Fri, 9 Feb 2024 06:19:02 -0500 Subject: [PATCH] updated version of the C++ Getting Started with a Roll The Dice (#3423) --- .../en/docs/languages/cpp/getting-started.md | 489 +++++++++++++----- static/refcache.json | 12 + 2 files changed, 368 insertions(+), 133 deletions(-) diff --git a/content/en/docs/languages/cpp/getting-started.md b/content/en/docs/languages/cpp/getting-started.md index 197318b6eb5c..b725a64822c3 100644 --- a/content/en/docs/languages/cpp/getting-started.md +++ b/content/en/docs/languages/cpp/getting-started.md @@ -1,185 +1,408 @@ --- title: Getting Started +description: Get telemetry for your app in less than 5 minutes! +cSpell:ignore: oatpp rolldice weight: 10 -# prettier-ignore -cSpell:ignore: Bazel DBUILD devel DWITH helloworld libcurl openssl tracestate xcode --- -Welcome to the OpenTelemetry C++ getting started guide! This guide will walk you -through the basic steps in installing, instrumenting with, configuring, and -exporting data from OpenTelemetry. +This page will show you how to get started with OpenTelemetry in C++. -You can use [CMake](https://cmake.org/) or [Bazel](https://bazel.build/) for -building OpenTelemetry C++. The following getting started guide will make use of -CMake and only provide you the most essential steps to have a working example -application (a HTTP server & HTTP client). For more details read -[these instructions](https://github.com/open-telemetry/opentelemetry-cpp/blob/main/INSTALL.md). +You will learn how to instrument a simple C++ application, such that +[traces](/docs/concepts/signals/traces/) are emitted to the terminal. ## Prerequisites -You can build OpenTelemetry C++ on Windows, macOS or Linux. First you need to -install some dependencies: +Ensure that you have the following installed locally: -{{< tabpane text=true >}} {{% tab "Linux (apt)" %}} +- Git +- C++ compiler supporting C++ version >= 14 +- Make +- CMake version >= 3.20 -```sh -sudo apt-get install git cmake g++ libcurl4-openssl-dev -``` +## Example Application -{{% /tab %}} {{% tab "Linux (yum)" %}} +The following example uses a basic [Oat++](https://oatpp.io/) application. If +you are not using Oat++, that's OK - you can use OpenTelemetry C++ with any +other web framework as well. -```sh -sudo yum install git cmake g++ libcurl-devel -``` +## Setup + +- Create a folder named `otel-cpp-starter`. +- move into the newly created folder. This will serve as your working directory. +- After setting up dependencies, your directory structure should resemble this: + + ```plaintext + otel-cpp-starter + │ + ├── oatpp + ├── opentelemetry-cpp + └── roll-dice + ``` + +## Dependencies + +To begin, install Oat++ locally using the +[source code](https://github.com/oatpp) and `make`, following these steps: + +1. Obtain the Oat++ source code by cloning from the + [oatpp/oatpp](https://github.com/oatpp/oatpp) GitHub repository. + + ```bash + git clone https://github.com/oatpp/oatpp.git + ``` + +2. Navigate to the `oatpp` directory. + + ```bash + cd oatpp + ``` + +3. Create a `build` subdirectory and navigate into it. -{{% /tab %}} {{% tab "Linux (alpine)" %}} + ```bash + mkdir build + cd build + ``` -```sh -sudo apk add git cmake g++ make curl-dev +4. Build oatpp using the `cmake` and `make` commands. This command will trigger + the build process specified in the `CMakeLists.txt` included in the oatpp + source code. + + ```bash + cmake .. + make + ``` + +5. Install oatpp. + +This command will install the built oatpp library and headers on your system, +making it accessible for development in your project. + +```bash +sudo make install ``` -{{% /tab %}} {{% tab "MacOS (homebrew)" %}} +To uninstall the built oatpp library and headers from your system. -```sh -xcode-select —install -/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -brew install git cmake +```bash +sudo make uninstall ``` -{{% /tab %}} {{< /tabpane >}} +Next, install and build +[OpenTelemetry C++](https://github.com/open-telemetry/opentelemetry-cpp) locally +using CMake, following these steps: + +1. 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 + ``` + +2. Change your working directory to the OpenTelemetry C++ SDK directory. + + ```bash + cd opentelemetry-cpp + ``` + +3. Create a build directory and navigate into it. + + ```bash + mkdir build + cd build + ``` + +4. In the `build` directory run CMake, to configure and generate the build + system. -## Building + ```bash + cmake .. + ``` -Get the `opentelemetry-cpp` source: + Or, if the `cmake --build` fails, you can also try: -```shell -git clone --recursive https://github.com/open-telemetry/opentelemetry-cpp + ```bash + cmake -DWITH_ABSEIL=ON .. + ``` + +5. Execute the build process. + + ```bash + cmake --build . + ``` + +With Oat++ and OpenTelemetry C++ ready, you can continue with creating the HTTP +Server, that we want to instrument eventually. + +## Create and launch an HTTP Server + +In your `otel-cpp-starter` folder, create a subfolder `roll-dice`, where the +Oat++ library will be used by referencing the oatpp headers and linking them +when compiling your project. + +Create a file called `CMakeLists.txt` to define the Oat++ library directories, +include paths, and link against Oat++ during the compilation process. + +```cmake +project(RollDiceServer) +cmake_minimum_required(VERSION 3.1) +# Set C++ standard (e.g., C++17) +set(CMAKE_CXX_STANDARD 17) +set(project_name roll-dice-server) + +# Define your project's source files +set(SOURCES + main.cpp # Add your source files here +) + +# Create an executable target +add_executable(dice-server ${SOURCES}) + +set(OATPP_ROOT ../oatpp) +find_library(OATPP_LIB NAMES liboatpp.a HINTS "${OATPP_ROOT}/build/src/" NO_DEFAULT_PATH) + +if (NOT OATPP_LIB) + message(SEND_ERROR "Did not find oatpp library ${OATPP_ROOT}/build/src") +endif() +#set the path to the directory containing "oatpp" package configuration files +include_directories(${OATPP_ROOT}/src) +target_link_libraries(dice-server PRIVATE ${OATPP_LIB}) ``` -Navigate to the repository cloned above, and create the CMake build -configuration: +Next, the sample HTTP server source code is needed. It will do the following: + +- Initialize an HTTP router and set up a request handler to generate a random + number as the response when a GET request is made to the `/rolldice` endpoint. +- Next, create a connection handler, a connection provider, and start the server + on . +- Lastly, initialize and run the application within the main function. + +In that `roll-dice` folder, create a file called `main.cpp` and add the +following code to the file. + +```cpp +#include "oatpp/web/server/HttpConnectionHandler.hpp" +#include "oatpp/network/Server.hpp" +#include "oatpp/network/tcp/server/ConnectionProvider.hpp" +#include +#include +#include + +using namespace std; + +class Handler : public oatpp::web::server::HttpRequestHandler { +public: + shared_ptr handle(const shared_ptr& request) override { + int low = 1; + int high = 7; + int random = rand() % (high - low) + low; + // Convert a std::string to oatpp::String + const string response = to_string(random); + return ResponseFactory::createResponse(Status::CODE_200, response.c_str()); + } +}; + +void run() { + auto router = oatpp::web::server::HttpRouter::createShared(); + router->route("GET", "/rolldice", std::make_shared()); + auto connectionHandler = oatpp::web::server::HttpConnectionHandler::createShared(router); + auto connectionProvider = oatpp::network::tcp::server::ConnectionProvider::createShared({"localhost", 8080, oatpp::network::Address::IP_4}); + oatpp::network::Server server(connectionProvider, connectionHandler); + OATPP_LOGI("Dice Server", "Server running on port %s", connectionProvider->getProperty("port").getData()); + server.run(); +} -```shell -cd opentelemetry-cpp -mkdir build && cd build -cmake -DBUILD_TESTING=OFF -DWITH_EXAMPLES_HTTP=ON .. +int main() { + oatpp::base::Environment::init(); + srand((int)time(0)); + run(); + oatpp::base::Environment::destroy(); + return 0; +} ``` -Once build configuration is created, build the CMake targets `http_client` and -`http_server`: +Build and run the application with the following CMake commands. -```shell -cmake --build . --target http_client http_server +```bash +mkdir build +cd build +cmake .. +cmake --build . ``` -If all goes well, you should find binaries `http_server` and `http_client` in -`./examples/http`: +After successfully building your project, you can run the generated executable. + +```bash +./dice-server +``` -```console -$ ls ./examples/http -CMakeFiles Makefile cmake_install.cmake http_client http_server +Then, open in your browser to ensure it is +working. + +## Instrumentation + +To add OpenTelemetry to your application, update the `CMakeLists.txt` file with +the following additional dependencies. + +```cmake +project(RollDiceServer) +cmake_minimum_required(VERSION 3.1) +# Set C++ standard (e.g., C++17) +set(CMAKE_CXX_STANDARD 17) +set(project_name roll-dice-server) + +# Define your project's source files +set(SOURCES + main.cpp # Add your source files here +) +# Create an executable target +add_executable(dice-server ${SOURCES}) + +set(OATPP_ROOT ../oatpp) +set(OPENTELEMETRY_ROOT ../opentelemetry-cpp) +find_library(OATPP_LIB NAMES liboatpp.a HINTS "${OATPP_ROOT}/build/src/" NO_DEFAULT_PATH) +if (NOT OATPP_LIB) + message(SEND_ERROR "Did not find oatpp library ${OATPP_ROOT}/build/src") +endif() +# set the path to the directory containing "oatpp" package configuration files +include_directories(${OATPP_ROOT}/src) + +include_directories(${OPENTELEMETRY_ROOT}/api/include) +include_directories(${OPENTELEMETRY_ROOT}/sdk/include) +include_directories(${OPENTELEMETRY_ROOT}/sdk/src) +include_directories(${OPENTELEMETRY_ROOT}/exporters/ostream/include) + +find_library(OPENTELEMETRY_COMMON_LIB NAMES libopentelemetry_common.a HINTS "${OPENTELEMETRY_ROOT}/build/sdk/src/common" NO_DEFAULT_PATH) +find_library(OPENTELEMETRY_TRACE_LIB NAMES libopentelemetry_trace.a HINTS "${OPENTELEMETRY_ROOT}/build/sdk/src/trace" NO_DEFAULT_PATH) +find_library(OPENTELEMETRY_EXPORTER_LIB NAMES libopentelemetry_exporter_ostream_span.a HINTS "${OPENTELEMETRY_ROOT}/build/exporters/ostream" NO_DEFAULT_PATH) +find_library(OPENTELEMETRY_RESOURCE_LIB NAMES libopentelemetry_resources.a HINTS "${OPENTELEMETRY_ROOT}/build/sdk/src/resource" NO_DEFAULT_PATH) + +if(OPENTELEMETRY_COMMON_LIB AND OPENTELEMETRY_TRACE_LIB AND OPENTELEMETRY_EXPORTER_LIB AND OPENTELEMETRY_RESOURCE_LIB) + message(STATUS "Found opentelemetry libraries") +else() + message(SEND_ERROR "Did not find opentelemetry libraries") +endif() + +target_link_libraries(dice-server PRIVATE ${OATPP_LIB} ${OPENTELEMETRY_COMMON_LIB} ${OPENTELEMETRY_TRACE_LIB} ${OPENTELEMETRY_EXPORTER_LIB} ${OPENTELEMETRY_RESOURCE_LIB}) ``` -## Run Application +Update the `main.cpp` file with the following code to initialize a tracer and to +emit spans when the `/rolldice` request handler is called. + +```cpp +#include "oatpp/web/server/HttpConnectionHandler.hpp" +#include "oatpp/network/Server.hpp" +#include "oatpp/network/tcp/server/ConnectionProvider.hpp" + +#include "opentelemetry/exporters/ostream/span_exporter_factory.h" +#include "opentelemetry/sdk/trace/exporter.h" +#include "opentelemetry/sdk/trace/processor.h" +#include "opentelemetry/sdk/trace/simple_processor_factory.h" +#include "opentelemetry/sdk/trace/tracer_provider_factory.h" +#include "opentelemetry/trace/provider.h" + +#include +#include +#include + +using namespace std; +namespace trace_api = opentelemetry::trace; +namespace trace_sdk = opentelemetry::sdk::trace; +namespace trace_exporter = opentelemetry::exporter::trace; + +namespace { + void InitTracer() { + auto exporter = trace_exporter::OStreamSpanExporterFactory::Create(); + auto processor = trace_sdk::SimpleSpanProcessorFactory::Create(std::move(exporter)); + std::shared_ptr provider = + trace_sdk::TracerProviderFactory::Create(std::move(processor)); + //set the global trace provider + trace_api::Provider::SetTracerProvider(provider); + } + void CleanupTracer() { + std::shared_ptr none; + trace_api::Provider::SetTracerProvider(none); + } -Open two terminals, in the first terminal, start the HTTP server: +} -```console -$ ./examples/http/http_server -Server is running..Press ctrl-c to exit.. +class Handler : public oatpp::web::server::HttpRequestHandler { +public: + shared_ptr handle(const shared_ptr& request) override { + auto tracer = opentelemetry::trace::Provider::GetTracerProvider()->GetTracer("my-app-tracer"); + auto span = tracer->StartSpan("RollDiceServer"); + int low = 1; + int high = 7; + int random = rand() % (high - low) + low; + // Convert a std::string to oatpp::String + const string response = to_string(random); + span->End(); + return ResponseFactory::createResponse(Status::CODE_200, response.c_str()); + } +}; + +void run() { + auto router = oatpp::web::server::HttpRouter::createShared(); + router->route("GET", "/rolldice", std::make_shared()); + auto connectionHandler = oatpp::web::server::HttpConnectionHandler::createShared(router); + auto connectionProvider = oatpp::network::tcp::server::ConnectionProvider::createShared({"localhost", 8080, oatpp::network::Address::IP_4}); + oatpp::network::Server server(connectionProvider, connectionHandler); + OATPP_LOGI("Dice Server", "Server running on port %s", connectionProvider->getProperty("port").getData()); + server.run(); +} + +int main() { + oatpp::base::Environment::init(); + InitTracer(); + srand((int)time(0)); + run(); + oatpp::base::Environment::destroy(); + CleanupTracer(); + return 0; +} ``` -In the other terminal, run the HTTP client: +Build your project again. -```sh -./examples/http/http_client +```bash +cd build +cmake .. +cmake --build . ``` -You should see client output similar to this: +After successfully building your project, you can run the generated executable. -```properties -{ - name : /helloworld - trace_id : 05eec7a55d3544434265dad89d7fe96f - span_id : 45fb62c58c907f05 - tracestate : - parent_span_id: 0000000000000000 - start : 1665577080650384378 - duration : 1640298 - description : - span kind : Client - status : Unset - attributes : - http.header.Date: Wed, 12 Oct 2022 12:18:00 GMT - http.header.Content-Length: 0 - http.status_code: 200 - http.method: GET - .header.Host: localhost - http.header.Content-Type: text/plain - http.header.Connection: keep-alive - .scheme: http - http.url: http://localhost:8800/helloworld - events : - links : - resources : - service.name: unknown_service - telemetry.sdk.version: 1.6.1 - telemetry.sdk.name: opentelemetry - telemetry.sdk.language: cpp - instr-lib : http-client -} +```bash +./dice-server ``` -Also the server should dump you a trace to the console: +When you send a request to the server at , you +will see a span being emitted to the terminal. -```properties +```json { - name : /helloworld - trace_id : 05eec7a55d3544434265dad89d7fe96f - span_id : 8df967d8547813fe - tracestate : - parent_span_id: 45fb62c58c907f05 - start : 1665577080651459495 - duration : 46331 - description : - span kind : Server - status : Unset - attributes : - http.header.Traceparent: 00-05eec7a55d3544434265dad89d7fe96f-45fb62c58c907f05-01 - http.header.Accept: */* - http.request_content_length: 0 - http.header.Host: localhost:8800 - http.scheme: http - http.client_ip: 127.0.0.1:49466 - http.method: GET - net.host.port: 8800 - net.host.name: localhost - events : - { - name : Processing request - timestamp : 1665577080651472827 - attributes : - } - links : - resources : - service.name: unknown_service - telemetry.sdk.version: 1.6.1 - telemetry.sdk.name: opentelemetry - telemetry.sdk.language: cpp - instr-lib : http-server + "name" : "RollDiceServer", + "trace_id": "f47bea385dc55e4d17470d51f9d3130b", + "span_id": "deed994b51f970fa", + "tracestate" : , + "parent_span_id": "0000000000000000", + "start": 1698991818716461000, + "duration": 64697, + "span kind": "Internal", + "status": "Unset", + "service.name": "unknown_service", + "telemetry.sdk.language": "cpp", + "telemetry.sdk.name": "opentelemetry", + "telemetry.sdk.version": "1.11.0", + "instr-lib": "my-app-tracer" } ``` -## What's next +## Next Steps -Enrich your instrumentation generated automatically with -[manual](/docs/languages/cpp/instrumentation) of your own codebase. This gets -you customized observability data. +For more information about instrumenting your code, refer the +[instrumentation](/docs/languages/cpp/instrumentation) documentation. -You'll also want to configure an appropriate exporter to -[export your telemetry data](/docs/languages/cpp/exporters) to one or more +You’ll also want to configure an appropriate exporter to +[export your telemetry data](/docs/languages/cpp/exporters/) to one or more telemetry backends. - -If you'd like to explore a more complex example, take a look at the -[OpenTelemetry Demo](/docs/demo/), which includes the C++ based -[Currency Service](/docs/demo/services/currency/). diff --git a/static/refcache.json b/static/refcache.json index 241fe415beac..89ee7bb3cefa 100644 --- a/static/refcache.json +++ b/static/refcache.json @@ -2587,6 +2587,14 @@ "StatusCode": 200, "LastSeen": "2024-01-18T19:11:34.796425-05:00" }, + "https://github.com/oatpp": { + "StatusCode": 200, + "LastSeen": "2024-02-09T11:48:44.797303+01:00" + }, + "https://github.com/oatpp/oatpp": { + "StatusCode": 200, + "LastSeen": "2024-02-09T11:48:45.252429+01:00" + }, "https://github.com/observIQ/observiq-otel-collector": { "StatusCode": 200, "LastSeen": "2024-01-24T14:55:03.346925+01:00" @@ -5107,6 +5115,10 @@ "StatusCode": 206, "LastSeen": "2024-01-30T05:18:29.229033-05:00" }, + "https://oatpp.io/": { + "StatusCode": 200, + "LastSeen": "2024-02-09T11:48:44.205582+01:00" + }, "https://observiq.com/blog/what-are-connectors-in-opentelemetry/": { "StatusCode": 206, "LastSeen": "2024-01-30T06:06:02.410999-05:00"