Example #1
0
class TestRateByService(TestCase):
    """
    Check we get feedback from the agent and we're able to process it.
    """
    def setUp(self):
        """
        Create a tracer without workers, while spying the ``send()`` method
        """
        # create a new API object to test the transport using synchronous calls
        self.tracer = get_dummy_tracer()
        self.api_json = API('localhost', 8126, encoder=JSONEncoder())
        self.api_msgpack = API('localhost', 8126, encoder=MsgpackEncoder())

    def test_send_single_trace(self):
        # register a single trace with a span and send them to the trace agent
        self.tracer.trace('client.testing').finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        # [TODO:christian] when CI has an agent that is able to process the v0.4
        # endpoint, add a check to:
        # - make sure the output is a valid JSON
        # - make sure the priority sampler (if enabled) is updated

        # test JSON encoder
        response = self.api_json.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)
Example #2
0
class TestRateByService(TestCase):
    """
    Check we get feedback from the agent and we're able to process it.
    """
    def setUp(self):
        """
        Create a tracer without workers, while spying the ``send()`` method
        """
        # create a new API object to test the transport using synchronous calls
        self.tracer = get_dummy_tracer()
        self.api_json = API('localhost', 8126, encoder=JSONEncoder())
        self.api_msgpack = API('localhost', 8126, encoder=MsgpackEncoder())

    def test_send_single_trace(self):
        # register a single trace with a span and send them to the trace agent
        self.tracer.trace('client.testing').finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        # [TODO:christian] when CI has an agent that is able to process the v0.4
        # endpoint, add a check to:
        # - make sure the output is a valid JSON
        # - make sure the priority sampler (if enabled) is updated

        # test JSON encoder
        response = self.api_json.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)
Example #3
0
class TestRateByService(TestCase):
    """
    Check we get feedback from the agent and we're able to process it.
    """
    def setUp(self):
        """
        Create a tracer without workers, while spying the ``send()`` method
        """
        # create a new API object to test the transport using synchronous calls
        self.tracer = get_dummy_tracer()
        self.api_json = API("localhost",
                            8126,
                            encoder=JSONEncoder(),
                            priority_sampling=True)
        self.api_msgpack = API("localhost",
                               8126,
                               encoder=MsgpackEncoder(),
                               priority_sampling=True)

    @pytest.mark.skipif(AGENT_VERSION == "testagent",
                        reason="Test agent doesn't yet support rate sampling.")
    def test_send_single_trace(self):
        # register a single trace with a span and send them to the trace agent
        self.tracer.trace("client.testing").finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        # [TODO:christian] when CI has an agent that is able to process the v0.4
        # endpoint, add a check to:
        # - make sure the output is a valid JSON
        # - make sure the priority sampler (if enabled) is updated

        # test JSON encoder
        responses = self.api_json.send_traces(traces)
        assert len(responses) == 1
        assert responses[0].status == 200
        resp = responses[0].get_json()
        assert isinstance(resp["rate_by_service"]["service:,env:"],
                          numeric_types)

        # test Msgpack encoder
        responses = self.api_msgpack.send_traces(traces)
        assert len(responses) == 1
        assert responses[0].status == 200
        resp = responses[0].get_json()
        assert isinstance(resp["rate_by_service"]["service:,env:"],
                          numeric_types)
Example #4
0
    def test_downgrade_api(self):
        # make a call to a not existing endpoint, downgrades
        # the current API to a stable one
        tracer = get_dummy_tracer()
        tracer.trace('client.testing').finish()
        trace = tracer.writer.pop()

        # the encoder is right but we're targeting an API
        # endpoint that is not available
        api = API('localhost', 8126)
        api._traces = '/v0.0/traces'
        assert isinstance(api._encoder, MsgpackEncoder)

        # after the call, we downgrade to a working endpoint
        response = api.send_traces([trace])
        assert response
        assert response.status == 200
        assert isinstance(api._encoder, JSONEncoder)
