def test_flush_from_multiple_threads(self): num_threads = 50 num_spans = 10 span_list = [] my_exporter = MySpanExporter(destination=span_list) span_processor = export.BatchExportSpanProcessor( my_exporter, max_queue_size=512, max_export_batch_size=128 ) def create_spans_and_flush(tno: int): for span_idx in range(num_spans): _create_start_and_end_span( "Span {}-{}".format(tno, span_idx), span_processor ) self.assertTrue(span_processor.force_flush()) with ThreadPoolExecutor(max_workers=num_threads) as executor: future_list = [] for thread_no in range(num_threads): future = executor.submit(create_spans_and_flush, thread_no) future_list.append(future) executor.shutdown() self.assertEqual(num_threads * num_spans, len(span_list))
def test_flush_empty(self): spans_names_list = [] my_exporter = MySpanExporter(destination=spans_names_list) span_processor = export.BatchExportSpanProcessor(my_exporter) self.assertTrue(span_processor.force_flush())
def test_batch_span_processor_environment_variables(self): batch_span_processor = export.BatchExportSpanProcessor( MySpanExporter(destination=[])) self.assertEqual(batch_span_processor.max_queue_size, 10) self.assertEqual(batch_span_processor.schedule_delay_millis, 2) self.assertEqual(batch_span_processor.max_export_batch_size, 3) self.assertEqual(batch_span_processor.export_timeout_millis, 4)
def test_flush_timeout(self): spans_names_list = [] my_exporter = MySpanExporter(destination=spans_names_list, export_timeout_millis=500) span_processor = export.BatchExportSpanProcessor(my_exporter) _create_start_and_end_span("foo", span_processor) # check that the timeout is not meet with self.assertLogs(level=WARNING): self.assertFalse(span_processor.force_flush(100)) span_processor.shutdown()
def test_batch_span_processor(self): spans_names_list = [] my_exporter = MySpanExporter(destination=spans_names_list) span_processor = export.BatchExportSpanProcessor(my_exporter) span_names = ["xxx", "bar", "foo"] for name in span_names: _create_start_and_end_span(name, span_processor) span_processor.shutdown() self.assertListEqual(span_names, spans_names_list)
def test_on_start_accepts_parent_context(self): # pylint: disable=no-self-use my_exporter = MySpanExporter(destination=[]) span_processor = mock.Mock( wraps=export.BatchExportSpanProcessor(my_exporter)) tracer_provider = trace.TracerProvider() tracer_provider.add_span_processor(span_processor) tracer = tracer_provider.get_tracer(__name__) context = Context() span = tracer.start_span("foo", context=context) span_processor.on_start.assert_called_once_with(span, parent_context=context)
def test_batch_span_processor_lossless(self): """Test that no spans are lost when sending max_queue_size spans""" spans_names_list = [] my_exporter = MySpanExporter(destination=spans_names_list, max_export_batch_size=128) span_processor = export.BatchExportSpanProcessor( my_exporter, max_queue_size=512, max_export_batch_size=128) for _ in range(512): _create_start_and_end_span("foo", span_processor) self.assertTrue(span_processor.force_flush()) self.assertEqual(len(spans_names_list), 512) span_processor.shutdown()
def test_batch_span_processor_scheduled_delay(self): """Test that spans are exported each schedule_delay_millis""" spans_names_list = [] my_exporter = MySpanExporter(destination=spans_names_list) span_processor = export.BatchExportSpanProcessor( my_exporter, schedule_delay_millis=50) # create single span _create_start_and_end_span("foo", span_processor) time.sleep(0.05 + 0.02) # span should be already exported self.assertEqual(len(spans_names_list), 1) span_processor.shutdown()
def test_shutdown(self): spans_names_list = [] my_exporter = MySpanExporter(destination=spans_names_list) span_processor = export.BatchExportSpanProcessor(my_exporter) span_names = ["xxx", "bar", "foo"] for name in span_names: _create_start_and_end_span(name, span_processor) span_processor.shutdown() self.assertTrue(my_exporter.is_shutdown) # check that spans are exported without an explicitly call to # force_flush() self.assertListEqual(span_names, spans_names_list)
def test_batch_span_processor_scheduled_delay(self): """Test that spans are exported each schedule_delay_millis""" spans_names_list = [] export_event = threading.Event() my_exporter = MySpanExporter( destination=spans_names_list, export_event=export_event ) span_processor = export.BatchExportSpanProcessor( my_exporter, schedule_delay_millis=50, ) # create single span start_time = time.time() _create_start_and_end_span("foo", span_processor) self.assertTrue(export_event.wait(2)) export_time = time.time() self.assertEqual(len(spans_names_list), 1) self.assertGreaterEqual((export_time - start_time) * 1e3, 50) span_processor.shutdown()
def test_batch_span_processor_not_sampled(self): tracer_provider = trace.TracerProvider( sampler=trace.sampling.ALWAYS_OFF) tracer = tracer_provider.get_tracer(__name__) spans_names_list = [] my_exporter = MySpanExporter(destination=spans_names_list, max_export_batch_size=128) span_processor = export.BatchExportSpanProcessor( my_exporter, max_queue_size=256, max_export_batch_size=64, schedule_delay_millis=100, ) tracer_provider.add_span_processor(span_processor) with tracer.start_as_current_span("foo"): pass time.sleep(0.05) # give some time for the exporter to upload spans self.assertTrue(span_processor.force_flush()) self.assertEqual(len(spans_names_list), 0) span_processor.shutdown()
def test_batch_span_processor_many_spans(self): """Test that no spans are lost when sending many spans""" spans_names_list = [] my_exporter = MySpanExporter(destination=spans_names_list, max_export_batch_size=128) span_processor = export.BatchExportSpanProcessor( my_exporter, max_queue_size=256, max_export_batch_size=64, schedule_delay_millis=100, ) for _ in range(4): for _ in range(256): _create_start_and_end_span("foo", span_processor) time.sleep(0.1) # give some time for the exporter to upload spans self.assertTrue(span_processor.force_flush()) self.assertEqual(len(spans_names_list), 1024) span_processor.shutdown()
def test_flush(self): spans_names_list = [] my_exporter = MySpanExporter(destination=spans_names_list) span_processor = export.BatchExportSpanProcessor(my_exporter) span_names0 = ["xxx", "bar", "foo"] span_names1 = ["yyy", "baz", "fox"] for name in span_names0: _create_start_and_end_span(name, span_processor) self.assertTrue(span_processor.force_flush()) self.assertListEqual(span_names0, spans_names_list) # create some more spans to check that span processor still works for name in span_names1: _create_start_and_end_span(name, span_processor) self.assertTrue(span_processor.force_flush()) self.assertListEqual(span_names0 + span_names1, spans_names_list) span_processor.shutdown()
def test_batch_span_processor_reset_timeout(self): """Test that the scheduled timeout is reset on cycles without spans""" spans_names_list = [] export_event = threading.Event() my_exporter = MySpanExporter( destination=spans_names_list, export_event=export_event, export_timeout_millis=50, ) span_processor = export.BatchExportSpanProcessor( my_exporter, schedule_delay_millis=50, ) with mock.patch.object(span_processor.condition, "wait") as mock_wait: _create_start_and_end_span("foo", span_processor) self.assertTrue(export_event.wait(2)) # give some time for exporter to loop # since wait is mocked it should return immediately time.sleep(0.05) mock_wait_calls = list(mock_wait.mock_calls) # find the index of the call that processed the singular span for idx, wait_call in enumerate(mock_wait_calls): _, args, __ = wait_call if args[0] <= 0: after_calls = mock_wait_calls[idx + 1 :] break self.assertTrue( all(args[0] >= 0.05 for _, args, __ in after_calls) ) span_processor.shutdown()