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]