This is an automated email from the ASF dual-hosted git repository.

astitcher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton.git


The following commit(s) were added to refs/heads/main by this push:
     new 800722dd0 PROTON-2487: [cpp] Implement distributed tracing using 
OpenTelemetry
800722dd0 is described below

commit 800722dd08c9bf75c70f2b6adce2e60fb3302283
Author: Rakhi Kumari <[email protected]>
AuthorDate: Tue Mar 29 15:51:03 2022 +0530

    PROTON-2487: [cpp] Implement distributed tracing using OpenTelemetry
    
    - Add the opentelemetry-cpp library dependencies
    - Add opentelemetry-cpp install/build steps in GHA
    - Add tracing_opentelemetry.cpp file
      - Add tracing spans for messaging operations
      - Add basic attributes[delivery_tag, delivery_state, source_address, 
destination_address]
    - Add tracing_stub.cpp file to handle the case when opentelemetry is not 
enabled
    - Add tracing demo files in examples: tracing_client.cpp and 
tracing_server.cpp
    - Add a test file
    - Add a tracing instructions file
---
 .github/workflows/build.yml       |   5 +
 ci/otel.sh                        |  43 +++++++
 cpp/CMakeLists.txt                |  14 ++-
 cpp/docs/pages.dox                |   1 +
 cpp/examples/CMakeLists.txt       |  10 ++
 cpp/examples/tracing.dox          | 107 +++++++++++++++++
 cpp/examples/tracing_client.cpp   | 194 +++++++++++++++++++++++++++++++
 cpp/examples/tracing_server.cpp   | 148 ++++++++++++++++++++++++
 cpp/include/proton/tracing.hpp    |  37 ++++++
 cpp/src/init_tracer_stub.cpp      |  29 +++++
 cpp/src/messaging_adapter.cpp     |   6 +-
 cpp/src/sender.cpp                |   9 +-
 cpp/src/tracing_opentelemetry.cpp | 235 ++++++++++++++++++++++++++++++++++++++
 cpp/src/tracing_private.hpp       |  55 +++++++++
 cpp/src/tracing_stub.cpp          |  48 ++++++++
 cpp/src/tracing_test.cpp          | 157 +++++++++++++++++++++++++
 cpp/tests.cmake                   |   5 +
 17 files changed, 1099 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4e8ac85c5..d4c550044 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -60,6 +60,11 @@ jobs:
       if: runner.os == 'macOS'
       run: |
         brew install libuv swig pkgconfig jsoncpp
+    - name: OTel build/install
+      if: runner.os == 'Linux'
+      working-directory: ${{github.workspace}}
+      run: sudo sh ./ci/otel.sh
+      shell: bash
     - name: cmake configure
       working-directory: ${{env.BuildDir}}
       run: cmake "${{github.workspace}}" "-DCMAKE_BUILD_TYPE=${BuildType}" 
"-DCMAKE_INSTALL_PREFIX=${InstallPrefix}" ${{matrix.cmake_extra}}
diff --git a/ci/otel.sh b/ci/otel.sh
new file mode 100644
index 000000000..cc539c6cb
--- /dev/null
+++ b/ci/otel.sh
@@ -0,0 +1,43 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+set -e
+
+sudo apt-get update
+
+# OTel dependencies
+
+sudo apt-get install libcurl4-openssl-dev
+sudo apt-get install libboost-locale-dev
+sudo apt-get install libthrift-dev
+
+# Clone OpenTelemetry-cpp
+
+git clone -b v1.6.1 --recursive 
https://github.com/open-telemetry/opentelemetry-cpp
+
+# Build/Install OpenTelemetry-cpp
+
+cd opentelemetry-cpp
+mkdir build
+cd build
+
+cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=ON 
-DCMAKE_POSITION_INDEPENDENT_CODE=ON -DBUILD_TESTING=OFF 
-DCMAKE_BUILD_TYPE=RelWithDebInfo -DWITH_JAEGER=ON
+cmake --build . --target all
+sudo cmake --install . --config RelWithDebInfo
+cd ../..
diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt
index 4b006aed0..2049fe94b 100644
--- a/cpp/CMakeLists.txt
+++ b/cpp/CMakeLists.txt
@@ -36,6 +36,17 @@ else()
   set(CONNECT_CONFIG_SRC src/connect_config_dummy.cpp)
 endif()
 
+# Check for OPENTELEMETRY-CPP for distributed tracing
+find_package(opentelemetry-cpp)
+option(ENABLE_OPENTELEMETRYCPP "Use opentelemetry for distributed tracing" 
${OPENTELEMETRY-CPP_FOUND})
+if (ENABLE_OPENTELEMETRYCPP)
+  include_directories(${OPENTELEMETRY_CPP_INCLUDE_DIRS})
+  set(TRACING_SRC src/tracing_opentelemetry.cpp src/tracing_stub.cpp)
+  set(TRACING_LIBS opentelemetry-cpp::trace)
+else()
+  set(TRACING_SRC src/tracing_stub.cpp src/init_tracer_stub.cpp)
+endif()
+
 list(APPEND PLATFORM_LIBS Threads::Threads)
 
 set(CXX_EXAMPLE_FLAGS "${CXX_WARNING_FLAGS} ${CXX_STANDARD}")
@@ -105,6 +116,7 @@ set(qpid-proton-cpp-source
   src/value.cpp
   src/work_queue.cpp
   ${CONNECT_CONFIG_SRC}
+  ${TRACING_SRC}
   )
 
 add_library(qpid-proton-cpp SHARED ${qpid-proton-cpp-source})
@@ -122,7 +134,7 @@ if(BUILD_STATIC_LIBS)
     EXPORT_NAME cpp)
 endif(BUILD_STATIC_LIBS)
 