Example #5
0
    def test_downgrade_api(self):
        # make a call to a not existing endpoint, downgrades
        # the current API to a stable one
        tracer = get_dummy_tracer()
        tracer.trace('client.testing').finish()
        trace = tracer.writer.pop()

        # the encoder is right but we're targeting an API
        # endpoint that is not available
        api = API('localhost', 8126)
        api._traces = '/v0.0/traces'
        ok_(isinstance(api._encoder, MsgpackEncoder))

        # after the call, we downgrade to a working endpoint
        response = api.send_traces([trace])
        ok_(response)
        eq_(response.status, 200)
        ok_(isinstance(api._encoder, JSONEncoder))
Example #6
0
class TestAPITransport(TestCase):
    """
    Ensures that traces are properly sent to a local agent. These are part
    of integration tests so real calls are triggered and you have to execute
    a real trace-agent to let them pass.
    """
    @mock.patch('ddtrace.internal.runtime.container.get_container_info')
    def setUp(self, get_container_info):
        """
        Create a tracer without workers, while spying the ``send()`` method
        """
        # Mock the container id we use for making requests
        get_container_info.return_value = CGroupInfo(
            container_id='test-container-id')

        # create a new API object to test the transport using synchronous calls
        self.tracer = get_dummy_tracer()
        self.api_json = API('localhost', 8126, encoder=JSONEncoder())
        self.api_msgpack = API('localhost', 8126, encoder=MsgpackEncoder())

    @mock.patch('ddtrace.api.httplib.HTTPConnection')
    def test_send_presampler_headers(self, mocked_http):
        # register a single trace with a span and send them to the trace agent
        self.tracer.trace('client.testing').finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        # make a call and retrieve the `conn` Mock object
        self.api_msgpack.send_traces(traces)
        request_call = mocked_http.return_value.request
        assert request_call.call_count == 1

        # retrieve the headers from the mocked request call
        expected_headers = {
            'Datadog-Container-Id': 'test-container-id',  # mocked in setUp()
            'Datadog-Meta-Lang': 'python',
            'Datadog-Meta-Lang-Interpreter': PYTHON_INTERPRETER,
            'Datadog-Meta-Lang-Version': PYTHON_VERSION,
            'Datadog-Meta-Tracer-Version': ddtrace.__version__,
            'X-Datadog-Trace-Count': '1',
            'Content-Type': 'application/msgpack',
        }
        params, _ = request_call.call_args_list[0]
        headers = params[3]
        assert len(expected_headers) == len(headers)
        for k, v in expected_headers.items():
            assert v == headers[k]

    @mock.patch('ddtrace.api.httplib.HTTPConnection')
    def test_send_presampler_headers_not_in_services(self, mocked_http):
        # register some services and send them to the trace agent
        services = [{
            'client.service': {
                'app': 'django',
                'app_type': 'web',
            },
        }]

        # make a call and retrieve the `conn` Mock object
        self.api_msgpack.send_services(services)
        request_call = mocked_http.return_value.request
        assert request_call.call_count == 0

    def _send_traces_and_check(self, traces, nresponses=1):
        # test JSON encoder
        responses = self.api_json.send_traces(traces)
        assert len(responses) == nresponses
        for response in responses:
            assert response.status == 200

        # test Msgpack encoder
        responses = self.api_msgpack.send_traces(traces)
        assert len(responses) == nresponses
        for response in responses:
            assert response.status == 200

    def test_send_single_trace(self):
        # register a single trace with a span and send them to the trace agent
        self.tracer.trace('client.testing').finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        self._send_traces_and_check(traces)

    def test_send_many_traces(self):
        # register a single trace with a span and send them to the trace agent
        self.tracer.trace('client.testing').finish()
        trace = self.tracer.writer.pop()
        # 30k is a right number to have both json and msgpack send 2 payload :)
        traces = [trace] * 30000

        self._send_traces_and_check(traces, 2)

    def test_send_single_with_wrong_errors(self):
        # if the error field is set to True, it must be cast as int so
        # that the agent decoder handles that properly without providing
        # a decoding error
        span = self.tracer.trace('client.testing')
        span.error = True
        span.finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        self._send_traces_and_check(traces)

    def test_send_multiple_traces(self):
        # register some traces and send them to the trace agent
        self.tracer.trace('client.testing').finish()
        trace_1 = self.tracer.writer.pop()
        self.tracer.trace('client.testing').finish()
        trace_2 = self.tracer.writer.pop()
        traces = [trace_1, trace_2]

        self._send_traces_and_check(traces)

    def test_send_single_trace_multiple_spans(self):
        # register some traces and send them to the trace agent
        with self.tracer.trace('client.testing'):
            self.tracer.trace('client.testing').finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        self._send_traces_and_check(traces)

    def test_send_multiple_traces_multiple_spans(self):
        # register some traces and send them to the trace agent
        with self.tracer.trace('client.testing'):
            self.tracer.trace('client.testing').finish()
        trace_1 = self.tracer.writer.pop()

        with self.tracer.trace('client.testing'):
            self.tracer.trace('client.testing').finish()
        trace_2 = self.tracer.writer.pop()

        traces = [trace_1, trace_2]

        self._send_traces_and_check(traces)

    def test_send_single_service(self):
        # register some services and send them to the trace agent
        services = [{
            'client.service': {
                'app': 'django',
                'app_type': 'web',
            },
        }]

        # test JSON encoder
        response = self.api_json.send_services(services)
        assert response is None

        # test Msgpack encoder
        response = self.api_msgpack.send_services(services)
        assert response is None

    def test_send_service_called_multiple_times(self):
        # register some services and send them to the trace agent
        services = [{
            'backend': {
                'app': 'django',
                'app_type': 'web',
            },
            'database': {
                'app': 'postgres',
                'app_type': 'db',
            },
        }]

        # test JSON encoder
        response = self.api_json.send_services(services)
        assert response is None

        # test Msgpack encoder
        response = self.api_msgpack.send_services(services)
        assert response is None
