示例#1
0
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

    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
    spans = json.loads(firehose_transport.output[0])
    assert len(spans) == 1

    span = spans[0]
    assert span['timestamp'] > old_time
    assert span['duration'] > 0
    assert span == get_span
示例#2
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]))
示例#3
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)

    WebTestApp(app_main).get('/pet/123?test=1', status=200)

    assert len(transport.output) == 1
    spans = json.loads(transport.output[0])
    assert len(spans) == 1

    span = spans[0]
    assert span['tags'] == {
        'http.uri': '/pet/123',
        'http.uri.qs': '/pet/123?test=1',
        'http.route': '/pet/{petId}',
        'response_status_code': '200',
        'other': '42',
    }
示例#4
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]))
示例#5
0
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]))
示例#6
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 = json.loads(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['parentId'] == server_span['id']
    assert foo_span['id'] != bar_span['id']
    assert foo_span['annotations'] == [
        {
            'timestamp': 2000000,
            'value': 'foo_client'
        },
    ]
    assert bar_span['annotations'] == [
        {
            'timestamp': 1000000,
            'value': 'bar_client'
        },
    ]
示例#7
0
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'
示例#8
0
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'

    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',
        },
    )

    spans = json.loads(transport.output[0])
    assert len(spans) == 1

    span = spans[0]
    assert span['traceId'] == trace_hex
    assert span['id'] == span_hex
    assert span['parentId'] == parent_hex
    assert span['kind'] == 'SERVER'
    assert span['shared'] is True
示例#9
0
def test_sample_server_ipv6(
    default_trace_id_generator,
    get_span,
):
    # Assert that pyramid_zipkin and py_zipkin correctly handle ipv6 addresses.
    settings = {
        'zipkin.tracing_percent': 100,
        'zipkin.trace_id_generator': default_trace_id_generator,
    }
    app_main, transport, _ = generate_app_main(settings)

    # py_zipkin uses `socket.gethostbyname` to get the current host ip if it's not
    # set in settings.
    with mock.patch(
        'socket.gethostbyname',
        return_value='2001:db8:85a3::8a2e:370:7334',
        autospec=True,
    ):
        WebTestApp(app_main).get('/sample', status=200)

    assert len(transport.output) == 1
    spans = json.loads(transport.output[0])

    assert len(spans) == 1
    span = spans[0]
    # Check that the span name is the raw url by default
    assert span['localEndpoint'] == {
        'serviceName': 'acceptance_service',
        'port': 80,
        'ipv6': '2001:db8:85a3::8a2e:370:7334',
    }
示例#10
0
def test_unsampled_request_has_no_span(default_trace_id_generator):
    settings = {
        'zipkin.tracing_percent': 0,
        'zipkin.trace_id_generator': default_trace_id_generator,
    }
    app_main, transport, _ = generate_app_main(settings)

    WebTestApp(app_main).get('/sample', status=200)

    assert len(transport.output) == 0
示例#11
0
def test_blacklisted_path_has_no_span(default_trace_id_generator):
    settings = {
        'zipkin.tracing_percent': 100,
        'zipkin.trace_id_generator': default_trace_id_generator,
        'zipkin.blacklisted_paths': [r'^/sample'],
    }
    app_main, transport, _ = generate_app_main(settings)

    WebTestApp(app_main).get('/sample', status=200)

    assert len(transport.output) == 0
示例#12
0
def test_blacklisted_route_has_no_span(default_trace_id_generator):
    settings = {
        'zipkin.tracing_percent': 100,
        'zipkin.trace_id_generator': default_trace_id_generator,
        'zipkin.blacklisted_routes': ['sample_route'],
    }
    app_main, transport, firehose = generate_app_main(settings, firehose=True)

    WebTestApp(app_main).get('/sample', status=200)

    assert len(transport.output) == 0
    assert len(firehose.output) == 0