-target_link_libraries (qpid-proton-cpp LINK_PRIVATE ${PLATFORM_LIBS} 
qpid-proton-core qpid-proton-proactor ${CONNECT_CONFIG_LIBS})
+target_link_libraries (qpid-proton-cpp LINK_PRIVATE ${PLATFORM_LIBS} 
qpid-proton-core qpid-proton-proactor ${CONNECT_CONFIG_LIBS} ${TRACING_LIBS})
 
 set_target_properties (
   qpid-proton-cpp
diff --git a/cpp/docs/pages.dox b/cpp/docs/pages.dox
index 818db9b38..4660015e6 100644
--- a/cpp/docs/pages.dox
+++ b/cpp/docs/pages.dox
@@ -4,3 +4,4 @@
 /// @page types_page AMQP and C++ types
 /// @page mt_page Multi-threading
 /// @page io_page IO integration
+/// @page tracing Tracing
diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt
index 7c123ce32..ed0abf083 100644
--- a/cpp/examples/CMakeLists.txt
+++ b/cpp/examples/CMakeLists.txt
@@ -82,6 +82,16 @@ foreach(example
   target_link_libraries(${example} Proton::cpp)
 endforeach()
 
+# Tracing examples
+if (ENABLE_OPENTELEMETRYCPP)
+foreach(example
+    tracing_client
+    tracing_server)
+  add_executable(${example} ${example}.cpp)
+  target_link_libraries(${example} Proton::cpp opentelemetry-cpp::trace 
opentelemetry-cpp::jaeger_trace_exporter 
opentelemetry-cpp::ostream_span_exporter)
+  endforeach()
+endif()
+
 # Examples that use threads directly
 foreach(example
     multithreaded_client
diff --git a/cpp/examples/tracing.dox b/cpp/examples/tracing.dox
new file mode 100644
index 000000000..6604aaad4
--- /dev/null
+++ b/cpp/examples/tracing.dox
@@ -0,0 +1,107 @@
+// -*-markdown-*-
+// NOTE: doxygen can include markdown pages directly but there seems to be a 
bug
+// that shows messed-up line numbers in \skip \until code extracts. This file
+// is markdown wrapped in a doxygen comment - which works. The file is best 
viewed/edited
+// as markdown.
+
+/**
+
+@page tracing Tracing
+
+The tracing support is added using OpenTelemetry-cpp.
+
+There are two types of spans:
+1. <b>Library generated spans</b>:
+
+    Send span <b>("amqp-message-send”)</b> gets created just before sending a 
message and ends when that message gets settled.
+
+    Receive span <b>("amqp-message-received")</b> gets created just before 
receiving a message and ends as soon as the message is received.
+
+2. <b>Application generated spans</b>:
+
+    Users can also create their own spans and those spans will get linked with 
the library generated spans.
+
+## Usage:
+
+### 1. Initialize the exporter
+
+       opentelemetry::exporter::jaeger::JaegerExporterOptions opts;
+       std::unique_ptr<opentelemetry::sdk::trace::SpanExporter> exporter = 
std::unique_ptr<opentelemetry::sdk::trace::SpanExporter>(
+            new opentelemetry::exporter::jaeger::JaegerExporter(opts));
+
+Above is an example of initializing a jaeger exporter. Apart from jaeger 
exporter, there are many other exporters supported by OpenTelelemetry.
+
+### 2. Set the Tracer Provider
+
+       auto processor = 
std::unique_ptr<opentelemetry::sdk::trace::SpanProcessor>(
+            new 
opentelemetry::sdk::trace::SimpleSpanProcessor(std::move(exporter)));
+       auto provider = 
opentelemetry::nostd::shared_ptr<opentelemetry::trace::TracerProvider>(
+            new 
opentelemetry::sdk::trace::TracerProvider(std::move(processor));
+       opentelemetry::trace::Provider::SetTracerProvider(provider);
+
+### 3. Enable tracing in Proton C++
+
+       proton::initOpenTelemetryTracer();
+
+This will generates the library spans ("amqp-message-send" and 
"amqp-message-received").
+
+In addition, users can create their own spans in the application. The @ref 
tracing_client and @ref tracing_server examples demonstrates how to do that 
with jaeger exporter.
+
+## Steps to run tracing examples: 
+
+    A working example of distributed tracing using broker, tracing_server and 
tracing_client examples.
+
+### Start Jaeger, for example: 
+
+docker run -d --name jaeger \
+  -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
+  -p 5775:5775/udp \
+  -p 6831:6831/udp \
+  -p 6832:6832/udp \
+  -p 5778:5778 \
+  -p 16686:16686 \
+  -p 14268:14268 \
+  -p 14250:14250 \
+  -p 9411:9411 \
+  jaegertracing/all-in-one:1.25 
+
+### Build/Install Opentelemetry-cpp: 
+
+Note: Thrift is jaeger exporter dependency.
+
+1. Clone opentelemetry-cpp  
+https://github.com/open-telemetry/opentelemetry-cpp
+
+2. cd opentelemetry-cpp
+
+3. mkdir bld 
+4. cd bld
+
+5. cmake .. -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=ON 
-DCMAKE_POSITION_INDEPENDENT_CODE=ON -DWITH_JAEGER=ON 
+6. make 
+7. sudo make install 
+
+### Demo with broker.
+
+
+WORKDIR cpp/examples  
+
+1. @ref broker.cpp   
+<b>In one window run:</b>  
+`./broker`  
+
+2. @ref tracing_server.cpp  
+<b>In another window run:</b>   
+`./tracing_server`
+
+3. @ref tracing_client.cpp  
+<b>In the final window:</b>  
+`./tracing_client`
+
+### Look in the Jaeger UI: 
+
+Browse to http://localhost:16686/. This should open up a console for the 
Jaeger tracing system.  
+Select the Service dropdown at the top of the Search options (if not already 
selected). 
+Hit Find Traces. 
+
+*/
diff --git a/cpp/examples/tracing_client.cpp b/cpp/examples/tracing_client.cpp
new file mode 100644
index 000000000..93f1239fc
--- /dev/null
+++ b/cpp/examples/tracing_client.cpp
@@ -0,0 +1,194 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "options.hpp"
+#include <proton/connection.hpp>
+#include <proton/container.hpp>
+#include <proton/delivery.hpp>
+#include <proton/message.hpp>
+#include <proton/messaging_handler.hpp>
+#include <proton/receiver_options.hpp>
+#include <proton/source_options.hpp>
+#include <proton/tracing.hpp>
+#include <proton/tracker.hpp>
+#include <proton/message_id.hpp>
+
+#include <bits/stdc++.h>
+#include <iostream>
+#include <string>
+#include <vector>
+#include <map>
+
+// Include opentelemetry header files
+#include <opentelemetry/sdk/trace/simple_processor.h>
+#include <opentelemetry/sdk/trace/tracer_provider.h>
+#include <opentelemetry/trace/provider.h>
+#include <opentelemetry/nostd/unique_ptr.h>
+#include <opentelemetry/exporters/jaeger/jaeger_exporter.h>
+#include <opentelemetry/exporters/ostream/span_exporter.h>
+#include <opentelemetry/sdk/resource/resource.h>
+
+#include <opentelemetry/trace/span.h>
+#include <opentelemetry/trace/tracer.h>
+#include <opentelemetry/trace/context.h>
+
+using proton::receiver_options;
+using proton::source_options;
+
+opentelemetry::nostd::shared_ptr<opentelemetry::trace::TracerProvider> 
provider;
+std::map<proton::message_id, std::shared_ptr<opentelemetry::trace::Scope>> 
scope_map;
+
+int id_counter = 0;
+
+class client : public proton::messaging_handler {
+  private:
+    std::string url;
+    std::vector<std::string> requests;
+    proton::sender sender;
+    proton::receiver receiver;
+
+  public:
+    client(const std::string &u, const std::vector<std::string>& r) : url(u), 
requests(r) {}
+
+    void on_container_start(proton::container &c) override {
+        sender = c.open_sender(url);
+        // Create a receiver requesting a dynamically created queue
+        // for the message source.
+        receiver_options opts = 
receiver_options().source(source_options().dynamic(true));
+        receiver = sender.connection().open_receiver("", opts);
+    }
+
+    void send_request() {
+        proton::message req;
+        req.body(requests.front());
+        req.reply_to(receiver.source().address());
+        req.id(id_counter);
+
+        opentelemetry::trace::StartSpanOptions options;
+        options.kind = opentelemetry::trace::SpanKind::kClient;
+
+        // Start a span here before send
+        opentelemetry::nostd::shared_ptr<opentelemetry::trace::Tracer> tracer 
= provider->GetTracer("qpid-tracer", OPENTELEMETRY_SDK_VERSION);
+        opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span> span = 
tracer->StartSpan("send_request",
+            {{"reply_to", req.reply_to()}, {"message", to_string(req.body())}},
+            options);
+        opentelemetry::trace::Scope scope = tracer->WithActiveSpan(span);
+
+        // Storing the 'scope' in a map to keep it alive and erasing it when a 
response is received.
+        scope_map[req.id()] = 
std::make_shared<opentelemetry::trace::Scope>(std::move(scope));
+        id_counter++;
+
+        sender.send(req);
+    }
+
+    void on_receiver_open(proton::receiver &) override {
+        send_request();
+    }
+
+    void on_message(proton::delivery &d, proton::message &response) override {
+        if (requests.empty()) return; // Spurious extra message!
+
+        // Converting the tag in proton::binary to std::string to add it as a 
span attribute. Tag in binary won't be visible.
+        proton::binary tag = d.tag();
+        std::string tag_in_string = std::string(tag);
+        std::stringstream ss;
+        for (int i = 0; i < (int)tag_in_string.length(); ++i)
+            ss << std::hex << (int)tag[i];
+        std::string delivery_tag = ss.str();
+
+        opentelemetry::trace::StartSpanOptions options;
+        options.kind = opentelemetry::trace::SpanKind::kClient;
+
+        // Get Tracer
+        opentelemetry::nostd::shared_ptr<opentelemetry::trace::Tracer> tracer 
= provider->GetTracer("qpid-tracer", OPENTELEMETRY_SDK_VERSION);
+
+        // Start span with or without attributes as required.
+        opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span> s = 
tracer->StartSpan("on_message",
+            {{"delivery_tag", delivery_tag}, {"message-received", 
to_string(response.body())}},
+            options);
+
+        // Mark span as active.
+        opentelemetry::trace::Scope sc = tracer->WithActiveSpan(s);
+
+        // Response has been received, thus erasing the 'scope' of the trace.
+        scope_map.erase(response.id());
+
+        std::cout << requests.front() << " => " << response.body() << 
std::endl;
+        requests.erase(requests.begin());
+
+        if (!requests.empty()) {
+            send_request();
+        } else {
+            d.connection().close();
+        }
+    }
+};
+
+int main(int argc, char **argv) {
+    try {
+        std::string url("127.0.0.1:5672/examples");
+
+        // 1. Initialize the exporter and the provider.
+        // 2. Set the global trace provider.
+        // 3. Call proton::initOpenTelemetryTracer().
+
+        opentelemetry::exporter::jaeger::JaegerExporterOptions opts;
+
+        // Initialize Jaeger Exporter
+        std::unique_ptr<opentelemetry::sdk::trace::SpanExporter> exporter = 
std::unique_ptr<opentelemetry::sdk::trace::SpanExporter>(
+            new opentelemetry::exporter::jaeger::JaegerExporter(opts));
+
+        // Set service-name
+        auto resource_attributes = 
opentelemetry::sdk::resource::ResourceAttributes
+        {
+            {"service.name", "qpid-example-client"}
+        };
+
+        // Creation of the resource for associating it with telemetry
+        auto resource = 
opentelemetry::sdk::resource::Resource::Create(resource_attributes);
+
+        auto processor = 
std::unique_ptr<opentelemetry::sdk::trace::SpanProcessor>(
+            new 
opentelemetry::sdk::trace::SimpleSpanProcessor(std::move(exporter)));
+        provider = 
opentelemetry::nostd::shared_ptr<opentelemetry::trace::TracerProvider>(
+            new 
opentelemetry::sdk::trace::TracerProvider(std::move(processor), resource));
+
+        // Set the global trace provider
+        opentelemetry::trace::Provider::SetTracerProvider(provider);
+
+        // Enable tracing in proton cpp
+        proton::initOpenTelemetryTracer();
+
+        // Sending 2 messages to the server.
+        std::vector<std::string> requests;
+        requests.push_back("Two roads diverged in a wood.");
+        requests.push_back("I took the one less traveled by.");
+
+        client c(url, requests);
+
+        proton::container(c).run();
+
+        return 0;
+    } catch (const std::exception& e) {
+        std::cerr << e.what() << std::endl;
+    }
+
+    return 1;
+}
diff --git a/cpp/examples/tracing_server.cpp b/cpp/examples/tracing_server.cpp
new file mode 100644
index 000000000..aa6a6adb4
--- /dev/null
+++ b/cpp/examples/tracing_server.cpp
@@ -0,0 +1,148 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "options.hpp"
+#include <proton/connection.hpp>
+#include <proton/container.hpp>
+#include <proton/message.hpp>
+#include <proton/message_id.hpp>
+#include <proton/messaging_handler.hpp>
+
+#include <proton/tracing.hpp>
+
+#include <iostream>
+#include <map>
+#include <string>
+#include <cctype>
+
+// Include opentelemetry header files
+#include <opentelemetry/sdk/trace/simple_processor.h>
+#include <opentelemetry/sdk/trace/tracer_provider.h>
+#include <opentelemetry/trace/provider.h>
+#include <opentelemetry/nostd/unique_ptr.h>
+#include <opentelemetry/exporters/jaeger/jaeger_exporter.h>
+#include <opentelemetry/exporters/ostream/span_exporter.h>
+#include <opentelemetry/sdk/resource/resource.h>
+
+#include <opentelemetry/trace/span.h>
+#include <opentelemetry/trace/tracer.h>
+#include <opentelemetry/trace/context.h>
+
+opentelemetry::nostd::shared_ptr<opentelemetry::trace::TracerProvider> 
provider;
+
+class server : public proton::messaging_handler {
+    std::string conn_url_;
+    std::string addr_;
+    proton::connection conn_;
+    std::map<std::string, proton::sender> senders_;
+
+  public:
+    server(const std::string& u, const std::string& a) :
+        conn_url_(u), addr_(a) {}
+
+    void on_container_start(proton::container& c) override {
+        conn_ = c.connect(conn_url_);
+        conn_.open_receiver(addr_);
+
+        std::cout << "Server connected to " << conn_url_ << std::endl;
+    }
+
+    std::string to_upper(const std::string& s) {
+        std::string uc(s);
+        size_t l = uc.size();
+
+        for (size_t i=0; i<l; i++) {
+            uc[i] = static_cast<char>(std::toupper(uc[i]));
+        }
+
+        return uc;
+    }
+
+    void on_message(proton::delivery&, proton::message& m) override {
+
+        // Start a span
+        opentelemetry::nostd::shared_ptr<opentelemetry::trace::Tracer> tracer 
= provider->GetTracer("qpid-tracer", OPENTELEMETRY_SDK_VERSION);
+        opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span> s = 
tracer->StartSpan("on_message");
+
+        opentelemetry::trace::Scope sc = tracer->WithActiveSpan(s);
+
+        std::cout << "Received " << m.body() << std::endl;
+
+        std::string reply_to = m.reply_to();
+        proton::message reply;
+
+        reply.to(reply_to);
+        reply.body(to_upper(proton::get<std::string>(m.body())));
+        reply.correlation_id(m.correlation_id());
+        reply.id(m.id());
+
+        if (!senders_[reply_to]) {
+            senders_[reply_to] = conn_.open_sender(reply_to);
+        }
+
+        senders_[reply_to].send(reply);
+    }
+};
+
+int main(int argc, char **argv) {
+    try {
+        std::string conn_url = argc > 1 ? argv[1] : "//127.0.0.1:5672";
+        std::string addr = argc > 2 ? argv[2] : "examples";
+
+        // 1. Initialize the exporter and the provider
+        // 2. Set the global trace provider
+        // 3. Call proton::initOpenTelemetryTracer()
+
+        // Initialize Jaeger Exporter
+        opentelemetry::exporter::jaeger::JaegerExporterOptions opts;
+        std::unique_ptr<opentelemetry::sdk::trace::SpanExporter> exporter = 
std::unique_ptr<opentelemetry::sdk::trace::SpanExporter>(
+            new opentelemetry::exporter::jaeger::JaegerExporter(opts));
+
+        // Set service-name
+        auto resource_attributes = 
opentelemetry::sdk::resource::ResourceAttributes
+        {
+            {"service.name", "qpid-example-server"}
+        };
+
+        // Creation of the resource for associating it with telemetry
+        auto resource = 
opentelemetry::sdk::resource::Resource::Create(resource_attributes);
+
+        auto processor = 
std::unique_ptr<opentelemetry::sdk::trace::SpanProcessor>(
+            new 
opentelemetry::sdk::trace::SimpleSpanProcessor(std::move(exporter)));
+        provider = 
opentelemetry::nostd::shared_ptr<opentelemetry::trace::TracerProvider>(
+            new 
opentelemetry::sdk::trace::TracerProvider(std::move(processor), resource));
+
+        // Set the global trace provider
+        opentelemetry::trace::Provider::SetTracerProvider(provider);
+    
+        // Enable tracing in proton cpp
+        proton::initOpenTelemetryTracer();
+
+        server srv(conn_url, addr);
+        proton::container(srv).run();
+
+        return 0;
+    } catch (const std::exception& e) {
+        std::cerr << e.what() << std::endl;
+    }
+
+    return 1;
+}
diff --git a/cpp/include/proton/tracing.hpp b/cpp/include/proton/tracing.hpp
new file mode 100644
index 000000000..a8e8d0686
--- /dev/null
+++ b/cpp/include/proton/tracing.hpp
@@ -0,0 +1,37 @@
+#ifndef PROTON_TRACING_HPP
+#define PROTON_TRACING_HPP
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "./internal/export.hpp"
+
+/// @file
+/// @copybrief proton::tracing
+
+namespace proton {
+
+/// Tracer initializer.
+PN_CPP_EXTERN void initOpenTelemetryTracer();
+
+} // namespace proton
+
+#endif // PROTON_TRACING_HPP
diff --git a/cpp/src/init_tracer_stub.cpp b/cpp/src/init_tracer_stub.cpp
new file mode 100644
index 000000000..b05c7cdc0
--- /dev/null
+++ b/cpp/src/init_tracer_stub.cpp
@@ -0,0 +1,29 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/tracing.hpp>
+
+namespace proton {
+
+/// Tracer initializer.
+void initOpenTelemetryTracer() {}
+
+} // namespace proton
diff --git a/cpp/src/messaging_adapter.cpp b/cpp/src/messaging_adapter.cpp
index 3cda8cd2d..84624f2aa 100644
--- a/cpp/src/messaging_adapter.cpp
+++ b/cpp/src/messaging_adapter.cpp
@@ -46,6 +46,8 @@
 #include <proton/session.h>
 #include <proton/transport.h>
 
+#include "tracing_private.hpp"
+
 #include <assert.h>
 
 namespace proton {
@@ -112,6 +114,7 @@ void on_delivery(messaging_handler& handler, pn_event_t* 
event) {
     pn_link_t *lnk = pn_event_link(event);
     pn_delivery_t *dlv = pn_event_delivery(event);
     link_context& lctx = link_context::get(lnk);
+    Tracing& ot = Tracing::getTracing();
 
     if (pn_link_is_receiver(lnk)) {
         delivery d(make_wrapper<delivery>(dlv));
@@ -128,7 +131,7 @@ void on_delivery(messaging_handler& handler, pn_event_t* 
event) {
                 if (lctx.auto_accept)
                     d.release();
             } else {
-                handler.on_message(d, msg);
+                ot.on_message_handler(handler, d, msg);
                 if (lctx.auto_accept && pn_delivery_local_state(dlv) == 0) // 
Not set by handler
                     d.accept();
                 if (lctx.draining && !pn_link_credit(lnk)) {
@@ -157,6 +160,7 @@ void on_delivery(messaging_handler& handler, pn_event_t* 
event) {
         // sender
         if (pn_delivery_updated(dlv)) {
             tracker t(make_wrapper<tracker>(dlv));
+            ot.on_settled_span(t);
             switch(pn_delivery_remote_state(dlv)) {
             case PN_ACCEPTED:
                 handler.on_tracker_accept(t);
diff --git a/cpp/src/sender.cpp b/cpp/src/sender.cpp
index 1fbb5ce6b..942e755b0 100644
--- a/cpp/src/sender.cpp
+++ b/cpp/src/sender.cpp
@@ -33,6 +33,7 @@
 
 #include "proton_bits.hpp"
 #include "contexts.hpp"
+#include "tracing_private.hpp"
 
 #include <assert.h>
 
@@ -71,7 +72,11 @@ tracker sender::send(const message &message, const binary 
&tag) {
         pn_object(),
         pn_dtag((reinterpret_cast<const char *>(&tag[0])), tag.size()));
     std::vector<char> buf;
-    message.encode(buf);
+
+    Tracing& ot = Tracing::getTracing();
+    tracker track = make_wrapper<tracker>(dlv);
+    ot.message_encode(message, buf, tag, track);
+
     assert(!buf.empty());
     pn_link_send(pn_object(), &buf[0], buf.size());
     pn_link_advance(pn_object());
@@ -79,7 +84,7 @@ tracker sender::send(const message &message, const binary 
&tag) {
         pn_delivery_settle(dlv);
     if (!pn_link_credit(pn_object()))
         link_context::get(pn_object()).draining = false;
-    return make_wrapper<tracker>(dlv);
+    return track;
 }
 
 void sender::return_credit() {
diff --git a/cpp/src/tracing_opentelemetry.cpp 
b/cpp/src/tracing_opentelemetry.cpp
new file mode 100644
index 000000000..be1234477
--- /dev/null
+++ b/cpp/src/tracing_opentelemetry.cpp
@@ -0,0 +1,235 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <opentelemetry/context/propagation/global_propagator.h>
+#include <opentelemetry/nostd/unique_ptr.h>
+#include <opentelemetry/sdk/trace/simple_processor.h>
+#include <opentelemetry/sdk/trace/tracer_provider.h>
+#include <opentelemetry/trace/context.h>
+#include <opentelemetry/trace/propagation/http_trace_context.h>
+#include <opentelemetry/trace/provider.h>
+#include <opentelemetry/trace/span.h>
+#include <opentelemetry/trace/tracer.h>
+
+#include <proton/messaging_handler.hpp>
+
+#include <proton/annotation_key.hpp>
+#include <proton/delivery.hpp>
+#include <proton/message.hpp>
+#include <proton/receiver.hpp>
+#include <proton/sender.hpp>
+#include <proton/source.hpp>
+#include <proton/target.hpp>
+#include <proton/tracing.hpp>
+#include <proton/tracker.hpp>
+#include <proton/transfer.hpp>
+
+#include "proton/link.hpp"
+#include <proton/link.h>
+
+#include "tracing_private.hpp"
+
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+
+// Custom specialization of std::hash injected in namespace std for 
proton::binary as a key in tag_span i.e. an unordered_map.
+template <> struct std::hash<proton::binary> {
+    std::size_t operator()(const proton::binary& k) const {
+        std::string s(k[0], k.size());
+        return std::hash<std::string>{}(s);
+    }
+};
+
+namespace proton
+{
+namespace nostd = opentelemetry::nostd;
+namespace sdktrace = opentelemetry::sdk::trace;
+
+const std::string kContextKey = "x-opt-qpid-tracestate";
+
+// TODO: Have a delivery context to do the work, instead of having a map to 
associate the spans with the delivery tags.
+
+// A map to associate the spans with the delivery tags, needed for ending the 
spans on message settled.
+// Deleting the map entries after the span is ended to avoid the memory 
leakage in future.
+std::unordered_map<binary, nostd::shared_ptr<opentelemetry::trace::Span>> 
tag_span;
+
+class AMQPMapCarrier : public 
opentelemetry::context::propagation::TextMapCarrier {
+  public:
+    AMQPMapCarrier(const proton::map<annotation_key, value>* 
message_annotations) : message_annotations_(message_annotations) {}
+    virtual nostd::string_view Get(nostd::string_view key) const noexcept 
override {
+        std::string key_to_compare = key.data();
+
+        proton::value v_tracing_map = 
message_annotations_->get(annotation_key(kContextKey));
+        proton::map<proton::annotation_key, proton::value> tracing_map;
+
+        if (!v_tracing_map.empty())
+            get(v_tracing_map, tracing_map);
+
+        if (tracing_map.exists(annotation_key(key_to_compare))) {
+            value extracted_value = 
tracing_map.get(annotation_key(key_to_compare));
+            std::string extracted_string = to_string(extracted_value);
+            extracted_strings.push_back(extracted_string);
+            nostd::string_view final_extracted_string = 
nostd::string_view(extracted_strings.back());
+
+            return final_extracted_string;
+        }
+        return "";
+    }
+    virtual void Set(nostd::string_view key,
+                     nostd::string_view val) noexcept override {
+
+        proton::value v_tracing_map = 
message_annotations_->get(annotation_key(kContextKey));
+        proton::map<proton::annotation_key, proton::value> tracing_map;
+
+        if (!v_tracing_map.empty())
+            get(v_tracing_map, tracing_map);
+
+        tracing_map.put(annotation_key(std::string(key)), 
value(std::string(val)));
+        ((proton::map<proton::annotation_key, 
proton::value>*)message_annotations_)->put(annotation_key(kContextKey), 
tracing_map);
+    }
+
+    const proton::map<annotation_key, value>* message_annotations_;
+    mutable std::vector<std::string> extracted_strings;
+};
+
+nostd::shared_ptr<opentelemetry::trace::Tracer> get_tracer() {
+    auto provider = opentelemetry::trace::Provider::GetTracerProvider();
+    nostd::shared_ptr<opentelemetry::trace::Tracer> tracer = 
provider->GetTracer("qpid-tracer", OPENTELEMETRY_SDK_VERSION);
+    return tracer;
+}
+
+class OpentelemetryTracing : public Tracing {
+  public:
+    void message_encode(const message& message, std::vector<char>& buf, const 
binary& tag, const tracker& track) override {
+        proton::message message_cp = message;
+
+        opentelemetry::trace::StartSpanOptions options;
+        options.kind = opentelemetry::trace::SpanKind::kProducer;
+
+        opentelemetry::context::Context ctx = 
opentelemetry::context::RuntimeContext::GetCurrent();
+        options.parent = opentelemetry::trace::GetSpan(ctx)->GetContext();
+
+        std::string tag_in_string = std::string(tag);
+        std::stringstream ss;
+        for (int i = 0; i < (int)tag_in_string.length(); ++i)
+            ss << std::hex << (int)tag[i];
+        std::string delivery_tag = ss.str();
+
+        sender s = track.sender();
+        target t = s.target();
+        std::string t_addr = t.address();
+
+        std::string delivery_state = to_string(track.state());
+
+        nostd::shared_ptr<opentelemetry::trace::Span> span = 
get_tracer()->StartSpan(
+            "amqp-delivery-send",
+            {{"Delivery_tag", delivery_tag}, {"Destination_address", t_addr}},
+            options);
+
+        opentelemetry::trace::Scope scope = 
proton::get_tracer()->WithActiveSpan(span);
+
+        // Inject current context into AMQP message annotations
+        opentelemetry::context::Context current_ctx = 
opentelemetry::context::RuntimeContext::GetCurrent();
+
+        AMQPMapCarrier carrier(&message_cp.message_annotations());
+        
nostd::shared_ptr<opentelemetry::context::propagation::TextMapPropagator> prop =
+            
opentelemetry::context::propagation::GlobalTextMapPropagator::GetGlobalPropagator();
+        prop->Inject(carrier, current_ctx);
+
+        tag_span[tag] = span;
+
+        message_cp.encode(buf);
+    }
+
+    void on_message_handler(messaging_handler& h, delivery& d, message& 
message) override {
+        opentelemetry::trace::StartSpanOptions options;
+        options.kind = opentelemetry::trace::SpanKind::kConsumer;
+
+        // Extract context from AMQP message annotations
+        const AMQPMapCarrier carrier(&message.message_annotations());
+
+        
nostd::shared_ptr<opentelemetry::context::propagation::TextMapPropagator> prop =
+            
opentelemetry::context::propagation::GlobalTextMapPropagator::GetGlobalPropagator();
+        opentelemetry::context::Context current_ctx = 
opentelemetry::context::RuntimeContext::GetCurrent();
+
+        opentelemetry::context::Context new_context = prop->Extract(carrier, 
current_ctx);
+
+        options.parent = 
opentelemetry::trace::GetSpan(new_context)->GetContext();
+
+        binary tag_in_binary = d.tag();
+        std::string tag_in_string = std::string(d.tag());
+        std::stringstream ss;
+        for (int i = 0; i < (int)tag_in_string.length(); ++i)
+            ss << std::hex << (int)tag_in_binary[i];
+        std::string delivery_tag = ss.str();
+
+        receiver r = d.receiver();
+        source s = r.source();
+        std::string s_addr = s.address();
+
+        transfer tt(d);
+        std::string delivery_state = to_string(tt.state());
+
+        nostd::shared_ptr<opentelemetry::trace::Span> span = 
get_tracer()->StartSpan(
+            "amqp-message-received",
+            {{"Delivery_tag", delivery_tag}, {"Source_address", s_addr}},
+            options);
+
+        opentelemetry::trace::Scope scope = get_tracer()->WithActiveSpan(span);
+
+        h.on_message(d, message);
+
+        span->End();
+    }
+
+    void on_settled_span(tracker& track) override {
+
+        binary tag = track.tag();
+        nostd::shared_ptr<opentelemetry::trace::Span> span = tag_span[tag];
+        std::string delivery_state = to_string(track.state());
+        span->AddEvent("delivery state: " + delivery_state);
+
+        span->End();
+
+        // Delete map entries.
+        tag_span.erase(tag);
+    }
+};
+
+static OpentelemetryTracing otel;
+
+void initOpenTelemetryTracer()
+{  
+    Tracing::activate(otel);
+
+    // Set global propagator
+    opentelemetry::context::propagation::GlobalTextMapPropagator::
+        SetGlobalPropagator(
+            nostd::shared_ptr<
+                opentelemetry::context::propagation::TextMapPropagator>(
+                new opentelemetry::trace::propagation::HttpTraceContext()));
+}
+
+}  // namespace proton
diff --git a/cpp/src/tracing_private.hpp b/cpp/src/tracing_private.hpp
new file mode 100644
index 000000000..89cbcd4bd
--- /dev/null
+++ b/cpp/src/tracing_private.hpp
@@ -0,0 +1,55 @@
+#ifndef PROTON_INTERNAL_TRACING_HPP
+#define PROTON_INTERNAL_TRACING_HPP
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <vector>
+
+namespace proton {
+
+class binary;
+class delivery;
+class message;
+class messaging_handler;
+class tracker;
+
+/// Base class for OpentelemetryTracing and StubTracing. An interface for 
Tracing.
+class Tracing {
+
+    static Tracing* the;
+
+  public:
+    /// Returns an object for the Tracing. If Tracing is enable, returns the 
object of OpentelemetryTracing.
+    /// By default returns the object of StubTracing.
+    inline static Tracing& getTracing() { return *the; }
+
+    /// Initialize the Tracing object with the OpentelemetryTracing object.
+    inline static void activate(Tracing& r) { Tracing::the = &r; }
+
+    virtual void message_encode(const message &m, std::vector<char> &buf, 
const binary &tag, const tracker &track) = 0;
+    virtual void on_message_handler(messaging_handler& h, delivery& d, 
message& message) = 0;
+    virtual void on_settled_span(tracker& track) = 0;
+};
+
+} // namespace proton
+
+#endif // PROTON_INTERNAL_TRACING_HPP
diff --git a/cpp/src/tracing_stub.cpp b/cpp/src/tracing_stub.cpp
new file mode 100644
index 000000000..fc4d1dde6
--- /dev/null
+++ b/cpp/src/tracing_stub.cpp
@@ -0,0 +1,48 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/annotation_key.hpp>
+#include <proton/message.hpp>
+#include <proton/messaging_handler.hpp>
+#include <proton/tracing.hpp>
+
+#include "tracing_private.hpp"
+
+namespace proton
+{
+
+class StubTracing : public Tracing {
+  public:
+    void message_encode(const message& m, std::vector<char>& buf, const 
binary& tag, const tracker& track) override {
+        m.encode(buf);
+    }
+
+    void on_message_handler(messaging_handler& h, delivery& d, message& 
message) override {
+        h.on_message(d, message);
+    }
+
+    void on_settled_span(tracker& track) override {}
+};
+
+static StubTracing dummy;
+Tracing* Tracing::the = &dummy;
+
+} // namespace proton
diff --git a/cpp/src/tracing_test.cpp b/cpp/src/tracing_test.cpp
new file mode 100644
index 000000000..9a2ef81f5
--- /dev/null
+++ b/cpp/src/tracing_test.cpp
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <proton/connection.hpp>
+#include <proton/connection_options.hpp>
+#include <proton/container.hpp>
+#include <proton/delivery.hpp>
+#include <proton/link.hpp>
+#include <proton/listen_handler.hpp>
+#include <proton/listener.hpp>
+#include <proton/message.hpp>
+#include <proton/message_id.hpp>
+#include <proton/messaging_handler.hpp>
+#include <proton/tracker.hpp>
+#include <proton/types.h>
+#include <proton/types.hpp>
+#include <proton/value.hpp>
+#include <proton/tracing.hpp>
+
+#include "proton/error_condition.hpp"
+#include "proton/receiver_options.hpp"
+#include "proton/transport.hpp"
+#include "proton/work_queue.hpp"
+#include "test_bits.hpp"
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <thread>
+
+#include <opentelemetry/sdk/trace/simple_processor.h>
+#include <opentelemetry/sdk/trace/tracer_provider.h>
+#include <opentelemetry/trace/provider.h>
+#include <opentelemetry/nostd/unique_ptr.h>
+#include <opentelemetry/exporters/ostream/span_exporter.h>
+
+namespace {
+std::mutex m;
+std::condition_variable cv;
+bool listener_ready = false;
+int listener_port;
+const std::string kKeyToCheck = "traceparent";
+} // namespace
+
+class test_recv : public proton::messaging_handler {
+  private:
+    class listener_ready_handler : public proton::listen_handler {
+        void on_open(proton::listener &l) override {
+            {
+                std::lock_guard<std::mutex> lk(m);
+                listener_port = l.port();
+                listener_ready = true;
+            }
+            cv.notify_one();
+        }
+    };
+
+    std::string url;
+    proton::listener listener;
+    listener_ready_handler listen_handler;
+
+  public:
+    test_recv(const std::string &s) : url(s) {}
+
+    void on_container_start(proton::container &c) override {
+        listener = c.listen(url, listen_handler);
+    }
+
+    void on_message(proton::delivery &d, proton::message &msg) override {
+        proton::map<proton::annotation_key, proton::value> tracing_map;
+
+        
ASSERT(!msg.message_annotations().get(proton::annotation_key("x-opt-qpid-tracestate")).empty());
+        
get(msg.message_annotations().get(proton::annotation_key("x-opt-qpid-tracestate")),
 tracing_map);
+        ASSERT(tracing_map.exists(proton::annotation_key(kKeyToCheck)));
+
+        d.receiver().close();
+        d.connection().close();
+        listener.stop();
+    }
+};
+
+class test_send : public proton::messaging_handler {
+  private:
+    std::string url;
+    proton::sender sender;
+
+  public:
+    test_send(const std::string &s) : url(s) {}
+
+    void on_container_start(proton::container &c) override {
+        proton::connection_options co;
+        sender = c.open_sender(url, co);
+    }
+
+    void on_sendable(proton::sender &s) override {
+        proton::message msg;
+        msg.body("message");
+        proton::binary test_tag_send("TESTTAG");
+        s.send(msg, test_tag_send);
+        s.connection().close();
+    }
+};
+
+int test_tracing() {
+    
+    std::string recv_address("127.0.0.1:0/test");
+    test_recv recv(recv_address);
+    proton::container c(recv);
+
+    auto exporter = std::unique_ptr<opentelemetry::sdk::trace::SpanExporter>(
+            new opentelemetry::exporter::trace::OStreamSpanExporter());
+
+    auto processor = std::unique_ptr<opentelemetry::sdk::trace::SpanProcessor>(
+        new 
opentelemetry::sdk::trace::SimpleSpanProcessor(std::move(exporter)));
+    auto provider = 
opentelemetry::nostd::shared_ptr<opentelemetry::trace::TracerProvider>(
+        new opentelemetry::sdk::trace::TracerProvider(std::move(processor)));
+
+    opentelemetry::trace::Provider::SetTracerProvider(provider);
+
+    proton::initOpenTelemetryTracer();
+
+    std::thread thread_recv([&c]() -> void { c.run(); });
+
+    // wait until listener is ready
+    std::unique_lock<std::mutex> lk(m);
+    cv.wait(lk, [] { return listener_ready; });
+
+    std::string send_address =
+        "127.0.0.1:" + std::to_string(listener_port) + "/test";
+    test_send send(send_address);
+    proton::container(send).run();
+    thread_recv.join();
+
+    return 0;
+}
+
+int main(int argc, char **argv) {
+    int failed = 0;
+    RUN_ARGV_TEST(failed, test_tracing());
+    return failed;
+}
diff --git a/cpp/tests.cmake b/cpp/tests.cmake
index 2063ba211..ee43b3c6e 100644
--- a/cpp/tests.cmake
+++ b/cpp/tests.cmake
@@ -70,6 +70,11 @@ if (ENABLE_JSONCPP)
   file(COPY  "${CMAKE_CURRENT_SOURCE_DIR}/testdata" DESTINATION 
"${CMAKE_CURRENT_BINARY_DIR}")
 endif()
 
+if (ENABLE_OPENTELEMETRYCPP)
+  add_cpp_test(tracing_test)
+  target_link_libraries(tracing_test opentelemetry-cpp::trace 
opentelemetry-cpp::jaeger_trace_exporter 
opentelemetry-cpp::ostream_span_exporter)
+endif()
+
 # TODO aconway 2018-10-31: Catch2 tests
 # This is a simple example of a C++ test using the Catch2 framework.
 # See c/tests/ for more interesting examples.


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to