Skip to content
This repository was archived by the owner on Jan 26, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ include_directories(SYSTEM 3rd_party/include)
set(SRCS src/propagation.cpp
src/dynamic_load.cpp
src/noop.cpp
src/scope_manager.cpp
src/thread_local_scope_manager.cpp
src/tracer.cpp
src/tracer_factory.cpp
src/ext/tags.cpp)
Expand Down
67 changes: 67 additions & 0 deletions include/opentracing/scope_manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#ifndef OPENTRACING_SCOPE_MANAGER_H
#define OPENTRACING_SCOPE_MANAGER_H

#include <opentracing/version.h>
#include <functional>
#include <memory>

namespace opentracing {
BEGIN_OPENTRACING_ABI_NAMESPACE

class Span;
class ScopeManager;

// Scope is returned by the ScopeManager when activating a span.
//
// The lifetime of the Scope instance represents the duration of the
// activation. Its lifetime can not exist beyond that of the
// ScopeManager. The specific implementation of ScopeManager may
// enforce additional constraints for the Scope object, please defer
// to the documentation of the ScopeManager for further information.
class Scope {
public:
using Callback = std::function<void()>;

// Create a Scope that will invoke callback on destruction.
Scope(Callback callback) noexcept;

Scope(Scope&& scope) noexcept;
~Scope();

private:
Scope(const Scope& scope) = delete;
Scope& operator=(const Scope&) = delete;
Scope& operator=(Scope&&) = delete;

Callback callback_;
};

// ScopeManager allows a Span to be activated for a specific scope.
//
// Once a Span has been activated, it can then be accessed via the
// ScopeManager. This interface can be implemented to provide
// different characteristics of Span propagation such as passing
// only within the same thread.
class ScopeManager {
public:
virtual ~ScopeManager() = default;

// Activate the given Span, returning a Scope to track its duration.
//
// A Span MUST be upgraded to a shared_ptr as consumers of the span
// via the ScopeManager may take ownership over it beyond the
// duration of the Scope. Implementations are expected to define the
// logic of Scope destrucion.
virtual Scope Activate(std::shared_ptr<Span> span) noexcept = 0;

// Return the current active Span.
//
// A span is always guaranteed to be returned. If there is no span
// active, then a default noop span instance should be returned.
virtual std::shared_ptr<Span> ActiveSpan() noexcept = 0;
};

END_OPENTRACING_ABI_NAMESPACE
} // namespace opentracing

#endif // OPENTRACING_SCOPE_MANAGER_H
43 changes: 43 additions & 0 deletions include/opentracing/thread_local_scope_manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef OPENTRACING_THREAD_LOCAL_SCOPE_MANAGER_H
#define OPENTRACING_THREAD_LOCAL_SCOPE_MANAGER_H

#include <opentracing/scope_manager.h>
#include <opentracing/version.h>

#include <memory>

namespace opentracing {
BEGIN_OPENTRACING_ABI_NAMESPACE

class Span;

// A ScopeManager for propagating Spans within the same thread.
//
// Once activated, during the lifetime of the Scope, the Span can be
// accessed only within the same thread. This behaviour is best for
// propagating Spans down the execution stack without requiring each
// component to forward it explicitly. This is achieved using
// thread_local variables.
class ThreadLocalScopeManager : public ScopeManager {
public:
// Activate the given Span, returning a Scope to track its duration.
//
// An activated Span is only accessible from the same thread as the
// Activation for the lifetime of the Scope. The Scope MUST be stored
// on the Stack and MUST NOT be moved beyond the time of
// instantiation, otherwise behaviour is undefined.
Scope Activate(std::shared_ptr<Span> span) noexcept override;

// Return the current active Span.
//
// A span is always guaranteed to be returned. If there is no span
// active, then a default noop span instance should be returned.
// Only active Spans from the same thread as the activation are
// returned.
std::shared_ptr<Span> ActiveSpan() noexcept override;
};

END_OPENTRACING_ABI_NAMESPACE
} // namespace opentracing

#endif // OPENTRACING_THREAD_LOCAL_SCOPE_MANAGER_H
15 changes: 15 additions & 0 deletions include/opentracing/tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
#define OPENTRACING_TRACER_H

