def setUp(self):
     self.exporter = MockDatadogSpanExporter()
     self.span_processor = datadog.DatadogExportSpanProcessor(self.exporter)
     tracer_provider = trace.TracerProvider()
     tracer_provider.add_span_processor(self.span_processor)
     self.tracer_provider = tracer_provider
     self.tracer = tracer_provider.get_tracer(__name__)
    def test_batch_span_processor_reset_timeout(self):
        """Test that the scheduled timeout is reset on cycles without spans"""
        delay = 50
        # pylint: disable=protected-access
        exporter = MockDatadogSpanExporter()
        exporter._agent_writer.write.side_effect = lambda spans: time.sleep(
            0.05)
        span_processor = datadog.DatadogExportSpanProcessor(
            exporter, schedule_delay_millis=delay)
        tracer_provider = trace.TracerProvider()
        tracer_provider.add_span_processor(span_processor)
        tracer = tracer_provider.get_tracer(__name__)
        with mock.patch.object(span_processor.condition, "wait") as mock_wait:
            with tracer.start_span("foo"):
                pass

            # give some time for exporter to loop
            # since wait is mocked it should return immediately
            time.sleep(0.1)
            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()
    def test_span_processor_accepts_parent_context(self):
        span_processor = mock.Mock(
            wraps=datadog.DatadogExportSpanProcessor(self.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_span_processor_lossless(self):
        """Test that no spans are lost when sending max_trace_size spans"""
        span_processor = datadog.DatadogExportSpanProcessor(self.exporter,
                                                            max_trace_size=128)
        tracer_provider = trace.TracerProvider()
        tracer_provider.add_span_processor(span_processor)
        tracer = tracer_provider.get_tracer(__name__)

        with tracer.start_as_current_span("root"):
            for _ in range(127):
                with tracer.start_span("foo"):
                    pass

        self.assertTrue(span_processor.force_flush())
        datadog_spans = get_spans(tracer, self.exporter)
        self.assertEqual(len(datadog_spans), 128)
        tracer_provider.shutdown()
    def test_span_processor_dropped_spans(self):
        """Test that spans are lost when exceeding max_trace_size spans"""
        span_processor = datadog.DatadogExportSpanProcessor(self.exporter,
                                                            max_trace_size=128)
        tracer_provider = trace.TracerProvider()
        tracer_provider.add_span_processor(span_processor)
        tracer = tracer_provider.get_tracer(__name__)

        with tracer.start_as_current_span("root"):
            for _ in range(127):
                with tracer.start_span("foo"):
                    pass
            with self.assertLogs(level=logging.WARNING):
                with tracer.start_span("one-too-many"):
                    pass

        self.assertTrue(span_processor.force_flush())
        datadog_spans = get_spans(tracer, self.exporter)
        self.assertEqual(len(datadog_spans), 128)
        tracer_provider.shutdown()
    def test_span_processor_scheduled_delay(self):
        """Test that spans are exported each schedule_delay_millis"""
        delay = 300
        span_processor = datadog.DatadogExportSpanProcessor(
            self.exporter, schedule_delay_millis=delay)
        tracer_provider = trace.TracerProvider()
        tracer_provider.add_span_processor(span_processor)
        tracer = tracer_provider.get_tracer(__name__)

        with tracer.start_span("foo"):
            pass

        time.sleep(delay / (1e3 * 2))
        datadog_spans = get_spans(tracer, self.exporter, shutdown=False)
        self.assertEqual(len(datadog_spans), 0)

        time.sleep(delay / (1e3 * 2) + 0.01)
        datadog_spans = get_spans(tracer, self.exporter, shutdown=False)
        self.assertEqual(len(datadog_spans), 1)

        tracer_provider.shutdown()