class TestTornado(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(TornadoScopeManager()) self.loop = ioloop.IOLoop.current() def test_main(self): # Start a Span and let the callback-chain # finish it when the task is done with TracerStackContext(): with self.tracer.start_active_span('one', 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)) # Since TracerStackContext propagates the active Span # from the first callback, we don't need to re-activate # it later on anymore. @gen.coroutine def submit(self): span = self.tracer.scope_manager.active.span @gen.coroutine def task1(): self.assertEqual(span, self.tracer.scope_manager.active.span) span.set_tag('key1', '1') @gen.coroutine def task2(): self.assertEqual(span, self.tracer.scope_manager.active.span) span.set_tag('key2', '2') @gen.coroutine def task3(): self.assertEqual(span, self.tracer.scope_manager.active.span) span.set_tag('key3', '3') span.finish() yield task3() yield task2() yield task1()
class TestTornado(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(TornadoScopeManager()) self.loop = ioloop.IOLoop.current() def test_main(self): parent_task = functools.partial(self.parent_task, 'message') with TracerStackContext(): 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]) @gen.coroutine def parent_task(self, message): with self.tracer.start_active_span('parent', True): res = yield self.child_task(message) raise gen.Return(res) @gen.coroutine def child_task(self, message): # No need to pass/activate the parent Span, as # it stays in the context. with self.tracer.start_active_span('child', True): raise gen.Return('%s::response' % message)
class TestGevent(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(GeventScopeManager()) def test_main(self): # Create a Span and use it as (explicit) parent of a pair of subtasks. parent_span = self.tracer.start_span('parent') self.submit_subtasks(parent_span) gevent.wait(timeout=5.0) # 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) # Fire away a few subtasks, passing a parent Span whose lifetime # is not tied at all to the children. def submit_subtasks(self, parent_span): def task(name): with self.tracer.start_active_span(name, True, child_of=parent_span): gevent.sleep(0.1) gevent.spawn(task, 'task1') gevent.spawn(task, 'task2')
class TestThreads(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer() self.executor = ThreadPoolExecutor(max_workers=3) def test_main(self): res = self.executor.submit(self.parent_task, 'message').result() 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]) def parent_task(self, message): with self.tracer.start_active_span('parent', True) as scope: f = self.executor.submit(self.child_task, message, scope.span) res = f.result() return res def child_task(self, message, span): with self.tracer.scope_manager.activate(span, False): with self.tracer.start_active_span('child', True): return '%s::response' % message
class TestTornado(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(TornadoScopeManager()) self.loop = ioloop.IOLoop.current() def test_main(self): @gen.coroutine def main_task(): with self.tracer.start_active_span('parent', True): tasks = self.submit_callbacks() yield tasks with TracerStackContext(): 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]) @gen.coroutine def task(self, interval, parent_span): logger.info('Starting task') # NOTE: No need to reactivate the parent_span, as TracerStackContext # keeps track of it, BUT a limitation is that, yielding # upon multiple coroutines, we cannot mess with the context, # so no active span set here. with self.tracer.start_span('task'): yield gen.sleep(interval) def submit_callbacks(self): parent_span = self.tracer.scope_manager.active.span tasks = [] for i in range(3): interval = 0.1 + random.randint(200, 500) * 0.001 t = self.task(interval, parent_span) tasks.append(t) return tasks
class TestAsyncio(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(AsyncioScopeManager()) self.loop = asyncio.get_event_loop() def test_main(self): # Start a Span and let the callback-chain # finish it when the task is done async def task(): with self.tracer.start_active_span('one', False): self.submit() self.loop.create_task(task()) stop_loop_when(self.loop, lambda: len(self.tracer.finished_spans()) == 1) self.loop.run_forever() 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)) def submit(self): span = self.tracer.scope_manager.active.span async def task1(): with self.tracer.scope_manager.activate(span, False): span.set_tag('key1', '1') async def task2(): with self.tracer.scope_manager.activate(span, False): span.set_tag('key2', '2') async def task3(): with self.tracer.scope_manager.activate(span, False): span.set_tag('key3', '3') span.finish() self.loop.create_task(task3()) self.loop.create_task(task2()) self.loop.create_task(task1())
class TestThreads(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer() self.queue = queue.Queue() self.server = Server(tracer=self.tracer, queue=self.queue) self.server.start() def test(self): client = Client(self.tracer, self.queue) client.send() await_until(lambda: len(self.tracer.finished_spans()) >= 2) 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))
class TestTornado(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(TornadoScopeManager()) self.loop = ioloop.IOLoop.current() 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 TracerStackContext(): 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) @gen.coroutine def task(self, span): # Create a new Span for this task with self.tracer.start_active_span('task', True): with self.tracer.scope_manager.activate(span, True): # Simulate work strictly related to the initial Span pass # Use the task span as parent of a new subtask with self.tracer.start_active_span('subtask', True): pass def submit_another_task(self, span): self.loop.add_callback(self.task, span)
class TestThreads(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer() self.executor = ThreadPoolExecutor(max_workers=3) def test_main(self): # Start a Span and let the callback-chain # finish it when the task is done with self.tracer.start_active_span('one', False): self.submit() # Cannot shutdown the executor and wait for the callbacks # to be run, as in such case only the first will be executed, # and the rest will get canceled. await_until(lambda: len(self.tracer.finished_spans()) == 1, 5) 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)) def submit(self): span = self.tracer.scope_manager.active.span def task1(): with self.tracer.scope_manager.activate(span, False): span.set_tag('key1', '1') def task2(): with self.tracer.scope_manager.activate(span, False): span.set_tag('key2', '2') def task3(): with self.tracer.scope_manager.activate(span, True): span.set_tag('key3', '3') self.executor.submit(task3) self.executor.submit(task2) self.executor.submit(task1)
class TestAsyncio(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(AsyncioScopeManager()) self.loop = asyncio.get_event_loop() def test_main(self): # Need to run within a Task, as the scope manager depends # on Task.current_task() async def main_task(): with self.tracer.start_active_span('parent', True): tasks = self.submit_callbacks() await asyncio.gather(*tasks) self.loop.create_task(main_task()) stop_loop_when(self.loop, lambda: len(self.tracer.finished_spans()) >= 4) self.loop.run_forever() 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]) async def task(self, interval, parent_span): logger.info('Starting task') with self.tracer.scope_manager.activate(parent_span, False): with self.tracer.start_active_span('task', True): await asyncio.sleep(interval) def submit_callbacks(self): parent_span = self.tracer.scope_manager.active.span tasks = [] for i in range(3): interval = 0.1 + random.randint(200, 500) * 0.001 t = self.loop.create_task(self.task(interval, parent_span)) tasks.append(t) return tasks
class TestAsyncio(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(AsyncioScopeManager()) self.queue = asyncio.Queue() self.loop = asyncio.get_event_loop() self.server = Server(tracer=self.tracer, queue=self.queue) def test(self): client = Client(self.tracer, self.queue) self.loop.create_task(self.server.run()) self.loop.create_task(client.send()) stop_loop_when(self.loop, lambda: len(self.tracer.finished_spans()) >= 2) self.loop.run_forever() 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))
class TestTornado(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(TornadoScopeManager()) self.queue = queues.Queue() self.loop = ioloop.IOLoop.current() self.server = Server(tracer=self.tracer, queue=self.queue) def test(self): client = Client(self.tracer, self.queue) with TracerStackContext(): 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))
class TestTornado(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(TornadoScopeManager()) self.loop = ioloop.IOLoop.current() def test_main(self): # Create a Span and use it as (explicit) parent of a pair of subtasks. with TracerStackContext(): 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) # Fire away a few subtasks, passing a parent Span whose lifetime # is not tied at all to the children. def submit_subtasks(self, parent_span): @gen.coroutine def task(name): logger.info('Running %s' % name) with self.tracer.start_active_span(name, True, child_of=parent_span): gen.sleep(0.1) self.loop.add_callback(task, 'task1') self.loop.add_callback(task, 'task2')
class TestAsyncio(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(AsyncioScopeManager()) self.loop = asyncio.get_event_loop() def test_main(self): # Create a Span and use it as (explicit) parent of a pair of subtasks. 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.run_forever() # 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) # Fire away a few subtasks, passing a parent Span whose lifetime # is not tied at all to the children. def submit_subtasks(self, parent_span): async def task(name): logger.info('Running %s' % name) with self.tracer.start_active_span(name, True, child_of=parent_span): asyncio.sleep(0.1) self.loop.create_task(task('task1')) self.loop.create_task(task('task2'))
class TestThreads(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(GeventScopeManager()) def test_main(self): client = Client(self.tracer) res = client.send_sync('message') self.assertEquals(res, 'message::response') spans = self.tracer.finished_spans() self.assertEqual(len(spans), 1) span = get_one_by_tag(spans, tags.SPAN_KIND, tags.SPAN_KIND_RPC_CLIENT) self.assertIsNotNone(span)
class TestGevent(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(GeventScopeManager()) self.queue = gevent.queue.Queue() self.server = Server(tracer=self.tracer, queue=self.queue) def test(self): client = Client(self.tracer, self.queue) gevent.spawn(self.server.run) gevent.spawn(client.send) gevent.wait(timeout=5.0) 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))
class TestThreads(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer() self.executor = ThreadPoolExecutor(max_workers=3) def test_main(self): try: scope = self.tracer.start_active_span('parent', False) scope.span._ref_count = RefCount(1) self.submit_callbacks(scope.span) finally: scope.close() if scope.span._ref_count.decr() == 0: scope.span.finish() self.executor.shutdown(True) 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]) def task(self, interval, parent_span): logger.info('Starting task') try: scope = self.tracer.scope_manager.activate(parent_span, False) with self.tracer.start_active_span('task', True): time.sleep(interval) finally: scope.close() if parent_span._ref_count.decr() == 0: parent_span.finish() def submit_callbacks(self, parent_span): for i in range(3): parent_span._ref_count.incr() self.executor.submit(self.task, 0.1 + random.randint(200, 500) * .001, parent_span)
class TestThreads(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer() self.executor = ThreadPoolExecutor(max_workers=3) 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') self.submit_another_task(span) self.executor.shutdown(True) 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) def task(self, span): # Create a new Span for this task with self.tracer.start_active_span('task', True): with self.tracer.scope_manager.activate(span, True): # Simulate work strictly related to the initial Span pass # Use the task span as parent of a new subtask with self.tracer.start_active_span('subtask', True): pass def submit_another_task(self, span): self.executor.submit(self.task, span)
class TestGevent(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(GeventScopeManager()) def test_main(self): # Start a Span and let the callback-chain # finish it when the task is done with self.tracer.start_active_span('one', False): self.submit() gevent.wait() 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)) def submit(self): span = self.tracer.scope_manager.active.span def task1(): with self.tracer.scope_manager.activate(span, False): span.set_tag('key1', '1') def task2(): with self.tracer.scope_manager.activate(span, False): span.set_tag('key2', '2') def task3(): with self.tracer.scope_manager.activate( span, True): span.set_tag('key3', '3') gevent.spawn(task3) gevent.spawn(task2) gevent.spawn(task1)
class TestGevent(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(GeventScopeManager()) def test_main(self): res = gevent.spawn(self.parent_task, 'message').get() 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]) def parent_task(self, message): with self.tracer.start_active_span('parent', True) as scope: res = gevent.spawn(self.child_task, message, scope.span).get() return res def child_task(self, message, span): with self.tracer.scope_manager.activate(span, False): with self.tracer.start_active_span('child', True): return '%s::response' % message
class TestGevent(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(GeventScopeManager()) def test_main(self): def main_task(): with self.tracer.start_active_span('parent', True): tasks = self.submit_callbacks() gevent.joinall(tasks) gevent.spawn(main_task) gevent.wait(timeout=5.0) 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]) def task(self, interval, parent_span): logger.info('Starting task') with self.tracer.scope_manager.activate(parent_span, False): with self.tracer.start_active_span('task', True): gevent.sleep(interval) def submit_callbacks(self): parent_span = self.tracer.scope_manager.active.span tasks = [] for i in range(3): interval = 0.1 + random.randint(200, 500) * 0.001 t = gevent.spawn(self.task, interval, parent_span) tasks.append(t) return tasks
class TestThreads(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer() self.executor = ThreadPoolExecutor(max_workers=3) def test_main(self): # Create a Span and use it as (explicit) parent of a pair of subtasks. parent_span = self.tracer.start_span('parent') self.submit_subtasks(parent_span) # Wait for the threadpool to be done. self.executor.shutdown(True) # 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) # Fire away a few subtasks, passing a parent Span whose lifetime # is not tied at all to the children. def submit_subtasks(self, parent_span): def task(name): with self.tracer.start_active_span(name, True, child_of=parent_span): time.sleep(0.1) self.executor.submit(task, 'task1') self.executor.submit(task, 'task2')
class TestAsyncio(OpenTracingTestCase): def setUp(self): self.tracer = MockTracer(AsyncioScopeManager()) self.loop = asyncio.get_event_loop() def test_main(self): res = self.loop.run_until_complete(self.parent_task('message')) 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]) async def parent_task(self, message): with self.tracer.start_active_span('parent', True) as scope: res = await self.child_task(message, scope.span) return res async def child_task(self, message, span): with self.tracer.scope_manager.activate(span, False): with self.tracer.start_active_span('child', True): return '%s::response' % message
class TestGevent(OpenTracingTestCase): ''' There is only one instance of 'RequestHandler' per 'Client'. Methods of 'RequestHandler' are executed concurrently in different threads which are reused (common pool). Therefore we cannot use current active span and activate span. So one issue here is setting correct parent span. ''' def setUp(self): self.tracer = MockTracer(GeventScopeManager()) self.client = Client(RequestHandler(self.tracer)) def test_two_callbacks(self): response_greenlet1 = gevent.spawn(self.client.send_task, 'message1') response_greenlet2 = gevent.spawn(self.client.send_task, 'message2') gevent.joinall([response_greenlet1, response_greenlet2]) self.assertEquals('message1::response', response_greenlet1.get()) self.assertEquals('message2::response', response_greenlet2.get()) spans = self.tracer.finished_spans() self.assertEquals(len(spans), 2) for span in spans: self.assertEquals(span.tags.get(tags.SPAN_KIND, None), tags.SPAN_KIND_RPC_CLIENT) self.assertNotSameTrace(spans[0], spans[1]) self.assertIsNone(spans[0].parent_id) self.assertIsNone(spans[1].parent_id) def test_parent_not_picked(self): '''Active parent should not be picked up by child.''' with self.tracer.start_active_span('parent', True): 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) def test_bad_solution_to_set_parent(self): '''Solution is bad because parent is per client (we don't have better choice)''' with self.tracer.start_active_span('parent', True) as scope: client = Client(RequestHandler(self.tracer, scope.span.context)) response = client.send_sync('correct_parent') self.assertEquals('correct_parent::response', response) 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.assertIsChildOf(spans[2], parent_span)
class TestAsyncio(OpenTracingTestCase): ''' There is only one instance of 'RequestHandler' per 'Client'. Methods of 'RequestHandler' are executed concurrently in different threads which are reused (common pool). Therefore we cannot use current active span and activate span. So one issue here is setting correct parent span. ''' def setUp(self): self.tracer = MockTracer(AsyncioScopeManager()) self.loop = asyncio.get_event_loop() self.client = Client(RequestHandler(self.tracer), self.loop) def test_two_callbacks(self): res_future1 = self.loop.create_task(self.client.send('message1')) res_future2 = self.loop.create_task(self.client.send('message2')) stop_loop_when(self.loop, lambda: len(self.tracer.finished_spans()) >= 2) self.loop.run_forever() self.assertEquals('message1::response', res_future1.result()) self.assertEquals('message2::response', res_future2.result()) spans = self.tracer.finished_spans() self.assertEquals(len(spans), 2) for span in spans: self.assertEquals(span.tags.get(tags.SPAN_KIND, None), tags.SPAN_KIND_RPC_CLIENT) self.assertNotSameTrace(spans[0], spans[1]) self.assertIsNone(spans[0].parent_id) self.assertIsNone(spans[1].parent_id) def test_parent_not_picked(self): '''Active parent should not be picked up by child.''' async def do(): with self.tracer.start_active_span('parent', True): response = await self.client.send_task('no_parent') self.assertEquals('no_parent::response', response) self.loop.run_until_complete(do()) 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) def test_bad_solution_to_set_parent(self): '''Solution is bad because parent is per client (we don't have better choice)''' async def do(): with self.tracer.start_active_span('parent', True) as scope: client = Client( RequestHandler(self.tracer, scope.span.context), self.loop) response = await client.send_task('correct_parent') self.assertEquals('correct_parent::response', response) # Send second request, now there is no active parent, but it will be set, ups response = await client.send_task('wrong_parent') self.assertEquals('wrong_parent::response', response) self.loop.run_until_complete(do()) 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.assertIsChildOf(spans[2], parent_span)