Skip to content
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

Add a page illustrating common instrumentation use cases #34

Merged
merged 4 commits into from
Jan 23, 2016

Conversation

yurishkuro
Copy link
Member

No description provided.


1. Attempt to deserialize Trace Context from the incoming request, in case the trace has already been started by the client.
1. Depending on the outcome, either start a new trace, or join the existing trace using deserialized Trace Context. This operation starts a new Span.
1. Store the newly created span in some _request context_ that is propagated throughout the application, either by application code, or by the RPC framework.
Copy link
Contributor

Choose a reason for hiding this comment

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

Might be worth adding "4. Finally, close the trace using span.finish() when the server has finished processing the request"

Copy link
Member Author

Choose a reason for hiding this comment

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

@dankosaur good catch, updated.

)
```

Here we set both arguments of the decoding method to the `headers` map. The Tracer object will have the knowledge which headers it needs to read in order to reconstruct Trace Context, which is comprised of a trace context ID and trace attributes.
Copy link
Contributor

Choose a reason for hiding this comment

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

I was reminded that with custom attributes we have the potential for naming collision with common HTTP headers -- do you think this is worth adding a note about in spec.md?

Copy link
Member Author

Choose a reason for hiding this comment

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

the way it's been implemented in a few places so far is that the custom attributes are prefixed by some string specific to the tracer. For example, our internal tracer serializes id into Uber-Trace-Id and attributes into UberCtx-***.

But it's definitely worth making explicit somewhere. I would prefer it to be in the docstring of the actual interface classes that people will implement, rather than in semantic documentation.

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: "The Tracer object will have the knowledge which headers it needs to read ..." -> "The Tracer object knows which headers it needs to read ..."

Copy link
Contributor

Choose a reason for hiding this comment

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

micronit / common English bug: when people write "is comprised of", they almost always mean "comprises". So, "... Trace Context, which comprises a trace context ID and trace attributes."

http://public.wsu.edu/~brians/errors/comprised.html

Copy link
Member Author

Choose a reason for hiding this comment

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

❤️ the reference :-)

@dkuebric
Copy link
Contributor

This is very clear and helpful @yurishkuro


### Logging Events

We have already used `log_event_with_payload` in the client span use case. Events can be logged without a payload, and not just where the span is being created / finished. For example, the application may record a cache miss event in the middle of execution, as long as it can get access to the current span from request context:
Copy link
Contributor

Choose a reason for hiding this comment

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

add ~ "These events also have a timestamp associated with them, which distinguishes them from a tag applying to the entire span." ?

Copy link
Member Author

Choose a reason for hiding this comment

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

done, and I also added a whole use case (unsupported atm) about recording externally captured timestamps.

Copy link
Contributor

Choose a reason for hiding this comment

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

where's the example of recording externally captured timestamps?

@@ -0,0 +1,89 @@
// https://github.com/ghiculescu/jekyll-table-of-contents
(function($){
Copy link
Contributor

Choose a reason for hiding this comment

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

why doesn't this use opentracing-javascript?! :)

@bhs
Copy link
Contributor

bhs commented Jan 23, 2016

I decided midstream that nitpicking at a minute level was probably annoying and certainly not a good use of your time! So I will stop.

The only substantial request I'd have is that we include – probably at the top – a totally utterly vanilla span that just starts with an operation name and stops within the same function scope. And maybe a second example where we create a child span in-process, also totally vanilla.

@yurishkuro
Copy link
Member Author

I don't mind nit-picking, but it will probably be less work for you, after I merge this, to do another commit by simply changing the wording.

I will add a vanilla span example, but I didn't what were the two things you mentioned, how are they different?

Vanilla example:

    def my_function():
        span = get_current_span().start_child('my-function') if get_current_span() else None
        try:
            . . . # business logic
        finally:
            if span:
                span.finish()

@bhs
Copy link
Contributor

bhs commented Jan 23, 2016

I guess I was imagining – just for the sake of starting simple – something like

def my_top_level_function():
    trivial_span = tracer.start_trace("top-level-function")
    try:
        . . .
    finally:
        trivial_span.finish()

Then of course things can get more complex from there.

@yurishkuro
Copy link
Member Author

@bensigelman comments addressed

@bhs
Copy link
Contributor

bhs commented Jan 23, 2016

great, LGTM, thanks! And agreed, if anyone cares I can take a pass at make my Composition professor happy with some silly line-edits as a separate PR. (Or not :)

yurishkuro added a commit that referenced this pull request Jan 23, 2016
Add a page illustrating common instrumentation use cases
@yurishkuro yurishkuro merged commit 0827d9c into master Jan 23, 2016
if parent_span is None:
span = tracer.start_trace(operation_name=operation)
else:
span = parent_span.start_child(operation_name=operation)
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe the API can do this as a one-liner.
The parent_span also has a SpanContext, using that we can use a simplified method along the lines of

Span Tracer.startTrace(String operation, @Nullable SpanContext cxt);

This also co-incidentally removes the need for span.start_child(..) which i've already advocated for.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1

Copy link

Choose a reason for hiding this comment

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

Also +1 to combining start_trace and start_child

span.set_tag('http.url', request.full_url)
```

The `operation` above refers to the name the server wants to give to the Span. For example, if the HTTP request was a POST against `/save_user/123`, the operation name can be set to `post:/save_user/`. OpenTracing API does not dictate how application calls the spans.
Copy link
Contributor

Choose a reason for hiding this comment

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

good note.

span = tracer.start_trace(operation_name=operation)
else:
span = parent_span.start_child(operation_name=operation)
span.set_tag('server.http.url', request.full_url)
Copy link
Contributor

Choose a reason for hiding this comment

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

ugh.. s/server.http.url/http.url/ please I understand why you are saying this, but ex in zipkin if there's actually an clash, it is tagged with an endpoint which compensates. On single-endpoint spans, this won't clash. This is likely to be read by people and I'd hate to make them stop and think about this part too much, or worse use it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants