Skip to content
This repository has been archived by the owner on Jan 26, 2024. It is now read-only.

Commit

Permalink
Add support for dynamic loading. (#45)
Browse files Browse the repository at this point in the history
* Dynamic load changes.

* Remove default timestamping.

* Add dynamic load functions.

* Use factory interface for dynamic loading.

* Separate TracerFactory from dynamic loading.

* Support specifying an error_code when dynamic load fails.

* Allow DynamicTracingLibraryHandle to be default constructible.

* Add documentation for make_opentracing_factory.

* Comment dynamic_load interface.

* Document tracer_factory.h

* Fix order in destructors.

* Correct typo.

* Remove windows stub.

* Update naming convention to be more consistent.

* Run clang-format.

* Correct typo.

* Add dynamic loading support to mocktracer.

* Add tests for dynamic loading.

* Run clang-format.

* Test for weak symbols.

* Run clang-format.

* Fix bazel build for dynamic loading support.

* link 3rd party libraries in statically.

* Correct include guards.

* Rearrange base64 code.

* Add missing base64 code.

* Include apache license.

* Correct typo.

* Writing manual serialization code.

* Add plugin library.

* Add serialization for SpanData.

* Suppress false positive from undefined behavior sanitizer.

* Represent duration with a string.

* Use string to represent trace/span-ids.

* Remove 3rd-party json library dependency.

* Run clang-format.

* Add missing include.

* Use strings for IDs in JSON.

* Run clang-format.

* Add dl library dependency.

* Return const pointer from const member function.

* Remove constexpr from rvalue-ref member.

* Fix bazel build.

* Add example usage with mocktracer.

* Add example for dynamic loading.

* Add missing include.
  • Loading branch information
rnburn authored Feb 22, 2018
1 parent d5fde12 commit 3fb91d3
Show file tree
Hide file tree
Showing 32 changed files with 990 additions and 46 deletions.
14 changes: 10 additions & 4 deletions BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
cc_library(
name = "opentracing",
srcs = glob(["src/*.cpp"]),
srcs = glob(["src/*.cpp"], exclude=["src/dynamic_load_unsupported.cpp"]),
hdrs = glob(["include/opentracing/*.h"]) + [
":include/opentracing/config.h",
":include/opentracing/version.h",
],
strip_include_prefix = "include",
Expand All @@ -19,14 +20,19 @@ genrule(
"cmake/*",
"src/*",
]),
outs = ["include/opentracing/version.h"],
outs = [
"include/opentracing/config.h",
"include/opentracing/version.h"
],
cmd = """
TEMP_DIR=$$(mktemp -d)
TARGET=$${PWD}/$@
CONFIG_H_OUT=$${PWD}/$(location :include/opentracing/config.h)
VERSION_H_OUT=$${PWD}/$(location :include/opentracing/version.h)
OPENTRACING_ROOT=$$(dirname $${PWD}/$(location :CMakeLists.txt))
cd $$TEMP_DIR
cmake -DBUILD_TESTING=OFF -DBUILD_MOCKTRACER=OFF -L $$OPENTRACING_ROOT
mv include/opentracing/version.h $$TARGET
mv include/opentracing/config.h $$CONFIG_H_OUT
mv include/opentracing/version.h $$VERSION_H_OUT
rm -rf $$TEMP_DIR
""",
)
72 changes: 60 additions & 12 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,14 @@ SET(CPACK_PACKAGE_VERSION_MINOR ${OPENTRACING_VERSION_MINOR})
SET(CPACK_PACKAGE_VERSION_PATCH ${OPENTRACING_VERSION_PATCH})
include(CPack)

# ==============================================================================
# Set up generated version.h

configure_file(version.h.in include/opentracing/version.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/opentracing
DESTINATION include)

# ==============================================================================
# Configure compilers

