Skip to content
This repository has been archived by the owner on May 23, 2023. It is now read-only.

In discrete steps, Simplify the API #7

Closed
wants to merge 6 commits into from

Conversation

michaelsembwever
Copy link
Contributor

This PR contains a sequence of commits to simplify the API.

Class renames:

  • TraceContext to SpanContext
  • TraceContextSource to TraceContext
  • TraceContextCodec to TraceCodec

Removing porcelain api:

  • Span.createChild(..)
  • TraceContext.ChildSpanContext
  • logging methods in Span (replaced with event(message, payload)).

Look in the individual commits for the rationale to each.

It's clearer to see the value of the changes by looking at the HEAD of the branch rather than evaluating the patch.

Rationale:
 The SpanContext holds context to a subtree in a Trace's tree of nodes.
 It is not created outside of a Trace and is not context to a Trace.
 SpanContext's attributes are
  - position of the subtree within the Trace's tree, specifically this is the parent Span's ID.
This ID is not exposed in the API, but is required state for functionality.
  - a set of tags that all Spans underneath it are created with
  - an ability to be serialised: providing support for distributed context propagation.
Rationale:
 After TraceContext was renamed to SpanContext, the more intuitive and accurate classname "TraceContext" was
available.
Rationale:
 TraceContext was renamed to SpanContext.
 While it might be appropriate to rename TraceContextCodec to SpanContextCodec, it's more more intuitive to
simply call it TraceCodec. After all, there is an expectation that all SpanContexts within a given trace are
encoded the same way.
 Rationale:
  This is only a convenience method.
  The real way of doing this is

     childContext = tracer.newChildContext(mySpan.traceContext);
     childSpan = tracer.newSpanWithContext(childContext);

  Adding it as a convenience method here complicates the serialisation of the Span.
  Needing a convenience method suggests the real way of doing it isn't intuitive enough, so let's
 try to address that first.
Rationale:
 None. Someone needs to explain to me the need to create from a SpanContext a child SpanContext without having a
