예제 #1
0
        def execute_with_instana(wrapped, instance, argv, kwargs):
            try:
                with tracer_stack_context():
                    ctx = None
                    if hasattr(instance.request.headers, '__dict__') and '_dict' in instance.request.headers.__dict__:
                        ctx = tornado_tracer.extract(opentracing.Format.HTTP_HEADERS, instance.request.headers.__dict__['_dict'])
                    scope = tornado_tracer.start_active_span('tornado-server', child_of=ctx)

                    # Query param scrubbing
                    if instance.request.query is not None and len(instance.request.query) > 0:
                        cleaned_qp = strip_secrets_from_query(instance.request.query, agent.options.secrets_matcher, agent.options.secrets_list)
                        scope.span.set_tag("http.params", cleaned_qp)

                    url = "%s://%s%s" % (instance.request.protocol, instance.request.host, instance.request.path)
                    scope.span.set_tag("http.url", url)
                    scope.span.set_tag("http.method", instance.request.method)

                    scope.span.set_tag("handler", instance.__class__.__name__)

                    # Custom header tracking support
                    if agent.options.extra_http_headers is not None:
                        for custom_header in agent.options.extra_http_headers:
                            if custom_header in instance.request.headers:
                                scope.span.set_tag("http.header.%s" % custom_header, instance.request.headers[custom_header])

                    setattr(instance.request, "_instana", scope)

                    # Set the context response headers now because tornado doesn't give us a better option to do so
                    # later for this request.
                    tornado_tracer.inject(scope.span.context, opentracing.Format.HTTP_HEADERS, instance._headers)
                    instance.set_header(name='Server-Timing', value="intid;desc=%s" % scope.span.context.trace_id)

                    return wrapped(*argv, **kwargs)
            except Exception:
                logger.debug("tornado execute", exc_info=True)
예제 #2
0
    def test_start_span_cb(self):
        def test_cb(span, request):
            span.operation_name = 'foo/' + request.method
            span.set_tag('component', 'tornado-client')

        tornado_opentracing.init_client_tracing(self.tracer,
                                                start_span_cb=test_cb)

        with tracer_stack_context():
            self.http_client.fetch(self.get_url('/'), self.stop)

        response = self.wait()
        self.assertEqual(response.code, 200)

        spans = self.tracer.finished_spans()
        self.assertEqual(len(spans), 1)
        self.assertTrue(spans[0].finished)
        self.assertEqual(spans[0].operation_name, 'foo/GET')
        self.assertEqual(
            spans[0].tags, {
                'component': 'tornado-client',
                'span.kind': 'client',
                'http.url': self.get_url('/'),
                'http.method': 'GET',
                'http.status_code': 200,
            })
예제 #3
0
    def test_good_solution_to_set_parent(self):
        """Solution is good because, though the RequestHandler being shared,
        the context will be properly detected."""

        with tracer_stack_context():
            with self.tracer.start_active_span('parent'):
                req_handler = RequestHandler(self.tracer,
                                             ignore_active_span=False)
                client = Client(req_handler, self.loop)
                response = client.send_sync('correct_parent')

                self.assertEquals('correct_parent::response', response)

        # Should NOT be a child of the previously activated Span
        response = client.send_sync('wrong_parent')
        self.assertEquals('wrong_parent::response', response)

        spans = self.tracer.finished_spans()
        self.assertEquals(len(spans), 3)

        spans = sorted(spans, key=lambda x: x.start_time)
        parent_span = get_one_by_operation_name(spans, 'parent')
        self.assertIsNotNone(parent_span)

        self.assertIsChildOf(spans[1], parent_span)
        self.assertIsNotChildOf(spans[2], parent_span)  # Proper parent (none).
예제 #4
0
        def wrapper(wrapped, instance, args, kwargs):
            if self._trace_all:
                return wrapped(*args, **kwargs)

            handler = instance

            with tracer_stack_context():
                try:
                    self._apply_tracing(handler, list(attributes))

                    # Run the actual function.
                    result = wrapped(*args, **kwargs)

                    # if it has `add_done_callback` it's a Future,
                    # else, a normal method/function.
                    if callable(getattr(result, 'add_done_callback', None)):
                        callback = functools.partial(
                            self._finish_tracing_callback, handler=handler)
                        result.add_done_callback(callback)
                    else:
                        self._finish_tracing(handler)

                except Exception as exc:
                    self._finish_tracing(handler, error=exc)
                    raise

            return result