set(CMAKE_CXX_STANDARD 11)
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything \
-Wno-c++98-compat \
-Wno-c++98-compat-pedantic \
-Wno-c++98-compat-bind-to-temporary-copy \
-Wno-weak-vtables \
-Wno-exit-time-destructors \
Expand All @@ -65,23 +58,70 @@ if(ENABLE_LINTING)
endif()

# ==============================================================================
# OpenTracing library targets
# Check for weak symbol support

include_directories(include)
include_directories(SYSTEM 3rd_party/include)
try_compile(
SUPPORTS_WEAK_SYMBOLS
"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeTmp"
SOURCES ${CMAKE_SOURCE_DIR}/cmake/weak_symbol.cpp)

This comment has been minimized.

Copy link
@andreivirtosu

andreivirtosu Feb 26, 2018

@rnburn Using CMAKE_SOURCE_DIR breaks the build when this project is included from within another CMakeLists.txt.
The error I get is: "Cannot find source file: .../weak_symbol.cpp
A quick fix here is to replace it with: {CMAKE_CURRENT_LIST_DIR}

This comment has been minimized.

Copy link
@rnburn

rnburn Feb 26, 2018

Author Contributor

Thanks, I'll put in a fix for it shortly.


# ==============================================================================
# Set up options

option(BUILD_SHARED_LIBS "Build as a shared library" ON)
option(BUILD_STATIC_LIBS "Build as a static library" ON)
option(BUILD_MOCKTRACER "Build mocktracer library" ON)
option(BUILD_DYNAMIC_LOADING "Build with dynamic loading support" ON)

if (BUILD_DYNAMIC_LOADING)
if (NOT SUPPORTS_WEAK_SYMBOLS OR NOT UNIX)
message(WARNING "Building without dynamic loading support.")
set(BUILD_DYNAMIC_LOADING OFF)
endif()
endif()

set(OPENTRACING_BUILD_DYNAMIC_LOADING ${BUILD_DYNAMIC_LOADING})

if (NOT BUILD_SHARED_LIBS AND NOT BUILD_STATIC_LIBS)
message(FATAL_ERROR "One or both of BUILD_SHARED_LIBS or BUILD_STATIC_LIBS must be set to ON to build")
endif()

set(SRCS src/propagation.cpp src/noop.cpp src/tracer.cpp)
# ==============================================================================
# Set up generated header files config.h and version.h

configure_file(version.h.in include/opentracing/version.h)
configure_file(config.h.in include/opentracing/config.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/opentracing
DESTINATION include)

# ==============================================================================
# OpenTracing library targets

include_directories(include)
include_directories(SYSTEM 3rd_party/include)

set(SRCS src/propagation.cpp
src/dynamic_load.cpp
src/noop.cpp
src/tracer.cpp
src/tracer_factory.cpp)

if (BUILD_DYNAMIC_LOADING)
list(APPEND SRCS src/dynamic_load_unix.cpp)
else()
list(APPEND SRCS src/dynamic_load_unsupported.cpp)
endif()

list(APPEND LIBRARIES "")
if (BUILD_DYNAMIC_LOADING)
list(APPEND LIBRARIES ${CMAKE_DL_LIBS})
endif()


if (BUILD_SHARED_LIBS)
add_library(opentracing SHARED ${SRCS})
target_link_libraries(opentracing ${LIBRARIES})
target_include_directories(opentracing INTERFACE "$<INSTALL_INTERFACE:include/>")
set_target_properties(opentracing PROPERTIES VERSION ${OPENTRACING_VERSION_STRING}
SOVERSION ${OPENTRACING_VERSION_MAJOR})
Expand All @@ -96,6 +136,7 @@ endif()

