def test_tracer_wrap_factory_nested(): # it should use a wrap_factory if defined even in nested tracing writer = DummyWriter() tracer = Tracer() tracer.writer = writer def wrap_executor(tracer, fn, args, kwargs, span_name=None, service=None, resource=None, span_type=None): with tracer.trace('wrap.overwrite') as span: span.set_tag('args', args) span.set_tag('kwargs', kwargs) return fn(*args, **kwargs) @tracer.wrap() def wrapped_function(param, kw_param=None): eq_(42, param) eq_(42, kw_param) # set the custom wrap factory after the wrapper has been called tracer.configure(wrap_executor=wrap_executor) # call the function expecting that the custom tracing wrapper is used with tracer.trace('wrap.parent', service='webserver'): wrapped_function(42, kw_param=42) eq_(writer.spans[0].name, 'wrap.parent') eq_(writer.spans[0].service, 'webserver') eq_(writer.spans[1].name, 'wrap.overwrite') eq_(writer.spans[1].service, 'webserver') eq_(writer.spans[1].get_tag('args'), '(42,)') eq_(writer.spans[1].get_tag('kwargs'), '{\'kw_param\': 42}')
def test_tracer_wrap_factory(): # it should use a wrap_factory if defined writer = DummyWriter() tracer = Tracer() tracer.writer = writer def wrap_executor(tracer, fn, args, kwargs, span_name=None, service=None, resource=None, span_type=None): with tracer.trace('wrap.overwrite') as span: span.set_tag('args', args) span.set_tag('kwargs', kwargs) return fn(*args, **kwargs) @tracer.wrap() def wrapped_function(param, kw_param=None): eq_(42, param) eq_(42, kw_param) # set the custom wrap factory after the wrapper has been called tracer.configure(wrap_executor=wrap_executor) # call the function expecting that the custom tracing wrapper is used wrapped_function(42, kw_param=42) eq_(writer.spans[0].name, 'wrap.overwrite') eq_(writer.spans[0].get_tag('args'), '(42,)') eq_(writer.spans[0].get_tag('kwargs'), '{\'kw_param\': 42}')
def test_detect_agentless_env_with_lambda(self): assert _in_aws_lambda() assert not _has_aws_lambda_agent_extension() tracer = Tracer() assert isinstance(tracer.writer, LogWriter) tracer.configure(enabled=True) assert isinstance(tracer.writer, LogWriter)
def test_configure_keeps_api_hostname_and_port(self): tracer = Tracer() # use real tracer with real api assert 'localhost' == tracer.writer.api.hostname assert 8126 == tracer.writer.api.port tracer.configure(hostname='127.0.0.1', port=8127) assert '127.0.0.1' == tracer.writer.api.hostname assert 8127 == tracer.writer.api.port tracer.configure(priority_sampling=True) assert '127.0.0.1' == tracer.writer.api.hostname assert 8127 == tracer.writer.api.port
def test_configure_keeps_api_hostname_and_port(self): tracer = Tracer() # use real tracer with real api eq_('localhost', tracer.writer.api.hostname) eq_(8126, tracer.writer.api.port) tracer.configure(hostname='127.0.0.1', port=8127) eq_('127.0.0.1', tracer.writer.api.hostname) eq_(8127, tracer.writer.api.port) tracer.configure(priority_sampling=True) eq_('127.0.0.1', tracer.writer.api.hostname) eq_(8127, tracer.writer.api.port)
def test_configure_dogstatsd_url_host_port(self): tracer = Tracer() tracer.configure(dogstatsd_url="foo:1234") assert tracer.writer.dogstatsd.host == "foo" assert tracer.writer.dogstatsd.port == 1234 tracer = Tracer() writer = AgentWriter("http://localhost:8126") tracer.configure(writer=writer, dogstatsd_url="foo:1234") assert tracer.writer.dogstatsd.host == "foo" assert tracer.writer.dogstatsd.port == 1234
def test_configure_dogstatsd_url_socket(self): tracer = Tracer() tracer.configure(dogstatsd_url="unix:///foo.sock") assert tracer.writer.dogstatsd.host is None assert tracer.writer.dogstatsd.port is None assert tracer.writer.dogstatsd.socket_path == "/foo.sock" tracer = Tracer() writer = AgentWriter("http://localhost:8126") tracer.configure(writer=writer, dogstatsd_url="unix:///foo.sock") assert tracer.writer.dogstatsd.host is None assert tracer.writer.dogstatsd.port is None assert tracer.writer.dogstatsd.socket_path == "/foo.sock"
def test_detect_agent_config_with_lambda_extension(self): def mock_os_path_exists(path): return path == "/opt/extensions/datadog-agent" assert _in_aws_lambda() with mock.patch("os.path.exists", side_effect=mock_os_path_exists): assert _has_aws_lambda_agent_extension() tracer = Tracer() assert isinstance(tracer.writer, AgentWriter) assert tracer.writer._sync_mode tracer.configure(enabled=False) assert isinstance(tracer.writer, AgentWriter) assert tracer.writer._sync_mode
class TestTornadoSettings(TornadoTestCase): """ Ensure that Tornado web application properly configures the given tracer. """ def get_app(self): # Override with a real tracer self.tracer = Tracer() super(TestTornadoSettings, self).get_app() def get_settings(self): # update tracer settings return { "datadog_trace": { "default_service": "custom-tornado", "tags": { "env": "production", "debug": "false" }, "enabled": False, "agent_hostname": "dd-agent.service.consul", "agent_port": 8126, "settings": { "FILTERS": [ TestFilter(), ], }, }, } def test_tracer_is_properly_configured(self): # the tracer must be properly configured assert self.tracer._tags.get("env") == "production" assert self.tracer._tags.get("debug") == "false" assert self.tracer.enabled is False assert self.tracer.agent_trace_url == "http://dd-agent.service.consul:8126" writer = DummyWriter() self.tracer.configure(enabled=True, writer=writer) with self.tracer.trace("keep"): pass spans = writer.pop() assert len(spans) == 1 with self.tracer.trace("drop"): pass spans = writer.pop() assert len(spans) == 0
class TestWorkers(TestCase): """ Ensures that a workers interacts correctly with the main thread. These are part of integration tests so real calls are triggered. """ def _decode(self, payload): """ Helper function that decodes data based on the given Encoder. """ if isinstance(self.api._encoder, JSONEncoder): return json.loads(payload) elif isinstance(self.api._encoder, MsgpackEncoder): return msgpack.unpackb(payload, encoding='utf-8') def setUp(self): """ Create a tracer with running workers, while spying the ``_put()`` method to keep trace of triggered API calls. """ # create a new tracer self.tracer = Tracer() # spy the send() method self.api = self.tracer.writer.api self.api._put = mock.Mock(self.api._put, wraps=self.api._put) def tearDown(self): """ Stop running worker """ self._wait_thread_flush() def _wait_thread_flush(self): """ Helper that waits for the thread flush """ self.tracer.writer.stop() self.tracer.writer.join(None) def _get_endpoint_payload(self, calls, endpoint): """ Helper to retrieve the endpoint call from a concurrent trace or service call. """ for call, _ in calls: if endpoint in call[0]: return call[0], self._decode(call[1]) return None, None @skipUnless(os.environ.get( 'TEST_DATADOG_INTEGRATION_UDS', False ), 'You should have a running trace agent on a socket and set TEST_DATADOG_INTEGRATION_UDS=1 env variable' ) def test_worker_single_trace_uds(self): self.tracer.configure(uds_path='/tmp/ddagent/trace.sock') # Write a first trace so we get a _worker self.tracer.trace('client.testing').finish() worker = self.tracer.writer worker._log_error_status = mock.Mock( worker._log_error_status, wraps=worker._log_error_status, ) self.tracer.trace('client.testing').finish() # one send is expected self._wait_thread_flush() # Check that no error was logged assert worker._log_error_status.call_count == 0 def test_worker_single_trace_uds_wrong_socket_path(self): self.tracer.configure(uds_path='/tmp/ddagent/nosockethere') # Write a first trace so we get a _worker self.tracer.trace('client.testing').finish() worker = self.tracer.writer worker._log_error_status = mock.Mock( worker._log_error_status, wraps=worker._log_error_status, ) self.tracer.trace('client.testing').finish() # one send is expected self._wait_thread_flush() # Check that no error was logged assert worker._log_error_status.call_count == 1 def test_worker_single_trace(self): # create a trace block and send it using the transport system tracer = self.tracer tracer.trace('client.testing').finish() # one send is expected self._wait_thread_flush() assert self.api._put.call_count == 1 # check and retrieve the right call endpoint, payload = self._get_endpoint_payload( self.api._put.call_args_list, '/v0.4/traces') assert endpoint == '/v0.4/traces' assert len(payload) == 1 assert len(payload[0]) == 1 assert payload[0][0]['name'] == 'client.testing' # DEV: If we can make the writer flushing deterministic for the case of tests, then we can re-enable this @skip( 'Writer flush intervals are impossible to time correctly to make this test not flaky' ) def test_worker_multiple_traces(self): # make a single send() if multiple traces are created before the flush interval tracer = self.tracer tracer.trace('client.testing').finish() tracer.trace('client.testing').finish() # one send is expected self._wait_thread_flush() assert self.api._put.call_count == 1 # check and retrieve the right call endpoint, payload = self._get_endpoint_payload( self.api._put.call_args_list, '/v0.4/traces') assert endpoint == '/v0.4/traces' assert len(payload) == 2 assert len(payload[0]) == 1 assert len(payload[1]) == 1 assert payload[0][0]['name'] == 'client.testing' assert payload[1][0]['name'] == 'client.testing' def test_worker_single_trace_multiple_spans(self): # make a single send() if a single trace with multiple spans is created before the flush tracer = self.tracer parent = tracer.trace('client.testing') tracer.trace('client.testing').finish() parent.finish() # one send is expected self._wait_thread_flush() assert self.api._put.call_count == 1 # check and retrieve the right call endpoint, payload = self._get_endpoint_payload( self.api._put.call_args_list, '/v0.4/traces') assert endpoint == '/v0.4/traces' assert len(payload) == 1 assert len(payload[0]) == 2 assert payload[0][0]['name'] == 'client.testing' assert payload[0][1]['name'] == 'client.testing' def test_worker_http_error_logging(self): # Tests the logging http error logic tracer = self.tracer self.tracer.writer.api = FlawedAPI(Tracer.DEFAULT_HOSTNAME, Tracer.DEFAULT_PORT) tracer.trace('client.testing').finish() log = logging.getLogger('ddtrace.internal.writer') log_handler = MockedLogHandler(level='DEBUG') log.addHandler(log_handler) self._wait_thread_flush() assert tracer.writer._last_error_ts < time.time() logged_errors = log_handler.messages['error'] assert len(logged_errors) == 1 assert 'Failed to send traces to Datadog Agent at localhost:8126: ' \ 'HTTP error status 400, reason Bad Request, message Content-Type:' \ in logged_errors[0] def test_worker_filter_request(self): self.tracer.configure(settings={ FILTERS_KEY: [FilterRequestsOnUrl(r'http://example\.com/health')] }) # spy the send() method self.api = self.tracer.writer.api self.api._put = mock.Mock(self.api._put, wraps=self.api._put) span = self.tracer.trace('testing.filteredurl') span.set_tag(http.URL, 'http://example.com/health') span.finish() span = self.tracer.trace('testing.nonfilteredurl') span.set_tag(http.URL, 'http://example.com/api/resource') span.finish() self._wait_thread_flush() # Only the second trace should have been sent assert self.api._put.call_count == 1 # check and retrieve the right call endpoint, payload = self._get_endpoint_payload( self.api._put.call_args_list, '/v0.4/traces') assert endpoint == '/v0.4/traces' assert len(payload) == 1 assert payload[0][0]['name'] == 'testing.nonfilteredurl'
class TestWorkers(TestCase): """ Ensures that a workers interacts correctly with the main thread. These are part of integration tests so real calls are triggered. """ def _decode(self, payload): """ Helper function that decodes data based on the given Encoder. """ if isinstance(self.api._encoder, JSONEncoder): return json.loads(payload) elif isinstance(self.api._encoder, MsgpackEncoder): return msgpack.unpackb(payload, encoding='utf-8') def setUp(self): """ Create a tracer with running workers, while spying the ``_put()`` method to keep trace of triggered API calls. """ # create a new tracer self.tracer = Tracer() # spy the send() method self.api = self.tracer.writer.api self.api._put = mock.Mock(self.api._put, wraps=self.api._put) def tearDown(self): """ Stop running worker """ self.tracer.writer._worker.stop() def _wait_thread_flush(self): """ Helper that waits for the thread flush """ self.tracer.writer._worker.stop() self.tracer.writer._worker.join() def _get_endpoint_payload(self, calls, endpoint): """ Helper to retrieve the endpoint call from a concurrent trace or service call. """ for call, _ in calls: if endpoint in call[0]: return call[0], self._decode(call[1]) return None, None def test_worker_single_trace(self): # create a trace block and send it using the transport system tracer = self.tracer tracer.trace('client.testing').finish() # one send is expected self._wait_thread_flush() eq_(self.api._put.call_count, 1) # check and retrieve the right call endpoint, payload = self._get_endpoint_payload(self.api._put.call_args_list, '/v0.3/traces') eq_(endpoint, '/v0.3/traces') eq_(len(payload), 1) eq_(len(payload[0]), 1) eq_(payload[0][0]['name'], 'client.testing') def test_worker_multiple_traces(self): # make a single send() if multiple traces are created before the flush interval tracer = self.tracer tracer.trace('client.testing').finish() tracer.trace('client.testing').finish() # one send is expected self._wait_thread_flush() eq_(self.api._put.call_count, 1) # check and retrieve the right call endpoint, payload = self._get_endpoint_payload(self.api._put.call_args_list, '/v0.3/traces') eq_(endpoint, '/v0.3/traces') eq_(len(payload), 2) eq_(len(payload[0]), 1) eq_(len(payload[1]), 1) eq_(payload[0][0]['name'], 'client.testing') eq_(payload[1][0]['name'], 'client.testing') def test_worker_single_trace_multiple_spans(self): # make a single send() if a single trace with multiple spans is created before the flush tracer = self.tracer parent = tracer.trace('client.testing') child = tracer.trace('client.testing').finish() parent.finish() # one send is expected self._wait_thread_flush() eq_(self.api._put.call_count, 1) # check and retrieve the right call endpoint, payload = self._get_endpoint_payload(self.api._put.call_args_list, '/v0.3/traces') eq_(endpoint, '/v0.3/traces') eq_(len(payload), 1) eq_(len(payload[0]), 2) eq_(payload[0][0]['name'], 'client.testing') eq_(payload[0][1]['name'], 'client.testing') def test_worker_single_service(self): # service must be sent correctly tracer = self.tracer tracer.set_service_info('client.service', 'django', 'web') tracer.trace('client.testing').finish() # expect a call for traces and services self._wait_thread_flush() eq_(self.api._put.call_count, 2) # check and retrieve the right call endpoint, payload = self._get_endpoint_payload(self.api._put.call_args_list, '/v0.3/services') eq_(endpoint, '/v0.3/services') eq_(len(payload.keys()), 1) eq_(payload['client.service'], {'app': 'django', 'app_type': 'web'}) def test_worker_service_called_multiple_times(self): # service must be sent correctly tracer = self.tracer tracer.set_service_info('backend', 'django', 'web') tracer.set_service_info('database', 'postgres', 'db') tracer.trace('client.testing').finish() # expect a call for traces and services self._wait_thread_flush() eq_(self.api._put.call_count, 2) # check and retrieve the right call endpoint, payload = self._get_endpoint_payload(self.api._put.call_args_list, '/v0.3/services') eq_(endpoint, '/v0.3/services') eq_(len(payload.keys()), 2) eq_(payload['backend'], {'app': 'django', 'app_type': 'web'}) eq_(payload['database'], {'app': 'postgres', 'app_type': 'db'}) def test_worker_http_error_logging(self): # Tests the logging http error logic tracer = self.tracer self.tracer.writer.api = FlawedAPI(Tracer.DEFAULT_HOSTNAME, Tracer.DEFAULT_PORT) tracer.trace('client.testing').finish() log = logging.getLogger("ddtrace.writer") log_handler = MockedLogHandler(level='DEBUG') log.addHandler(log_handler) # sleeping 1.01 secs to prevent writer from exiting before logging time.sleep(1.01) self._wait_thread_flush() assert tracer.writer._worker._last_error_ts < time.time() logged_errors = log_handler.messages['error'] eq_(len(logged_errors), 1) ok_('failed_to_send traces to Agent: HTTP error status 400, reason Bad Request, message Content-Type:' in logged_errors[0]) def test_worker_filter_request(self): self.tracer.configure(settings={FILTERS_KEY: [FilterRequestsOnUrl(r'http://example\.com/health')]}) # spy the send() method self.api = self.tracer.writer.api self.api._put = mock.Mock(self.api._put, wraps=self.api._put) span = self.tracer.trace('testing.filteredurl') span.set_tag(http.URL, 'http://example.com/health') span.finish() span = self.tracer.trace('testing.nonfilteredurl') span.set_tag(http.URL, 'http://example.com/api/resource') span.finish() self._wait_thread_flush() # Only the second trace should have been sent eq_(self.api._put.call_count, 1) # check and retrieve the right call endpoint, payload = self._get_endpoint_payload(self.api._put.call_args_list, '/v0.3/traces') eq_(endpoint, '/v0.3/traces') eq_(len(payload), 1) eq_(payload[0][0]['name'], 'testing.nonfilteredurl')
class TestWorkers(TestCase): """ Ensures that a workers interacts correctly with the main thread. These are part of integration tests so real calls are triggered. """ def _decode(self, payload): """ Helper function that decodes data based on the given Encoder. """ if isinstance(self.api._encoder, JSONEncoder): return json.loads(payload) elif isinstance(self.api._encoder, MsgpackEncoder): return msgpack.unpackb(payload, encoding='utf-8') def setUp(self): """ Create a tracer with running workers, while spying the ``_put()`` method to keep trace of triggered API calls. """ # create a new tracer self.tracer = Tracer() # spy the send() method self.api = self.tracer.writer.api self.api._put = mock.Mock(self.api._put, wraps=self.api._put) def tearDown(self): """ Stop running worker """ self.tracer.writer._worker.stop() def _wait_thread_flush(self): """ Helper that waits for the thread flush """ self.tracer.writer._worker.stop() self.tracer.writer._worker.join() def _get_endpoint_payload(self, calls, endpoint): """ Helper to retrieve the endpoint call from a concurrent trace or service call. """ for call, _ in calls: if endpoint in call[0]: return call[0], self._decode(call[1]) return None, None def test_worker_single_trace(self): # create a trace block and send it using the transport system tracer = self.tracer tracer.trace('client.testing').finish() # one send is expected self._wait_thread_flush() eq_(self.api._put.call_count, 1) # check and retrieve the right call endpoint, payload = self._get_endpoint_payload( self.api._put.call_args_list, '/v0.3/traces') eq_(endpoint, '/v0.3/traces') eq_(len(payload), 1) eq_(len(payload[0]), 1) eq_(payload[0][0]['name'], 'client.testing') # DEV: If we can make the writer flushing deterministic for the case of tests, then we can re-enable this @skip( 'Writer flush intervals are impossible to time correctly to make this test not flaky' ) def test_worker_multiple_traces(self): # make a single send() if multiple traces are created before the flush interval tracer = self.tracer tracer.trace('client.testing').finish() tracer.trace('client.testing').finish() # one send is expected self._wait_thread_flush() eq_(self.api._put.call_count, 1) # check and retrieve the right call endpoint, payload = self._get_endpoint_payload( self.api._put.call_args_list, '/v0.3/traces') eq_(endpoint, '/v0.3/traces') eq_(len(payload), 2) eq_(len(payload[0]), 1) eq_(len(payload[1]), 1) eq_(payload[0][0]['name'], 'client.testing') eq_(payload[1][0]['name'], 'client.testing') def test_worker_single_trace_multiple_spans(self): # make a single send() if a single trace with multiple spans is created before the flush tracer = self.tracer parent = tracer.trace('client.testing') child = tracer.trace('client.testing').finish() parent.finish() # one send is expected self._wait_thread_flush() eq_(self.api._put.call_count, 1) # check and retrieve the right call endpoint, payload = self._get_endpoint_payload( self.api._put.call_args_list, '/v0.3/traces') eq_(endpoint, '/v0.3/traces') eq_(len(payload), 1) eq_(len(payload[0]), 2) eq_(payload[0][0]['name'], 'client.testing') eq_(payload[0][1]['name'], 'client.testing') def test_worker_single_service(self): # service must be sent correctly tracer = self.tracer tracer.set_service_info('client.service', 'django', 'web') tracer.trace('client.testing').finish() # expect a call for traces and services self._wait_thread_flush() eq_(self.api._put.call_count, 2) # check and retrieve the right call endpoint, payload = self._get_endpoint_payload( self.api._put.call_args_list, '/v0.3/services') eq_(endpoint, '/v0.3/services') eq_(len(payload.keys()), 1) eq_(payload['client.service'], {'app': 'django', 'app_type': 'web'}) def test_worker_service_called_multiple_times(self): # service must be sent correctly tracer = self.tracer tracer.set_service_info('backend', 'django', 'web') tracer.set_service_info('database', 'postgres', 'db') tracer.trace('client.testing').finish() # expect a call for traces and services self._wait_thread_flush() eq_(self.api._put.call_count, 2) # check and retrieve the right call endpoint, payload = self._get_endpoint_payload( self.api._put.call_args_list, '/v0.3/services') eq_(endpoint, '/v0.3/services') eq_(len(payload.keys()), 2) eq_(payload['backend'], {'app': 'django', 'app_type': 'web'}) eq_(payload['database'], {'app': 'postgres', 'app_type': 'db'}) def test_worker_http_error_logging(self): # Tests the logging http error logic tracer = self.tracer self.tracer.writer.api = FlawedAPI(Tracer.DEFAULT_HOSTNAME, Tracer.DEFAULT_PORT) tracer.trace('client.testing').finish() log = logging.getLogger("ddtrace.writer") log_handler = MockedLogHandler(level='DEBUG') log.addHandler(log_handler) # sleeping 1.01 secs to prevent writer from exiting before logging time.sleep(1.01) self._wait_thread_flush() assert tracer.writer._worker._last_error_ts < time.time() logged_errors = log_handler.messages['error'] eq_(len(logged_errors), 1) ok_('failed_to_send traces to Agent: HTTP error status 400, reason Bad Request, message Content-Type:' in logged_errors[0]) def test_worker_filter_request(self): self.tracer.configure(settings={ FILTERS_KEY: [FilterRequestsOnUrl(r'http://example\.com/health')] }) # spy the send() method self.api = self.tracer.writer.api self.api._put = mock.Mock(self.api._put, wraps=self.api._put) span = self.tracer.trace('testing.filteredurl') span.set_tag(http.URL, 'http://example.com/health') span.finish() span = self.tracer.trace('testing.nonfilteredurl') span.set_tag(http.URL, 'http://example.com/api/resource') span.finish() self._wait_thread_flush() # Only the second trace should have been sent eq_(self.api._put.call_count, 1) # check and retrieve the right call endpoint, payload = self._get_endpoint_payload( self.api._put.call_args_list, '/v0.3/traces') eq_(endpoint, '/v0.3/traces') eq_(len(payload), 1) eq_(payload[0][0]['name'], 'testing.nonfilteredurl')
class TestWorkers(TestCase): """ Ensures that a workers interacts correctly with the main thread. These are part of integration tests so real calls are triggered. """ def setUp(self): """ Create a tracer with running workers, while spying the ``_put()`` method to keep trace of triggered API calls. """ # create a new tracer self.tracer = Tracer() # spy the send() method self.api = self.tracer.writer.api self.api._put = mock.Mock(self.api._put, wraps=self.api._put) def tearDown(self): """ Stop running worker """ self._wait_thread_flush() def _wait_thread_flush(self): """ Helper that waits for the thread flush """ self.tracer.writer.flush_queue() self.tracer.writer.stop() self.tracer.writer.join(None) def _get_endpoint_payload(self, calls, endpoint): """ Helper to retrieve the endpoint call from a concurrent trace or service call. """ for call, _ in calls: if endpoint in call[0]: return call[0], self.api._encoder._decode(call[1]) return None, None @pytest.mark.skipif(AGENT_VERSION == "v5" or AGENT_VERSION == "testagent", reason="Agent doesn't support UDS") def test_worker_single_trace_uds(self): self.tracer.configure(uds_path="/tmp/ddagent/trace.sock") # Write a first trace so we get a _worker self.tracer.trace("client.testing").finish() worker = self.tracer.writer worker._log_error_status = mock.Mock( worker._log_error_status, wraps=worker._log_error_status, ) self.tracer.trace("client.testing").finish() # one send is expected self._wait_thread_flush() # Check that no error was logged assert worker._log_error_status.call_count == 0 def test_worker_single_trace_uds_wrong_socket_path(self): self.tracer.configure(uds_path="/tmp/ddagent/nosockethere") # Write a first trace so we get a _worker self.tracer.trace("client.testing").finish() worker = self.tracer.writer worker._log_error_status = mock.Mock( worker._log_error_status, wraps=worker._log_error_status, ) self.tracer.trace("client.testing").finish() # one send is expected self._wait_thread_flush() # Check that no error was logged assert worker._log_error_status.call_count == 1 def test_worker_single_trace(self): # create a trace block and send it using the transport system tracer = self.tracer tracer.trace("client.testing").finish() # one send is expected self._wait_thread_flush() assert self.api._put.call_count == 1 # check and retrieve the right call endpoint, payload = self._get_endpoint_payload( self.api._put.call_args_list, "/v0.4/traces") assert endpoint == "/v0.4/traces" assert len(payload) == 1 assert len(payload[0]) == 1 assert payload[0][0][b"name"] == b"client.testing" # DEV: If we can make the writer flushing deterministic for the case of tests, then we can re-enable this @skip( "Writer flush intervals are impossible to time correctly to make this test not flaky" ) def test_worker_multiple_traces(self): # make a single send() if multiple traces are created before the flush interval tracer = self.tracer tracer.trace("client.testing").finish() tracer.trace("client.testing").finish() # one send is expected self._wait_thread_flush() assert self.api._put.call_count == 1 # check and retrieve the right call endpoint, payload = self._get_endpoint_payload( self.api._put.call_args_list, "/v0.4/traces") assert endpoint == "/v0.4/traces" assert len(payload) == 2 assert len(payload[0]) == 1 assert len(payload[1]) == 1 assert payload[0][0][b"name"] == b"client.testing" assert payload[1][0][b"name"] == b"client.testing" def test_worker_single_trace_multiple_spans(self): # make a single send() if a single trace with multiple spans is created before the flush tracer = self.tracer parent = tracer.trace("client.testing") tracer.trace("client.testing").finish() parent.finish() # one send is expected self._wait_thread_flush() assert self.api._put.call_count == 1 # check and retrieve the right call endpoint, payload = self._get_endpoint_payload( self.api._put.call_args_list, "/v0.4/traces") assert endpoint == "/v0.4/traces" assert len(payload) == 1 assert len(payload[0]) == 2 assert payload[0][0][b"name"] == b"client.testing" assert payload[0][1][b"name"] == b"client.testing" @pytest.mark.skipif(AGENT_VERSION == "testagent", reason="Test agent doesn't support json API.") def test_worker_http_error_logging(self): # Tests the logging http error logic tracer = self.tracer self.tracer.writer.api = FlawedAPI(Tracer.DEFAULT_HOSTNAME, Tracer.DEFAULT_PORT) tracer.trace("client.testing").finish() log = logging.getLogger("ddtrace.internal.writer") log_handler = MockedLogHandler(level="DEBUG") log.addHandler(log_handler) self._wait_thread_flush() assert tracer.writer._last_error_ts < monotonic() logged_errors = log_handler.messages["error"] assert len(logged_errors) == 1 assert ( "Failed to send traces to Datadog Agent at http://localhost:8126: " "HTTP error status 400, reason Bad Request, message Content-Type:" in logged_errors[0]) def test_worker_filter_request(self): self.tracer.configure(settings={ FILTERS_KEY: [FilterRequestsOnUrl(r"http://example\.com/health")] }) # spy the send() method span = self.tracer.trace("testing.filteredurl") span.set_tag(http.URL, "http://example.com/health") span.finish() span = self.tracer.trace("testing.nonfilteredurl") span.set_tag(http.URL, "http://example.com/api/resource") span.finish() self._wait_thread_flush() # Only the second trace should have been sent assert self.api._put.call_count == 1 # check and retrieve the right call endpoint, payload = self._get_endpoint_payload( self.api._put.call_args_list, "/v0.4/traces") assert endpoint == "/v0.4/traces" assert len(payload) == 1 assert payload[0][0][b"name"] == b"testing.nonfilteredurl"
import ddtrace.filters from ddtrace.tracer import Tracer tracer = Tracer() tracer.configure( settings={"FILTERS": [ddtrace.filters.FilterRequestsOnUrl(r".+/-/health/$"),],} )