mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-07-31 22:23:12 +08:00
106 lines
4.2 KiB
Python
106 lines
4.2 KiB
Python
from tornado.web import HTTPError
|
|
|
|
from .constants import CONFIG_KEY, REQUEST_CONTEXT_KEY, REQUEST_SPAN_KEY
|
|
from .stack_context import TracerStackContext
|
|
from ...constants import ANALYTICS_SAMPLE_RATE_KEY
|
|
from ...ext import SpanTypes, http
|
|
from ...propagation.http import HTTPPropagator
|
|
from ...settings import config
|
|
|
|
|
|
def execute(func, handler, args, kwargs):
|
|
"""
|
|
Wrap the handler execute method so that the entire request is within the same
|
|
``TracerStackContext``. This simplifies users code when the automatic ``Context``
|
|
retrieval is used via ``Tracer.trace()`` method.
|
|
"""
|
|
# retrieve tracing settings
|
|
settings = handler.settings[CONFIG_KEY]
|
|
tracer = settings['tracer']
|
|
service = settings['default_service']
|
|
distributed_tracing = settings['distributed_tracing']
|
|
|
|
with TracerStackContext():
|
|
# attach the context to the request
|
|
setattr(handler.request, REQUEST_CONTEXT_KEY, tracer.get_call_context())
|
|
|
|
# Read and use propagated context from HTTP headers
|
|
if distributed_tracing:
|
|
propagator = HTTPPropagator()
|
|
context = propagator.extract(handler.request.headers)
|
|
if context.trace_id:
|
|
tracer.context_provider.activate(context)
|
|
|
|
# store the request span in the request so that it can be used later
|
|
request_span = tracer.trace(
|
|
'tornado.request',
|
|
service=service,
|
|
span_type=SpanTypes.WEB
|
|
)
|
|
# set analytics sample rate
|
|
# DEV: tornado is special case maintains separate configuration from config api
|
|
analytics_enabled = settings['analytics_enabled']
|
|
if (config.analytics_enabled and analytics_enabled is not False) or analytics_enabled is True:
|
|
request_span.set_tag(
|
|
ANALYTICS_SAMPLE_RATE_KEY,
|
|
settings.get('analytics_sample_rate', True)
|
|
)
|
|
|
|
setattr(handler.request, REQUEST_SPAN_KEY, request_span)
|
|
|
|
return func(*args, **kwargs)
|
|
|
|
|
|
def on_finish(func, handler, args, kwargs):
|
|
"""
|
|
Wrap the ``RequestHandler.on_finish`` method. This is the last executed method
|
|
after the response has been sent, and it's used to retrieve and close the
|
|
current request span (if available).
|
|
"""
|
|
request = handler.request
|
|
request_span = getattr(request, REQUEST_SPAN_KEY, None)
|
|
if request_span:
|
|
# use the class name as a resource; if an handler is not available, the
|
|
# default handler class will be used so we don't pollute the resource
|
|
# space here
|
|
klass = handler.__class__
|
|
request_span.resource = '{}.{}'.format(klass.__module__, klass.__name__)
|
|
request_span.set_tag('http.method', request.method)
|
|
request_span.set_tag('http.status_code', handler.get_status())
|
|
request_span.set_tag(http.URL, request.full_url().rsplit('?', 1)[0])
|
|
if config.tornado.trace_query_string:
|
|
request_span.set_tag(http.QUERY_STRING, request.query)
|
|
request_span.finish()
|
|
|
|
return func(*args, **kwargs)
|
|
|
|
|
|
def log_exception(func, handler, args, kwargs):
|
|
"""
|
|
Wrap the ``RequestHandler.log_exception``. This method is called when an
|
|
Exception is not handled in the user code. In this case, we save the exception
|
|
in the current active span. If the Tornado ``Finish`` exception is raised, this wrapper
|
|
will not be called because ``Finish`` is not an exception.
|
|
"""
|
|
# safe-guard: expected arguments -> log_exception(self, typ, value, tb)
|
|
value = args[1] if len(args) == 3 else None
|
|
if not value:
|
|
return func(*args, **kwargs)
|
|
|
|
# retrieve the current span
|
|
tracer = handler.settings[CONFIG_KEY]['tracer']
|
|
current_span = tracer.current_span()
|
|
|
|
if isinstance(value, HTTPError):
|
|
# Tornado uses HTTPError exceptions to stop and return a status code that
|
|
# is not a 2xx. In this case we want to check the status code to be sure that
|
|
# only 5xx are traced as errors, while any other HTTPError exception is handled as
|
|
# usual.
|
|
if 500 <= value.status_code <= 599:
|
|
current_span.set_exc_info(*args)
|
|
else:
|
|
# any other uncaught exception should be reported as error
|
|
current_span.set_exc_info(*args)
|
|
|
|
return func(*args, **kwargs)
|