Skip to content

Commit 54e28f6

Browse files
authored
Merge pull request #91 from DataDog/matt/services
Matt/services
2 parents eb905fe + dd62176 commit 54e28f6

File tree

5 files changed

+50
-28
lines changed

5 files changed

+50
-28
lines changed

ddtrace/api.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,21 @@ def send_traces(self, traces):
2323
self.send_spans(spans)
2424

2525
def send_spans(self, spans):
26+
if not spans:
27+
return
2628
start = time.time()
2729
data = ddtrace.encoding.encode_spans(spans)
2830
self._send_span_data(data)
2931
log.debug("reported %d spans in %.5fs", len(spans), time.time() - start)
3032

3133
def send_services(self, services):
34+
if not services:
35+
return
3236
log.debug("Reporting %d services", len(services))
33-
data = ddtrace.encoding.encode_services(services)
37+
s = {}
38+
for service in services:
39+
s.update(service)
40+
data = ddtrace.encoding.encode_services(s)
3441
self._put("/services", data, self.headers)
3542

3643
def _send_span_data(self, data):

ddtrace/tracer.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ def __init__(self):
4646
# in production.
4747
self.debug_logging = False
4848

49+
# a buffer for service info so we dont' perpetually send the same
50+
# things.
51+
self._services = {}
52+
4953
def configure(self, enabled=None, hostname=None, port=None, sampler=None):
5054
"""Configure an existing Tracer the easy way.
5155
@@ -169,20 +173,28 @@ def set_service_info(self, service, app, app_type):
169173
:param str app: the off the shelf name of the application (e.g. rails, postgres, custom-app)
170174
:param str app_type: the type of the application (e.g. db, web)
171175
"""
172-
173-
services = {
174-
service : {
175-
"app" : app,
176-
"app_type": app_type,
177-
}
178-
}
179-
180-
if self.debug_logging:
181-
log.debug("set_service_info: service:%s app:%s type:%s",
182-
service, app, app_type)
183-
184-
if self.enabled and self.writer:
185-
self.writer.write(services=services)
176+
try:
177+
# don't bother sending the same services over and over.
178+
info = (service, app, app_type)
179+
if self._services.get(service, None) == info:
180+
return
181+
self._services[service] = info
182+
183+
if self.debug_logging:
184+
log.debug("set_service_info: service:%s app:%s type:%s", service, app, app_type)
185+
186+
# If we had changes, send them to the writer.
187+
if self.enabled and self.writer:
188+
189+
# translate to the form the server understands.
190+
services = {}
191+
for service, app, app_type in self._services.values():
192+
services[service] = {"app" : app, "app_type" : app_type}
193+
194+
# queue them for writes.
195+
self.writer.write(services=services)
196+
except Exception:
197+
log.exception("error setting service info")
186198

