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 are emitted to the terminal.
Ensure that you have the following installed locally:
The following example uses a basic Oat++ application. If you are not using Oat++, that’s OK - you can use OpenTelemetry C++ with any other web framework as well.
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:
otel-cpp-starter
│
├── oatpp
├── opentelemetry-cpp
└── roll-dice
To begin, install Oat++ locally using the
source code and make
, following these steps:
Obtain the Oat++ source code by cloning from the oatpp/oatpp GitHub repository.
git clone https://github.com/oatpp/oatpp.git
Navigate to the oatpp
directory and switch to 1.3.0 version for now:
cd oatpp
git checkout 1.3.0-latest
Create a build
subdirectory and navigate into it.
mkdir build
cd build
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.
cmake ..
make
Install oatpp.
This command will install the built oatpp library and headers on your system, making it accessible for development in your project.
sudo make install
To uninstall the built oatpp library and headers from your system.
sudo make uninstall
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.
git clone https://github.com/open-telemetry/opentelemetry-cpp.git
Change your working directory to the OpenTelemetry C++ SDK directory.
cd opentelemetry-cpp
Create a build directory and navigate into it.
mkdir build
cd build
In the build
directory run CMake, to configure and generate the build
system without enabling tests:
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
With Oat++ and OpenTelemetry C++ ready, you can continue with creating the HTTP Server, that we want to instrument eventually.
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
inside roll-dice
to define the Oat++
library directories, include paths, and link against Oat++ during the
compilation process.
cmake_minimum_required(VERSION 3.25)
project(RollDiceServer)
# 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:
/rolldice
endpoint.In that roll-dice
folder, create a file called main.cpp
and add the
following code to the file.
#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", static_cast<const char*>(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.
mkdir build
cd build
cmake ..
cmake --build .
After successfully building your project, you can run the generated executable.
./dice-server
Then, open http://localhost:8080/rolldice in your browser to ensure it is working.
To add OpenTelemetry to your application, update the CMakeLists.txt
file with
the following additional dependencies.
cmake_minimum_required(VERSION 3.25)
project(RollDiceServer)
# 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-cpp_DIR ../otel-cpp/lib/cmake/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)
# Use find_package to include OpenTelemetry C++
find_package(opentelemetry-cpp CONFIG REQUIRED NO_DEFAULT_PATH)
# Link against each OpenTelemetry C++ library
target_link_libraries(dice-server PRIVATE
${OATPP_LIB}
${OPENTELEMETRY_CPP_LIBRARIES})
Update the main.cpp
file with the following code to initialize a tracer and to
emit spans when the /rolldice
request handler is called.
#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", static_cast<const char*>(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.
cd build
cmake ..
cmake --build .
After successfully building your project, you can run the generated executable.
./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.
{
"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"
}
For more information about instrumenting your code, refer the instrumentation documentation.
You’ll also want to configure an appropriate exporter to export your telemetry data to one or more telemetry backends.
[i18n] feedback_question
Thank you. Your feedback is appreciated!
Please let us know how we can improve this page. Your feedback is appreciated!