Skip to content
This repository was archived by the owner on Sep 17, 2025. It is now read-only.

Commit 186c931

Browse files
wkiserliyanhui1228
authored andcommitted
Update span ids to be 16 char hex strings (#147)
1 parent 471939e commit 186c931

19 files changed

+244
-261
lines changed

opencensus/trace/propagation/binary_format.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import logging
1818
import struct
1919

20-
from opencensus.trace.span_context import SpanContext
20+
from opencensus.trace import span_context as span_context_module
2121
from opencensus.trace.trace_options import TraceOptions
2222

2323
# Used for decoding hex bytes to hex string.
@@ -54,7 +54,7 @@
5454
trace_id_field_id=UNSIGNED_CHAR,
5555
trace_id='{}{}'.format(TRACE_ID_SIZE, CHAR_ARRAY_FORMAT),
5656
span_id_field_id=UNSIGNED_CHAR,
57-
span_id=UNSIGNED_LONG_LONG,
57+
span_id='{}{}'.format(SPAN_ID_SIZE, CHAR_ARRAY_FORMAT),
5858
trace_option_field_id=UNSIGNED_CHAR,
5959
trace_option=UNSIGNED_CHAR)
6060

@@ -80,15 +80,15 @@ class BinaryFormatPropagator(object):
8080
[SpanContext]
8181
trace_id: hex string with length 32.
8282
e.g. 'a0b72ca15c1a4bd18962d0ac59dc90b9'
83-
span_id: 64 bits integer.
84-
e.g. 7433567179112518326
83+
span_id: hex string with length 16.
84+
e.g. 'a0b72ca15c1a4bd1'
8585
enabled (trace option): bool.
8686
e.g. True
8787
[Binary Format]
8888
trace_id: Bytes with length 16.
8989
e.g. b'\xa0\xb7,\xa1\\\x1aK\xd1\x89b\xd0\xacY\xdc\x90\xb9'
9090
span_id: Bytes with length 8.
91-
e.g. b'\xb6\x12\x01\xf5\xf6U)g'
91+
e.g. b'\x00\xf0g\xaa\x0b\xa9\x02\xb7'
9292
trace_option: Byte with length 1.
9393
e.g. b'\x01'
9494
"""
@@ -106,25 +106,28 @@ def from_header(self, binary):
106106
"""
107107
# If no binary provided, generate a new SpanContext
108108
if binary is None:
109-
return SpanContext(from_header=False)
109+
return span_context_module.SpanContext(from_header=False)
110110

111111
# If cannot parse, return a new SpanContext and ignore the context
112112
# from binary.
113113
try:
114114
data = Header._make(struct.unpack(BINARY_FORMAT, binary))
115115
except struct.error:
116-
logging.warn('Cannot parse the incoming binary data {}, '
117-
'wrong format. Total bytes length should be {}.'
118-
.format(binary, FORMAT_LENGTH))
119-
return SpanContext(from_header=False)
116+
logging.warning(
117+
'Cannot parse the incoming binary data {}, '
118+
'wrong format. Total bytes length should be {}.'.format(
119+
binary, FORMAT_LENGTH
120+
)
121+
)
122+
return span_context_module.SpanContext(from_header=False)
120123

121124
# data.trace_id is in bytes with length 16, hexlify it to hex bytes
122125
# with length 32, then decode it to hex string using utf-8.
123126
trace_id = str(binascii.hexlify(data.trace_id).decode(UTF8))
124-
span_id = data.span_id
127+
span_id = str(binascii.hexlify(data.span_id).decode(UTF8))
125128
trace_options = TraceOptions(data.trace_option)
126129