class TestAPITransport(TestCase):
    """
    Ensures that traces are properly sent to a local agent. These are part
    of integration tests so real calls are triggered and you have to execute
    a real trace-agent to let them pass.
    """
    def setUp(self):
        """
        Create a tracer without workers, while spying the ``send()`` method
        """
        # create a new API object to test the transport using synchronous calls
        self.tracer = get_dummy_tracer()
        self.api_json = API('localhost', 7777, encoder=JSONEncoder())
        self.api_msgpack = API('localhost', 7777, encoder=MsgpackEncoder())

    def test_send_single_trace(self):
        # register a single trace with a span and send them to the trace agent
        self.tracer.trace('client.testing').finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        # test JSON encoder
        response = self.api_json.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

    def test_send_multiple_traces(self):
        # register some traces and send them to the trace agent
        self.tracer.trace('client.testing').finish()
        trace_1 = self.tracer.writer.pop()
        self.tracer.trace('client.testing').finish()
        trace_2 = self.tracer.writer.pop()
        traces = [trace_1, trace_2]

        # test JSON encoder
        response = self.api_json.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

    def test_send_single_trace_multiple_spans(self):
        # register some traces and send them to the trace agent
        with self.tracer.trace('client.testing'):
            self.tracer.trace('client.testing').finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        # test JSON encoder
        response = self.api_json.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

    def test_send_multiple_traces_multiple_spans(self):
        # register some traces and send them to the trace agent
        with self.tracer.trace('client.testing'):
            self.tracer.trace('client.testing').finish()
        trace_1 = self.tracer.writer.pop()

        with self.tracer.trace('client.testing'):
            self.tracer.trace('client.testing').finish()
        trace_2 = self.tracer.writer.pop()

        traces = [trace_1, trace_2]

        # test JSON encoder
        response = self.api_json.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

    def test_send_single_service(self):
        # register some services and send them to the trace agent
        services = [{
            'client.service': {
                'app': 'django',
                'app_type': 'web',
            },
        }]

        # test JSON encoder
        response = self.api_json.send_services(services)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_services(services)
        ok_(response)
        eq_(response.status, 200)

    def test_send_service_called_multiple_times(self):
        # register some services and send them to the trace agent
        services = [{
            'backend': {
                'app': 'django',
                'app_type': 'web',
            },
            'database': {
                'app': 'postgres',
                'app_type': 'db',
            },
        }]

        # test JSON encoder
        response = self.api_json.send_services(services)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_services(services)
        ok_(response)
        eq_(response.status, 200)