187199
def wrap(self, name=None, service=None, resource=None, span_type=None):
188200
"""A decorator used to trace an entire function.

tests/test_compat.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,48 +12,49 @@
1212
# results for each Python version rather than writing a generic "works for both" test suite
1313
if PY2:
1414
class TestCompatPY2(object):
15+
1516
def test_to_unicode_string(self):
16-
""" Calling `compat.to_unicode` on a non-unicode string """
17+
# Calling `compat.to_unicode` on a non-unicode string
1718
res = to_unicode('test')
1819
eq_(type(res), unicode)
1920
eq_(res, 'test')
2021

2122
def test_to_unicode_unicode_encoded(self):
22-
""" Calling `compat.to_unicode` on a unicode encoded string """
23+
# Calling `compat.to_unicode` on a unicode encoded string
2324
res = to_unicode('\xc3\xbf')
2425
eq_(type(res), unicode)
2526
eq_(res, u'ÿ')
2627

2728
def test_to_unicode_unicode_double_decode(self):
28-
""" Calling `compat.to_unicode` on a unicode decoded string """
29+
# Calling `compat.to_unicode` on a unicode decoded string
2930
# This represents the double-decode issue, which can cause a `UnicodeEncodeError`
3031
# `'\xc3\xbf'.decode('utf-8').decode('utf-8')`
3132
res = to_unicode('\xc3\xbf'.decode('utf-8'))
3233
eq_(type(res), unicode)
3334
eq_(res, u'ÿ')
3435

3536
def test_to_unicode_unicode_string(self):
36-
""" Calling `compat.to_unicode` on a unicode string """
37+
# Calling `compat.to_unicode` on a unicode string
3738
res = to_unicode(u'ÿ')
3839
eq_(type(res), unicode)
3940
eq_(res, u'ÿ')
4041

4142
def test_to_unicode_bytearray(self):
42-
""" Calling `compat.to_unicode` with a `bytearray` containing unicode """
43+
# Calling `compat.to_unicode` with a `bytearray` containing unicode
4344
res = to_unicode(bytearray('\xc3\xbf'))
4445
eq_(type(res), unicode)
4546
eq_(res, u'ÿ')
4647

4748
def test_to_unicode_bytearray_double_decode(self):
48-
""" Calling `compat.to_unicode` with an already decoded `bytearray` """
49+
# Calling `compat.to_unicode` with an already decoded `bytearray`
4950
# This represents the double-decode issue, which can cause a `UnicodeEncodeError`
5051
# `bytearray('\xc3\xbf').decode('utf-8').decode('utf-8')`
5152
res = to_unicode(bytearray('\xc3\xbf').decode('utf-8'))
5253
eq_(type(res), unicode)
5354
eq_(res, u'ÿ')
5455

5556
def test_to_unicode_non_string(self):
56-
""" Calling `compat.to_unicode` on non-string types """
57+
# Calling `compat.to_unicode` on non-string types
5758
eq_(to_unicode(1), u'1')
5859
eq_(to_unicode(True), u'True')
5960
eq_(to_unicode(None), u'None')
@@ -62,31 +63,31 @@ def test_to_unicode_non_string(self):
6263
else:
6364
class TestCompatPY3(object):
6465
def test_to_unicode_string(self):
65-
""" Calling `compat.to_unicode` on a non-unicode string """
66+
# Calling `compat.to_unicode` on a non-unicode string
6667
res = to_unicode('test')
6768
eq_(type(res), str)
6869
eq_(res, 'test')
6970

7071
def test_to_unicode_unicode_encoded(self):
71-
""" Calling `compat.to_unicode` on a unicode encoded string """
72+
# Calling `compat.to_unicode` on a unicode encoded string
7273
res = to_unicode('\xff')
7374
eq_(type(res), str)
7475
eq_(res, 'ÿ')
7576

7677
def test_to_unicode_unicode_string(self):
77-
""" Calling `compat.to_unicode` on a unicode string """
78+
# Calling `compat.to_unicode` on a unicode string
7879
res = to_unicode('ÿ')
7980
eq_(type(res), str)
8081
eq_(res, 'ÿ')
8182

8283
def test_to_unicode_bytearray(self):
83-
""" Calling `compat.to_unicode` with a `bytearray` containing unicode """
84+
# Calling `compat.to_unicode` with a `bytearray` containing unicode """
8485
res = to_unicode(bytearray('\xff', 'utf-8'))
8586
eq_(type(res), str)
8687
eq_(res, 'ÿ')
8788

8889
def test_to_unicode_non_string(self):
89-
""" Calling `compat.to_unicode` on non-string types """
90+
# Calling `compat.to_unicode` on non-string types
9091
eq_(to_unicode(1), '1')
9192
eq_(to_unicode(True), 'True')
9293
eq_(to_unicode(None), 'None')

tests/test_sampler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def test_concurrency(self):
117117
tracer = Tracer()
118118
tracer.writer = writer
119119

120-
total_time = 10
120+
total_time = 3
121121
concurrency = 100
122122
end_time = time.time() + total_time
123123

tox.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ envlist =
2121
{py27,py34}-pymongo{30,31,32,33}-mongoengine
2222
{py27,py34}-requests{208,209,210,211}
2323
{py27,py34}-sqlalchemy{10,11}-psycopg2
24+
{py27,py34}-redis
2425
{py27,py34}-all
2526

2627
[testenv]
@@ -103,6 +104,7 @@ commands =
103104
{py27,py34}-pymongo{30,31,32,33}: nosetests {posargs} tests/contrib/pymongo/
104105
{py27,py34}-mongoengine: nosetests {posargs} tests/contrib/mongoengine
105106
{py27,py34}-psycopg2: nosetests {posargs} tests/contrib/psycopg
107+
{py27,py34}-redis: nosetests {posargs} tests/contrib/redis
106108
{py27,py34}-requests{200,208,209,210,211}: nosetests {posargs} tests/contrib/requests
107109
{py27,py34}-sqlalchemy{10,11}: nosetests {posargs} tests/contrib/sqlalchemy
108110

0 commit comments

Comments
 (0)