127-
span_context = SpanContext(
130+
span_context = span_context_module.SpanContext(
128131
trace_id=trace_id,
129132
span_id=span_id,
130133
trace_options=trace_options,
@@ -149,7 +152,7 @@ def to_header(self, span_context):
149152
# If there is no span_id in this context, set it to 0, which is
150153
# considered invalid and won't be set as the downstream parent span_id.
151154
if span_id is None:
152-
span_id = 0
155+
span_id = span_context_module.INVALID_SPAN_ID
153156

154157
# Convert trace_id to bytes with length 16, treat span_id as 64 bit
155158
# integer which is unsigned long long type and convert it to bytes with
@@ -160,6 +163,6 @@ def to_header(self, span_context):
160163
TRACE_ID_FIELD_ID,
161164
binascii.unhexlify(trace_id),
162165
SPAN_ID_FIELD_ID,
163-
span_id,
166+
binascii.unhexlify(span_id),
164167
TRACE_OPTION_FIELD_ID,
165168
trace_options)

opencensus/trace/propagation/google_cloud_format.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from opencensus.trace.span_context import SpanContext
1919
from opencensus.trace.trace_options import TraceOptions
2020

21-
_TRACE_CONTEXT_HEADER_FORMAT = '([0-9a-f]{32})(\/(\d+))?(;o=(\d+))?'
21+
_TRACE_CONTEXT_HEADER_FORMAT = '([0-9a-f]{32})(\/([0-9a-f]{16}))?(;o=(\d+))?'
2222
_TRACE_CONTEXT_HEADER_RE = re.compile(_TRACE_CONTEXT_HEADER_FORMAT)
2323
_TRACE_ID_DELIMETER = '/'
2424
_SPAN_ID_DELIMETER = ';'

opencensus/trace/propagation/trace_context_http_header_format.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def from_header(self, header):
6161
# Need to convert span_id from hex string to int
6262
span_context = SpanContext(
6363
trace_id=trace_id,
64-
span_id=int(span_id, 16),
64+
span_id=span_id,
6565
trace_options=TraceOptions(trace_options),
6666
from_header=True)
6767
return span_context
@@ -90,10 +90,6 @@ def to_header(self, span_context):
9090
span_id = span_context.span_id
9191
trace_options = span_context.trace_options.enabled
9292

93-
# Need to convert span_id from int to hex string
94-
span_id_hex = hex(span_id)
95-
span_id = span_id_hex[2:].zfill(16)
96-
9793
# Convert the trace options
9894
trace_options = '01' if trace_options else '00'
9995

opencensus/trace/span_context.py

Lines changed: 42 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,17 @@
1515
"""SpanContext encapsulates the current context within the request's trace."""
1616

1717
import logging
18-
import random
1918
import re
2019
import uuid
2120

2221
from opencensus.trace import trace_options
2322

2423
_INVALID_TRACE_ID = '0' * 32
25-
_INVALID_SPAN_ID = 0
24+
INVALID_SPAN_ID = '0' * 16
2625
_TRACE_HEADER_KEY = 'X_CLOUD_TRACE_CONTEXT'
27-
_TRACE_ID_FORMAT = '[0-9a-f]{32}?'
26+
27+
TRACE_ID_PATTERN = re.compile('[0-9a-f]{32}?')
28+
SPAN_ID_PATTERN = re.compile('[0-9a-f]{16}?')
2829

2930
# Default options, enable tracing
3031
DEFAULT_OPTIONS = 1
@@ -42,8 +43,9 @@ class SpanContext(object):
4243
:param trace_id: (Optional) Trace_id is a 32 digits uuid for the trace.
4344
If not given, will generate one automatically.
4445
45-
:type span_id: int
46+
:type span_id: str
4647
:param span_id: (Optional) Identifier for the span, unique within a trace.
48+
If not given, will generate one automatically.
4749
4850
:type trace_options: :class: `~opencensus.trace.trace_options.TraceOptions`
4951
:param trace_options: (Optional) TraceOptions indicates 8 trace options.
@@ -64,10 +66,10 @@ def __init__(
6466
if trace_options is None:
6567
trace_options = DEFAULT
6668

67-
self.trace_id = self.check_trace_id(trace_id)
68-
self.span_id = self.check_span_id(span_id)
69-
self.trace_options = trace_options
7069
self.from_header = from_header
70+
self.trace_id = self._check_trace_id(trace_id)
71+
self.span_id = self._check_span_id(span_id)
72+
self.trace_options = trace_options
7173

7274
def __str__(self):
7375
"""Returns a string form of the SpanContext. This is the format of
@@ -84,41 +86,42 @@ def __str__(self):
8486
int(enabled))
8587
return header
8688

87-
def check_span_id(self, span_id):
88-
"""Check the type of span_id to ensure it is int. If it is not int,
89-
first try to convert it to int, if failed to convert, then log a
90-
warning message and set the span_id to None.
89+
def _check_span_id(self, span_id):
90+
"""Check the format of the span_id to ensure it is 16-character hex
91+
value representing a 64-bit number. If span_id is invalid, logs a
92+
warning message and returns None
9193
92-
:type span_id: int
93-
:param span_id: Identifier for the span, unique within a trace.
94+
:type span_id: str
95+
:param span_id: Identifier for the span, unique within a span.
9496
95-
:rtype: int
97+
:rtype: str
9698
:returns: Span_id for the current span.
9799
"""
98100
if span_id is None:
99101
return None
102+
assert isinstance(span_id, str)
100103

101-
if span_id == 0:
104+
if span_id is INVALID_SPAN_ID:
102105
logging.warning(
103-
'Span_id {} is invalid, cannot be zero.'.format(span_id))
106+
'Span_id {} is invalid (cannot be all zero)'.format(span_id))
104107
self.from_header = False
105108
return None
106109

107-
if not isinstance(span_id, int):
108-
try:
109-
span_id = int(span_id)
110-
except (TypeError, ValueError):
111-
logging.warning(
112-
'The type of span_id should be int, got {}.'.format(
113-
span_id.__class__.__name__))
114-
self.from_header = False
115-
span_id = None
110+
match = SPAN_ID_PATTERN.match(span_id)
116111

117-
return span_id
112+
if match:
113+
return span_id
114+
else:
115+
logging.warning(
116+
'Span_id {} does not the match the '
117+
'required format'.format(span_id))
118+
self.from_header = False
119+
return None
118120

119-
def check_trace_id(self, trace_id):
121+
def _check_trace_id(self, trace_id):
120122
"""Check the format of the trace_id to ensure it is 32-character hex
121-
value representing a 128-bit number. Also the trace_id cannot be zero.
123+
value representing a 128-bit number. If trace_id is invalid, returns a
124+
randomly generated trace id
122125
123126
:type trace_id: str
124127
:param trace_id:
@@ -131,41 +134,39 @@ def check_trace_id(self, trace_id):
131134
if trace_id is _INVALID_TRACE_ID:
132135
logging.warning(
133136
'Trace_id {} is invalid (cannot be all zero), '
134-
'generate a new one.'.format(trace_id))
137+
'generating a new one.'.format(trace_id))
135138
self.from_header = False
136139
return generate_trace_id()
137140

138-
trace_id_pattern = re.compile(_TRACE_ID_FORMAT)
139-
140-
match = trace_id_pattern.match(trace_id)
141+
match = TRACE_ID_PATTERN.match(trace_id)
141142

142143
if match:
143144
return trace_id
144145
else:
145146
logging.warning(
146147
'Trace_id {} does not the match the required format,'
147-
'generate a new one instead.'.format(trace_id))
148+
'generating a new one instead.'.format(trace_id))
148149
self.from_header = False
149150
return generate_trace_id()
150151

151152

152153
def generate_span_id():
153-
"""Return the random generated span ID for a span. Must be 16 digits
154-
as Stackdriver Trace V2 API only accepts 16 digits span ID.
154+
"""Return the random generated span ID for a span. Must be a 16 character
155+
hexadecimal encoded string
155156
156-
:rtype: int
157-
:returns: Identifier for the span. Must be a 64-bit integer other
158-
than 0 and unique within a trace.
157+
:rtype: str
158+
:returns: 16 digit randomly generated hex trace id.
159159
"""
160-
span_id = random.randint(10**15, 10**16 - 1)
160+
span_id = uuid.uuid4().hex[:16]
161161
return span_id
162162

163163

164164
def generate_trace_id():
165-
"""Generate a trace_id randomly.
165+
"""Generate a trace_id randomly. Must be a 32 character
166+
hexadecimal encoded string
166167
167168
:rtype: str
168-
:returns: 32 digit randomly generated trace ID.
169+
:returns: 32 digit randomly generated hex trace id.
169170
"""
170171
trace_id = uuid.uuid4().hex
171172
return trace_id

tests/system/trace/basic_trace/basic_trace_system_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def test_tracer(self):
3232
from opencensus.trace.propagation import google_cloud_format
3333

3434
trace_id = 'f8739df974a4481f98748cd92b27177d'
35-
span_id = '16971691944144156899'
35+
span_id = '6e0c63257de34c92'
3636
trace_option = 1
3737

3838
trace_header = '{}/{};o={}'.format(trace_id, span_id, trace_option)

tests/system/trace/django/django_system_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def wait_app_to_start():
4343
def generate_header():
4444
"""Generate a trace header."""
4545
trace_id = uuid.uuid4().hex
46-
span_id = random.randint(10**15, 10**16 - 1)
46+
span_id = uuid.uuid4().hex[:16]
4747
trace_option = 1
4848

4949
header = '{}/{};o={}'.format(trace_id, span_id, trace_option)

tests/system/trace/flask/flask_system_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def wait_app_to_start():
4242
def generate_header():
4343
"""Generate a trace header."""
4444
trace_id = uuid.uuid4().hex
45-
span_id = random.randint(10**15, 10**16 - 1)
45+
span_id = uuid.uuid4().hex[:16]
4646
trace_option = 1
4747

4848
header = '{}/{};o={}'.format(trace_id, span_id, trace_option)

tests/unit/trace/exporters/test_stackdriver_exporter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ def test_translate_to_stackdriver(self):
144144
project_id = 'PROJECT'
145145
trace_id = '6e0c63257de34c92bf9efcd03927272e'
146146
span_name = 'test span'
147-
span_id = 1234
147+
span_id = '6e0c63257de34c92'
148148
attributes = {
149149
'attributeMap': {
150150
'key': {
@@ -155,7 +155,7 @@ def test_translate_to_stackdriver(self):
155155
}
156156
}
157157
}
158-
parent_span_id = 1111
158+
parent_span_id = '6e0c63257de34c93'
159159
start_time = 'test start time'
160160
end_time = 'test end time'
161161
trace = {

tests/unit/trace/exporters/test_zipkin_exporter.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ def test_translate_to_zipkin_span_kind_none(self):
9898
span_data_module.SpanData(
9999
name='child_span',
100100
context=span_context.SpanContext(trace_id=trace_id),
101-
span_id=1234567890,
102-
parent_span_id=1111111111,
101+
span_id='6e0c63257de34c92',
102+
parent_span_id='6e0c63257de34c93',
103103
attributes={'test_key': 'test_value'},
104104
start_time='2017-08-15T18:02:26.071158Z',
105105
end_time='2017-08-15T18:02:36.071158Z',
@@ -114,8 +114,8 @@ def test_translate_to_zipkin_span_kind_none(self):
114114
span_data_module.SpanData(
115115
name='child_span',
116116
context=span_context.SpanContext(trace_id=trace_id),
117-
span_id=1234567890,
118-
parent_span_id=1111111111,
117+
span_id='6e0c63257de34c92',
118+
parent_span_id='6e0c63257de34c93',
119119
attributes={'test_key': 1},
120120
start_time='2017-08-15T18:02:26.071158Z',
121121
end_time='2017-08-15T18:02:36.071158Z',
@@ -134,7 +134,7 @@ def test_translate_to_zipkin_span_kind_none(self):
134134
span_data_module.SpanData(
135135
name='child_span',
136136
context=span_context.SpanContext(trace_id=trace_id),
137-
span_id=1234567890,
137+
span_id='6e0c63257de34c92',
138138
parent_span_id=None,
139139
attributes={
140140
'test_key': False,
@@ -172,8 +172,8 @@ def test_translate_to_zipkin_span_kind_none(self):
172172
expected_zipkin_spans_ipv4 = [
173173
{
174174
'traceId': '6e0c63257de34c92bf9efcd03927272e',
175-
'id': '1234567890',
176-
'parentId': '1111111111',
175+
'id': '6e0c63257de34c92',
176+
'parentId': '6e0c63257de34c93',
177177
'name': 'child_span',
178178
'timestamp': 1502820146000000,
179179
'duration': 10000000,
@@ -182,8 +182,8 @@ def test_translate_to_zipkin_span_kind_none(self):
182182
},
183183
{
184184
'traceId': '6e0c63257de34c92bf9efcd03927272e',
185-
'id': '1234567890',
186-
'parentId': '1111111111',
185+
'id': '6e0c63257de34c92',
186+
'parentId': '6e0c63257de34c93',
187187
'name': 'child_span',
188188
'timestamp': 1502820146000000,
189189
'duration': 10000000,
@@ -195,7 +195,7 @@ def test_translate_to_zipkin_span_kind_none(self):
195195
expected_zipkin_spans_ipv6 = [
196196
{
197197
'traceId': '6e0c63257de34c92bf9efcd03927272e',
198-
'id': '1234567890',
198+
'id': '6e0c63257de34c92',
199199
'name': 'child_span',
200200
'timestamp': 1502820146000000,
201201
'duration': 10000000,

0 commit comments

Comments
 (0)