Skip to content

Commit 5558268

Browse files
author
Emanuele Palazzetti
authored
Merge pull request #434 from palazzem/requests-split
[requests] use the domain name as a service name
2 parents 4da1073 + 8d86d7c commit 5558268

File tree

4 files changed

+59
-7
lines changed

4 files changed

+59
-7
lines changed

ddtrace/compat.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
from io import StringIO
2727

2828
try:
29-
import urlparse
29+
import urlparse as parse
3030
except ImportError:
31-
from urllib import parse as urlparse
31+
from urllib import parse
3232

3333
try:
3434
from asyncio import iscoroutinefunction
@@ -88,5 +88,5 @@ def to_unicode(s):
8888
'stringify',
8989
'StringIO',
9090
'urlencode',
91-
'urlparse',
91+
'parse',
9292
]

ddtrace/contrib/requests/connection.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,32 @@
66
from .constants import DEFAULT_SERVICE
77

88
from ...ext import http
9+
from ...compat import parse
910
from ...propagation.http import HTTPPropagator
1011

1112

1213
log = logging.getLogger(__name__)
1314

1415

15-
def _extract_service_name(session, span):
16+
def _extract_service_name(session, span, netloc=None):
1617
"""Extracts the right service name based on the following logic:
1718
- `requests` is the default service name
1819
- users can change it via `session.service_name = 'clients'`
1920
- if the Span doesn't have a parent, use the set service name
2021
or fallback to the default
2122
- if the Span has a parent, use the set service name or the
2223
parent service value if the set service name is the default
24+
- if `split_by_domain` is used, always override users settings
25+
and use the network location as a service name
2326
2427
The priority can be represented as:
2528
Updated service name > parent service name > default to `requests`.
2629
"""
27-
service_name = config.get_from(session)['service_name']
30+
cfg = config.get_from(session)
31+
if cfg['split_by_domain'] and netloc:
32+
return netloc
33+
34+
service_name = cfg['service_name']
2835
if (service_name == DEFAULT_SERVICE and
2936
span._parent is not None and
3037
span._parent.service is not None):
@@ -47,10 +54,11 @@ def _wrap_request(func, instance, args, kwargs):
4754
method = kwargs.get('method') or args[0]
4855
url = kwargs.get('url') or args[1]
4956
headers = kwargs.get('headers', {})
57+
parsed_uri = parse.urlparse(url)
5058

5159
with tracer.trace("requests.request", span_type=http.TYPE) as span:
5260
# update the span service name before doing any action
53-
span.service = _extract_service_name(instance, span)
61+
span.service = _extract_service_name(instance, span, netloc=parsed_uri.netloc)
5462

5563
# propagate distributed tracing headers
5664
if config.get_from(instance).get('distributed_tracing'):

ddtrace/contrib/requests/patch.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
config._add('requests',{
1717
'service_name': get_env('requests', 'service_name', DEFAULT_SERVICE),
1818
'distributed_tracing': asbool(get_env('requests', 'distributed_tracing', False)),
19+
'split_by_domain': asbool(get_env('requests', 'split_by_domain', False)),
1920
})
2021

2122

tests/contrib/requests/test_requests.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
import requests
33

44
from requests import Session
5-
from nose.tools import eq_
5+
from requests.exceptions import MissingSchema
6+
from nose.tools import eq_, assert_raises
67

78
from ddtrace import config
89
from ddtrace.ext import http, errors
@@ -225,3 +226,45 @@ def test_user_service_name_precedence(self):
225226

226227
eq_(s.name, 'requests.request')
227228
eq_(s.service, 'clients')
229+
230+
def test_split_by_domain(self):
231+
# ensure a service name is generated by the domain name
232+
# of the ongoing call
233+
cfg = config.get_from(self.session)
234+
cfg['split_by_domain'] = True
235+
out = self.session.get(URL_200)
236+
eq_(out.status_code, 200)
237+
238+
spans = self.tracer.writer.pop()
239+
eq_(len(spans), 1)
240+
s = spans[0]
241+
242+
eq_(s.service, 'httpbin.org')
243+
244+
def test_split_by_domain_precedence(self):
245+
# ensure the split by domain has precedence all the time
246+
cfg = config.get_from(self.session)
247+
cfg['split_by_domain'] = True
248+
cfg['service_name'] = 'intake'
249+
out = self.session.get(URL_200)
250+
eq_(out.status_code, 200)
251+
252+
spans = self.tracer.writer.pop()
253+
eq_(len(spans), 1)
254+
s = spans[0]
255+
256+
eq_(s.service, 'httpbin.org')
257+
258+
def test_split_by_domain_wrong(self):
259+
# ensure the split by domain doesn't crash in case of a wrong URL;
260+
# in that case, the default service name must be used
261+
cfg = config.get_from(self.session)
262+
cfg['split_by_domain'] = True
263+
with assert_raises(MissingSchema):
264+
self.session.get('http:/some>thing')
265+
266+
spans = self.tracer.writer.pop()
267+
eq_(len(spans), 1)
268+
s = spans[0]
269+
270+
eq_(s.service, 'requests')

0 commit comments

Comments
 (0)