Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions ddtrace/contrib/elasticsearch/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ def perform_request(self, method, url, params=None, body=None):
_, data = result
took = data.get("took")
if took:
# TODO: move that to a metric instead
s.set_tag(metadata.TOOK, took)
s.set_metric(metadata.TOOK, int(took))

return result

Expand Down
2 changes: 1 addition & 1 deletion ddtrace/contrib/psycopg/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def execute(self, query, vars=None):
try:
return super(TracedCursor, self).execute(query, vars)
finally:
s.set_tag("db.rowcount", self.rowcount)
s.set_metric("db.rowcount", self.rowcount)

def callproc(self, procname, vars=None):
""" just wrap the execution in a span """
Expand Down
11 changes: 4 additions & 7 deletions ddtrace/contrib/redis/tracers.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,8 @@ def execute(self, *args, **kwargs):

s.set_tags(_extract_conn_tags(self.connection_pool.connection_kwargs))
s.set_tags(self._datadog_meta)
# FIXME[leo]: convert to metric?
s.set_tag(redisx.PIPELINE_LEN, len(self.command_stack))
s.set_tag(redisx.PIPELINE_AGE, time.time()-self._datadog_pipeline_creation)
s.set_metric(redisx.PIPELINE_LEN, len(self.command_stack))
s.set_metric(redisx.PIPELINE_AGE, time.time()-self._datadog_pipeline_creation)

return super(TracedPipeline, self).execute(self, *args, **kwargs)

Expand All @@ -84,8 +83,7 @@ def immediate_execute_command(self, *args, **kwargs):

s.set_tags(_extract_conn_tags(self.connection_pool.connection_kwargs))
s.set_tags(self._datadog_meta)
# FIXME[leo]: convert to metric?
s.set_tag(redisx.ARGS_LEN, len(args))
s.set_metric(redisx.ARGS_LEN, len(args))

s.set_tag(redisx.IMMEDIATE_PIPELINE, True)

Expand Down Expand Up @@ -113,8 +111,7 @@ def execute_command(self, *args, **options):

s.set_tags(_extract_conn_tags(self.connection_pool.connection_kwargs))
s.set_tags(self._datadog_meta)
# FIXME[leo]: convert to metric?
s.set_tag(redisx.ARGS_LEN, len(args))
s.set_metric(redisx.ARGS_LEN, len(args))

return super(TracedRedis, self).execute_command(*args, **options)

Expand Down
18 changes: 17 additions & 1 deletion ddtrace/span.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import numbers
import random
import sys
import time
Expand Down Expand Up @@ -89,7 +90,7 @@ def set_tag(self, key, value):
try:
self.meta[key] = stringify(value)
except Exception:
log.warning("error setting tag. ignoring", exc_info=True)
log.warning("error setting tag %s, ignoring it", key, exc_info=True)

def get_tag(self, key):
""" Return the given tag or None if it doesn't exist.
Expand All @@ -110,6 +111,18 @@ def set_meta(self, k, v):
def set_metas(self, kvs):
self.set_tags(kvs)

def set_metric(self, key, value):
try:
# If the value isn't a typed as a number (ex: a string), try to cast it
if not isinstance(value, numbers.Number):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a failing test set_metric("a", "b") or something

value = float(value)
self.metrics[key] = value
except Exception:
log.warning("error setting metric %s, ignoring it", key, exc_info=True)

def get_metric(self, key):
return self.metrics.get(key)

def to_dict(self):
d = {
'trace_id' : self.trace_id,
Expand All @@ -131,6 +144,9 @@ def to_dict(self):
if self.meta:
d['meta'] = self.meta

if self.metrics:
d['metrics'] = self.metrics

if self.span_type:
d['type'] = self.span_type

Expand Down
3 changes: 1 addition & 2 deletions tests/contrib/elasticsearch/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,4 @@ def test_elasticsearch(self):
eq_(span.get_tag(metadata.BODY).replace(" ", ""), '{"query":{"match_all":{}}}')
eq_(set(span.get_tag(metadata.PARAMS).split('&')), {'sort=name%3Adesc', 'size=100'})

self.assertTrue(int(span.get_tag(metadata.TOOK)) > 0)

self.assertTrue(span.get_metric(metadata.TOOK) > 0)
16 changes: 11 additions & 5 deletions tests/contrib/redis/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,18 @@ def test_basic_class(self):
eq_(span.name, 'redis.command')
eq_(span.span_type, 'redis')
eq_(span.error, 0)
eq_(span.meta, {'out.host': u'localhost', 'redis.raw_command': u'GET cheese', 'out.port': u'6379', 'redis.args_length': u'2', 'out.redis_db': u'0'})
eq_(span.meta, {
'out.host': u'localhost',
'redis.raw_command': u'GET cheese',
'out.port': u'6379',
'out.redis_db': u'0',
})
eq_(span.get_metric('redis.args_length'), 2)
eq_(span.resource, 'GET cheese')

services = writer.pop_services()
expected = {
self.SERVICE: {"app":"redis", "app_type":"db"}
self.SERVICE: {"app": "redis", "app_type": "db"}
}
eq_(services, expected)

Expand Down Expand Up @@ -88,15 +94,15 @@ def test_basic_class_pipeline(self):
span = spans[0]
eq_(span.service, self.SERVICE)
eq_(span.name, 'redis.pipeline')
eq_(span.resource, u'SET blah 32\nRPUSH foo éé\nHGETALL xxx')
eq_(span.span_type, 'redis')
eq_(span.error, 0)
eq_(span.get_tag('out.redis_db'), '0')
eq_(span.get_tag('out.host'), 'localhost')
ok_(float(span.get_tag('redis.pipeline_age')) > 0)
eq_(span.get_tag('redis.pipeline_length'), '3')
eq_(span.get_tag('out.port'), '6379')
eq_(span.resource, u'SET blah 32\nRPUSH foo éé\nHGETALL xxx')
eq_(span.get_tag('redis.raw_command'), u'SET blah 32\nRPUSH foo éé\nHGETALL xxx')
ok_(span.get_metric('redis.pipeline_age') > 0)
eq_(span.get_metric('redis.pipeline_length'), 3)

def test_custom_class(self):
class MyCustomRedis(redis.Redis):
Expand Down
26 changes: 26 additions & 0 deletions tests/test_span.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,32 @@ def test_tags():
}
eq_(d["meta"], expected)

def test_set_valid_metrics():
s = Span(tracer=None, name="foo")
s.set_metric("a", 0)
s.set_metric("b", -12)
s.set_metric("c", 12.134)
s.set_metric("d", 1231543543265475686787869123)
s.set_metric("e", "12.34")
d = s.to_dict()
expected = {
"a": 0,
"b": -12,
"c": 12.134,
"d": 1231543543265475686787869123,
"e": 12.34,
}
eq_(d["metrics"], expected)


def test_set_invalid_metric():
s = Span(tracer=None, name="foo")

# Set an invalid metric: shouldn't crash nor set any value
s.set_metric("a", "forty-twelve")

eq_(s.get_metric("a"), None)

def test_tags_not_string():
# ensure we can cast as strings
class Foo(object):
Expand Down