예제 #5
0
    def test_main(self):
        parent_task = functools.partial(self.parent_task, 'message')
        with tracer_stack_context():
            res = self.loop.run_sync(parent_task)
        self.assertEqual(res, 'message::response')

        spans = self.tracer.finished_spans()
        self.assertEqual(len(spans), 2)
        self.assertNamesEqual(spans, ['child', 'parent'])
        self.assertIsChildOf(spans[0], spans[1])
예제 #6
0
def span_in_stack_context(span):
    """
    Create Tornado's (4.x, 5.x) StackContext that stores the given span in the
    thread-local request context. This function is intended for use
    in Tornado applications based on IOLoop, although will work fine
    in single-threaded apps like Flask, albeit with more overhead.

    StackContext has been deprecated in Tornado 6 and higher.
    Because of asyncio nature of Tornado 6.x, consider using
    `span_in_context` with opentracing scope manager `ContextVarScopeManager`

    ## Usage example in Tornado application

    Suppose you have a method `handle_request(request)` in the http server.
    Instead of calling it directly, use a wrapper:

    .. code-block:: python

        from opentracing_instrumentation import request_context

        @tornado.gen.coroutine
        def handle_request_wrapper(request, actual_handler, *args, **kwargs)

            request_wrapper = TornadoRequestWrapper(request=request)
            span = http_server.before_request(request=request_wrapper)

            with request_context.span_in_stack_context(span):
                return actual_handler(*args, **kwargs)

    :param span:
    :return:
        Return StackContext that wraps the request context.
    """
    if not _tornado_supported:
        raise RuntimeError('span_in_stack_context requires Tornado')

    if not is_stack_context_supported():
        raise RuntimeError('tornado.stack_context is not supported in '
                           'Tornado >= 6.x')
    if not isinstance(opentracing.tracer.scope_manager, TornadoScopeManager):
        raise RuntimeError('scope_manager is not TornadoScopeManager')

    # Enter the newly created stack context so we have
    # storage available for Span activation.
    context = tracer_stack_context()
    entered_context = _TracerEnteredStackContext(context)

    if span is None:
        return entered_context

    opentracing.tracer.scope_manager.activate(span, False)
    assert opentracing.tracer.active_span is not None
    assert opentracing.tracer.active_span is span

    return entered_context
예제 #7
0
def execute(func, handler, args, kwargs):
    """
    Wrap the handler ``_execute`` method to trace incoming requests,
    extracting the context from the headers, if available.
    """
    tracing = handler.settings.get('opentracing_tracing')

    with tracer_stack_context():
        if tracing._trace_all:
            attrs = handler.settings.get('opentracing_traced_attributes', [])
            tracing._apply_tracing(handler, attrs)

        return func(*args, **kwargs)
예제 #8
0
    def test(self):
        client = Client(self.tracer, self.queue)
        with tracer_stack_context():
            self.loop.add_callback(self.server.run)
            self.loop.add_callback(client.send)

        stop_loop_when(self.loop,
                       lambda: len(self.tracer.finished_spans()) >= 2)
        self.loop.start()

        spans = self.tracer.finished_spans()
        self.assertIsNotNone(
            get_one_by_tag(spans, tags.SPAN_KIND, tags.SPAN_KIND_RPC_SERVER))
        self.assertIsNotNone(
            get_one_by_tag(spans, tags.SPAN_KIND, tags.SPAN_KIND_RPC_CLIENT))
예제 #9
0
    def test_start_span_cb_exception(self):
        def test_cb(span, request):
            raise RuntimeError('This should not happen')

        tornado_opentracing.init_client_tracing(self.tracer,
                                                start_span_cb=test_cb)

        with tracer_stack_context():
            self.http_client.fetch(self.get_url('/'), self.stop)

        response = self.wait()
        self.assertEqual(response.code, 200)

        spans = self.tracer.finished_spans()
        self.assertEqual(len(spans), 1)
        self.assertFalse(spans[0].tags.get('error', False))
