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

Commit 17b9279

Browse files
mayurkale22liyanhui1228
authored andcommitted
Exporter/Zipkin: Add annotations (#327)
1 parent c960835 commit 17b9279

2 files changed

Lines changed: 196 additions & 1 deletion

File tree

opencensus/trace/exporters/zipkin_exporter.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ def translate_to_zipkin(self, span_datas):
176176
'duration': int(round(duration_ms)),
177177
'localEndpoint': local_endpoint,
178178
'tags': _extract_tags_from_span(span.attributes),
179+
'annotations': _extract_annotations_from_span(span),
179180
}
180181

181182
span_kind = span.span_kind
@@ -211,3 +212,24 @@ def _extract_tags_from_span(attr):
211212
continue
212213
tags[attribute_key] = value
213214
return tags
215+
216+
217+
def _extract_annotations_from_span(span):
218+
"""Extract and convert time event annotations to zipkin annotations"""
219+
if span.time_events is None:
220+
return []
221+
222+
annotations = []
223+
for time_event in span.time_events:
224+
annotation = time_event.annotation
225+
if not annotation:
226+
continue
227+
228+
event_time = datetime.datetime.strptime(time_event.timestamp,
229+
ISO_DATETIME_REGEX)
230+
epoch_time = calendar.timegm(
231+
event_time.timetuple()) * 1e6 + event_time.microsecond
232+
annotations.append({'timestamp': int(round(epoch_time)),
233+
'value': annotation.description})
234+
235+
return annotations

tests/unit/trace/exporters/test_zipkin_exporter.py

Lines changed: 174 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515
import unittest
1616

1717
import mock
18-
18+
from datetime import datetime
1919
from opencensus.trace import span_context
2020
from opencensus.trace import span_data as span_data_module
21+
from opencensus.trace import time_event
2122
from opencensus.trace.exporters import zipkin_exporter
2223

2324

