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 working examples with Jaeger tracer. #12

Merged
merged 3 commits into from May 29, 2018
Merged

add working examples with Jaeger tracer. #12

merged 3 commits into from May 29, 2018

Conversation

ror6ax
Copy link
Contributor

@ror6ax ror6ax commented May 8, 2018

I've added examples that use Jaeger instead of Lightstep, introduce serialization to the wire, and are bare minimal for ease of understanding.

Before running both files you need to set JAEGER_HOST and WEBSERVER_HOST environment variables.

@bhs @yurishkuro - please let me know if the approach seems good for you. I'll be writing README after your thumbs up on general direction.

@ror6ax ror6ax requested review from bhs and yurishkuro May 8, 2018 13:24
ls_tracer = lightstep.tracer.init_tracer(group_name="example client", access_token="{your_lightstep_token}")
# this tracer does not trace all requests, so the @tracer.trace() decorator must be used
tracer = FlaskTracer(ls_tracer)
JAEGER_HOST = environ.get('JAEGER_HOST')

Choose a reason for hiding this comment

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

maybe default to local host?


config = Config(config={'sampler': {'type': 'const', 'param': 1},

Choose a reason for hiding this comment

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

this could use a comment explaining what's happening, i.e. "configuring and creating an instance of Jaeger Tracer with 100% sampling and debug logging of spans".

for i in range(numrequests):
send_request()
return "Requests sent"
install_all_patches()

Choose a reason for hiding this comment

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

could use a comment explaining what this does

span.set_tag(tags.HTTP_URL, url)
span.set_tag(tags.SPAN_KIND, tags.SPAN_KIND_RPC_CLIENT)
headers = {}
tracer.inject(span, Format.HTTP_HEADERS, headers)

Choose a reason for hiding this comment

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

sorry, why is this needed? Since you're calling install_all_patches() above, the requests module is automatically instrumented and will do the exact same thing.


time.sleep(2)

Choose a reason for hiding this comment

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

this may confuse people, I recommend adding a comment

# allow tracer to flush the spans - https://github.com/jaegertracing/jaeger-client-python/issues/50

'local_agent':
{'reporting_host': JAEGER_HOST}},
service_name="jaeger_opentracing_example")
ls_tracer = config.initialize_tracer()

Choose a reason for hiding this comment

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

rename to jaeger_tracer

@tracer.trace()
def log():

span_ctx = ls_tracer.extract(Format.HTTP_HEADERS, request.headers)

Choose a reason for hiding this comment

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

similar to client, the point of using @tracer.trace() is that the handlers are automatically instrumented, but you're doing it again manually

Copy link
Contributor

@bhs bhs left a comment

Choose a reason for hiding this comment

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

I'm approving this for the LightStep removals only (i.e., I'm not commenting on the Jaeger pieces). Glad to see this change!

One error of omission: you should scrub the LightStep bits from the README, too.

@ror6ax
Copy link
Contributor Author

ror6ax commented May 14, 2018

@bhs , @yurishkuro - this is ready for re-review. I've added new images, removed code duplication as per Yuri's comments and re-written parts README.

This is a server-client example and I'll be adding server-server one as a separate PR.

app, and the trace will include a span on both the client and server sides. This
occurs automatically since both the client and server functions are decorated
with @tracer.trace().
To see the traced requests, go to Jaeger web interface.

Choose a reason for hiding this comment

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

"and refresh the page"

![span with log](https://raw.githubusercontent.com/kcamenzind/flask_opentracing/master/example/img/log.png)
Browse to http://localhost:5000/log and compare the trace in Jaeger.
The last one has 2 spans instead of 3. The span of webserver's GET method is missing.
That is because in client.py we pass already existing span over the wire, whereas the request from your browser has to tracing data in it.

Choose a reason for hiding this comment

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

That is because client.py starts a trace and passes trace context over the wire, whereas the request from your browser has to tracing context in it.

span. This example demonstrates how you can trace non-RPC function calls in your
app, through accessing the current span as follows:
In log function of the server app, we are creating current_span. This is done to
trace the work that is being done to render the response to /log. Suppose there's

Choose a reason for hiding this comment

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

"response to /log endpoint"

trace the work that is being done to render the response to /log. Suppose there's
a database connection happening. By creating a separate span for it, you'll be able
to trace the DB request separately from rendering or the response. This gives a
lot of flexibility to the user.

Choose a reason for hiding this comment

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

maybe it's worth mentioning that install_patches will do that automatically for some frameworks like SqlAlchemy, Redis client, etc.

tracer = FlaskTracer(jaeger_tracer)

@app.route('/log')
# Indicate that /log endpoint should be traced

Choose a reason for hiding this comment

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

nit: this would read better on the same line as the decorator

# Extract the span information for request object.
request_span = tracer.get_span(request)
# Start internal span to trace some kind of business logic for /log.
current_span = jaeger_tracer.start_span("python webserver internal span of log method",

Choose a reason for hiding this comment

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

the preferred syntax here would be

with jaeger_tracer.start_span("inner-span", child_of=request_span) as span:
    # Perform some computations to be traced.
    span.log_kv({'event': 'my computer knows math!', 'result': c})

@ror6ax
Copy link
Contributor Author

ror6ax commented May 15, 2018

@yurishkuro Fixed per your comments.

-p 16686:16686 \
-p 14268:14268 \
-p 9411:9411 \
jaegertracing/all-in-one:latest

Choose a reason for hiding this comment

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

would it make sense to just use host networking? Most of these ports are not actually necessary for this example anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's the way Jaeger manual presents it. I don't want to confuse people who may not be into details of Docker. In any case, ports do not hurt anyone.
Agree?

### Add spans to the trace manually:
Speaking about databases, using install_all_patches() method from
opentracing_instrumentation package gives you a way to trace
your MySQLdb, SQLAlchemy, Redis queries with without writing boilerplate code.

Choose a reason for hiding this comment

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

typo: "with without"

def log():
request_span = tracer.get_span(request)
# Extract the span information for request object.
with jaeger_tracer.start_span("python webserver internal span of log method",

Choose a reason for hiding this comment

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

personally I would not use such span name even in the example, because it might make people think this is a good practice.

@ror6ax ror6ax merged commit 05a5c78 into master May 29, 2018
@ror6ax ror6ax changed the title WIP: add working examples with Jaeger tracer. add working examples with Jaeger tracer. May 29, 2018
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.

None yet

3 participants