-
Notifications
You must be signed in to change notification settings - Fork 438
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add http client/server example (#632)
- Loading branch information
Showing
11 changed files
with
354 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
find_package(CURL) | ||
|
||
if(NOT CURL_FOUND) | ||
message(WARNING "Skipping http client/server example build: CURL not found") | ||
else() | ||
include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include | ||
${CMAKE_SOURCE_DIR}/ext/include ${CMAKE_SOURCE_DIR/}) | ||
|
||
add_executable(http_client client.cc) | ||
add_executable(http_server server.cc) | ||
|
||
target_link_libraries( | ||
http_client | ||
${CMAKE_THREAD_LIBS_INIT} | ||
${CORE_RUNTIME_LIBS} | ||
opentelemetry_trace | ||
http_client_curl | ||
opentelemetry_exporter_ostream_span | ||
${CURL_LIBRARIES}) | ||
|
||
target_link_libraries( | ||
http_server ${CMAKE_THREAD_LIBS_INIT} ${CORE_RUNTIME_LIBS} | ||
opentelemetry_trace http_client_curl opentelemetry_exporter_ostream_span) | ||
endif() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# OpenTelemetry C++ Example | ||
|
||
## HTTP | ||
|
||
This is a simple example that demonstrates tracing an HTTP request from client to server. The example shows several aspects of tracing such as: | ||
|
||
* Using the `TracerProvider` | ||
* Span Attributes | ||
* Span Events | ||
* Using the ostream exporter | ||
* Nested spans (TBD) | ||
* W3c Trace Context Propagation (TBD) | ||
|
||
### Running the example | ||
|
||
1. The example uses HTTP server and client provided as part of this repo: | ||
* [HTTP Client](https://github.com/open-telemetry/opentelemetry-cpp/tree/main/ext/include/opentelemetry/ext/http/client) | ||
* [HTTP Server](https://github.com/open-telemetry/opentelemetry-cpp/tree/main/ext/include/opentelemetry/ext/http/server) | ||
|
||
2. Build and Deploy the opentelementry-cpp as described in [INSTALL.md](../../INSTALL.md) | ||
|
||
3. Start the server from the `examples/http` directory | ||
|
||
```console | ||
$ http_server 8800 | ||
Server is running..Press ctrl-c to exit... | ||
``` | ||
|
||
4. In a separate terminal window, run the client to make a single request: | ||
|
||
```console | ||
$ ./http_client 8800 | ||
... | ||
... | ||
``` | ||
|
||
5. You should see console exporter output for both the client and server sessions. | ||
* Client console | ||
|
||
```console | ||
{ | ||
name : /helloworld | ||
trace_id : 15c7ca1993b536085f4097f2818a7be4 | ||
span_id : 7d9136e4eb4cb59d | ||
parent_span_id: 0000000000000000 | ||
start : 1617075613395810300 | ||
duration : 1901100 | ||
description : | ||
span kind : Client | ||
status : Unset | ||
attributes : | ||
http.header.Date: Tue, 30 Mar 2021 03:40:13 GMT | ||
http.header.Content-Length: 0 | ||
http.status_code: 200 | ||
http.method: GET | ||
http.header.Host: localhost | ||
http.header.Content-Type: text/plain | ||
http.header.Connection: keep-alive | ||
http.scheme: http | ||
http.url: h**p://localhost:8800/helloworld | ||
} | ||
``` | ||
|
||
* Server console | ||
|
||
```console | ||
{ | ||
name : /helloworld | ||
trace_id : bfa611a4bbb8b1871ef6a222d6a0f4dd | ||
span_id : 19e3cda7df63c9b9 | ||
parent_span_id: 0000000000000000 | ||
start : 1617075522491536300 | ||
duration : 50700 | ||
description : | ||
span kind : Server | ||
status : Unset | ||
attributes : | ||
http.header.Accept: */* | ||
http.request_content_length: 0 | ||
http.header.Host: localhost:8800 | ||
http.scheme: http | ||
http.client_ip: 127.0.0.1:44616 | ||
http.method: GET | ||
net.host.port: 8800 | ||
http.server_name: localhost | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
#include "opentelemetry/ext/http/client/http_client_factory.h" | ||
#include "opentelemetry/ext/http/common/url_parser.h" | ||
#include "tracer_common.hpp" | ||
|
||
namespace | ||
{ | ||
|
||
void sendRequest(const std::string &url) | ||
{ | ||
auto http_client = opentelemetry::ext::http::client::HttpClientFactory::CreateSync(); | ||
|
||
// start active span | ||
opentelemetry::trace::StartSpanOptions options; | ||
options.kind = opentelemetry::trace::SpanKind::kClient; // client | ||
opentelemetry::ext::http::common::UrlParser url_parser(url); | ||
|
||
std::string span_name = url_parser.path_; | ||
auto span = get_tracer("http-client") | ||
->StartSpan(span_name, | ||
{{"http.url", url_parser.url_}, | ||
{"http.scheme", url_parser.scheme_}, | ||
{"http.method", "GET"}}, | ||
options); | ||
auto scope = get_tracer("http-client")->WithActiveSpan(span); | ||
|
||
opentelemetry::ext::http::client::Result result = http_client->Get(url); | ||
if (result) | ||
{ | ||
// set span attributes | ||
auto status_code = result.GetResponse().GetStatusCode(); | ||
span->SetAttribute("http.status_code", status_code); | ||
result.GetResponse().ForEachHeader([&span](opentelemetry::nostd::string_view header_name, | ||
opentelemetry::nostd::string_view header_value) { | ||
span->SetAttribute("http.header." + std::string(header_name.data()), header_value); | ||
return true; | ||
}); | ||
|
||
if (status_code >= 400) | ||
{ | ||
span->SetStatus(opentelemetry::trace::StatusCode::kError); | ||
} | ||
} | ||
else | ||
{ | ||
span->SetStatus(opentelemetry::trace::StatusCode::kError, | ||
"Response Status :" + | ||
std::to_string(static_cast<typename std::underlying_type< | ||
opentelemetry::ext::http::client::SessionState>::type>( | ||
result.GetSessionState()))); | ||
} | ||
// end span and export data | ||
span->End(); | ||
} | ||
|
||
} // namespace | ||
|
||
int main(int argc, char *argv[]) | ||
{ | ||
initTracer(); | ||
constexpr char default_host[] = "localhost"; | ||
constexpr char default_path[] = "/helloworld"; | ||
constexpr uint16_t default_port = 8800; | ||
uint16_t port; | ||
|
||
// The port the validation service listens to can be specified via the command line. | ||
if (argc > 1) | ||
{ | ||
port = atoi(argv[1]); | ||
} | ||
else | ||
{ | ||
port = default_port; | ||
} | ||
|
||
std::string url = "http://" + std::string(default_host) + ":" + std::to_string(port) + | ||
std::string(default_path); | ||
sendRequest(url); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
#include "server.hpp" | ||
#include "tracer_common.hpp" | ||
|
||
#include <iostream> | ||
#include <thread> | ||
|
||
namespace | ||
{ | ||
uint16_t server_port = 8800; | ||
constexpr char server_name[] = "localhost"; | ||
|
||
class RequestHandler : public HTTP_SERVER_NS::HttpRequestCallback | ||
{ | ||
public: | ||
virtual int onHttpRequest(HTTP_SERVER_NS::HttpRequest const &request, | ||
HTTP_SERVER_NS::HttpResponse &response) override | ||
{ | ||
opentelemetry::trace::StartSpanOptions options; | ||
options.kind = opentelemetry::trace::SpanKind::kServer; // server | ||
std::string span_name = request.uri; | ||
|
||
auto span = get_tracer("http-server") | ||
->StartSpan(span_name, | ||
{{"http.server_name", server_name}, | ||
{"net.host.port", server_port}, | ||
{"http.method", request.method}, | ||
{"http.scheme", "http"}, | ||
{"http.request_content_length", request.content.length()}, | ||
{"http.client_ip", request.client}}, | ||
options); | ||
|
||
auto scope = get_tracer("http_server")->WithActiveSpan(span); | ||
for (auto &kv : request.headers) | ||
{ | ||
span->SetAttribute("http.header." + std::string(kv.first.data()), kv.second); | ||
} | ||
if (request.uri == "/helloworld") | ||
{ | ||
span->AddEvent("Processing request"); | ||
response.headers[HTTP_SERVER_NS::CONTENT_TYPE] = HTTP_SERVER_NS::CONTENT_TYPE_TEXT; | ||
span->End(); | ||
return 200; | ||
} | ||
span->End(); | ||
return 404; | ||
} | ||
}; | ||
} // namespace | ||
|
||
int main(int argc, char *argv[]) | ||
{ | ||
initTracer(); | ||
uint16_t port; | ||
|
||
// The port the validation service listens to can be specified via the command line. | ||
if (argc > 1) | ||
{ | ||
server_port = atoi(argv[1]); | ||
} | ||
|
||
HttpServer http_server(server_name, server_port); | ||
RequestHandler req_handler; | ||
http_server.AddHandler("/helloworld", &req_handler); | ||
auto root_span = get_tracer("http_server")->StartSpan(__func__); | ||
opentelemetry::trace::Scope scope(root_span); | ||
http_server.Start(); | ||
std::cout << "Server is running..Press ctrl-c to exit...\n"; | ||
while (1) | ||
{ | ||
std::this_thread::sleep_for(std::chrono::seconds(100)); | ||
} | ||
http_server.Stop(); | ||
root_span->End(); | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#pragma once | ||
#include "opentelemetry/ext/http/server/http_server.h" | ||
#include<string> | ||
#include<atomic> | ||
|
||
|
||
namespace { | ||
|
||
class HttpServer : public HTTP_SERVER_NS::HttpRequestCallback | ||
{ | ||
|
||
protected: | ||
HTTP_SERVER_NS::HttpServer server_; | ||
std::string server_url_ ; | ||
uint16_t port_ ; | ||
std::atomic<bool> is_running_{false}; | ||
|
||
public: | ||
|
||
HttpServer(std::string server_name = "test_server",uint16_t port = 8800): port_(port){ | ||
server_.setServerName(server_name); | ||
server_.setKeepalive(false); | ||
} | ||
|
||
void AddHandler(std::string path, HTTP_SERVER_NS::HttpRequestCallback *request_handler){ | ||
server_.addHandler(path, *request_handler); | ||
} | ||
|
||
void Start() { | ||
if (!is_running_.exchange(true)) { | ||
server_.addListeningPort(port_); | ||
server_.start(); | ||
} | ||
} | ||
|
||
void Stop() { | ||
if (is_running_.exchange(false)){ | ||
server_.stop(); | ||
} | ||
} | ||
|
||
~HttpServer(){ | ||
Stop(); | ||
} | ||
}; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#pragma once | ||
#include "opentelemetry/exporters/ostream/span_exporter.h" | ||
#include "opentelemetry/sdk/trace/simple_processor.h" | ||
#include "opentelemetry/sdk/trace/tracer_provider.h" | ||
#include "opentelemetry/trace/provider.h" | ||
|
||
#include <iostream> | ||
|
||
namespace { | ||
|
||
void initTracer() { | ||
auto exporter = std::unique_ptr<sdktrace::SpanExporter>( | ||
new opentelemetry::exporter::trace::OStreamSpanExporter); | ||
auto processor = std::shared_ptr<sdktrace::SpanProcessor>( | ||
new sdktrace::SimpleSpanProcessor(std::move(exporter))); | ||
auto provider = nostd::shared_ptr<opentelemetry::trace::TracerProvider>( | ||
new sdktrace::TracerProvider(processor, opentelemetry::sdk::resource::Resource::Create({}), | ||
std::make_shared<opentelemetry::sdk::trace::AlwaysOnSampler>())); | ||
// Set the global trace provider | ||
opentelemetry::trace::Provider::SetTracerProvider(provider); | ||
} | ||
|
||
nostd::shared_ptr<opentelemetry::trace::Tracer> get_tracer(std::string tracer_name) | ||
{ | ||
auto provider = opentelemetry::trace::Provider::GetTracerProvider(); | ||
return provider->GetTracer(tracer_name); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.