Example #8
0
class TestAPITransport(TestCase):
    """
    Ensures that traces are properly sent to a local agent. These are part
    of integration tests so real calls are triggered and you have to execute
    a real trace-agent to let them pass.
    """
    def setUp(self):
        """
        Create a tracer without workers, while spying the ``send()`` method
        """
        # create a new API object to test the transport using synchronous calls
        self.tracer = get_dummy_tracer()
        self.api_json = API('localhost', 8126, encoder=JSONEncoder())
        self.api_msgpack = API('localhost', 8126, encoder=MsgpackEncoder())

    @mock.patch('ddtrace.api.httplib.HTTPConnection')
    def test_send_presampler_headers(self, mocked_http):
        # register a single trace with a span and send them to the trace agent
        self.tracer.trace('client.testing').finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        # make a call and retrieve the `conn` Mock object
        response = self.api_msgpack.send_traces(traces)
        request_call = mocked_http.return_value.request
        eq_(request_call.call_count, 1)

        # retrieve the headers from the mocked request call
        expected_headers = {
                'Datadog-Meta-Lang': 'python',
                'Datadog-Meta-Lang-Interpreter': PYTHON_INTERPRETER,
                'Datadog-Meta-Lang-Version': PYTHON_VERSION,
                'Datadog-Meta-Tracer-Version': ddtrace.__version__,
                'X-Datadog-Trace-Count': '1',
                'Content-Type': 'application/msgpack'
        }
        params, _ = request_call.call_args_list[0]
        headers = params[3]
        eq_(len(expected_headers), len(headers))
        for k, v in expected_headers.items():
            eq_(v, headers[k])

    @mock.patch('ddtrace.api.httplib.HTTPConnection')
    def test_send_presampler_headers_not_in_services(self, mocked_http):
        # register some services and send them to the trace agent
        services = [{
            'client.service': {
                'app': 'django',
                'app_type': 'web',
            },
        }]

        # make a call and retrieve the `conn` Mock object
        response = self.api_msgpack.send_services(services)
        request_call = mocked_http.return_value.request
        eq_(request_call.call_count, 1)

        # retrieve the headers from the mocked request call
        expected_headers = {
                'Datadog-Meta-Lang': 'python',
                'Datadog-Meta-Lang-Interpreter': PYTHON_INTERPRETER,
                'Datadog-Meta-Lang-Version': PYTHON_VERSION,
                'Datadog-Meta-Tracer-Version': ddtrace.__version__,
                'Content-Type': 'application/msgpack'
        }
        params, _ = request_call.call_args_list[0]
        headers = params[3]
        eq_(len(expected_headers), len(headers))
        for k, v in expected_headers.items():
            eq_(v, headers[k])

        # retrieve the headers from the mocked request call
        params, _ = request_call.call_args_list[0]
        headers = params[3]
        ok_('X-Datadog-Trace-Count' not in headers.keys())

    def test_send_single_trace(self):
        # register a single trace with a span and send them to the trace agent
        self.tracer.trace('client.testing').finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        # test JSON encoder
        response = self.api_json.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

    def test_send_single_with_wrong_errors(self):
        # if the error field is set to True, it must be cast as int so
        # that the agent decoder handles that properly without providing
        # a decoding error
        span = self.tracer.trace('client.testing')
        span.error = True
        span.finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        # test JSON encoder
        response = self.api_json.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

    def test_send_multiple_traces(self):
        # register some traces and send them to the trace agent
        self.tracer.trace('client.testing').finish()
        trace_1 = self.tracer.writer.pop()
        self.tracer.trace('client.testing').finish()
        trace_2 = self.tracer.writer.pop()
        traces = [trace_1, trace_2]

        # test JSON encoder
        response = self.api_json.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

    def test_send_single_trace_multiple_spans(self):
        # register some traces and send them to the trace agent
        with self.tracer.trace('client.testing'):
            self.tracer.trace('client.testing').finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        # test JSON encoder
        response = self.api_json.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

    def test_send_multiple_traces_multiple_spans(self):
        # register some traces and send them to the trace agent
        with self.tracer.trace('client.testing'):
            self.tracer.trace('client.testing').finish()
        trace_1 = self.tracer.writer.pop()

        with self.tracer.trace('client.testing'):
            self.tracer.trace('client.testing').finish()
        trace_2 = self.tracer.writer.pop()

        traces = [trace_1, trace_2]

        # test JSON encoder
        response = self.api_json.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

    def test_send_single_service(self):
        # register some services and send them to the trace agent
        services = [{
            'client.service': {
                'app': 'django',
                'app_type': 'web',
            },
        }]

        # test JSON encoder
        response = self.api_json.send_services(services)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_services(services)
        ok_(response)
        eq_(response.status, 200)

    def test_send_service_called_multiple_times(self):
        # register some services and send them to the trace agent
        services = [{
            'backend': {
                'app': 'django',
                'app_type': 'web',
            },
            'database': {
                'app': 'postgres',
                'app_type': 'db',
            },
        }]

        # test JSON encoder
        response = self.api_json.send_services(services)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_services(services)
        ok_(response)
        eq_(response.status, 200)
