Support adding links to span (#351)
This commit is contained in:
parent
c504cfb51e
commit
2bab26e249
|
@ -68,9 +68,10 @@ public:
|
|||
nostd::shared_ptr<trace::Span> StartSpan(
|
||||
nostd::string_view name,
|
||||
const common::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);
|
||||
|
|
|
@ -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"
|
||||
|
@ -66,6 +67,7 @@ public:
|
|||
// Tracer
|
||||
nostd::shared_ptr<Span> StartSpan(nostd::string_view /*name*/,
|
||||
const common::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
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include "opentelemetry/common/attribute_value.h"
|
||||
#include "opentelemetry/common/key_value_iterable_view.h"
|
||||
#include "opentelemetry/nostd/function_ref.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, const opentelemetry::common::KeyValueIterable &)>
|
||||
callback) const noexcept = 0;
|
||||
/**
|
||||
* @return the number of key-value pairs
|
||||
*/
|
||||
virtual size_t size() const noexcept = 0;
|
||||
};
|
||||
} // namespace trace
|
||||
OPENTELEMETRY_END_NAMESPACE
|
|
@ -0,0 +1,113 @@
|
|||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "opentelemetry/common/key_value_iterable_view.h"
|
||||
#include "opentelemetry/nostd/utility.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, common::KeyValueIterableView<T>)
|
||||
{}
|
||||
|
||||
template <class T, nostd::enable_if_t<common::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, const opentelemetry::common::KeyValueIterable &)>
|
||||
callback) const noexcept override
|
||||
{
|
||||
auto iter = std::begin(*container_);
|
||||
auto last = std::end(*container_);
|
||||
for (; iter != last; ++iter)
|
||||
{
|
||||
if (!this->do_callback(iter->first, iter->second, callback))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t size() const noexcept override { return nostd::size(*container_); }
|
||||
|
||||
private:
|
||||
const T *container_;
|
||||
|
||||
bool do_callback(
|
||||
SpanContext span_context,
|
||||
const common::KeyValueIterable &attributes,
|
||||
nostd::function_ref<bool(SpanContext, const opentelemetry::common::KeyValueIterable &)>
|
||||
callback) const noexcept
|
||||
{
|
||||
if (!callback(span_context, attributes))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class U,
|
||||
nostd::enable_if_t<common::detail::is_key_value_iterable<U>::value> * = nullptr>
|
||||
bool do_callback(
|
||||
SpanContext span_context,
|
||||
const U &attributes,
|
||||
nostd::function_ref<bool(SpanContext, const common::KeyValueIterable &)> callback) const
|
||||
noexcept
|
||||
{
|
||||
return do_callback(span_context, common::KeyValueIterableView<U>(attributes), callback);
|
||||
}
|
||||
|
||||
bool do_callback(
|
||||
SpanContext span_context,
|
||||
std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>> attributes,
|
||||
nostd::function_ref<bool(SpanContext, const common::KeyValueIterable &)> callback) const
|
||||
noexcept
|
||||
{
|
||||
return do_callback(span_context,
|
||||
nostd::span<const std::pair<nostd::string_view, common::AttributeValue>>{
|
||||
attributes.begin(), attributes.end()},
|
||||
callback);
|
||||
}
|
||||
};
|
||||
} // namespace trace
|
||||
OPENTELEMETRY_END_NAMESPACE
|
|
@ -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>
|
||||
|
@ -33,12 +34,13 @@ public:
|
|||
*/
|
||||
virtual nostd::shared_ptr<Span> StartSpan(nostd::string_view name,
|
||||
const common::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,
|
||||
|
@ -47,7 +49,20 @@ public:
|
|||
const T &attributes,
|
||||
const StartSpanOptions &options = {}) noexcept
|
||||
{
|
||||
return this->StartSpan(name, common::KeyValueIterableView<T>(attributes), options);
|
||||
return this->StartSpan(name, attributes, {}, options);
|
||||
}
|
||||
|
||||
template <class T,
|
||||
class U,
|
||||
nostd::enable_if_t<common::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, common::KeyValueIterableView<T>(attributes),
|
||||
SpanContextKeyValueIterableView<U>(links), options);
|
||||
}
|
||||
|
||||
nostd::shared_ptr<Span> StartSpan(
|
||||
|
@ -55,10 +70,60 @@ public:
|
|||
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<common::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<common::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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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}}}});
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ public:
|
|||
Span(std::shared_ptr<Tracer> &&tracer,
|
||||
nostd::string_view name,
|
||||
const opentelemetry::common::KeyValueIterable & /*attributes*/,
|
||||
const opentelemetry::trace::SpanContextKeyValueIterable & /*links*/,
|
||||
const trace::StartSpanOptions & /*options*/) noexcept
|
||||
: tracer_{std::move(tracer)}, name_{name}, span_context_{trace::SpanContext::GetInvalid()}
|
||||
{
|
||||
|
@ -66,8 +67,9 @@ Tracer::Tracer(nostd::string_view /*output*/) {}
|
|||
nostd::shared_ptr<trace::Span> Tracer::StartSpan(
|
||||
nostd::string_view name,
|
||||
const opentelemetry::common::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}};
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ public:
|
|||
opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span> StartSpan(
|
||||
opentelemetry::nostd::string_view name,
|
||||
const opentelemetry::common::KeyValueIterable & /*attributes*/,
|
||||
const opentelemetry::trace::SpanContextKeyValueIterable & /*links*/,
|
||||
const opentelemetry::trace::StartSpanOptions & /*options */) noexcept override;
|
||||
|
||||
void ForceFlushWithMicroseconds(uint64_t /*timeout*/) noexcept override {}
|
||||
|
|
|
@ -47,6 +47,7 @@ public:
|
|||
nostd::shared_ptr<trace_api::Span> StartSpan(
|
||||
nostd::string_view name,
|
||||
const opentelemetry::common::KeyValueIterable &attributes,
|
||||
const trace_api::SpanContextKeyValueIterable &links,
|
||||
const trace_api::StartSpanOptions &options = {}) noexcept override;
|
||||
|
||||
void ForceFlushWithMicroseconds(uint64_t timeout) noexcept override;
|
||||
|
|
|
@ -61,6 +61,7 @@ Span::Span(std::shared_ptr<Tracer> &&tracer,
|
|||
std::shared_ptr<SpanProcessor> processor,
|
||||
nostd::string_view name,
|
||||
const opentelemetry::common::KeyValueIterable &attributes,
|
||||
const trace_api::SpanContextKeyValueIterable &links,
|
||||
const trace_api::StartSpanOptions &options,
|
||||
const trace_api::SpanContext &parent_span_context) noexcept
|
||||
: tracer_{std::move(tracer)},
|
||||
|
@ -98,6 +99,12 @@ Span::Span(std::shared_ptr<Tracer> &&tracer,
|
|||
return true;
|
||||
});
|
||||
|
||||
links.ForEachKeyValue([&](opentelemetry::trace::SpanContext span_context,
|
||||
const opentelemetry::common::KeyValueIterable &attributes) {
|
||||
recordable_->AddLink(span_context, attributes);
|
||||
return true;
|
||||
});
|
||||
|
||||
recordable_->SetStartTime(NowOr(options.start_system_time));
|
||||
start_steady_time = NowOr(options.start_steady_time);
|
||||
processor_->OnStart(*recordable_);
|
||||
|
|
|
@ -19,6 +19,7 @@ public:
|
|||
std::shared_ptr<SpanProcessor> processor,
|
||||
nostd::string_view name,
|
||||
const opentelemetry::common::KeyValueIterable &attributes,
|
||||
const trace_api::SpanContextKeyValueIterable &links,
|
||||
const trace_api::StartSpanOptions &options,
|
||||
const trace_api::SpanContext &parent_span_context) noexcept;
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ trace_api::SpanContext GetCurrentSpanContext(const trace_api::SpanContext &expli
|
|||
nostd::shared_ptr<trace_api::Span> Tracer::StartSpan(
|
||||
nostd::string_view name,
|
||||
const opentelemetry::common::KeyValueIterable &attributes,
|
||||
const trace_api::SpanContextKeyValueIterable &links,
|
||||
const trace_api::StartSpanOptions &options) noexcept
|
||||
{
|
||||
trace_api::SpanContext parent = GetCurrentSpanContext(options.parent);
|
||||
|
@ -72,7 +73,7 @@ nostd::shared_ptr<trace_api::Span> Tracer::StartSpan(
|
|||
else
|
||||
{
|
||||
auto span = nostd::shared_ptr<trace_api::Span>{new (std::nothrow) Span{
|
||||
this->shared_from_this(), processor_.load(), name, attributes, options, parent}};
|
||||
this->shared_from_this(), processor_.load(), name, attributes, links, options, parent}};
|
||||
|
||||
// if the attributes is not nullptr, add attributes to the span.
|
||||
if (sampling_result.attributes)
|
||||
|
|
|
@ -13,6 +13,7 @@ using opentelemetry::core::SteadyTimestamp;
|
|||
using opentelemetry::core::SystemTimestamp;
|
||||
namespace nostd = opentelemetry::nostd;
|
||||
namespace common = opentelemetry::common;
|
||||
using opentelemetry::common::KeyValueIterableView;
|
||||
using opentelemetry::exporter::memory::InMemorySpanData;
|
||||
using opentelemetry::exporter::memory::InMemorySpanExporter;
|
||||
using opentelemetry::trace::SpanContext;
|
||||
|
@ -332,6 +333,83 @@ TEST(Tracer, SpanSetEvents)
|
|||
ASSERT_EQ(1, span_data_events[2].GetAttributes().size());
|
||||
}
|
||||
|
||||
TEST(Tracer, SpanSetLinks)
|
||||
{
|
||||
std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
|
||||
std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
|
||||
auto tracer = initTracer(std::move(exporter));
|
||||
|
||||
{
|
||||
|
||||
// Single span link passed through Initialization list
|
||||
tracer->StartSpan("efg", {{"attr1", 1}}, {{SpanContext(false, false), {{"attr2", 2}}}})->End();
|
||||
auto spans = span_data->GetSpans();
|
||||
ASSERT_EQ(1, spans.size());
|
||||
|
||||
auto &span_data_links = spans.at(0)->GetLinks();
|
||||
ASSERT_EQ(1, span_data_links.size());
|
||||
auto link = span_data_links.at(0);
|
||||
ASSERT_EQ(nostd::get<int>(link.GetAttributes().at("attr2")), 2);
|
||||
}
|
||||
{
|
||||
|
||||
// Multiple span links passed through Initialization list
|
||||
tracer
|
||||
->StartSpan("efg", {{"attr1", 1}},
|
||||
{{SpanContext(false, false), {{"attr2", 2}}},
|
||||
{SpanContext(false, false), {{"attr3", 3}}}})
|
||||
->End();
|
||||
auto spans = span_data->GetSpans();
|
||||
ASSERT_EQ(1, spans.size());
|
||||
|
||||
auto &span_data_links = spans.at(0)->GetLinks();
|
||||
ASSERT_EQ(2, span_data_links.size());
|
||||
auto link1 = span_data_links.at(0);
|
||||
ASSERT_EQ(nostd::get<int>(link1.GetAttributes().at("attr2")), 2);
|
||||
auto link2 = span_data_links.at(1);
|
||||
ASSERT_EQ(nostd::get<int>(link2.GetAttributes().at("attr3")), 3);
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
// Multiple links, each with multiple attributes passed through Initialization list
|
||||
tracer
|
||||
->StartSpan("efg", {{"attr1", 1}},
|
||||
{{SpanContext(false, false), {{"attr2", 2}, {"attr3", 3}}},
|
||||
{SpanContext(false, false), {{"attr4", 4}}}})
|
||||
->End();
|
||||
auto spans = span_data->GetSpans();
|
||||
ASSERT_EQ(1, spans.size());
|
||||
|
||||
auto &span_data_links = spans.at(0)->GetLinks();
|
||||
ASSERT_EQ(2, span_data_links.size());
|
||||
auto link1 = span_data_links.at(0);
|
||||
ASSERT_EQ(nostd::get<int>(link1.GetAttributes().at("attr2")), 2);
|
||||
ASSERT_EQ(nostd::get<int>(link1.GetAttributes().at("attr3")), 3);
|
||||
auto link2 = span_data_links.at(1);
|
||||
ASSERT_EQ(nostd::get<int>(link2.GetAttributes().at("attr4")), 4);
|
||||
}
|
||||
|
||||
{
|
||||
std::map<std::string, std::string> attrs1 = {{"attr1", "1"}, {"attr2", "2"}};
|
||||
std::map<std::string, std::string> attrs2 = {{"attr3", "3"}, {"attr4", "4"}};
|
||||
|
||||
std::vector<std::pair<SpanContext, std::map<std::string, std::string>>> links = {
|
||||
{SpanContext(false, false), attrs1}, {SpanContext(false, false), attrs2}};
|
||||
tracer->StartSpan("efg", attrs1, links)->End();
|
||||
auto spans = span_data->GetSpans();
|
||||
|
||||
auto &span_data_links = spans.at(0)->GetLinks();
|
||||
ASSERT_EQ(2, span_data_links.size());
|
||||
auto link1 = span_data_links.at(0);
|
||||
ASSERT_EQ(nostd::get<std::string>(link1.GetAttributes().at("attr1")), "1");
|
||||
ASSERT_EQ(nostd::get<std::string>(link1.GetAttributes().at("attr2")), "2");
|
||||
auto link2 = span_data_links.at(1);
|
||||
ASSERT_EQ(nostd::get<std::string>(link2.GetAttributes().at("attr3")), "3");
|
||||
ASSERT_EQ(nostd::get<std::string>(link2.GetAttributes().at("attr4")), "4");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Tracer, TestAlwaysOnSampler)
|
||||
{
|
||||
std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
|
||||
|
|
Loading…
Reference in New Issue