-
Notifications
You must be signed in to change notification settings - Fork 578
[SDK] Do not use MultiSpanProcessor for single processors #4043
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
base: main
Are you sure you want to change the base?
Changes from all commits
7cf05ff
04a566f
fc3af44
4bcf251
6d78235
c62b8bb
57975a2
9ea0b08
d64ed35
7c58e6c
6377e54
75d829f
b7bfe4d
e43f22c
6839cda
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,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" | ||
|
|
@@ -49,6 +50,33 @@ using namespace opentelemetry::sdk::trace; | |
| using namespace opentelemetry::sdk::resource; | ||
| using opentelemetry::sdk::instrumentationscope::ScopeConfigurator; | ||
|
|
||
| OPENTELEMETRY_BEGIN_NAMESPACE | ||
| namespace sdk | ||
| { | ||
| namespace trace | ||
| { | ||
| class MultiSpanProcessorTestPeer | ||
| { | ||
| public: | ||
| static std::vector<SpanProcessor *> GetProcessors(MultiSpanProcessor *multi_span_processor) | ||
| { | ||
| std::vector<SpanProcessor *> 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<SpanProcessor> processor(new SimpleSpanProcessor(nullptr)); | ||
|
|
@@ -329,6 +357,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<SpanProcessor> processor(new SimpleSpanProcessor(nullptr)); | ||
| std::vector<std::unique_ptr<SpanProcessor>> processors; | ||
| processors.push_back(std::move(processor)); | ||
|
|
||
| std::unique_ptr<TracerContext> 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<SimpleSpanProcessor *>(&span_processor); | ||
| #else | ||
| auto processor_typeed = static_cast<SimpleSpanProcessor *>(&span_processor); | ||
| #endif | ||
| ASSERT_NE(nullptr, processor_typeed); | ||
| } | ||
|
|
||
| // get a MultiSpanProcessor back that wraps both processors | ||
| TEST(TracerProvider, GetProcessorsTwo) | ||
| { | ||
| std::vector<SpanProcessor *> 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<SpanProcessor> processor1(processors_raw[0]); | ||
| std::unique_ptr<SpanProcessor> processor2(processors_raw[1]); | ||
|
|
||
| std::vector<std::unique_ptr<SpanProcessor>> processors; | ||
| processors.push_back(std::move(processor1)); | ||
| processors.push_back(std::move(processor2)); | ||
|
|
||
| std::unique_ptr<TracerContext> 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<MultiSpanProcessor *>(&span_processor); | ||
| #else | ||
| auto processor_typeed = static_cast<MultiSpanProcessor *>(&span_processor); | ||
| #endif | ||
| ASSERT_NE(nullptr, processor_typeed); | ||
|
|
||
| std::vector<SpanProcessor *> 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<SpanProcessor *> 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<SpanProcessor> processor1(processors_raw[0]); | ||
| std::unique_ptr<SpanProcessor> processor2(processors_raw[1]); | ||
| std::unique_ptr<SpanProcessor> processor3(processors_raw[2]); | ||
| std::vector<std::unique_ptr<SpanProcessor>> processors; | ||
| processors.push_back(std::move(processor1)); | ||
| processors.push_back(std::move(processor2)); | ||
| processors.push_back(std::move(processor3)); | ||
|
|
||
| std::unique_ptr<TracerContext> 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<MultiSpanProcessor *>(&span_processor); | ||
| #else | ||
| auto processor_typeed = static_cast<MultiSpanProcessor *>(&span_processor); | ||
| #endif | ||
| ASSERT_NE(nullptr, processor_typeed); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shoule we check
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, but how?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can add friend class only for test, like OtlpHttpExporterTestPeer in exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_exporter.h and exporters/otlp/test/otlp_http_exporter_test.cc |
||
|
|
||
| std::vector<SpanProcessor *> contained_processors = | ||
| MultiSpanProcessorTestPeer::GetProcessors(processor_typeed); | ||
| EXPECT_EQ(processors_raw, contained_processors); | ||
| } | ||
|
|
||
| TEST(TracerProvider, Shutdown) | ||
| { | ||
| std::unique_ptr<SpanProcessor> processor(new SimpleSpanProcessor(nullptr)); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this break spans that were already started before
AddProcessor()runs? Those spans keep the recordable created by the old single processor, but after this lineSpan::End()will callMultiSpanProcessor::OnEnd(), which expects aMultiRecordable. Maybe promotion needs to preserve the old processor path for existing spans.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm. yes I agree that it breaks currently live spans in they way you describe. unfortunate. do you have a suggestion on how to get around this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the cleanest fix is for
Spanto remember the processor used when it was started.That should not require shared ownership or another heap allocation per span. It could just store a raw
SpanProcessor*captured at start, then use that same processor forOnEnd(). The span already keeps the tracer/context alive, so the processor lifetime should still be covered.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Hailios - Just checking in on this. I think the PR still needs a code change here before it can be approved.
The main invariant is that a span should use the same
SpanProcessorforMakeRecordable(),OnStart(), andOnEnd(). Otherwise spans that were already in flight beforeAddProcessor()can still end through the newMultiSpanProcessor.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, I'm in a busy period, I'm aware of the wish to have that work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lalitb - could you have a look at the current patch set, I've added a pointer to the Span class to keep track of its SpanProcessor?