Example #9
0
class TestAPITransport(TestCase):
    """
    Ensures that traces are properly sent to a local agent. These are part
    of integration tests so real calls are triggered and you have to execute
    a real trace-agent to let them pass.
    """
    def setUp(self):
        """
        Create a tracer without workers, while spying the ``send()`` method
        """
        # create a new API object to test the transport using synchronous calls
        self.tracer = get_dummy_tracer()
        self.api_json = API('localhost', 8126, encoder=JSONEncoder())
        self.api_msgpack = API('localhost', 8126, encoder=MsgpackEncoder())

    @mock.patch('ddtrace.api.httplib.HTTPConnection')
    def test_send_presampler_headers(self, mocked_http):
        # register a single trace with a span and send them to the trace agent
        self.tracer.trace('client.testing').finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        # make a call and retrieve the `conn` Mock object
        response = self.api_msgpack.send_traces(traces)
        request_call = mocked_http.return_value.request
        eq_(request_call.call_count, 1)

        # retrieve the headers from the mocked request call
        expected_headers = {
            'Datadog-Meta-Lang': 'python',
            'Datadog-Meta-Lang-Interpreter': PYTHON_INTERPRETER,
            'Datadog-Meta-Lang-Version': PYTHON_VERSION,
            'Datadog-Meta-Tracer-Version': ddtrace.__version__,
            'X-Datadog-Trace-Count': '1',
            'Content-Type': 'application/msgpack'
        }
        params, _ = request_call.call_args_list[0]
        headers = params[3]
        eq_(len(expected_headers), len(headers))
        for k, v in expected_headers.items():
            eq_(v, headers[k])

    @mock.patch('ddtrace.api.httplib.HTTPConnection')
    def test_send_presampler_headers_not_in_services(self, mocked_http):
        # register some services and send them to the trace agent
        services = [{
            'client.service': {
                'app': 'django',
                'app_type': 'web',
            },
        }]

        # make a call and retrieve the `conn` Mock object
        response = self.api_msgpack.send_services(services)
        request_call = mocked_http.return_value.request
        eq_(request_call.call_count, 1)

        # retrieve the headers from the mocked request call
        expected_headers = {
            'Datadog-Meta-Lang': 'python',
            'Datadog-Meta-Lang-Interpreter': PYTHON_INTERPRETER,
            'Datadog-Meta-Lang-Version': PYTHON_VERSION,
            'Datadog-Meta-Tracer-Version': ddtrace.__version__,
            'Content-Type': 'application/msgpack'
        }
        params, _ = request_call.call_args_list[0]
        headers = params[3]
        eq_(len(expected_headers), len(headers))
        for k, v in expected_headers.items():
            eq_(v, headers[k])

        # retrieve the headers from the mocked request call
        params, _ = request_call.call_args_list[0]
        headers = params[3]
        ok_('X-Datadog-Trace-Count' not in headers.keys())

    def test_send_single_trace(self):
        # register a single trace with a span and send them to the trace agent
        self.tracer.trace('client.testing').finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        # test JSON encoder
        response = self.api_json.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

    def test_send_single_with_wrong_errors(self):
        # if the error field is set to True, it must be cast as int so
        # that the agent decoder handles that properly without providing
        # a decoding error
        span = self.tracer.trace('client.testing')
        span.error = True
        span.finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        # test JSON encoder
        response = self.api_json.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

    def test_send_multiple_traces(self):
        # register some traces and send them to the trace agent
        self.tracer.trace('client.testing').finish()
        trace_1 = self.tracer.writer.pop()
        self.tracer.trace('client.testing').finish()
        trace_2 = self.tracer.writer.pop()
        traces = [trace_1, trace_2]

        # test JSON encoder
        response = self.api_json.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

    def test_send_single_trace_multiple_spans(self):
        # register some traces and send them to the trace agent
        with self.tracer.trace('client.testing'):
            self.tracer.trace('client.testing').finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        # test JSON encoder
        response = self.api_json.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

    def test_send_multiple_traces_multiple_spans(self):
        # register some traces and send them to the trace agent
        with self.tracer.trace('client.testing'):
            self.tracer.trace('client.testing').finish()
        trace_1 = self.tracer.writer.pop()

        with self.tracer.trace('client.testing'):
            self.tracer.trace('client.testing').finish()
        trace_2 = self.tracer.writer.pop()

        traces = [trace_1, trace_2]

        # test JSON encoder
        response = self.api_json.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_traces(traces)
        ok_(response)
        eq_(response.status, 200)

    def test_send_single_service(self):
        # register some services and send them to the trace agent
        services = [{
            'client.service': {
                'app': 'django',
                'app_type': 'web',
            },
        }]

        # test JSON encoder
        response = self.api_json.send_services(services)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_services(services)
        ok_(response)
        eq_(response.status, 200)

    def test_send_service_called_multiple_times(self):
        # register some services and send them to the trace agent
        services = [{
            'backend': {
                'app': 'django',
                'app_type': 'web',
            },
            'database': {
                'app': 'postgres',
                'app_type': 'db',
            },
        }]

        # test JSON encoder
        response = self.api_json.send_services(services)
        ok_(response)
        eq_(response.status, 200)

        # test Msgpack encoder
        response = self.api_msgpack.send_services(services)
        ok_(response)
        eq_(response.status, 200)
