def test_max_span_batch_size(default_trace_id_generator): settings = { 'zipkin.tracing_percent': 0, 'zipkin.trace_id_generator': default_trace_id_generator, 'zipkin.max_span_batch_size': 1, } app_main, normal_transport, firehose_transport = generate_app_main( settings, firehose=True, ) WebTestApp(app_main).get('/decorator_context', status=200) # Assert the expected number of batches for two spans assert len(normal_transport.output) == 0 assert len(firehose_transport.output) == 2 # Assert proper hierarchy batch_one = decode_thrift(firehose_transport.output[0]) assert len(batch_one) == 1 child_span = batch_one[0] batch_two = decode_thrift(firehose_transport.output[1]) assert len(batch_two) == 1 server_span = batch_two[0] assert child_span.parent_id == server_span.id assert child_span.name == 'my_span'
def test_upstream_zipkin_headers_sampled(default_trace_id_generator): settings = {'zipkin.trace_id_generator': default_trace_id_generator} app_main, transport, _ = generate_app_main(settings) trace_hex = 'aaaaaaaaaaaaaaaa' span_hex = 'bbbbbbbbbbbbbbbb' parent_hex = 'cccccccccccccccc' def validate(span_objs): assert len(span_objs) == 1 span = span_objs[0] assert span.trace_id == unsigned_hex_to_signed_int(trace_hex) assert span.id == unsigned_hex_to_signed_int(span_hex) assert span.parent_id == unsigned_hex_to_signed_int(parent_hex) # Since Zipkin headers are passed in, the span in assumed to be the # server part of a span started by an upstream client, so doesn't have # to log timestamp/duration. assert span.timestamp is None assert span.duration is None WebTestApp(app_main).get( '/sample', status=200, headers={ 'X-B3-TraceId': trace_hex, 'X-B3-SpanId': span_hex, 'X-B3-ParentSpanId': parent_hex, 'X-B3-Flags': '0', 'X-B3-Sampled': '1', }, ) validate(decode_thrift(transport.output[0]))
def test_binary_annotations_404(default_trace_id_generator): settings = { 'zipkin.tracing_percent': 100, 'zipkin.trace_id_generator': default_trace_id_generator, } app_main, transport, _ = generate_app_main(settings) def validate_span(span_objs): assert len(span_objs) == 1 span_obj = span_objs[0] # Assert that the only present binary_annotations are ones we expect expected_annotations = { 'http.uri': '/abcd', 'http.uri.qs': '/abcd?test=1', 'http.route': '', 'response_status_code': '404', } result_span = test_helper.massage_result_span(span_obj) for ann in result_span['binary_annotations']: assert ann['value'] == expected_annotations.pop(ann['key']) assert len(expected_annotations) == 0 WebTestApp(app_main).get('/abcd?test=1', status=404) assert len(transport.output) == 1 validate_span(decode_thrift(transport.output[0]))
def test_binary_annotations(default_trace_id_generator): def set_extra_binary_annotations(dummy_request, response): return {'other': dummy_request.registry.settings['other_attr']} settings = { 'zipkin.tracing_percent': 100, 'zipkin.trace_id_generator': default_trace_id_generator, 'zipkin.set_extra_binary_annotations': set_extra_binary_annotations, 'other_attr': '42', } app_main, transport, _ = generate_app_main(settings) def validate_span(span_objs): assert len(span_objs) == 1 span_obj = span_objs[0] # Assert that the only present binary_annotations are ones we expect expected_annotations = { 'http.uri': '/pet/123', 'http.uri.qs': '/pet/123?test=1', 'http.route': '/pet/{petId}', 'response_status_code': '200', 'other': '42', } result_span = test_helper.massage_result_span(span_obj) for ann in result_span['binary_annotations']: assert ann['value'] == expected_annotations.pop(ann['key']) assert len(expected_annotations) == 0 WebTestApp(app_main).get('/pet/123?test=1', status=200) assert len(transport.output) == 1 validate_span(decode_thrift(transport.output[0]))
def test_defaults_at_using_raw_url_path(default_trace_id_generator): settings = { 'zipkin.tracing_percent': 100, 'zipkin.trace_id_generator': default_trace_id_generator, 'other_attr': '42', } app_main, transport, _ = generate_app_main(settings) def validate_span(span_objs): assert len(span_objs) == 1 result_span = test_helper.massage_result_span(span_objs[0]) # Check that the span name is the raw url by default assert result_span['name'] == 'GET /pet/123' WebTestApp(app_main).get('/pet/123?test=1', status=200) assert len(transport.output) == 1 validate_span(decode_thrift(transport.output[0]))
def test_report_root_timestamp(): settings = { 'zipkin.report_root_timestamp': True, 'zipkin.tracing_percent': 100.0, } app_main, transport, _ = generate_app_main(settings) old_time = time.time() * 1000000 def check_for_timestamp_and_duration(span_objs): span_obj = span_objs[0] assert span_obj.timestamp > old_time assert span_obj.duration > 0 WebTestApp(app_main).get('/sample', status=200) assert len(transport.output) == 1 check_for_timestamp_and_duration(decode_thrift(transport.output[0]))
def test_add_logging_annotation(): settings = { 'zipkin.tracing_percent': 100, 'zipkin.add_logging_annotation': True, } app_main, transport, _ = generate_app_main(settings) WebTestApp(app_main).get('/sample', status=200) assert len(transport.output) == 1 span_list = decode_thrift(transport.output[0]) assert len(span_list) == 1 server_span = span_list[0] # Just make sure py-zipkin added an annotation for when logging started assert any( annotation.value == 'py_zipkin.logging_end' for annotation in server_span.annotations )
def test_use_pattern_as_span_name(default_trace_id_generator): settings = { 'zipkin.tracing_percent': 100, 'zipkin.trace_id_generator': default_trace_id_generator, 'other_attr': '42', 'zipkin.use_pattern_as_span_name': True, } app_main, transport, _ = generate_app_main(settings) def validate_span(span_objs): assert len(span_objs) == 1 result_span = test_helper.massage_result_span(span_objs[0]) # Check that the span name is the pyramid pattern and not the raw url assert result_span['name'] == 'GET /pet/{petId}' WebTestApp(app_main).get('/pet/123?test=1', status=200) assert len(transport.output) == 1 validate_span(decode_thrift(transport.output[0]))
def test_host_and_port_in_span(): settings = { 'zipkin.tracing_percent': 100, 'zipkin.host': '1.2.2.1', 'zipkin.port': 1231, } app_main, transport, _ = generate_app_main(settings) def validate_span(span_objs): assert len(span_objs) == 1 span_obj = span_objs[0] # Assert ipv4 and port match what we expect expected_ipv4 = (1 << 24) | (2 << 16) | (2 << 8) | 1 assert expected_ipv4 == span_obj.annotations[0].host.ipv4 assert 1231 == span_obj.annotations[0].host.port WebTestApp(app_main).get('/sample?test=1', status=200) assert len(transport.output) == 1 validate_span(decode_thrift(transport.output[0]))
def test_span_context(default_trace_id_generator): # Tests that log lines with 'service_name' keys are logged as # new client spans. settings = { 'zipkin.tracing_percent': 100, 'zipkin.trace_id_generator': default_trace_id_generator, } app_main, transport, _ = generate_app_main(settings) WebTestApp(app_main).get('/span_context', status=200) # Spans are batched # The order of span logging goes from innermost (grandchild) up. assert len(transport.output) == 1 span_list = decode_thrift(transport.output[0]) assert len(span_list) == 3 grandchild_span = span_list[0] child_span = span_list[1] server_span = span_list[2] # Assert proper hierarchy assert child_span.parent_id == server_span.id assert grandchild_span.parent_id == child_span.id # Assert annotations are properly assigned assert_extra_annotations(child_span, {'child_annotation': 1000000}) assert_extra_binary_annotations( child_span, {'foo': 'bar', 'child': 'true'}) assert_extra_annotations( grandchild_span, {'grandchild_annotation': 1000000}) assert_extra_binary_annotations(grandchild_span, {'grandchild': 'true'}) # For the span produced by SpanContext, assert cs==sr and ss==cr # Initialize them all so the equalities won't be true. annotations = { 'cs': 0, 'sr': 1, 'ss': 2, 'cr': 3 } for annotation in child_span.annotations: if annotation.value in annotations: annotations[annotation.value] = annotation.timestamp assert annotations['cs'] == annotations['sr'] assert annotations['ss'] == annotations['cr']
def test_decorator(default_trace_id_generator): # Tests that log lines with 'service_name' keys are logged as # new client spans. settings = { 'zipkin.tracing_percent': 100, 'zipkin.trace_id_generator': default_trace_id_generator, } app_main, transport, _ = generate_app_main(settings) WebTestApp(app_main).get('/decorator_context', status=200) # Two spans are logged - child span, then server span assert len(transport.output) == 1 span_list = decode_thrift(transport.output[0]) assert len(span_list) == 2 child_span = span_list[0] server_span = span_list[1] # Assert proper hierarchy and annotations assert child_span.parent_id == server_span.id assert_extra_binary_annotations(child_span, {'a': '1'}) assert child_span.name == 'my_span'
def test_sample_server_span_with_firehose_tracing(default_trace_id_generator, get_span): settings = { 'zipkin.tracing_percent': 0, 'zipkin.trace_id_generator': default_trace_id_generator, 'zipkin.firehose_handler': default_trace_id_generator, } app_main, normal_transport, firehose_transport = generate_app_main( settings, firehose=True, ) old_time = time.time() * 1000000 def validate_span(span_objs): assert len(span_objs) == 1 span_obj = span_objs[0] result_span = test_helper.massage_result_span(span_obj) timestamps = test_helper.get_timestamps(result_span) get_span['trace_id'] = unsigned_hex_to_signed_int( default_trace_id_generator(span_obj), ) # The request to this service had no incoming Zipkin headers, so it's # assumed to be the root span of a trace, which means it logs # timestamp and duration. assert result_span.pop('timestamp') > old_time assert result_span.pop('duration') > 0 assert get_span == result_span assert old_time <= timestamps['sr'] assert timestamps['sr'] <= timestamps['ss'] with mock.patch( 'pyramid_zipkin.request_helper.generate_random_64bit_string' ) as mock_generate_random_64bit_string: mock_generate_random_64bit_string.return_value = '1' WebTestApp(app_main).get('/sample', status=200) assert len(normal_transport.output) == 0 assert len(firehose_transport.output) == 1 validate_span(decode_thrift(firehose_transport.output[0]))
def test_log_new_client_spans(default_trace_id_generator): # Tests that log lines with 'service_name' keys are logged as # new client spans. settings = { 'zipkin.tracing_percent': 100, 'zipkin.trace_id_generator': default_trace_id_generator, } app_main, transport, _ = generate_app_main(settings) WebTestApp(app_main).get('/sample_v2_client', status=200) assert len(transport.output) == 1 span_list = decode_thrift(transport.output[0]) assert len(span_list) == 3 foo_span = span_list[0] bar_span = span_list[1] server_span = span_list[2] # Some sanity checks on the new client spans for client_span in (foo_span, bar_span): assert client_span.parent_id == server_span.id assert foo_span.id != bar_span.id assert_extra_annotations(foo_span, {'foo_client': 2000000}) assert_extra_annotations(bar_span, {'bar_client': 1000000})