#include <opentracing/propagation.h>
#include <opentracing/scope_manager.h>
#include <opentracing/span.h>
#include <opentracing/string_view.h>
#include <opentracing/symbols.h>
#include <opentracing/thread_local_scope_manager.h>
#include <opentracing/util.h>
#include <opentracing/version.h>
#include <chrono>
Expand Down Expand Up @@ -147,6 +149,13 @@ class OPENTRACING_API Tracer {
return reader.Extract(*this);
}

// Return a reference to the tracer's ScopeManager.
//
// If not overriden, the default ThreadLocalScopeManager will be returned.
// The ScopeManager is merged with the Tracer for convenience so as not to
// require users to manage ownership themselves.
virtual opentracing::ScopeManager& ScopeManager() const;

// Close is called when a tracer is finished processing spans. It is not
// required to be called and its effect is unspecified. For example, an
// implementation might use this function to flush buffered spans to its
Expand All @@ -163,6 +172,12 @@ class OPENTRACING_API Tracer {
std::shared_ptr<Tracer> tracer) noexcept;

static bool IsGlobalTracerRegistered() noexcept;

private:
// The default ScopeManager to use if the Tracer doesn't provide their own.
//
// This is also required for backwards compatiblity.
mutable ThreadLocalScopeManager scope_manager_;
};

// StartTimestamp is a StartSpanOption that sets an explicit start timestamp for
Expand Down
18 changes: 18 additions & 0 deletions src/scope_manager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <opentracing/noop.h>
#include <opentracing/scope_manager.h>

namespace opentracing {
BEGIN_OPENTRACING_ABI_NAMESPACE

Scope::Scope(Callback callback) noexcept : callback_(callback) {}

Scope::Scope(Scope&& scope) noexcept { std::swap(callback_, scope.callback_); }

Scope::~Scope() {
if (callback_) {
callback_();
}
}

END_OPENTRACING_ABI_NAMESPACE
} // namespace opentracing
38 changes: 38 additions & 0 deletions src/thread_local_scope_manager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include <opentracing/noop.h>
#include <opentracing/thread_local_scope_manager.h>

#include <map>
#include <utility>

namespace opentracing {
BEGIN_OPENTRACING_ABI_NAMESPACE

namespace {

const std::shared_ptr<Span> noopspan{MakeNoopTracer()->StartSpan("")};
using ThreadLocalSpanMap =
std::map<ThreadLocalScopeManager*, std::shared_ptr<Span>>;
thread_local ThreadLocalSpanMap thread_local_span_map;

} // anonymous namespace

Scope ThreadLocalScopeManager::Activate(std::shared_ptr<Span> span) noexcept {
auto it_bool = thread_local_span_map.insert(std::make_pair(this, span));
if (it_bool.second) {
return Scope{[this]() { thread_local_span_map.erase(this); }};
} else {
std::swap(it_bool.first->second, span);
return Scope{[this, span]() { thread_local_span_map[this] = span; }};
}
}

std::shared_ptr<Span> ThreadLocalScopeManager::ActiveSpan() noexcept {
auto active_it = thread_local_span_map.find(this);
if (active_it != thread_local_span_map.end()) {
return active_it->second;
}
return noopspan;
}

END_OPENTRACING_ABI_NAMESPACE
} // namespace opentracing
3 changes: 3 additions & 0 deletions src/tracer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,8 @@ std::shared_ptr<Tracer> Tracer::InitGlobal(
bool Tracer::IsGlobalTracerRegistered() noexcept {
return TracerRegistry::instance().is_registered();
}

opentracing::ScopeManager& Tracer::ScopeManager() const { return scope_manager_; }

END_OPENTRACING_ABI_NAMESPACE
} // namespace opentracing
15 changes: 15 additions & 0 deletions test/BUILD
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
TEST_NAMES = [
"scope_manager_test",
"string_view_test",
"tracer_test",
"util_test",
Expand All @@ -14,6 +15,20 @@ TEST_NAMES = [
],
) for test_name in TEST_NAMES]

cc_test(
name = "thread_local_scope_manager_test",
srcs = [
"thread_local_scope_manager_test.cpp"
],
deps = [
"//:opentracing",
"//3rd_party:catch2",
],
linkopts = [
"-lpthread",
]
)

cc_test(
name = "mutiple_tracer_link_test",
srcs = [
Expand Down
10 changes: 10 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ else()
set(OPENTRACING_LIBRARY opentracing-static)
endif()

find_package(Threads)

add_executable(tracer_test tracer_test.cpp)
target_link_libraries(tracer_test ${OPENTRACING_LIBRARY})
add_test(NAME tracer_test COMMAND tracer_test)
Expand All @@ -17,6 +19,14 @@ add_test(NAME value_test COMMAND value_test)
add_executable(util_test util_test.cpp)
add_test(NAME util_test COMMAND util_test)

add_executable(scope_manager_test scope_manager_test.cpp)
target_link_libraries(scope_manager_test ${OPENTRACING_LIBRARY})
add_test(NAME scope_manager_test COMMAND scope_manager_test)

add_executable(thread_local_scope_manager_test thread_local_scope_manager_test.cpp)
target_link_libraries(thread_local_scope_manager_test ${OPENTRACING_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
add_test(NAME thread_local_scope_manager_test COMMAND thread_local_scope_manager_test)

if (BUILD_SHARED_LIBS AND BUILD_MOCKTRACER AND BUILD_DYNAMIC_LOADING)
add_executable(dynamic_load_test dynamic_load_test.cpp)
target_link_libraries(dynamic_load_test ${OPENTRACING_LIBRARY})
Expand Down
27 changes: 27 additions & 0 deletions test/scope_manager_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include <opentracing/scope_manager.h>

using namespace opentracing;

#define CATCH_CONFIG_MAIN
#include <opentracing/catch2/catch.hpp>

TEST_CASE("scope") {
SECTION("Scope invokes callback on destruction") {
int called = 0;
{
Scope scope{[&called]() { ++called; }};
CHECK(called == 0);
}
CHECK(called == 1);
}

SECTION("Scope can be moved") {
int called = 0;
{
Scope scope{[&called]() { ++called; }};
{ Scope scope2{std::move(scope)}; }
CHECK(called == 1);
}
CHECK(called == 1); // check for double calls
}
}
57 changes: 57 additions & 0 deletions test/thread_local_scope_manager_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include <opentracing/noop.h>
#include <opentracing/thread_local_scope_manager.h>
#include <memory>
#include <thread>

using namespace opentracing;

#define CATCH_CONFIG_MAIN
#include <opentracing/catch2/catch.hpp>

TEST_CASE("thread_local_scope_manager") {
ThreadLocalScopeManager sm;
std::shared_ptr<Span> default_span = sm.ActiveSpan();

SECTION("Returns noop span with no activations") { CHECK(default_span); }

auto tracer = MakeNoopTracer();

SECTION("Basic span activation/deactivation") {
std::shared_ptr<Span> span{tracer->StartSpan("a")};
CHECK(sm.ActiveSpan() == default_span);
{
auto scope = sm.Activate(span);
CHECK(sm.ActiveSpan() == span);
}
CHECK(sm.ActiveSpan() == default_span);
}

SECTION("Nested span activation/deactivation") {
std::shared_ptr<Span> span1{tracer->StartSpan("1")};
std::shared_ptr<Span> span2{tracer->StartSpan("2")};
CHECK(sm.ActiveSpan() == default_span);
{
auto scope1 = sm.Activate(span1);
CHECK(sm.ActiveSpan() == span1);
{
auto scope2 = sm.Activate(span2);
CHECK(sm.ActiveSpan() == span2);
}
CHECK(sm.ActiveSpan() == span1);
}
CHECK(sm.ActiveSpan() == default_span);
}

SECTION("Validate span activation is local to thread") {
std::shared_ptr<Span> thread_span;
std::shared_ptr<Span> span{tracer->StartSpan("a")};
auto scope = sm.Activate(span);

// Start thread which captures active span
std::thread{[&thread_span, &sm]() {
thread_span = sm.ActiveSpan();
}}.join();

CHECK(thread_span != span);
}
}
6 changes: 6 additions & 0 deletions test/tracer_test.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <opentracing/ext/tags.h>
#include <opentracing/noop.h>
#include <opentracing/tracer.h>
#include <memory>
using namespace opentracing;

#define CATCH_CONFIG_MAIN
Expand Down Expand Up @@ -33,6 +34,11 @@ TEST_CASE("tracer") {
ChildOf(nullptr).Apply(options);
CHECK(options.references.size() == 0);
}

SECTION("Tracer provides a valid ScopeManager") {
std::shared_ptr<Span> span{tracer->StartSpan("s")};
tracer->ScopeManager().Activate(span);
}
}

TEST_CASE("A tracer can be globally registered") {
Expand Down