-
Notifications
You must be signed in to change notification settings - Fork 114
opentracing-cpp re-redux (virtual inheritance) #7
Conversation
It seems to me there is a misunderstanding of what "custom carriers" are meant to achieve. Carriers are used by instrumentation code. The primary objective of OT spec is to make instrumentation code portable. The above example is the absolute opposite of that, it makes instrumentation code dependent on the specific tracing implementation. To me, the custom carriers are not supposed to know the implementation details of the tracer. They are "custom" because they are specific to the current framework being instrumented with OT, e.g. an RPC frameworks that either has a specialized wire protocol, or more likely just a different abstraction of the "request" object that needs an adapter in order to satisfy the standard carrier interfaces that all tracers are supposed to support (text map, http headers, binary). |
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.
A few misc thoughts (not a detailed review since I know this is just a sketch)
*/ | ||
virtual ~Writer(); | ||
}; | ||
virtual void cleanup(const SpanOptions* opts) = 0; |
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'd prefer that we leave deallocation out of the Tracer interface... seems like a preoptimization and a possible point of confusion
*/ | ||
ErrTraceCorrupted | ||
}; | ||
virtual const SpanContext* getContext(const Span*) = 0; |
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.
why not just Span::getContext
?
*/ | ||
const Span * parent; | ||
public: | ||
virtual SpanOptions* makeSpanOptions() = 0; |
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.
why do implementations need to create their own versions of SpanOptions
? I would have expected it to be a glorified struct, implemented directly in the opentracing lib.
virtual int getBaggage(const StringRef& key, | ||
std::vector<std::string>* baggage) const = 0; | ||
|
||
virtual int externalize(std::vector<TextMapPair> *) = 0; |
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.
as discussed here and there, this has intentionally been left out of the OT spec... happy to discuss again if you want :)
template <typename T> | ||
int tag(const StringRef& key, const T& val); | ||
|
||
virtual int log(const StringRef& key, int16_t) = 0; |
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.
re the various log
methods... maybe we could do something like the zero-allocation approach in opentracing-go
? in any case, it's important for log
to support multiple key:value fields per log call.
Hi @jquinn47, wondering if I can close this PR. Please feel free to open a new issue when it's time for another take at a C++98 API. |
sure, We can close this I think
…On Mon, Sep 4, 2017 at 3:53 PM Ted Young ***@***.***> wrote:
Hi @jquinn47 <https://github.com/jquinn47>, wondering if I can close this
PR. Please feel free to open a new issue when it's time for another take at
a C++98 API.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#7 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAwLbyuiEVMSGgMLyk43Zs3xfHzSu7c7ks5sfFVAgaJpZM4LtEXT>
.
|
Picking up from #6 and based off our google hang out chat, it sounded like we wanted to experiment with a virtual inheritance model:
The only problem @SaintDubious and I saw with this approach originally was that having the
Tracer
be responsible for being the glue betweenSpan
/Contexts
andCarriers
had some unfavorable physical side effects when it came to library organization.Now @jmacd's idea is a good one: we should be able to shift this burden into the carriers themselves, avoiding adding all library organization problems introduced by the previous implementations layout.
This PR is a rough draft outline of what that might look like. The pain point at the moment is carrier code. Say we have
RedTracer
andRedContext
. Application code wouldn't look surprising:Injects could be specialized on the implementation type:
Extracts are a bit more confusing. If a carrier needs to support multiple tracer implementations, it would have to do some extra checks to make sure the type it received over the wire is the same type as its being asked to extract into.
There is a very ambiguous contract how Readers/Writers interact here and the upgrade path gets messy. If we add a
BlueContext
, all applications need to be upgraded to understand both, then over time, decommissioningRedContext
. For that to work, all the carrier messages need to be able toinject
a single context multiple times, in different formats, and extracts need to be on the look out for the same. All of this is doable, but gross.As we discussed in the hangout, this is a well known upgrade/migration technique. I don't see anything too crazy about it. The only downside is that every carrier implementation has to get it right now, instead of a single tracer library.
As one final footnote, @SaintDubious and I were discussing how Bloomberg would do this. We would likely define a single BloombergSpanContext type, and have all of our carriers perform a
static_cast<BloombergSpanContext*>
. I do not think we'd take advantage of the carrier fallback feature set, but using CRTP when we have a simple alternative that benefits other organizations seems like overkill.