opentelemetry-python-contrib/reference/ddtrace/contrib/molten/wrappers.py

96 lines
3.1 KiB
Python

from ddtrace.vendor import wrapt
import molten
from ... import Pin
from ...utils.importlib import func_name
MOLTEN_ROUTE = 'molten.route'
def trace_wrapped(resource, wrapped, *args, **kwargs):
pin = Pin.get_from(molten)
if not pin or not pin.enabled():
return wrapped(*args, **kwargs)
with pin.tracer.trace(func_name(wrapped), service=pin.service, resource=resource):
return wrapped(*args, **kwargs)
def trace_func(resource):
"""Trace calls to function using provided resource name
"""
@wrapt.function_wrapper
def _trace_func(wrapped, instance, args, kwargs):
pin = Pin.get_from(molten)
if not pin or not pin.enabled():
return wrapped(*args, **kwargs)
with pin.tracer.trace(func_name(wrapped), service=pin.service, resource=resource):
return wrapped(*args, **kwargs)
return _trace_func
class WrapperComponent(wrapt.ObjectProxy):
""" Tracing of components """
def can_handle_parameter(self, *args, **kwargs):
func = self.__wrapped__.can_handle_parameter
cname = func_name(self.__wrapped__)
resource = '{}.{}'.format(cname, func.__name__)
return trace_wrapped(resource, func, *args, **kwargs)
# TODO[tahir]: the signature of a wrapped resolve method causes DIError to
# be thrown since paramter types cannot be determined
class WrapperRenderer(wrapt.ObjectProxy):
""" Tracing of renderers """
def render(self, *args, **kwargs):
func = self.__wrapped__.render
cname = func_name(self.__wrapped__)
resource = '{}.{}'.format(cname, func.__name__)
return trace_wrapped(resource, func, *args, **kwargs)
class WrapperMiddleware(wrapt.ObjectProxy):
""" Tracing of callable functional-middleware """
def __call__(self, *args, **kwargs):
func = self.__wrapped__.__call__
resource = func_name(self.__wrapped__)
return trace_wrapped(resource, func, *args, **kwargs)
class WrapperRouter(wrapt.ObjectProxy):
""" Tracing of router on the way back from a matched route """
def match(self, *args, **kwargs):
# catch matched route and wrap tracer around its handler and set root span resource
func = self.__wrapped__.match
route_and_params = func(*args, **kwargs)
pin = Pin.get_from(molten)
if not pin or not pin.enabled():
return route_and_params
if route_and_params is not None:
route, params = route_and_params
route.handler = trace_func(func_name(route.handler))(route.handler)
# update root span resource while we know the matched route
resource = '{} {}'.format(
route.method,
route.template,
)
root_span = pin.tracer.current_root_span()
root_span.resource = resource
# if no root route set make sure we record it based on this resolved
# route
if root_span and not root_span.get_tag(MOLTEN_ROUTE):
root_span.set_tag(MOLTEN_ROUTE, route.name)
return route, params
return route_and_params