if (BUILD_STATIC_LIBS)
add_library(opentracing-static STATIC ${SRCS})
target_link_libraries(opentracing-static ${LIBRARIES})
set_target_properties(opentracing-static PROPERTIES OUTPUT_NAME opentracing)
target_include_directories(opentracing-static INTERFACE "$<INSTALL_INTERFACE:include/>")
install(TARGETS opentracing-static EXPORT OpenTracingTargets
Expand Down Expand Up @@ -147,3 +188,10 @@ include(CTest)
if(BUILD_TESTING)
add_subdirectory(test)
endif()

# ==============================================================================
# Examples

if(BUILD_TESTING)
add_subdirectory(example)
endif()
3 changes: 3 additions & 0 deletions cmake/weak_symbol.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
void __attribute((weak)) f();

int main() { return 0; }
3 changes: 3 additions & 0 deletions config.h.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#cmakedefine OPENTRACING_BUILD_DYNAMIC_LOADING
2 changes: 2 additions & 0 deletions example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
add_subdirectory(tutorial)
add_subdirectory(dynamic_load)
4 changes: 4 additions & 0 deletions example/dynamic_load/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
if (BUILD_DYNAMIC_LOADING AND BUILD_SHARED_LIBS)
add_executable(dynamic_load-example dynamic_load-example.cpp)
target_link_libraries(dynamic_load-example opentracing)
endif()
64 changes: 64 additions & 0 deletions example/dynamic_load/dynamic_load-example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Demonstrates how to load a tracer library in at runtime and how to use it
// to construct spans. To run it using the mocktracer, invoke with
//
// TRACER_CONFIG=`mktemp`
// echo '{ "output_file": "/dev/stdout" }' > $TRACER_CONFIG
// dynamic_load-example /path/to/libopentracing_mocktracer.so $TRACER_CONFIG

#include <opentracing/dynamic_load.h>
#include <cassert>
#include <cerrno>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>

int main(int argc, char* argv[]) {
if (argc != 3) {
std::cerr << "Usage: <tracer_library> <tracer_config_file>\n";
return -1;
}

// Load the tracer library.
std::string error_message;
auto handle_maybe =
opentracing::DynamicallyLoadTracingLibrary(argv[1], error_message);
if (!handle_maybe) {
std::cerr << "Failed to load tracer library " << error_message << "\n";
return -1;
}

// Read in the tracer's configuration.
std::ifstream istream{argv[2]};
if (!istream.good()) {
std::cerr << "Failed to open tracer config file " << argv[2] << ": "
<< std::strerror(errno) << "\n";
return -1;
}
std::string tracer_config{std::istreambuf_iterator<char>{istream},
std::istreambuf_iterator<char>{}};

// Construct a tracer.
auto& tracer_factory = handle_maybe->tracer_factory();
auto tracer_maybe =
tracer_factory.MakeTracer(tracer_config.c_str(), error_message);
if (!tracer_maybe) {
std::cerr << "Failed to create tracer " << error_message << "\n";
return -1;
}
auto& tracer = *tracer_maybe;

// Use the tracer to create some spans.
{
auto span_a = tracer->StartSpan("A");
assert(span_a != nullptr);
span_a->SetTag("abc", 123);
auto span_b =
tracer->StartSpan("B", {opentracing::ChildOf(&span_a->context())});
assert(span_b != nullptr);
span_b->SetTag("xyz", 987);
}

tracer->Close();
return 0;
}
5 changes: 5 additions & 0 deletions example/tutorial/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
if (BUILD_MOCKTRACER AND BUILD_SHARED_LIBS)
include_directories(${CMAKE_SOURCE_DIR}/mocktracer/include)

This comment has been minimized.

Copy link
@andreivirtosu

andreivirtosu Feb 26, 2018

@rnburn Using CMAKE_SOURCE_DIR breaks the build when this project is included from within another CMakeLists.txt.
The error I get is: "Cannot find source file: .../json_recorder
A quick fix here is to replace it with: ${CMAKE_CURRENT_LIST_DIR}/../../

add_executable(tutorial-example tutorial-example.cpp)
target_link_libraries(tutorial-example opentracing_mocktracer)
endif()
37 changes: 37 additions & 0 deletions example/tutorial/text_map_carrier.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef LIGHTSTEP_TEXT_MAP_CARRIER
#define LIGHTSTEP_TEXT_MAP_CARRIER

#include <opentracing/propagation.h>
#include <string>
#include <unordered_map>

using opentracing::TextMapReader;
using opentracing::TextMapWriter;
using opentracing::expected;
using opentracing::string_view;

class TextMapCarrier : public TextMapReader, public TextMapWriter {
public:
TextMapCarrier(std::unordered_map<std::string, std::string>& text_map)
: text_map_(text_map) {}

expected<void> Set(string_view key, string_view value) const override {
text_map_[key] = value;
return {};
}

expected<void> ForeachKey(
std::function<expected<void>(string_view key, string_view value)> f)
const override {
for (const auto& key_value : text_map_) {
auto result = f(key_value.first, key_value.second);
if (!result) return result;
}
return {};
}

private:
std::unordered_map<std::string, std::string>& text_map_;
};

#endif // LIGHTSTEP_TEXT_MAP_CARRIER
99 changes: 99 additions & 0 deletions example/tutorial/tutorial-example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Demonstrates basic usage of the OpenTracing API. Uses OpenTracing's
// mocktracer to capture all the recorded spans as JSON.

#include <opentracing/mocktracer/json_recorder.h>
#include <opentracing/mocktracer/tracer.h>
#include <cassert>
#include <iostream>
#include <sstream>
#include <unordered_map>
#include "text_map_carrier.h"
using namespace opentracing;
using namespace opentracing::mocktracer;

int main() {
MockTracerOptions options;
std::unique_ptr<std::ostringstream> output{new std::ostringstream{}};
std::ostringstream& oss = *output;
options.recorder = std::unique_ptr<mocktracer::Recorder>{
new JsonRecorder{std::move(output)}};

std::shared_ptr<opentracing::Tracer> tracer{
new MockTracer{std::move(options)}};

auto parent_span = tracer->StartSpan("parent");
assert(parent_span);

// Create a child span.
{
auto child_span =
tracer->StartSpan("childA", {ChildOf(&parent_span->context())});
assert(child_span);

// Set a simple tag.
child_span->SetTag("simple tag", 123);

// Set a complex tag.
child_span->SetTag("complex tag",
Values{123, Dictionary{{"abc", 123}, {"xyz", 4.0}}});

// Log simple values.
child_span->Log({{"event", "simple log"}, {"abc", 123}});

// Log complex values.
child_span->Log({{"event", "complex log"},
{"data", Dictionary{{"a", 1}, {"b", Values{1, 2}}}}});

child_span->Finish();
}

// Create a follows from span.
{
auto child_span =
tracer->StartSpan("childB", {FollowsFrom(&parent_span->context())});

// child_span's destructor will finish the span if not done so explicitly.
}

// Use custom timestamps.
{
auto t1 = SystemClock::now();
auto t2 = SteadyClock::now();
auto span = tracer->StartSpan(
"useCustomTimestamps",
{ChildOf(&parent_span->context()), StartTimestamp(t1)});
assert(span);
span->Finish({FinishTimestamp(t2)});
}

// Extract and Inject a span context.
{
std::unordered_map<std::string, std::string> text_map;
TextMapCarrier carrier(text_map);
auto err = tracer->Inject(parent_span->context(), carrier);
assert(err);
auto span_context_maybe = tracer->Extract(carrier);
assert(span_context_maybe);
auto span = tracer->StartSpan("propagationSpan",
{ChildOf(span_context_maybe->get())});
}

// You get an error when trying to extract a corrupt span.
{
std::unordered_map<std::string, std::string> text_map = {
{"x-ot-span-context", "123"}};
TextMapCarrier carrier(text_map);
auto err = tracer->Extract(carrier);
assert(!err);
assert(err.error() == span_context_corrupted_error);
// How to get a readable message from the error.
std::cout << "Example error message: \"" << err.error().message() << "\"\n";
}

parent_span->Finish();
tracer->Close();

std::cout << "\nRecorded spans as JSON:\n\n";
std::cout << oss.str() << "\n";
return 0;
}
Loading

0 comments on commit 3fb91d3

Please sign in to comment.