Skip to content

Commit

Permalink
Enhance existing http example to support w3c trace context propagation (
Browse files Browse the repository at this point in the history
  • Loading branch information
lalitb authored May 8, 2021
1 parent 01b7a84 commit d8467a7
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 97 deletions.
6 changes: 3 additions & 3 deletions examples/http/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ cc_binary(
name = "example_http_client",
srcs = [
"client.cc",
"tracer_common.hpp",
"tracer_common.h",
],
# TODO: Move copts/linkopts for static CURL usage into shared bzl file.
copts = [
Expand Down Expand Up @@ -30,8 +30,8 @@ cc_binary(
name = "example_http_server",
srcs = [
"server.cc",
"server.hpp",
"tracer_common.hpp",
"server.h",
"tracer_common.h",
],
deps = [
"//api",
Expand Down
41 changes: 30 additions & 11 deletions examples/http/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
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`
* Using the `GlobalPropagator`
* Span Attributes
* Span Events
* Using the ostream exporter
* Nested spans (TBD)
* W3c Trace Context Propagation (TBD)
* W3C Trace Context Propagation

### Running the example

Expand Down Expand Up @@ -38,18 +39,20 @@ This is a simple example that demonstrates tracing an HTTP request from client t
* Client console

```console

{
name : /helloworld
trace_id : 15c7ca1993b536085f4097f2818a7be4
span_id : 7d9136e4eb4cb59d
trace_id : baa922bc0da6f79d46373371f4416463
span_id : 83bed4da7a01267d
tracestate :
parent_span_id: 0000000000000000
start : 1617075613395810300
duration : 1901100
start : 1620287026111457000
duration : 5164400
description :
span kind : Client
status : Unset
attributes :
http.header.Date: Tue, 30 Mar 2021 03:40:13 GMT
http.header.Date: Thu, 06 May 2021 07:43:46 GMT
http.header.Content-Length: 0
http.status_code: 200
http.method: GET
Expand All @@ -58,30 +61,46 @@ This is a simple example that demonstrates tracing an HTTP request from client t
http.header.Connection: keep-alive
http.scheme: http
http.url: h**p://localhost:8800/helloworld
events :
links :

}
```

* Server console

```console

{
name : /helloworld
trace_id : bfa611a4bbb8b1871ef6a222d6a0f4dd
span_id : 19e3cda7df63c9b9
parent_span_id: 0000000000000000
start : 1617075522491536300
trace_id : baa922bc0da6f79d46373371f4416463
span_id : c3e7e23042eb670e
tracestate :
parent_span_id: 83bed4da7a01267d
start : 1620287026115443300
duration : 50700
description :
span kind : Server
status : Unset
attributes :
http.header.Traceparent: 00-baa922bc0da6f79d46373371f4416463-83bed4da7a01267d-01
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.client_ip: 127.0.0.1:50792
http.method: GET
net.host.port: 8800
http.server_name: localhost
events :
{
name : Processing request
timestamp : 1620287026115464000
attributes :
}
links :

}
```

As seen from example above, `trace_id` and `parent_span_id` is propagated from client to server.
11 changes: 9 additions & 2 deletions examples/http/client.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "opentelemetry/ext/http/client/http_client_factory.h"
#include "opentelemetry/ext/http/common/url_parser.h"
#include "tracer_common.hpp"
#include "tracer_common.h"

namespace
{
Expand All @@ -23,7 +23,14 @@ void sendRequest(const std::string &url)
options);
auto scope = get_tracer("http-client")->WithActiveSpan(span);

opentelemetry::ext::http::client::Result result = http_client->Get(url);
// inject current context into http header
auto current_ctx = opentelemetry::context::RuntimeContext::GetCurrent();
HttpTextMapCarrier<opentelemetry::ext::http::client::Headers> carrier;
auto prop = opentelemetry::context::propagation::GlobalTextMapPropagator::GetGlobalPropagator();
prop->Inject(carrier, current_ctx);

// send http request
opentelemetry::ext::http::client::Result result = http_client->Get(url, carrier.headers_);
if (result)
{
// set span attributes
Expand Down
14 changes: 12 additions & 2 deletions examples/http/server.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "server.hpp"
#include "tracer_common.hpp"
#include "server.h"
#include "tracer_common.h"

#include <iostream>
#include <thread>
Expand All @@ -19,6 +19,15 @@ class RequestHandler : public HTTP_SERVER_NS::HttpRequestCallback
options.kind = opentelemetry::trace::SpanKind::kServer; // server
std::string span_name = request.uri;

// extract context from http header
const HttpTextMapCarrier<std::map<std::string, std::string>> carrier(
(std::map<std::string, std::string> &)request.headers);
auto prop = opentelemetry::context::propagation::GlobalTextMapPropagator::GetGlobalPropagator();
auto current_ctx = opentelemetry::context::RuntimeContext::GetCurrent();
auto new_context = prop->Extract(carrier, current_ctx);
options.parent = GetSpanFromContext(new_context)->GetContext();

// start span with parent context extracted from http header
auto span = get_tracer("http-server")
->StartSpan(span_name,
{{"http.server_name", server_name},
Expand All @@ -30,6 +39,7 @@ class RequestHandler : public HTTP_SERVER_NS::HttpRequestCallback
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);
Expand Down
50 changes: 50 additions & 0 deletions examples/http/server.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#pragma once
#include <atomic>
#include <string>
#include "opentelemetry/ext/http/server/http_server.h"

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(); }
};

} // namespace
47 changes: 0 additions & 47 deletions examples/http/server.hpp

This file was deleted.

95 changes: 95 additions & 0 deletions examples/http/tracer_common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#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 "opentelemetry/context/propagation/global_propagator.h"
#include "opentelemetry/context/propagation/text_map_propagator.h"
#include "opentelemetry/trace/propagation/http_trace_context.h"

#include <cstring>
#include <iostream>
#include <vector>
#include "opentelemetry/ext/http/client/http_client.h"
#include "opentelemetry/nostd/shared_ptr.h"

namespace
{
// TBD - This function be removed once #723 is merged
inline nostd::shared_ptr<opentelemetry::trace::Span> GetSpanFromContext(
const opentelemetry::context::Context &context)
{
opentelemetry::context::ContextValue span = context.GetValue(opentelemetry::trace::kSpanKey);
if (nostd::holds_alternative<nostd::shared_ptr<opentelemetry::trace::Span>>(span))
{
return nostd::get<nostd::shared_ptr<opentelemetry::trace::Span>>(span);
}
static nostd::shared_ptr<opentelemetry::trace::Span> invalid_span{
new opentelemetry::trace::DefaultSpan(opentelemetry::trace::SpanContext::GetInvalid())};
return invalid_span;
}

template <typename T>
class HttpTextMapCarrier : public opentelemetry::context::propagation::TextMapCarrier
{
public:
HttpTextMapCarrier<T>(T &headers) : headers_(headers) {}
HttpTextMapCarrier() = default;
virtual nostd::string_view Get(nostd::string_view key) const noexcept override
{
std::string key_to_compare = key.data();
// Header's first letter seems to be automatically capitaliazed by our test http-server, so
// compare accordingly.
if (key == opentelemetry::trace::propagation::kTraceParent)
{
key_to_compare = "Traceparent";
}
else if (key == opentelemetry::trace::propagation::kTraceState)
{
key_to_compare == "Tracestate";
}
auto it = headers_.find(key_to_compare);
if (it != headers_.end())
{
return it->second;
}
return "";
}

virtual void Set(nostd::string_view key, nostd::string_view value) noexcept override
{
headers_.insert(std::pair<std::string, std::string>(std::string(key), std::string(value)));
}

T headers_;
};

void initTracer()
{
auto exporter = std::unique_ptr<sdktrace::SpanExporter>(
new opentelemetry::exporter::trace::OStreamSpanExporter);
auto processor = std::unique_ptr<sdktrace::SpanProcessor>(
new sdktrace::SimpleSpanProcessor(std::move(exporter)));
std::vector<std::unique_ptr<sdktrace::SpanProcessor>> processors;
processors.push_back(std::move(processor));
// Default is an always-on sampler.
auto context = std::make_shared<sdktrace::TracerContext>(std::move(processors));
auto provider = nostd::shared_ptr<opentelemetry::trace::TracerProvider>(
new sdktrace::TracerProvider(context));
// Set the global trace provider
opentelemetry::trace::Provider::SetTracerProvider(provider);

// set global propagator
opentelemetry::context::propagation::GlobalTextMapPropagator::SetGlobalPropagator(
nostd::shared_ptr<opentelemetry::context::propagation::TextMapPropagator>(
new opentelemetry::trace::propagation::HttpTraceContext()));
}

nostd::shared_ptr<opentelemetry::trace::Tracer> get_tracer(std::string tracer_name)
{
auto provider = opentelemetry::trace::Provider::GetTracerProvider();
return provider->GetTracer(tracer_name);
}

} // namespace
32 changes: 0 additions & 32 deletions examples/http/tracer_common.hpp

This file was deleted.

0 comments on commit d8467a7

Please sign in to comment.