@@ -179,6 +180,166 @@ def test_translate_to_zipkin_span_kind_none(self):
179180
'duration': 10000000,
180181
'localEndpoint': local_endpoint_ipv4,
181182
'tags': {'test_key': 'test_value'},
183+
'annotations': [],
184+
},
185+
{
186+
'traceId': '6e0c63257de34c92bf9efcd03927272e',
187+
'id': '6e0c63257de34c92',
188+
'parentId': '6e0c63257de34c93',
189+
'name': 'child_span',
190+
'timestamp': 1502820146071158,
191+
'duration': 10000000,
192+
'localEndpoint': local_endpoint_ipv4,
193+
'tags': {'test_key': '1'},
194+
'annotations': [],
195+
},
196+
]
197+
198+
expected_zipkin_spans_ipv6 = [
199+
{
200+
'traceId': '6e0c63257de34c92bf9efcd03927272e',
201+
'id': '6e0c63257de34c92',
202+
'name': 'child_span',
203+
'timestamp': 1502820146071158,
204+
'duration': 10000000,
205+
'localEndpoint': local_endpoint_ipv6,
206+
'tags': {'test_key': 'False', 'test_key2': 'raw_value'},
207+
'kind': 'SERVER',
208+
'annotations': [],
209+
},
210+
]
211+
212+
# Test ipv4 local endpoint
213+
exporter_ipv4 = zipkin_exporter.ZipkinExporter(
214+
service_name='my_service', ipv4=ipv4)
215+
zipkin_spans_ipv4 = exporter_ipv4.translate_to_zipkin(
216+
span_datas=spans_ipv4)
217+
218+
self.assertEqual(zipkin_spans_ipv4, expected_zipkin_spans_ipv4)
219+
220+
# Test ipv6 local endpoint
221+
exporter_ipv6 = zipkin_exporter.ZipkinExporter(
222+
service_name='my_service', ipv6=ipv6)
223+
zipkin_spans_ipv6 = exporter_ipv6.translate_to_zipkin(
224+
span_datas=spans_ipv6)
225+
226+
self.assertEqual(zipkin_spans_ipv6, expected_zipkin_spans_ipv6)
227+
228+
def test_translate_to_zipkin_with_annotations(self):
229+
trace_id = '6e0c63257de34c92bf9efcd03927272e'
230+
231+
annotation_attributes = {
232+
'annotation_bool': True,
233+
'annotation_string': 'annotation_test',
234+
'key_float': .3
235+
}
236+
237+
s = '2017-08-15T18:02:26.071158'
238+
time = datetime.strptime(s, '%Y-%m-%dT%H:%M:%S.%f')
239+
time_events = [
240+
time_event.TimeEvent(
241+
timestamp=time,
242+
annotation=time_event.Annotation(
243+
description='First Annotation',
244+
attributes=annotation_attributes)),
245+
time_event.TimeEvent(
246+
timestamp=time,
247+
message_event=time_event.MessageEvent(
248+
id='message-event-id',
249+
uncompressed_size_bytes=0,
250+
)),
251+
]
252+
253+
spans_ipv4 = [
254+
span_data_module.SpanData(
255+
name='child_span',
256+
context=span_context.SpanContext(trace_id=trace_id),
257+
span_id='6e0c63257de34c92',
258+
parent_span_id='6e0c63257de34c93',
259+
attributes={'test_key': 'test_value'},
260+
start_time='2017-08-15T18:02:26.071158Z',
261+
end_time='2017-08-15T18:02:36.071158Z',
262+
child_span_count=None,
263+
stack_trace=None,
264+
time_events=time_events,
265+
links=None,
266+
status=None,
267+
same_process_as_parent_span=None,
268+
span_kind=0,
269+
),
270+
span_data_module.SpanData(
271+
name='child_span',
272+
context=span_context.SpanContext(trace_id=trace_id),
273+
span_id='6e0c63257de34c92',
274+
parent_span_id='6e0c63257de34c93',
275+
attributes={'test_key': 1},
276+
start_time='2017-08-15T18:02:26.071158Z',
277+
end_time='2017-08-15T18:02:36.071158Z',
278+
child_span_count=None,
279+
stack_trace=None,
280+
time_events=time_events,
281+
links=None,
282+
status=None,
283+
same_process_as_parent_span=None,
284+
span_kind=None,
285+
),
286+
]
287+
288+
spans_ipv6 = [
289+
span_data_module.SpanData(
290+
name='child_span',
291+
context=span_context.SpanContext(trace_id=trace_id),
292+
span_id='6e0c63257de34c92',
293+
parent_span_id=None,
294+
attributes={
295+
'test_key': False,
296+
'test_key2': 'raw_value',
297+
# these tags are malformed and should be omitted
298+
'test_key3': 0.1,
299+
},
300+
start_time='2017-08-15T18:02:26.071158Z',
301+
end_time='2017-08-15T18:02:36.071158Z',
302+
child_span_count=None,
303+
stack_trace=None,
304+
time_events=time_events,
305+
links=None,
306+
status=None,
307+
same_process_as_parent_span=None,
308+
span_kind=1,
309+
),
310+
]
311+
312+
ipv4 = '127.0.0.1'
313+
ipv6 = '2001:0db8:85a3:0000:0000:8a2e:0370:7334'
314+
315+
local_endpoint_ipv4 = {
316+
'serviceName': 'my_service',
317+
'ipv4': ipv4,
318+
'port': 9411,
319+
}
320+
321+
local_endpoint_ipv6 = {
322+
'serviceName': 'my_service',
323+
'ipv6': ipv6,
324+
'port': 9411,
325+
}
326+
327+
expected_zipkin_spans_ipv4 = [
328+
{
329+
'traceId': '6e0c63257de34c92bf9efcd03927272e',
330+
'id': '6e0c63257de34c92',
331+
'parentId': '6e0c63257de34c93',
332+
'name': 'child_span',
333+
'timestamp': 1502820146071158,
334+
'duration': 10000000,
335+
'localEndpoint': local_endpoint_ipv4,
336+
'tags': {'test_key': 'test_value'},
337+
'annotations': [
338+
{
339+
'timestamp': 1502820146071158,
340+
'value': 'First Annotation'
341+
}
342+
]
182343
},
183344
{
184345
'traceId': '6e0c63257de34c92bf9efcd03927272e',
@@ -189,6 +350,12 @@ def test_translate_to_zipkin_span_kind_none(self):
189350
'duration': 10000000,
190351
'localEndpoint': local_endpoint_ipv4,
191352
'tags': {'test_key': '1'},
353+
'annotations': [
354+
{
355+
'timestamp': 1502820146071158,
356+
'value': 'First Annotation'
357+
}
358+
]
192359
},
193360
]
194361

@@ -202,6 +369,12 @@ def test_translate_to_zipkin_span_kind_none(self):
202369
'localEndpoint': local_endpoint_ipv6,
203370
'tags': {'test_key': 'False', 'test_key2': 'raw_value'},
204371
'kind': 'SERVER',
372+
'annotations': [
373+
{
374+
'timestamp': 1502820146071158,
375+
'value': 'First Annotation'
376+
}
377+
]
205378
},
206379
]
207380

0 commit comments

Comments
 (0)