예제 #10
0
    def test_main(self):
        # Start a Span and let the callback-chain
        # finish it when the task is done
        with tracer_stack_context():
            with self.tracer.start_active_span('one', finish_on_close=False):
                self.submit()

        stop_loop_when(self.loop,
                       lambda: len(self.tracer.finished_spans()) == 1)
        self.loop.start()

        spans = self.tracer.finished_spans()
        self.assertEqual(len(spans), 1)
        self.assertEqual(spans[0].operation_name, 'one')

        for i in range(1, 4):
            self.assertEqual(spans[0].tags.get('key%s' % i, None), str(i))
예제 #11
0
    def test_server_not_found(self):
        tornado_opentracing.init_client_tracing(self.tracer)

        with tracer_stack_context():
            self.http_client.fetch(self.get_url('/doesnotexist'), self.stop)

        response = self.wait()
        self.assertEqual(response.code, 404)

        spans = self.tracer.finished_spans()
        self.assertEqual(len(spans), 1)
        self.assertEqual(spans[0].operation_name, 'GET')

        tags = spans[0].tags
        self.assertEqual(tags.get('http.status_code', None), 404)
        self.assertEqual(tags.get('error', None), None)  # no error.

        self.assertEqual(len(spans[0].logs), 0)
예제 #12
0
    def test_simple(self):
        with tracer_stack_context():
            self.http_client.fetch(self.get_url('/'), self.stop)

        response = self.wait()
        self.assertEqual(response.code, 200)

        spans = self.tracer.finished_spans()
        self.assertEqual(len(spans), 1)
        self.assertTrue(spans[0].finished)
        self.assertEqual(spans[0].operation_name, 'GET')
        self.assertEqual(
            spans[0].tags, {
                'component': 'tornado',
                'span.kind': 'client',
                'http.url': self.get_url('/'),
                'http.method': 'GET',
                'http.status_code': 200,
            })
예제 #13
0
    def test_simple(self):
        tornado_opentracing.init_client_tracing(tracing)

        with tracer_stack_context():
            self.http_client.fetch(self.get_url('/decorated'), self.stop)

        response = self.wait()
        self.assertEqual(response.code, 200)

        spans = tracing.tracer.finished_spans()
        self.assertEqual(len(spans), 2)

        # Client
        span = spans[1]
        self.assertTrue(span.finished)
        self.assertEqual(span.operation_name, 'GET')
        self.assertEqual(
            span.tags, {
                'component': 'tornado',
                'span.kind': 'client',
                'http.url': self.get_url('/decorated'),
                'http.method': 'GET',
                'http.status_code': 200,
            })

        # Server
        span2 = spans[0]
        self.assertTrue(span2.finished)
        self.assertEqual(span2.operation_name, 'DecoratedHandler')
        self.assertEqual(
            span2.tags, {
                'component': 'tornado',
                'span.kind': 'server',
                'http.url': '/decorated',
                'http.method': 'GET',
                'http.status_code': 200,
                'protocol': 'http',
            })

        # Make sure the context was propagated,
        # and the client/server have the proper child_of relationship.
        self.assertEqual(span.context.trace_id, span2.context.trace_id)
        self.assertEqual(span.context.span_id, span2.parent_id)
예제 #14
0
    def test_parent_not_picked(self):
        """Active parent should not be picked up by child
        as we pass ignore_active_span=True to the RequestHandler"""

        with tracer_stack_context():
            with self.tracer.start_active_span('parent'):
                response = self.client.send_sync('no_parent')
                self.assertEquals('no_parent::response', response)

        spans = self.tracer.finished_spans()
        self.assertEquals(len(spans), 2)

        child_span = get_one_by_operation_name(spans, 'send')
        self.assertIsNotNone(child_span)

        parent_span = get_one_by_operation_name(spans, 'parent')
        self.assertIsNotNone(parent_span)

        # Here check that there is no parent-child relation.
        self.assertIsNotChildOf(child_span, parent_span)