Example #10
0
class TestAPITransport(TestCase):
    """
    Ensures that traces are properly sent to a local agent. These are part
    of integration tests so real calls are triggered and you have to execute
    a real trace-agent to let them pass.
    """
    @mock.patch("ddtrace.internal.runtime.container.get_container_info")
    def setUp(self, get_container_info):
        """
        Create a tracer without workers, while spying the ``send()`` method
        """
        # Mock the container id we use for making requests
        get_container_info.return_value = CGroupInfo(
            container_id="test-container-id")

        # create a new API object to test the transport using synchronous calls
        self.tracer = get_dummy_tracer()
        self.api_json = API("localhost", 8126, encoder=JSONEncoder())
        self.api_msgpack = API("localhost", 8126, encoder=MsgpackEncoder())

    @mock.patch("ddtrace.api.httplib.HTTPConnection")
    def test_send_presampler_headers(self, mocked_http):
        # register a single trace with a span and send them to the trace agent
        self.tracer.trace("client.testing").finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        # make a call and retrieve the `conn` Mock object
        self.api_msgpack.send_traces(traces)
        request_call = mocked_http.return_value.request
        assert request_call.call_count == 1

        # retrieve the headers from the mocked request call
        expected_headers = {
            "Datadog-Container-Id": "test-container-id",  # mocked in setUp()
            "Datadog-Meta-Lang": "python",
            "Datadog-Meta-Lang-Interpreter": PYTHON_INTERPRETER,
            "Datadog-Meta-Lang-Version": PYTHON_VERSION,
            "Datadog-Meta-Tracer-Version": ddtrace.__version__,
            "X-Datadog-Trace-Count": "1",
            "Content-Type": "application/msgpack",
        }
        params, _ = request_call.call_args_list[0]
        headers = params[3]
        assert expected_headers == headers

    def _send_traces_and_check(self, traces, nresponses=1):
        # test JSON encoder
        responses = self.api_json.send_traces(traces)
        assert len(responses) == nresponses
        for response in responses:
            assert isinstance(response, Exception) or response.status == 200

        # test Msgpack encoder
        responses = self.api_msgpack.send_traces(traces)
        assert len(responses) == nresponses
        for response in responses:
            assert isinstance(response, Exception) or response.status == 200

    def test_send_single_trace(self):
        # register a single trace with a span and send them to the trace agent
        self.tracer.trace("client.testing").finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        self._send_traces_and_check(traces)

    def test_send_many_traces(self):
        # register a single trace with a span and send them to the trace agent
        self.tracer.trace("client.testing").finish()
        trace = self.tracer.writer.pop()
        # 20k is a right number to have both json and msgpack send 2 payload :)
        traces = [trace] * 20000

        self._send_traces_and_check(traces, 2)

    def test_send_single_trace_max_payload(self):
        payload = Payload()

        # compute number of spans to create to surpass max payload
        trace = [Span(self.tracer, "child.span")]
        trace_size = len(payload.encoder.encode_trace(trace))
        num_spans = int(math.floor(payload.max_payload_size / trace_size))

        # setup logging capture
        log = logging.getLogger("ddtrace.api")
        log_handler = MockedLogHandler(level="WARNING")
        log.addHandler(log_handler)

        with self.tracer.trace("client.testing"):
            for n in range(num_spans):
                self.tracer.trace("child.span").finish()

        trace = self.tracer.writer.pop()

        self._send_traces_and_check([trace], 1)

        logged_warnings = log_handler.messages["warning"]
        assert len(logged_warnings) == 1
        assert "Trace is larger than the max payload size, dropping it" in logged_warnings[
            0]

    def test_send_multiple_trace_max_payload(self):
        payload = Payload()

        # compute number of spans to create to surpass max payload
        trace = [Span(self.tracer, "child.span")]
        trace_size = len(payload.encoder.encode_trace(trace))
        num_spans = int(
            math.floor((payload.max_payload_size - trace_size) / trace_size))

        # setup logging capture
        log = logging.getLogger("ddtrace.api")
        log_handler = MockedLogHandler(level="WARNING")
        log.addHandler(log_handler)

        self.tracer.trace("client.testing").finish()
        traces = [self.tracer.writer.pop()]

        # create a trace larger than max payload size
        with self.tracer.trace("client.testing"):
            for n in range(num_spans):
                self.tracer.trace("child.span").finish()

        traces.append(self.tracer.writer.pop())

        self._send_traces_and_check(traces, 2)

        logged_warnings = log_handler.messages["warning"]
        assert len(logged_warnings) == 1
        assert "Trace is too big to fit in a payload, dropping it" in logged_warnings[
            0]

    def test_send_single_with_wrong_errors(self):
        # if the error field is set to True, it must be cast as int so
        # that the agent decoder handles that properly without providing
        # a decoding error
        span = self.tracer.trace("client.testing")
        span.error = True
        span.finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        self._send_traces_and_check(traces)

    def test_send_multiple_traces(self):
        # register some traces and send them to the trace agent
        self.tracer.trace("client.testing").finish()
        trace_1 = self.tracer.writer.pop()
        self.tracer.trace("client.testing").finish()
        trace_2 = self.tracer.writer.pop()
        traces = [trace_1, trace_2]

        self._send_traces_and_check(traces)

    def test_send_single_trace_multiple_spans(self):
        # register some traces and send them to the trace agent
        with self.tracer.trace("client.testing"):
            self.tracer.trace("client.testing").finish()
        trace = self.tracer.writer.pop()
        traces = [trace]

        self._send_traces_and_check(traces)

    def test_send_multiple_traces_multiple_spans(self):
        # register some traces and send them to the trace agent
        with self.tracer.trace("client.testing"):
            self.tracer.trace("client.testing").finish()
        trace_1 = self.tracer.writer.pop()

        with self.tracer.trace("client.testing"):
            self.tracer.trace("client.testing").finish()
        trace_2 = self.tracer.writer.pop()

        traces = [trace_1, trace_2]

        self._send_traces_and_check(traces)