Span inbetween.
…sage, payload)` method.

Rationale:
 This is the simplest solution, and an appropriate plumbing API, that solves the use-case of
info/error and parameterised message formatting.
 OpenTracing API may adopt a porcelain API for those info/error logging-style methods down the
road once the plumbing api has been battle tested a bit more.
Span error(String message, Object... args);
* @todo
**/
Span event(String message, Map<String,String> payload);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The api of payload is still unclear to me
ref: opentracing/opentracing.io#30 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack. before that comment, I'd guess @Nullable Object payload

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adriancole that's the idea... it is an arbitrary object that implementations can record in total, in part, or not at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see #9

@bhs
Copy link
Contributor

bhs commented Jan 22, 2016

@michaelsembwever thank you for sending this out. Per gitter, we are not on the same page.

It is apparent that either the goals of OpenTracing haven't been communicated well or you don't agree with them. :) Especially given the comments that have come up in this PR, what you propose here is not an API simplification: it removes entire swaths of semantic functionality. If that's intended, call a spade a spade. If it's not, imagine writing (or actually write if you have the time!) example calling code that

  • serializes a Span to and from the wire (c.f. your enthusiasm for removing the Codec),
  • sets a trace attribute in a client process and reads it in a server/peer process (c.f. your enthusiasm for removing the attribute getter),
  • creates a child Span from a parent Span when the Tracer is not accessible (c.f. your removal of Span.startChild),
  • and creates a child Span that has a parent_id tag (c.f. your removal of ChildSpanContext)

... all without peeking through to the OpenTracing implementation.

As for naming (less important given the scope of the problems above):

  • SpanContext is an ok (if unconventional w.r.t. existing systems) name in my eyes... no strong feelings on my part, though
  • what you now call TraceContext (formerly TraceContextSource) is not about a single trace, nor is it a context object, so that name confuses me
  • TraceCodec does not encode or decode traces, it encodes or decodes a slender set of ids that refer to a span and a trace... and for that reason seems like a naming regression as well.

@michaelsembwever
Copy link
Contributor Author

It is apparent that either the goals of OpenTracing haven't been communicated well …

Quite possibly. I am late to the game, but so will every subsequent person after me.
If there's documentation to which I obviously haven't read; do please reference them during the discussion.

My understanding of OpenTracing is

  • a specification that defines the constraints upon instrumentation libraries, and
  • an SPI that instrumentation libraries implement, and to which application code only needs to code against.

The second point implies that only the OpenTracing language-specific library is required as a compile-time dependency. Tracing platform specific instrumentation libraries become run-time dependencies.

This permits the application to

  • switch instrumentation libraries within the one tracing platform, and
  • switch instrumentation libraries over to a new tracing platform.¹

The OpenTracing SPI then, as I've understood it, only concerns itself with what is imposed upon the application code. And the simpler that SPI is the greener the field we create.

The OpenTracing Specification on the other hand will need to impose constraints upon the instrumentation libraries that the application code need not be concerned about.

( ¹ It's also possible to use an instrumentation library that delegates on to multiple other instrumentation libraries, useful for example when blue-green deploying tracing platforms. )

imagine writing … example calling code ... all without peeking through to the OpenTracing implementation.

There's a difference between "peeking through" the OpenTracing implementation, and using that OpenTracing SPI. The first list of bulleted examples cover things that instrumentation libraries need to do, not things the application code needs to do.

So there is the OpenTracing specification, the OpenTracing SPI, the tracing platform, and then the tracing instrumentation libraries to each platform.

So I would say: don't fall into the trap of thinking we must define all the OpenTracing Specification into the OpenTracing SPI. That is, the SPI isn't the universal documentation (nor a set of constraints) for the different instrumentation libraries to adhere to; that's the role of the Specification. In this manner of thinking, there will also be other constraints impose by the specific tracing platforms upon their instrumentation libraries that are not of concern to either OpenTracing's Specification or its SPI.

Going beyond this I can see that the OpenTracing API consists of three separate parts

  • the public SPI (that which the application codes against and what the instrumentation library must itself implement),
  • the public API (that which the application codes against and which the OpenTracing language-specific library can provide a final concrete implementation of),
  • the internal API (that which is invisible to the application code, but which the OpenTracing language-specific library provides for convenience to the instrumentation library implementation)

I hinted partially to this in #7 (comment)

I think the public API and the internal API are not important things to define in the first pass of things.

  • what you now call TraceContext (formerly TraceContextSource) is not about a single trace, nor is it a context object, so that name confuses me

We're on the same page here, and that discussion continues in this PR.

The other bulleted points in your comment I'll reply to in context to the code and the previous ongoing discussions.

* the current service.
* @return a new child Span in "started" state.
*/
Span startChild(String operationName);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From @bensigelman #7 (comment)

  • creates a child Span from a parent Span when the Tracer is not accessible (c.f. your removal of Span.startChild),

I do not understand how it is possible that a Tracer is not accessible, nor the point of creating a Span in any environment when no Tracer exists.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bensigelman None of the examples raised by @yurishkuro nor anything else i've seen demonstrates any need for the method span.startChild(..) when processing spans postmortem from a different system.

@bhs
Copy link
Contributor

bhs commented Jan 22, 2016

I'm torn between a point-by-point response to all of the various issues here and something higher-level. I'll go for the latter since it'll be less noisy for everyone involved...

I am thankful that you sent this out, as this review and some of the gitter traffic demonstrates (to me) that the current set of OpenTracing primitives apparently leads to mass confusion: surely a fault of the API/scheme, not the masses. :) Or maybe it's just missing documentation, but my instinct tells me that the problem is deeper than that.

I am going to try to send out a PR that basically gets rid of SpanContext as an API primitive... overall I think/hope it will make for an equally portable tracing API and less confusion for OpenTracing contributors present and future. In order to evaluate that I need to make sure I can adapt the (portable) OpenTracing client code I've already written with the revised/trimmed API... If I fail, then I'll come back and we can go through a lengthy micro-review (i.e., where this is headed at the moment).

Sound reasonable?
Ben

@yurishkuro
Copy link
Member

Thanks, Ben. In turn, I will post a PR with documentation of the Common Use Cases we've discussed when designing the API, with code examples of how each use case is solved by the current API.

@michaelsembwever
Copy link
Contributor Author

Sounds reasonable @bensigelman
Outside of just API there's a number understandings I raised in #7 (comment)
If any of these are wrong can you highlight them.

@michaelsembwever
Copy link
Contributor Author

@yurishkuro Can you push these as documentation into opentracing.github.io ?

This really would be invaluable information for newcomers.

@yurishkuro
Copy link
Member

@michaelsembwever already in PR opentracing/opentracing.io#34

@michaelsembwever
Copy link
Contributor Author

@yurishkuro thanks for the examples.

They all match my previous understandings of what we're trying to achieve. So far I haven't been able to find any reasons why the API simplifications offered in the file changes here can't or shouldn't be adopted. Although I'm interested in @bensigelman's proposed work to remove TraceContext/SpanContext altogether, and can rebase these simplifications on top of that if it's accepted.

The examples do add context to two separate discussions in this PR: the getter method in SpanContext and the codec class. I'll add my thoughts to these existing discussions.

@michaelsembwever
Copy link
Contributor Author

Summarising the status of the PR so far.

  • That TraceContext can be renamed to something better like SpanContext, and the renaming of Span.traceContext(), has been superseded by @bensigelman proposing to offer a patch that removes it altogether.
  • Removing the info/error methods in Span, has been agreed upon.
  • Removing Span.createChild(..) and ChildSpanContext remains a valid proposal, as there's no examples raised (yet) of where they are needed.
  • Renaming TraceContextSource to TraceContext. This depends on Ben's proposed patch to remove the TraceContext.
  • Rename TraceContextCodec to TraceCodec. There's confusion here because of the terms codec and serialisation. This can be spun off into a separate PR.

Actions to take.

  • Remove the "Rename TraceContextCodec to TraceCodec" commit from this PR. I will spawn a new PR suggesting alternative names, like SpanExtractor.
  • Wait for (agreement upon) Ben's patch to remove the TraceContext.
  • Evaluate naming of TraceContextSource (maybe Ben solves it).
  • change Span event(String message, Map<String,String> payload); to Span event(String message, @Nullable Object payload);

Other suggestions that have been raised in this PR.

  • Tracer.startTrace(..) and tracer.jointrace(..) would be simpler as one method.
  • Change the documentation on setAttribute(..) so the regular expression of keys is only a recommendation. This has been agreed upon.

Is this clear? Does everyone agree?

@bhs
Copy link
Contributor

bhs commented Jan 24, 2016

I sent out opentracing/opentracing-go#40 (for better or worse, !Java since I wanted to compile against a working example implementation and a working caller that propagates across HTTP)...

@michaelsembwever if people like the direction of my RFC above, we can get rid of a lot of stuff here. And also save a lot of time and energy arguing about names that would no longer exist :)

PS: @michaelsembwever sorry I didn't respond to all of the various minor points above where you @bensigelman'd me -- I thought it would be wasted effort for both of us since so much of the debated material is presently in jeopardy :)

@michaelsembwever
Copy link
Contributor Author

That's fine @bensigelman , i'll be happy to see the work here come to fruition any way possible.

As listed in my previous comment everything that this PR proposes is eventuating one way or another, plus more, and that makes me happy.

I'd only hoped that you got many more of these types of reviews opened before you started considering anything vaguely resembling a 1.0 release.

michaelsembwever added a commit that referenced this pull request Jan 31, 2016
Remove TraceContextSource, as methods from it now belong in Tracer.
Remove Tracer.joinTrace(..) as Span.startChild(..) already does this.
Simplify the SpanPropagator. Having to split responsibilities for span and trace identification versus trace
attributes is not something the end-user cares about.

ref:
 - opentracing/opentracing.io#42
 - #7
@michaelsembwever
Copy link
Contributor Author

Closing this PR, the first step in a simpler API it superseded with #8

michaelsembwever added a commit that referenced this pull request Feb 2, 2016
Remove TraceContextSource, as methods from it now belong in Tracer.
Remove Tracer.joinTrace(..) as Span.startChild(..) already does this.

ref:
 - opentracing/opentracing.io#42
 - #7
michaelsembwever added a commit to opentracing/opentracing.io that referenced this pull request Feb 2, 2016
 - simply initial api (just one way of doing things)
 - avoid Heisenberg tracing

References:
 - opentracing/opentracing-java#7 (comment)
 - #47
@bhs bhs deleted the mck/simplified-api-design-0 branch March 15, 2017 04:54
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants