Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support adding links to span #351

Merged
merged 27 commits into from
Nov 12, 2020
Merged
Show file tree
Hide file tree
Changes from 19 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
3 changes: 2 additions & 1 deletion api/include/opentelemetry/plugin/tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ class Tracer final : public trace::Tracer, public std::enable_shared_from_this<T
nostd::shared_ptr<trace::Span> StartSpan(
nostd::string_view name,
const trace::KeyValueIterable &attributes,
const trace::SpanContextKeyValueIterable &links,
const trace::StartSpanOptions &options = {}) noexcept override
{
auto span = tracer_handle_->tracer().StartSpan(name, attributes, options);
auto span = tracer_handle_->tracer().StartSpan(name, attributes, links, options);
if (span == nullptr)
{
return nostd::shared_ptr<trace::Span>(nullptr);
Expand Down
2 changes: 2 additions & 0 deletions api/include/opentelemetry/trace/noop.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "opentelemetry/nostd/unique_ptr.h"
#include "opentelemetry/trace/span.h"
#include "opentelemetry/trace/span_context.h"
#include "opentelemetry/trace/span_context_kv_iterable.h"
#include "opentelemetry/trace/tracer.h"
#include "opentelemetry/trace/tracer_provider.h"
#include "opentelemetry/version.h"
Expand Down Expand Up @@ -66,6 +67,7 @@ class NoopTracer final : public Tracer, public std::enable_shared_from_this<Noop
// Tracer
nostd::shared_ptr<Span> StartSpan(nostd::string_view /*name*/,
const KeyValueIterable & /*attributes*/,
const SpanContextKeyValueIterable & /*links*/,
const StartSpanOptions & /*options*/) noexcept override
{
// Don't allocate a no-op span for every StartSpan call, but use a static
Expand Down
35 changes: 35 additions & 0 deletions api/include/opentelemetry/trace/span_context_kv_iterable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include "opentelemetry/common/attribute_value.h"
#include "opentelemetry/nostd/function_ref.h"
#include "opentelemetry/trace/key_value_iterable_view.h"
#include "opentelemetry/version.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace trace
{
/**
* Supports internal iteration over a collection of SpanContext/key-value pairs.
*/
class SpanContextKeyValueIterable
{
public:
virtual ~SpanContextKeyValueIterable() = default;

/**
* Iterate over SpanContext/key-value pairs
* @param callback a callback to invoke for each key-value for each SpanContext.
* If the callback returns false, the iteration is aborted.
* @return true if every SpanContext/key-value pair was iterated over
*/
virtual bool ForEachKeyValue(
nostd::function_ref<
bool(SpanContext, nostd::string_view, common::AttributeValue, bool /*is_last_kv */)>
callback) const noexcept = 0;
/**
* @return the number of key-value pairs
*/
virtual size_t size() const noexcept = 0;
};
} // namespace trace
OPENTELEMETRY_END_NAMESPACE
99 changes: 99 additions & 0 deletions api/include/opentelemetry/trace/span_context_kv_iterable_view.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#pragma once

#include <iterator>
#include <type_traits>
#include <utility>

#include "opentelemetry/nostd/utility.h"
#include "opentelemetry/trace/key_value_iterable_view.h"
#include "opentelemetry/trace/span_context_kv_iterable.h"
#include "opentelemetry/version.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace trace
{
namespace detail
{
template <class T>
inline void take_span_context_kv(SpanContext, opentelemetry::trace::KeyValueIterableView<T>)
{}

template <class T, nostd::enable_if_t<detail::is_key_value_iterable<T>::value> * = nullptr>
inline void take_span_context_kv(SpanContext, T &)
{}

inline void take_span_context_kv(
SpanContext,
std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>>)
{}

template <class T>
auto is_span_context_kv_iterable_impl(T iterable)
-> decltype(take_span_context_kv(std::begin(iterable)->first, std::begin(iterable)->second),
nostd::size(iterable),
std::true_type{});

std::false_type is_span_context_kv_iterable_impl(...);

template <class T>
struct is_span_context_kv_iterable
{
static const bool value =
decltype(detail::is_span_context_kv_iterable_impl(std::declval<T>()))::value;
};
} // namespace detail

template <class T>
class SpanContextKeyValueIterableView final : public SpanContextKeyValueIterable
{
static_assert(detail::is_span_context_kv_iterable<T>::value,
"Must be a context/key-value iterable");

public:
explicit SpanContextKeyValueIterableView(const T &links) noexcept : container_{&links} {}

bool ForEachKeyValue(
nostd::function_ref<bool(SpanContext, nostd::string_view, common::AttributeValue, bool)>
callback) const noexcept override
lalitb marked this conversation as resolved.
Show resolved Hide resolved
{
auto iter = std::begin(*container_);
auto last = std::end(*container_);
for (; iter != last; ++iter)
{
auto kv_iter = std::begin(iter->second);
auto kv_end = std::end(iter->second);
// attributes are optional, and so may be empty container
if (kv_iter == kv_end)
{
if (!callback(iter->first, "", static_cast<nostd::string_view>(""), true))
{
return false;
}
}
else
{
auto kv_last = std::prev(kv_end);
bool is_last_kv = false;
for (; kv_iter != kv_end; ++kv_iter)
{
if (kv_iter == kv_last)
{
is_last_kv = true;
}
if (!callback(iter->first, kv_iter->first, kv_iter->second, is_last_kv))
{
return false;
}
}
}
}
return true;
}

size_t size() const noexcept override { return nostd::size(*container_); }

private:
const T *container_;
};
} // namespace trace
OPENTELEMETRY_END_NAMESPACE
69 changes: 66 additions & 3 deletions api/include/opentelemetry/trace/tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "opentelemetry/trace/default_span.h"
#include "opentelemetry/trace/scope.h"
#include "opentelemetry/trace/span.h"
#include "opentelemetry/trace/span_context_kv_iterable_view.h"
#include "opentelemetry/version.h"

#include <chrono>
Expand Down Expand Up @@ -33,31 +34,93 @@ class Tracer
*/
virtual nostd::shared_ptr<Span> StartSpan(nostd::string_view name,
const KeyValueIterable &attributes,
const SpanContextKeyValueIterable &links,
const StartSpanOptions &options = {}) noexcept = 0;

nostd::shared_ptr<Span> StartSpan(nostd::string_view name,
const StartSpanOptions &options = {}) noexcept
{
return this->StartSpan(name, {}, options);
return this->StartSpan(name, {}, {}, options);
}

template <class T, nostd::enable_if_t<detail::is_key_value_iterable<T>::value> * = nullptr>
nostd::shared_ptr<Span> StartSpan(nostd::string_view name,
const T &attributes,
const StartSpanOptions &options = {}) noexcept
{
return this->StartSpan(name, KeyValueIterableView<T>(attributes), options);
return this->StartSpan(name, attributes, {}, options);
}

template <class T,
class U,
nostd::enable_if_t<detail::is_key_value_iterable<T>::value> * = nullptr,
nostd::enable_if_t<detail::is_span_context_kv_iterable<U>::value> * = nullptr>
nostd::shared_ptr<Span> StartSpan(nostd::string_view name,
const T &attributes,
const U &links,
const StartSpanOptions &options = {}) noexcept
{
return this->StartSpan(name, KeyValueIterableView<T>(attributes),
SpanContextKeyValueIterableView<U>(links), options);
}

nostd::shared_ptr<Span> StartSpan(
nostd::string_view name,
std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>> attributes,
const StartSpanOptions &options = {}) noexcept
{

return this->StartSpan(name, attributes, {}, options);
}

template <class T, nostd::enable_if_t<detail::is_key_value_iterable<T>::value> * = nullptr>
nostd::shared_ptr<Span> StartSpan(
nostd::string_view name,
const T &attributes,
std::initializer_list<
std::pair<SpanContext,
std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>>>>
links,
const StartSpanOptions &options = {}) noexcept
{
return this->StartSpan(
name, attributes,
nostd::span<const std::pair<SpanContext, std::initializer_list<std::pair<
nostd::string_view, common::AttributeValue>>>>{
links.begin(), links.end()},
options);
}

template <class T, nostd::enable_if_t<detail::is_key_value_iterable<T>::value> * = nullptr>
nostd::shared_ptr<Span> StartSpan(
nostd::string_view name,
std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>> attributes,
const T &links,
const StartSpanOptions &options = {}) noexcept
{
return this->StartSpan(name,
nostd::span<const std::pair<nostd::string_view, common::AttributeValue>>{
attributes.begin(), attributes.end()},
options);
links, options);
}

nostd::shared_ptr<Span> StartSpan(
nostd::string_view name,
std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>> attributes,
std::initializer_list<
std::pair<SpanContext,
std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>>>>
links,
const StartSpanOptions &options = {}) noexcept
{
return this->StartSpan(
name,
nostd::span<const std::pair<nostd::string_view, common::AttributeValue>>{attributes.begin(),
attributes.end()},
nostd::span<const std::pair<SpanContext, std::initializer_list<std::pair<
nostd::string_view, common::AttributeValue>>>>{
links.begin(), links.end()},
options);
}

/**
Expand Down
12 changes: 12 additions & 0 deletions api/test/trace/noop_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,15 @@ TEST(NoopTest, UseNoopTracers)

s1->GetContext();
}

TEST(NoopTest, StartSpan)
{
std::shared_ptr<Tracer> tracer{new NoopTracer{}};

std::map<std::string, std::string> attrs = {{"a", "3"}};
std::vector<std::pair<SpanContext, std::map<std::string, std::string>>> links = {
{SpanContext(false, false), attrs}};
auto s1 = tracer->StartSpan("abc", attrs, links);

auto s2 = tracer->StartSpan("efg", {{"a", 3}}, {{SpanContext(false, false), {{"b", 4}}}});
lalitb marked this conversation as resolved.
Show resolved Hide resolved
}
4 changes: 3 additions & 1 deletion examples/plugin/plugin/tracer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Span final : public trace::Span
Span(std::shared_ptr<Tracer> &&tracer,
nostd::string_view name,
const opentelemetry::trace::KeyValueIterable & /*attributes*/,
const opentelemetry::trace::SpanContextKeyValueIterable & /*links*/,
const trace::StartSpanOptions & /*options*/) noexcept
: tracer_{std::move(tracer)}, name_{name}, span_context_{trace::SpanContext::GetInvalid()}
{
Expand Down Expand Up @@ -66,8 +67,9 @@ Tracer::Tracer(nostd::string_view /*output*/) {}
nostd::shared_ptr<trace::Span> Tracer::StartSpan(
nostd::string_view name,
const opentelemetry::trace::KeyValueIterable &attributes,
const opentelemetry::trace::SpanContextKeyValueIterable &links,
const trace::StartSpanOptions &options) noexcept
{
return nostd::shared_ptr<opentelemetry::trace::Span>{
new (std::nothrow) Span{this->shared_from_this(), name, attributes, options}};
new (std::nothrow) Span{this->shared_from_this(), name, attributes, links, options}};
}
1 change: 1 addition & 0 deletions examples/plugin/plugin/tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class Tracer final : public opentelemetry::trace::Tracer,
opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span> StartSpan(
opentelemetry::nostd::string_view name,
const opentelemetry::trace::KeyValueIterable & /*attributes*/,
const opentelemetry::trace::SpanContextKeyValueIterable & /*links*/,
const opentelemetry::trace::StartSpanOptions & /*options */) noexcept override;

void ForceFlushWithMicroseconds(uint64_t /*timeout*/) noexcept override {}
Expand Down
1 change: 1 addition & 0 deletions sdk/include/opentelemetry/sdk/trace/tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class Tracer final : public trace_api::Tracer, public std::enable_shared_from_th
nostd::shared_ptr<trace_api::Span> StartSpan(
nostd::string_view name,
const trace_api::KeyValueIterable &attributes,
const trace_api::SpanContextKeyValueIterable &links,
const trace_api::StartSpanOptions &options = {}) noexcept override;

void ForceFlushWithMicroseconds(uint64_t timeout) noexcept override;
Expand Down
38 changes: 38 additions & 0 deletions sdk/src/trace/span.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "opentelemetry/trace/trace_flags.h"
#include "opentelemetry/version.h"

#include <unordered_map>

OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
Expand Down Expand Up @@ -61,6 +63,7 @@ Span::Span(std::shared_ptr<Tracer> &&tracer,
std::shared_ptr<SpanProcessor> processor,
nostd::string_view name,
const trace_api::KeyValueIterable &attributes,
const trace_api::SpanContextKeyValueIterable &links,
const trace_api::StartSpanOptions &options,
const trace_api::SpanContext &parent_span_context) noexcept
: tracer_{std::move(tracer)},
Expand Down Expand Up @@ -98,6 +101,41 @@ Span::Span(std::shared_ptr<Tracer> &&tracer,
return true;
});

