409 lines
12 KiB
Markdown
409 lines
12 KiB
Markdown
---
|
||
title: Getting Started
|
||
description: Get telemetry for your app in less than 5 minutes!
|
||
cSpell:ignore: oatpp rolldice
|
||
weight: 10
|
||
---
|
||
|
||
This page will show you how to get started with OpenTelemetry in C++.
|
||
|
||
You will learn how to instrument a simple C++ application, such that
|
||
[traces](/docs/concepts/signals/traces/) are emitted to the terminal.
|
||
|
||
## Prerequisites
|
||
|
||
Ensure that you have the following installed locally:
|
||
|
||
- Git
|
||
- C++ compiler supporting C++ version >= 14
|
||
- Make
|
||
- CMake version >= 3.20
|
||
|
||
## Example Application
|
||
|
||
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.
|
||
|
||
## 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.
|
||
|
||
```bash
|
||
mkdir build
|
||
cd build
|
||
```
|
||
|
||
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
|
||
```
|
||
|
||
To uninstall the built oatpp library and headers from your system.
|
||
|
||
```bash
|
||
sudo make uninstall
|
||
```
|
||
|
||
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.
|
||
|
||
```bash
|
||
cmake ..
|
||
```
|
||
|
||
Or, if the `cmake --build` fails, you can also try:
|
||
|
||
```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})
|
||
```
|
||
|
||
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 <localhost:8080>.
|
||
- 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 <cstdlib>
|
||
#include <ctime>
|
||
#include <string>
|
||
|
||
using namespace std;
|
||
|
||
class Handler : public oatpp::web::server::HttpRequestHandler {
|
||
public:
|
||
shared_ptr<OutgoingResponse> handle(const shared_ptr<IncomingRequest>& 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<Handler>());
|
||
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();
|
||
srand((int)time(0));
|
||
run();
|
||
oatpp::base::Environment::destroy();
|
||
return 0;
|
||
}
|
||
```
|
||
|
||
Build and run the application with the following CMake commands.
|
||
|
||
```bash
|
||
mkdir build
|
||
cd build
|
||
cmake ..
|
||
cmake --build .
|
||
```
|
||
|
||
After successfully building your project, you can run the generated executable.
|
||
|
||
```bash
|
||
./dice-server
|
||
```
|
||
|
||
Then, open <http://localhost:8080/rolldice> 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})
|
||
```
|
||
|
||
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 <cstdlib>
|
||
#include <ctime>
|
||
#include <string>
|
||
|
||
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<opentelemetry::trace::TracerProvider> provider =
|
||
trace_sdk::TracerProviderFactory::Create(std::move(processor));
|
||
//set the global trace provider
|
||
trace_api::Provider::SetTracerProvider(provider);
|
||
}
|
||
void CleanupTracer() {
|
||
std::shared_ptr<opentelemetry::trace::TracerProvider> none;
|
||
trace_api::Provider::SetTracerProvider(none);
|
||
}
|
||
|
||
}
|
||
|
||
class Handler : public oatpp::web::server::HttpRequestHandler {
|
||
public:
|
||
shared_ptr<OutgoingResponse> handle(const shared_ptr<IncomingRequest>& 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<Handler>());
|
||
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;
|
||
}
|
||
```
|
||
|
||
Build your project again.
|
||
|
||
```bash
|
||
cd build
|
||
cmake ..
|
||
cmake --build .
|
||
```
|
||
|
||
After successfully building your project, you can run the generated executable.
|
||
|
||
```bash
|
||
./dice-server
|
||
```
|
||
|
||
When you send a request to the server at <http://localhost:8080/rolldice>, you
|
||
will see a span being emitted to the terminal.
|
||
|
||
```json
|
||
{
|
||
"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"
|
||
}
|
||
```
|
||
|
||
## Next Steps
|
||
|
||
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
|
||
telemetry backends.
|