def call_wrapper(service, parent, *args, **kwargs): """Wraps ServiceAction.__call__""" service_name = parent.meta.service_name operation_name = 'boto3:{}:{}'.format( service_name, xform_name(service._action_model.request.operation)) span = utils.start_child_span(operation_name=operation_name, parent=get_current_span()) span.set_tag(tags.SPAN_KIND, tags.SPAN_KIND_RPC_CLIENT) span.set_tag(tags.COMPONENT, 'boto3') span.set_tag('boto3.service_name', service_name) with span: try: response = _service_action_call(service, parent, *args, **kwargs) except ClientError as error: self.set_request_id_tag(span, error.response) raise else: if isinstance(response, dict): self.set_request_id_tag(span, response) return response
def produce_wrapper(producer, value, key=None, **kwargs): """Wraps Producer._produce""" parent_ctx = get_current_span() if parent_ctx: span = start_child_span( operation_name='kafka:produce', parent=parent_ctx, ) span.set_tag(tags.MESSAGE_BUS_DESTINATION, producer.get_topic_name()) if key is not None: span.set_tag('key', str(key)) headers = kwargs.pop('headers', {}) try: opentracing.tracer.inject(span_context=span.context, format=Format.TEXT_MAP, carrier=headers) except opentracing.UnsupportedFormatException: pass with span: try: _Producer_produce(producer, value, key=key, headers=headers, **kwargs) except Exception as error: span.set_tag(tags.ERROR, True) span.log_kv({ 'event': tags.ERROR, 'error.object': error, }) raise else: _Producer_produce(producer, value, key=key, **kwargs)
def before_client_send(target, context, method, kwargs, operation): """ A hook to be executed before RPC request is sent from the client side. It returns a Span object that can be used as a context manager around the actual RPC call implementation, or in case of async callback, it needs its `finish()` method to be called explicitly. Also, loads the child span context to the service's context object. Expects context object to have span attribute. :param target: RPC target object :param context: context object :param method: RPM method name :param kwargs: RPM method kwargs :return: returns child tracing span encapsulating this request """ # try to extract parent span, using request_context's get_current_span # for api service or rpc_context_span_extractor for other services. req_context_span = get_current_span() rpc_span = rpc_context_span_extractor(context) parent_span = req_context_span or rpc_span log.debug( "req_context_span: {}, rpc_span: {} ... Parent span: {}".format( req_context_span, rpc_span, parent_span)) span = utils.start_child_span(operation_name=operation, parent=parent_span) # Set the needed tags for the span span.set_tag(ext_tags.SPAN_KIND, ext_tags.SPAN_KIND_RPC_CLIENT) span.set_tag('rpc_method', method) span.set_tag('kwargs', str(kwargs)) request_id = context.request_id if request_id: span.set_tag('request.id', request_id) try: carrier = {} opentracing.tracer.inject(span_context=span.context, format=Format.TEXT_MAP, carrier=carrier) log.debug( "context object to be used for injecting {}".format(context)) span_dict = dict() for key, value in six.iteritems(carrier): span_dict[key] = value context.span = span_dict except opentracing.UnsupportedFormatException: log.warn("Error injecting opentracing span to context") return span
def patched_run(*args, **kwargs): span = start_child_span( operation_name=operation, parent=parent_ctx, ) with span, span_in_context(span): try: return run(*args, **kwargs) except Exception as error: span.set_tag(tags.ERROR, True) span.log_kv({ 'event': tags.ERROR, 'error.object': error, }) raise
def before_request(cmd, name): """ A common method to record the memcache calls :param cmd: either 'get' or 'set' :param name: name of the key gettting or setting (Added as a tag) :return: the created span """ operation_name = 'memcache:%s' % (cmd) span = utils.start_child_span(operation_name=operation_name, parent=get_current_span()) span.set_tag(ext_tags.SPAN_KIND, ext_tags.SPAN_KIND_RPC_CLIENT) # TODO: What is the PEER_SERVICE ? span.set_tag(ext_tags.PEER_SERVICE, 'memcache') span.set_tag('memcache_key', name) return span
def group_join_wrapper(group, timeout=None, raise_error=False): parent_ctx = get_current_span() if parent_ctx: operation = 'gevent:{}:join'.format(group.__class__.__name__) tags_dict = { 'greenlets': self._get_greenlet_names(group.greenlets), 'timeout': timeout, 'raise_error': raise_error, } span = start_child_span( operation_name=operation, parent=parent_ctx, tags=tags_dict, ) with span: return _Group_join(group, timeout, raise_error) else: return _Group_join(group, timeout, raise_error)
def before_http_request(request, current_span_extractor): """ A hook to be executed before HTTP request is executed. It returns a Span object that can be used as a context manager around the actual HTTP call implementation, or in case of async callback, it needs its `finish()` method to be called explicitly. :param request: request must match API defined by AbstractRequestWrapper :param current_span_extractor: function that extracts current span from some context :return: returns child tracing span encapsulating this request """ span = utils.start_child_span(operation_name=request.operation, parent=current_span_extractor()) span.set_tag(tags.SPAN_KIND, tags.SPAN_KIND_RPC_CLIENT) span.set_tag(tags.HTTP_URL, request.full_url) service_name = request.service_name host, port = request.host_port if service_name: span.set_tag(tags.PEER_SERVICE, service_name) if host: span.set_tag(tags.PEER_HOST_IPV4, host) if port: span.set_tag(tags.PEER_PORT, port) # fire interceptors for interceptor in ClientInterceptors.get_interceptors(): interceptor.process(request=request, span=span) try: carrier = {} opentracing.tracer.inject(span_context=span.context, format=Format.HTTP_HEADERS, carrier=carrier) for key, value in six.iteritems(carrier): request.add_header(key, value) except opentracing.UnsupportedFormatException: pass return span
def joinall_wrapper(greenlets, timeout=None, raise_error=False, count=None): parent_ctx = get_current_span() if parent_ctx: operation = 'gevent:joinall' tags_dict = { 'greenlets': self._get_greenlet_names(greenlets), 'timeout': timeout, 'raise_error': raise_error, 'count': count, } span = start_child_span( operation_name=operation, parent=parent_ctx, tags=tags_dict, ) with span: return _joinall(greenlets, timeout, raise_error, count) else: return _joinall(greenlets, timeout, raise_error, count)
def decorator(*args, **kwargs): parent_span = get_current_span() if parent_span is None and require_active_trace: return func(*args, **kwargs) span = utils.start_child_span(operation_name=operation_name, parent=parent_span) if callable(on_start): on_start(span, *args, **kwargs) with span, span_in_context(span): try: return func(*args, **kwargs) except Exception as error: span.set_tag(tags.ERROR, True) span.log_kv({ 'event': tags.ERROR, 'error.object': error, }) raise
def decorator(*args, **kwargs): parent_span = get_current_span() if parent_span is None and require_active_trace: return func(*args, **kwargs) span = utils.start_child_span( operation_name=operation_name, parent=parent_span) if callable(on_start): on_start(span, *args, **kwargs) with span, span_in_context(span): try: return func(*args, **kwargs) except Exception as error: span.set_tag(tags.ERROR, True) span.log_kv({ 'event': tags.ERROR, 'error.object': error, }) raise
def before_http_request(request, current_span_extractor): """ A hook to be executed before HTTP request is executed. It returns a Span object that can be used as a context manager around the actual HTTP call implementation, or in case of async callback, it needs its `finish()` method to be called explicitly. :param request: request must match API defined by AbstractRequestWrapper :param current_span_extractor: function that extracts current span from some context :return: returns child tracing span encapsulating this request """ span = utils.start_child_span( operation_name=request.operation, parent=current_span_extractor() ) span.set_tag(tags.SPAN_KIND, tags.SPAN_KIND_RPC_CLIENT) span.set_tag(tags.HTTP_URL, request.full_url) service_name = request.service_name host, port = request.host_port if service_name: span.set_tag(tags.PEER_SERVICE, service_name) if host: span.set_tag(tags.PEER_HOST_IPV4, host) if port: span.set_tag(tags.PEER_PORT, port) try: carrier = {} opentracing.tracer.inject(span_context=span.context, format=Format.HTTP_HEADERS, carrier=carrier) for key, value in carrier.iteritems(): request.add_header(key, value) except opentracing.UnsupportedFormatException: pass return span
def perform_call(self, original_func, kind, service_name, operation_name, *args, **kwargs): span = utils.start_child_span(operation_name='boto3:{}:{}:{}'.format( kind, service_name, operation_name), parent=get_current_span()) span.set_tag(tags.SPAN_KIND, tags.SPAN_KIND_RPC_CLIENT) span.set_tag(tags.COMPONENT, 'boto3') span.set_tag('boto3.service_name', service_name) with span, span_in_stack_context(span): try: response = original_func(*args, **kwargs) except ClientError as error: self.set_request_id_tag(span, error.response) raise else: if isinstance(response, dict): self.set_request_id_tag(span, response) return response
def func_span(func, tags=None, require_active_trace=True): """ Creates a new local span for execution of the given `func`. The returned span is best used as a context manager, e.g. .. code-block:: python with func_span('my_function'): return my_function(...) At this time the func should be a string name. In the future this code can be enhanced to accept a real function and derive its qualified name. :param func: name of the function or method :param tags: optional tags to add to the child span :param require_active_trace: controls what to do when there is no active trace. If require_active_trace=True, then no span is created. If require_active_trace=False, a new trace is started. :return: new child span, or a dummy context manager if there is no active/current parent span """ current_span = get_current_span() if current_span is None and require_active_trace: @contextlib.contextmanager def empty_ctx_mgr(): yield None return empty_ctx_mgr() # TODO convert func to a proper name: module:class.func operation_name = str(func) span = utils.start_child_span(operation_name=operation_name, parent=current_span, tags=tags) with span_in_context(span): return span
def func_span(func, tags=None, require_active_trace=True): """ Creates a new local span for execution of the given `func`. The returned span is best used as a context manager, e.g. .. code-block:: python with func_span('my_function'): return my_function(...) At this time the func should be a string name. In the future this code can be enhanced to accept a real function and derive its qualified name. :param func: name of the function or method :param tags: optional tags to add to the child span :param require_active_trace: controls what to do when there is no active trace. If require_active_trace=True, then no span is created. If require_active_trace=False, a new trace is started. :return: new child span, or a dummy context manager if there is no active/current parent span """ current_span = get_current_span() if current_span is None and require_active_trace: @contextlib.contextmanager def empty_ctx_mgr(): yield None return empty_ctx_mgr() # TODO convert func to a proper name: module:class.func operation_name = str(func) span = utils.start_child_span( operation_name=operation_name, parent=current_span, tags=tags) with span_in_context(span): return span