示例#13
0
def test_custom_create_zipkin_attr():
    custom_create_zipkin_attr = mock.Mock(return_value=ZipkinAttrs(
        trace_id='1234',
        span_id='1234',
        parent_span_id='5678',
        flags=0,
        is_sampled=True,
    ))

    settings = {'zipkin.create_zipkin_attr': custom_create_zipkin_attr}
    app_main, transport, _ = generate_app_main(settings)

    WebTestApp(app_main).get('/sample?test=1', status=200)

    assert custom_create_zipkin_attr.called
示例#14
0
def _assert_headers_present(settings, is_sampled):
    # Helper method for smoke testing proper setting of headers.
    # TraceId and ParentSpanId are set by default_trace_id_generator
    # and mock_generate_string in upstream test methods.
    expected = {
        'X-B3-Flags': '0',
        'X-B3-ParentSpanId': '17133d482ba4f605',
        'X-B3-Sampled': is_sampled,
        'X-B3-TraceId': '17133d482ba4f605',
    }

    app_main, _, _ = generate_app_main(settings)
    headers = WebTestApp(app_main).get('/sample_child_span', status=200)
    headers_json = headers.json
    headers_json.pop('X-B3-SpanId')  # Randomly generated - Ignore.

    assert expected == headers_json
示例#15
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)

    WebTestApp(app_main).get('/pet/123?test=1', status=200)

    assert len(transport.output) == 1
    spans = json.loads(transport.output[0])

    assert len(spans) == 1
    span = spans[0]
    # Check that the span name is the raw url by default
    assert span['name'] == 'GET /pet/123'
示例#16
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]))
示例#17
0
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)

    WebTestApp(app_main).get('/pet/123?test=1', status=200)

    assert len(transport.output) == 1
    spans = json.loads(transport.output[0])

    assert len(spans) == 1
    span = spans[0]
    # Check that the span name is the pyramid pattern and not the raw url
    assert span['name'] == 'GET /pet/{petId}'
示例#18
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]))
示例#19
0
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]))
示例#20
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
    )
示例#21
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]))
示例#22
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)

    WebTestApp(app_main).get('/abcd?test=1', status=404)

    assert len(transport.output) == 1
    spans = json.loads(transport.output[0])
    assert len(spans) == 1

    span = spans[0]
    assert span['tags'] == {
        'http.uri': '/abcd',
        'http.uri.qs': '/abcd?test=1',
        'http.route': '',
        'response_status_code': '404',
    }
示例#23
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)

    WebTestApp(app_main).get('/sample?test=1', status=200)

    assert len(transport.output) == 1
    spans = json.loads(transport.output[0])
    assert len(spans) == 1

    span = spans[0]
    assert span['localEndpoint'] == {
        'ipv4': '1.2.2.1',
        'port': 1231,
        'serviceName': 'acceptance_service',
    }
示例#24
0
def test_unsampled_request_has_no_span(
    default_trace_id_generator,
    set_post_handler_hook,
    called,
):
    settings = {
        'zipkin.tracing_percent': 0,
        'zipkin.trace_id_generator': default_trace_id_generator,
    }

    mock_post_handler_hook = mock.Mock()
    if set_post_handler_hook:
        settings['zipkin.post_handler_hook'] = mock_post_handler_hook

    app_main, transport, _ = generate_app_main(settings)

    WebTestApp(app_main).get('/sample', status=200)

    assert len(transport.output) == 0
    assert mock_post_handler_hook.call_count == called
示例#25
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']
示例#26
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

    WebTestApp(app_main).get('/sample', status=200)

    assert len(transport.output) == 1
    spans = json.loads(transport.output[0])
    assert len(spans) == 1

    span = spans[0]
    # report_root_timestamp means there's no client span with the
    # same id, so the 'shared' flag should not be set.
    assert 'shared' not in span
    assert span['timestamp'] > old_time
    assert span['duration'] > 0
示例#27
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 = json.loads(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 server_span['annotations'] == [
        {
            'timestamp': mock.ANY,
            'value': 'py_zipkin.logging_end'
        },
    ]
示例#28
0
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 = json.loads(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['parentId'] == server_span['id']
    assert child_span['tags'] == {'a': '1'}
    assert child_span['name'] == 'my_span'
示例#29
0
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'
示例#30
0
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]))