[SDK] Do not use MultiSpanProcessor for single processors#4043
[SDK] Do not use MultiSpanProcessor for single processors#4043Hailios wants to merge 11 commits into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4043 +/- ##
==========================================
- Coverage 82.01% 81.71% -0.29%
==========================================
Files 385 385
Lines 16023 16036 +13
==========================================
- Hits 13139 13102 -37
- Misses 2884 2934 +50
🚀 New features to boost your workflow:
|
58faa51 to
00e2150
Compare
dbarker
left a comment
There was a problem hiding this comment.
Thanks for the PR! Supporting replacement of the MultiSpanProcessor with a user defined processor is a nice addition. Please see a few comments and request for test cases.
| // this is the first processor to be added, maybe the MultiSpanProcessor is not needed | ||
| processor_ = std::move(processor); | ||
| } | ||
| else if (num_processors_ == 1) |
There was a problem hiding this comment.
Please add test cases for these if/else branches
| else if (num_processors_ == 1) | ||
| { | ||
| // if there already is a processor, then make a new MultiSpanProcessor to handle both | ||
| std::unique_ptr<MultiSpanProcessor> multi_processor(new MultiSpanProcessor({})); |
There was a problem hiding this comment.
it looks like the rest of the code using the pattern above with first calling new and putting it in a smart pointer. and the specific case of creating an empty MultiSpanProcessor is not as easy with make_unique, since one would need to type out all the letters to make an empty vector of unique pointers of processors, rather than "{}".
77e0e8e to
c2df133
Compare
| #else | ||
| auto processor_typeed = static_cast<MultiSpanProcessor *>(&span_processor); | ||
| #endif | ||
| ASSERT_NE(nullptr, processor_typeed); |
There was a problem hiding this comment.
Shoule we check processor_typeed contains all of processor1,processor2 and processor3 here?
There was a problem hiding this comment.
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
marcalff
left a comment
There was a problem hiding this comment.
Thanks for the contribution.
This is a good improvement, and will save overhead in the most frequent cases.
Suggestions for a different implementation:
Have the following attributes:
std::unique_ptr<SpanProcessor> processor_;
MultiSpanProcessor *multi_processor_; // yes, raw pointer.
processor_ will point to a single or multi processor, we don't know looking at this member alone.
multi_processor_ == nullptr means processor_ is a single processor.
multi_processor_ != nullptr means processor_ is a multi processor, and the raw pointer can be used to add more processors to it directly.
This should avoid the need to count processors, and cast back and forth between abstract and more narrow types, which causes confusion.
Drop the processor count, not needed.
Given that this class holds a unique pointer in processors_, the raw multi_processor_ pointer is safe to use.
7412f4b to
d8ad645
Compare
I updated the implementation to follow this advice |
1f2bfe4 to
fc50aae
Compare
|
|
||
| auto multi_processor = static_cast<MultiSpanProcessor *>(processor_.get()); | ||
| multi_processor->AddProcessor(std::move(processor)); | ||
| processor_ = std::move(multi_processor); |
There was a problem hiding this comment.
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 line Span::End() will call MultiSpanProcessor::OnEnd(), which expects a MultiRecordable. Maybe promotion needs to preserve the old processor path for existing spans.
There was a problem hiding this comment.
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.
Maybe the cleanest fix is for Span to 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 for OnEnd(). The span already keeps the tracer/context alive, so the processor lifetime should still be covered.
lalitb
left a comment
There was a problem hiding this comment.
As mentioned here. We need to preserver the behavior as documented here -
opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/tracer_provider.h
Lines 107 to 110 in 76f0872
Fixes # (issue)
Changes
do not wrap single processors in a multi span processor. that is, use it when needed, otherwise not. idea here is to save execution time by not needlessly going through the multi span processor.
For significant contributions please make sure you have completed the following items:
CHANGELOG.mdupdated for non-trivial changes