예제 #15
0
    def test_main(self):
        @gen.coroutine
        def main_task():
            with self.tracer.start_active_span('parent'):
                tasks = self.submit_callbacks()
                yield tasks

        with tracer_stack_context():
            self.loop.add_callback(main_task)

        stop_loop_when(self.loop,
                       lambda: len(self.tracer.finished_spans()) == 4)
        self.loop.start()

        spans = self.tracer.finished_spans()
        self.assertEquals(len(spans), 4)
        self.assertNamesEqual(spans, ['task', 'task', 'task', 'parent'])

        for i in range(3):
            self.assertSameTrace(spans[i], spans[-1])
            self.assertIsChildOf(spans[i], spans[-1])
예제 #16
0
    def test_main(self):
        # Create a Span and use it as (explicit) parent of a pair of subtasks.
        with tracer_stack_context():
            parent_span = self.tracer.start_span('parent')
            self.submit_subtasks(parent_span)

        stop_loop_when(self.loop,
                       lambda: len(self.tracer.finished_spans()) >= 2)
        self.loop.start()

        # Late-finish the parent Span now.
        parent_span.finish()

        spans = self.tracer.finished_spans()
        self.assertEqual(len(spans), 3)
        self.assertNamesEqual(spans, ['task1', 'task2', 'parent'])

        for i in range(2):
            self.assertSameTrace(spans[i], spans[-1])
            self.assertIsChildOf(spans[i], spans[-1])
            self.assertTrue(spans[i].finish_time <= spans[-1].finish_time)
예제 #17
0
    def test_main(self):
        # Start an isolated task and query for its result -and finish it-
        # in another task/thread
        span = self.tracer.start_span('initial')
        with tracer_stack_context():
            self.submit_another_task(span)

        stop_loop_when(self.loop,
                       lambda: len(self.tracer.finished_spans()) >= 3)
        self.loop.start()

        spans = self.tracer.finished_spans()
        self.assertEqual(len(spans), 3)
        self.assertNamesEqual(spans, ['initial', 'subtask', 'task'])

        # task/subtask are part of the same trace,
        # and subtask is a child of task
        self.assertSameTrace(spans[1], spans[2])
        self.assertIsChildOf(spans[1], spans[2])

        # initial task is not related in any way to those two tasks
        self.assertNotSameTrace(spans[0], spans[1])
        self.assertEqual(spans[0].parent_id, None)
예제 #18
0
    def test_server_error(self):
        tornado_opentracing.init_client_tracing(self.tracer)

        with tracer_stack_context():
            self.http_client.fetch(self.get_url('/error'), self.stop)

        response = self.wait()
        self.assertEqual(response.code, 500)

        spans = self.tracer.finished_spans()
        self.assertEqual(len(spans), 1)
        self.assertTrue(spans[0].finished)
        self.assertEqual(spans[0].operation_name, 'GET')

        tags = spans[0].tags
        self.assertEqual(tags.get('http.status_code', None), 500)
        self.assertEqual(tags.get('error', None), True)

        logs = spans[0].logs
        self.assertEqual(len(logs), 1)
        self.assertEqual(logs[0].key_values.get('event', None), 'error')
        self.assertTrue(
            isinstance(logs[0].key_values.get('error.object', None),
                       Exception))
예제 #19
0
    def test_explicit_parameters(self):
        tornado_opentracing.init_client_tracing(self.tracer)

        with tracer_stack_context():
            self.http_client.fetch(self.get_url('/error'),
                                   self.stop,
                                   raise_error=False,
                                   method='POST',
                                   body='')
        response = self.wait()
        self.assertEqual(response.code, 500)

        spans = self.tracer.finished_spans()
        self.assertEqual(len(spans), 1)
        self.assertTrue(spans[0].finished)
        self.assertEqual(spans[0].operation_name, 'POST')
        self.assertEqual(
            spans[0].tags, {
                'component': 'tornado',
                'span.kind': 'client',
                'http.url': self.get_url('/error'),
                'http.method': 'POST',
                'http.status_code': 500,
            })
예제 #20
0
파일: test_tornado.py 프로젝트: ziq211/hue
 def run_test(self, test_fn):
     with tracer_stack_context():
         ioloop.IOLoop.current().run_sync(test_fn)