diff --git a/sdk/include/opentelemetry/sdk/trace/multi_span_processor.h b/sdk/include/opentelemetry/sdk/trace/multi_span_processor.h index 7b0172dc8e..85caf5f1a1 100644 --- a/sdk/include/opentelemetry/sdk/trace/multi_span_processor.h +++ b/sdk/include/opentelemetry/sdk/trace/multi_span_processor.h @@ -194,6 +194,9 @@ class MultiSpanProcessor : public SpanProcessor ProcessorNode *head_{nullptr}; ProcessorNode *tail_{nullptr}; size_t count_{0}; + + // For testing + friend class MultiSpanProcessorTestPeer; }; } // namespace trace } // namespace sdk diff --git a/sdk/include/opentelemetry/sdk/trace/tracer_context.h b/sdk/include/opentelemetry/sdk/trace/tracer_context.h index 81edbb5322..b2c219398c 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer_context.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer_context.h @@ -23,6 +23,9 @@ namespace sdk namespace trace { +// forward declare to be able to have a raw pointer to it +class MultiSpanProcessor; + /** * A class which stores the TracerProvider context. * @@ -120,6 +123,8 @@ class TracerContext std::unique_ptr id_generator_; std::unique_ptr processor_; std::unique_ptr> tracer_configurator_; + // shares the pointer with processor_ if it is a MultiSpanProcessor, null otherwise + MultiSpanProcessor *multi_processor_; }; } // namespace trace diff --git a/sdk/src/trace/tracer_context.cc b/sdk/src/trace/tracer_context.cc index c3cbfb9d76..f72564f4b8 100644 --- a/sdk/src/trace/tracer_context.cc +++ b/sdk/src/trace/tracer_context.cc @@ -32,9 +32,22 @@ TracerContext::TracerContext(std::vector> &&proce : resource_(resource), sampler_(std::move(sampler)), id_generator_(std::move(id_generator)), - processor_(std::unique_ptr(new MultiSpanProcessor(std::move(processors)))), - tracer_configurator_(std::move(tracer_configurator)) -{} + tracer_configurator_(std::move(tracer_configurator)), + multi_processor_(nullptr) +{ + if (processors.empty()) + { + processor_ = std::unique_ptr(new MultiSpanProcessor(std::move(processors))); + } + else + { + // at least one processor is available here + for (auto &&processor : processors) + { + AddProcessor(std::move(processor)); + } + } +} Sampler &TracerContext::GetSampler() const noexcept { @@ -59,9 +72,31 @@ opentelemetry::sdk::trace::IdGenerator &TracerContext::GetIdGenerator() const no void TracerContext::AddProcessor(std::unique_ptr processor) noexcept { + if (!processor) + { + return; + } + + if (!processor_) + { + // this is the first processor to be added + processor_ = std::move(processor); + } + else if (multi_processor_ == nullptr) + { + // a processor exists, but it's not a MultiSpanProcessor. make a new MultiSpanProcessor + multi_processor_ = new MultiSpanProcessor({}); + std::unique_ptr multi_processor(multi_processor_); + multi_processor->AddProcessor(std::move(processor_)); + multi_processor->AddProcessor(std::move(processor)); - auto multi_processor = static_cast(processor_.get()); - multi_processor->AddProcessor(std::move(processor)); + processor_ = std::move(multi_processor); + } + else /*if (multi_processor_ != nullptr)*/ + { + // already have a MultiSpanProcessor, add the processor to it + multi_processor_->AddProcessor(std::move(processor)); + } } SpanProcessor &TracerContext::GetProcessor() const noexcept diff --git a/sdk/test/trace/tracer_provider_test.cc b/sdk/test/trace/tracer_provider_test.cc index a3434afdd1..5fc968a892 100644 --- a/sdk/test/trace/tracer_provider_test.cc +++ b/sdk/test/trace/tracer_provider_test.cc @@ -13,6 +13,7 @@ #include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/sdk/trace/exporter.h" #include "opentelemetry/sdk/trace/id_generator.h" +#include "opentelemetry/sdk/trace/multi_span_processor.h" #include "opentelemetry/sdk/trace/processor.h" #include "opentelemetry/sdk/trace/random_id_generator.h" #include "opentelemetry/sdk/trace/sampler.h" @@ -38,6 +39,33 @@ using namespace opentelemetry::sdk::trace; using namespace opentelemetry::sdk::resource; +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace trace +{ +class MultiSpanProcessorTestPeer +{ +public: + static std::vector GetProcessors(MultiSpanProcessor *multi_span_processor) + { + std::vector res; + + MultiSpanProcessor::ProcessorNode *node = multi_span_processor->head_; + while (node != nullptr) + { + auto processor = node->value_.get(); + res.emplace_back(processor); + node = node->next_; + } + + return res; + } +}; +} // namespace trace +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE + TEST(TracerProvider, GetTracer) { std::unique_ptr processor(new SimpleSpanProcessor(nullptr)); @@ -318,6 +346,90 @@ TEST(TracerProvider, GetTracerAbiv2) } #endif /* OPENTELEMETRY_ABI_VERSION_NO >= 2 */ +// get the same processor back, not wrapped in a MultiSpanProcessor +TEST(TracerProvider, GetProcessor) +{ + std::unique_ptr processor(new SimpleSpanProcessor(nullptr)); + std::vector> processors; + processors.push_back(std::move(processor)); + + std::unique_ptr context1(new TracerContext(std::move(processors))); + + auto &span_processor = context1->GetProcessor(); + + // Should be the SimpleSpanProcessor processor that was created above. +#ifdef OPENTELEMETRY_RTTI_ENABLED + auto processor_typeed = dynamic_cast(&span_processor); +#else + auto processor_typeed = static_cast(&span_processor); +#endif + ASSERT_NE(nullptr, processor_typeed); +} + +// get a MultiSpanProcessor back that wraps both processors +TEST(TracerProvider, GetProcessorsTwo) +{ + std::vector processors_raw(2); + processors_raw[0] = new SimpleSpanProcessor(nullptr); // deleted via unique_ptr + processors_raw[1] = new SimpleSpanProcessor(nullptr); // deleted via unique_ptr + + std::unique_ptr processor1(processors_raw[0]); + std::unique_ptr processor2(processors_raw[1]); + + std::vector> processors; + processors.push_back(std::move(processor1)); + processors.push_back(std::move(processor2)); + + std::unique_ptr context1(new TracerContext(std::move(processors))); + + auto &span_processor = context1->GetProcessor(); + + // Should be the SimpleSpanProcessor processor that was created above. +#ifdef OPENTELEMETRY_RTTI_ENABLED + auto processor_typeed = dynamic_cast(&span_processor); +#else + auto processor_typeed = static_cast(&span_processor); +#endif + ASSERT_NE(nullptr, processor_typeed); + + std::vector contained_processors = + MultiSpanProcessorTestPeer::GetProcessors(processor_typeed); + EXPECT_EQ(processors_raw, contained_processors); +} + +// get a MultiSpanProcessor back that wraps all three processors +TEST(TracerProvider, GetProcessorsThree) +{ + std::vector processors_raw(3); + processors_raw[0] = new SimpleSpanProcessor(nullptr); // deleted via unique_ptr + processors_raw[1] = new SimpleSpanProcessor(nullptr); // deleted via unique_ptr + processors_raw[2] = new SimpleSpanProcessor(nullptr); // deleted via unique_ptr + + std::unique_ptr processor1(processors_raw[0]); + std::unique_ptr processor2(processors_raw[1]); + std::unique_ptr processor3(processors_raw[2]); + std::vector> processors; + processors.push_back(std::move(processor1)); + processors.push_back(std::move(processor2)); + processors.push_back(std::move(processor3)); + + std::unique_ptr context1(new TracerContext(std::move(processors))); + + auto &span_processor = context1->GetProcessor(); + + // Should be the SimpleSpanProcessor processor that was created above. +#ifdef OPENTELEMETRY_RTTI_ENABLED + auto processor_typeed = dynamic_cast(&span_processor); +#else + auto processor_typeed = static_cast(&span_processor); +#endif + ASSERT_NE(nullptr, processor_typeed); + + std::vector contained_processors = + MultiSpanProcessorTestPeer::GetProcessors(processor_typeed); + EXPECT_EQ(processors_raw, contained_processors); +} + TEST(TracerProvider, Shutdown) { std::unique_ptr processor(new SimpleSpanProcessor(nullptr));