links.ForEachKeyValue([&](trace_api::SpanContext span_context, nostd::string_view key,
opentelemetry::common::AttributeValue value, bool is_last_kv) noexcept {
lalitb marked this conversation as resolved.
Show resolved Hide resolved
static std::unordered_map<nostd::string_view, opentelemetry::common::AttributeValue>
link_attributes = {};
if (is_last_kv)
{
if (key.size())
{
link_attributes.insert(
std::make_pair<nostd::string_view, opentelemetry::common::AttributeValue>(
std::move(key), std::move(value)));
}
if (link_attributes.size())
{
recordable_->AddLink(
span_context,
trace_api::KeyValueIterableView<
std::unordered_map<nostd::string_view, opentelemetry::common::AttributeValue>>(
link_attributes));
}
else
{
recordable_->AddLink(span_context);
}
link_attributes.clear();
}
else
{
link_attributes.insert(
std::make_pair<nostd::string_view, opentelemetry::common::AttributeValue>(
std::move(key), std::move(value)));
}
return true;
});

recordable_->SetStartTime(NowOr(options.start_system_time));
start_steady_time = NowOr(options.start_steady_time);
processor_->OnStart(*recordable_);
Expand Down
1 change: 1 addition & 0 deletions sdk/src/trace/span.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Span final : public trace_api::Span
std::shared_ptr<SpanProcessor> processor,
nostd::string_view name,
const trace_api::KeyValueIterable &attributes,
const trace_api::SpanContextKeyValueIterable &links,
const trace_api::StartSpanOptions &options,
const trace_api::SpanContext &parent_span_context) noexcept;

Expand Down
Loading