Skip to content

Commit 0cebf74

Browse files
authored
Improved Tag Validation & Reporting (#247)
* Use repr instead of str * Add tests for sets and more json tests * Use six for type checking * Use regexp to validate set strings * Remove redundant escape
1 parent d97910e commit 0cebf74

File tree

3 files changed

+53
-20
lines changed

3 files changed

+53
-20
lines changed

instana/span.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,11 @@
1+
import six
12
import sys
23
from .log import logger
34
from .util import DictionaryOfStan
45
from basictracer.span import BasicSpan
56
import opentracing.ext.tags as ot_tags
67

78

8-
PY3 = sys.version_info[0] == 3
9-
10-
if PY3:
11-
string_type = str
12-
else:
13-
string_type = basestring
14-
15-
169
class SpanContext():
1710
def __init__(
1811
self,
@@ -49,22 +42,32 @@ def finish(self, finish_time=None):
4942
super(InstanaSpan, self).finish(finish_time)
5043

5144
def set_tag(self, key, value):
52-
if not isinstance(key, string_type):
45+
# Key validation
46+
if not isinstance(key, six.text_type) and not isinstance(key, six.string_types) :
5347
logger.debug("(non-fatal) span.set_tag: tag names must be strings. tag discarded for %s", type(key))
5448
return self
5549

5650
final_value = value
5751
value_type = type(value)
58-
if value_type not in [bool, float, int, list, str]:
52+
53+
# Value validation
54+
if value_type in [bool, float, int, list, str]:
55+
return super(InstanaSpan, self).set_tag(key, final_value)
56+
57+
elif isinstance(value, six.text_type):
58+
final_value = str(value)
59+
60+
else:
5961
try:
60-
final_value = str(value)
62+
final_value = repr(value)
6163
except:
62-
final_value = "(non-fatal) span.set_tag: values must be one of these types: bool, float, int, list or str. tag discarded"
64+
final_value = "(non-fatal) span.set_tag: values must be one of these types: bool, float, int, list, " \
65+
"set, str or alternatively support 'repr'. tag discarded"
6366
logger.debug(final_value, exc_info=True)
67+
return self
6468

6569
return super(InstanaSpan, self).set_tag(key, final_value)
6670

67-
6871
def mark_as_errored(self, tags = None):
6972
"""
7073
Mark this span as errored.

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def check_setuptools():
5757
'fysom>=2.1.2',
5858
'opentracing>=2.0.0',
5959
'requests>=2.8.0',
60+
'six>=1.12.0',
6061
'urllib3>=1.18.1'],
6162
entry_points={
6263
'instana': ['string = instana:load'],

tests/opentracing/test_ot_span.py

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1+
import re
2+
import sys
3+
import json
14
import time
25
import unittest
36
import opentracing
47
from uuid import UUID
58
from instana.util import to_json
69
from instana.singletons import tracer
710

11+
PY2 = sys.version_info[0] == 2
12+
PY3 = sys.version_info[0] == 3
813

914
class TestOTSpan(unittest.TestCase):
1015
def setUp(self):
@@ -146,7 +151,7 @@ def test_span_kind(self):
146151
span = spans[4]
147152
self.assertEqual(3, span.k)
148153

149-
def test_bad_tag_values(self):
154+
def test_tag_values(self):
150155
with tracer.start_active_span('test') as scope:
151156
# Set a UUID class as a tag
152157
# If unchecked, this causes a json.dumps error: "ValueError: Circular reference detected"
@@ -155,33 +160,57 @@ def test_bad_tag_values(self):
155160
scope.span.set_tag('tracer', tracer)
156161
scope.span.set_tag('none', None)
157162
scope.span.set_tag('mylist', [1, 2, 3])
158-
163+
scope.span.set_tag('myset', {"one", 2})
159164

160165
spans = tracer.recorder.queued_spans()
161166
assert len(spans) == 1
162167

163168
test_span = spans[0]
164169
assert(test_span)
165-
assert(len(test_span.data['sdk']['custom']['tags']) == 4)
166-
assert(test_span.data['sdk']['custom']['tags']['uuid'] == '12345678-1234-5678-1234-567812345678')
170+
assert(len(test_span.data['sdk']['custom']['tags']) == 5)
171+
assert(test_span.data['sdk']['custom']['tags']['uuid'] == "UUID('12345678-1234-5678-1234-567812345678')")
167172
assert(test_span.data['sdk']['custom']['tags']['tracer'])
168173
assert(test_span.data['sdk']['custom']['tags']['none'] == 'None')
169174
assert(test_span.data['sdk']['custom']['tags']['mylist'] == [1, 2, 3])
170-
175+
if PY2:
176+
set_regexp = re.compile(r"set\(\[.*,.*\]\)")
177+
assert(set_regexp.search(test_span.data['sdk']['custom']['tags']['myset']))
178+
else:
179+
set_regexp = re.compile(r"\{.*,.*\}")
180+
assert(set_regexp.search(test_span.data['sdk']['custom']['tags']['myset']))
181+
182+
# Convert to JSON
171183
json_data = to_json(test_span)
172184
assert(json_data)
173185

174-
def test_bad_tag_names(self):
186+
# And back
187+
span_dict = json.loads(json_data)
188+
assert(len(span_dict['data']['sdk']['custom']['tags']) == 5)
189+
assert(span_dict['data']['sdk']['custom']['tags']['uuid'] == "UUID('12345678-1234-5678-1234-567812345678')")
190+
assert(span_dict['data']['sdk']['custom']['tags']['tracer'])
191+
assert(span_dict['data']['sdk']['custom']['tags']['none'] == 'None')
192+
assert(span_dict['data']['sdk']['custom']['tags']['mylist'] == [1, 2, 3])
193+
if PY2:
194+
set_regexp = re.compile(r"set\(\[.*,.*\]\)")
195+
assert(set_regexp.search(test_span.data['sdk']['custom']['tags']['myset']))
196+
else:
197+
set_regexp = re.compile(r"{.*,.*}")
198+
assert(set_regexp.search(test_span.data['sdk']['custom']['tags']['myset']))
199+
200+
def test_tag_names(self):
175201
with tracer.start_active_span('test') as scope:
176202
# Tag names (keys) must be strings
177203
scope.span.set_tag(1234567890, 'This should not get set')
204+
# Unicode key name
205+
scope.span.set_tag(u'asdf', 'This should be ok')
178206

179207
spans = tracer.recorder.queued_spans()
180208
assert len(spans) == 1
181209

182210
test_span = spans[0]
183211
assert(test_span)
184-
assert(len(test_span.data['sdk']['custom']['tags']) == 0)
212+
assert(len(test_span.data['sdk']['custom']['tags']) == 1)
213+
assert(test_span.data['sdk']['custom']['tags']['asdf'] == 'This should be ok')
185214

186215
json_data = to_json(test_span)
187216
assert(json_data)

0 commit comments

Comments
 (0)