예제 #1
0
def test_get_default_tracer(mock_contextvar):
    # We're in python 3.7+
    assert storage.get_default_tracer() == storage._contextvars_tracer.get()

    storage._contextvars_tracer = None

    # We're in python 2.7 to 3.6
    assert storage.get_default_tracer() == storage._thread_local_tracer.tracer
예제 #2
0
def clean_thread_local():
    yield

    stack = ThreadLocalStack()
    while stack.pop():
        pass

    default_span_storage().clear()

    while get_default_tracer().pop_zipkin_attrs():
        pass
    get_default_tracer()._span_storage.clear()
예제 #3
0
def create_http_headers_for_new_span(context_stack=None, tracer=None):
    """
    Generate the headers for a new zipkin span.

    .. note::

        If the method is not called from within a zipkin_trace context,
        empty dict will be returned back.

    :returns: dict containing (X-B3-TraceId, X-B3-SpanId, X-B3-ParentSpanId,
                X-B3-Flags and X-B3-Sampled) keys OR an empty dict.
    """
    if tracer:
        zipkin_attrs = tracer.get_zipkin_attrs()
    elif context_stack:
        zipkin_attrs = context_stack.get()
    else:
        zipkin_attrs = get_default_tracer().get_zipkin_attrs()

    if not zipkin_attrs:
        return {}

    return {
        'X-B3-TraceId': zipkin_attrs.trace_id,
        'X-B3-SpanId': generate_random_64bit_string(),
        'X-B3-ParentSpanId': zipkin_attrs.span_id,
        'X-B3-Flags': '0',
        'X-B3-Sampled': '1' if zipkin_attrs.is_sampled else '0',
    }
예제 #4
0
def test_memory_leak():
    # In py_zipkin >= 0.13.0 and <= 0.14.0 this test fails since the
    # span_storage contains 10 spans once you exit the for loop.
    mock_transport_handler, mock_logs = mock_logger()
    assert len(get_default_tracer().get_spans()) == 0
    for _ in range(10):
        with zipkin.zipkin_client_span(
                service_name='test_service_name',
                span_name='test_span_name',
                transport_handler=mock_transport_handler,
                sample_rate=0.0,
                encoding=Encoding.V2_JSON,
        ):
            with zipkin.zipkin_span(
                    service_name='inner_service_name',
                    span_name='inner_span_name',
            ):
                pass

    assert len(mock_logs) == 0
    assert len(get_default_tracer().get_spans()) == 0
예제 #5
0
def test_zipkin_tween_context_stack(
    dummy_request,
    dummy_response,
):
    old_context_stack = get_default_tracer()._context_stack
    dummy_request.registry.settings = {
        'zipkin.is_tracing': lambda _: False,
        'zipkin.transport_handler': MockTransport(),
        'zipkin.request_context': 'rctxstorage.zipkin_context',
    }

    context_stack = mock.Mock(spec=Stack)
    dummy_request.rctxstorage = DummyRequestContext(
        zipkin_context=context_stack, )

    handler = mock.Mock(return_value=dummy_response)
    response = tween.zipkin_tween(handler, None)(dummy_request)
    get_default_tracer()._context_stack = old_context_stack

    assert response == dummy_response

    assert context_stack.push.call_count == 1
    assert context_stack.pop.call_count == 1
예제 #6
0
def run_inside_another_thread(transport):
    """Run this function inside a different thread.

    :param transport: transport handler. We need to pass it in since any
        assertion we do inside this thread gets silently swallowed, so we
        need a way to return the results to the main thread.
    :type transport: MockTransportHandler
    """
    with get_default_tracer().zipkin_span(
            service_name='webapp',
            span_name='index',
            transport_handler=transport,
            sample_rate=100.0,
            encoding=Encoding.V2_JSON,
    ):
        do_stuff()
예제 #7
0
    def tween(request):
        zipkin_settings = _get_settings_from_request(request)
        tracer = get_default_tracer()

        tween_kwargs = dict(
            service_name=zipkin_settings.service_name,
            span_name=zipkin_settings.span_name,
            zipkin_attrs=zipkin_settings.zipkin_attrs,
            transport_handler=zipkin_settings.transport_handler,
            host=zipkin_settings.host,
            port=zipkin_settings.port,
            add_logging_annotation=zipkin_settings.add_logging_annotation,
            report_root_timestamp=zipkin_settings.report_root_timestamp,
            context_stack=zipkin_settings.context_stack,
            max_span_batch_size=zipkin_settings.max_span_batch_size,
            encoding=zipkin_settings.encoding,
            kind=Kind.SERVER,
        )

        # Only set the firehose_handler if it's defined and only if the current
        # request is not blacklisted. This prevents py_zipkin from emitting
        # firehose spans for blacklisted paths like /status
        if zipkin_settings.firehose_handler is not None and \
                not should_not_sample_path(request) and \
                not should_not_sample_route(request):
            tween_kwargs['firehose_handler'] = zipkin_settings.firehose_handler

        with tracer.zipkin_span(**tween_kwargs) as zipkin_context:
            response = handler(request)
            if zipkin_settings.use_pattern_as_span_name and request.matched_route:
                zipkin_context.override_span_name('{} {}'.format(
                    request.method,
                    request.matched_route.pattern,
                ))
            zipkin_context.update_binary_annotations(
                get_binary_annotations(request, response),
            )

            if zipkin_settings.post_handler_hook:
                zipkin_settings.post_handler_hook(
                    request,
                    response,
                    zipkin_context
                )

            return response
예제 #8
0
def get_thread_local_zipkin_attrs():
    """A wrapper to return _thread_local.zipkin_attrs

    Returns a list of ZipkinAttrs objects, used for intra-process context
    propagation.

    .. deprecated::
       Use the Tracer interface which offers better multi-threading support.
       get_thread_local_zipkin_attrs will be removed in version 1.0.

    :returns: list that may contain zipkin attribute tuples
    :rtype: list
    """
    log.warning(
        'get_thread_local_zipkin_attrs is deprecated. See DEPRECATIONS.rst'
        ' for details on how to migrate to using Tracer.')
    return get_default_tracer()._context_stack._storage
예제 #9
0
def get_thread_local_span_storage():
    """A wrapper to return _thread_local.span_storage

    Returns a SpanStorage object used to temporarily store all spans created in
    the current process. The transport handlers will pull from this storage when
    they emit the spans.

    .. deprecated::
       Use the Tracer interface which offers better multi-threading support.
       get_thread_local_span_storage will be removed in version 1.0.

    :returns: SpanStore object containing all non-root spans.
    :rtype: py_zipkin.storage.SpanStore
    """
    log.warning(
        'get_thread_local_span_storage is deprecated. See DEPRECATIONS.rst'
        ' for details on how to migrate to using Tracer.')
    return get_default_tracer()._span_storage
예제 #10
0
def create_http_headers(
    context_stack=None, tracer=None, new_span_id=False,
):
    """
    Generate the headers for a new zipkin span.

    .. note::

        If the method is not called from within a zipkin_trace context,
        empty dict will be returned back.

    :returns: dict containing (X-B3-TraceId, X-B3-SpanId, X-B3-ParentSpanId,
                X-B3-Flags and X-B3-Sampled) keys OR an empty dict.
    """
    if tracer:
        zipkin_attrs = tracer.get_zipkin_attrs()
    elif context_stack:
        zipkin_attrs = context_stack.get()
    else:
        zipkin_attrs = get_default_tracer().get_zipkin_attrs()

    # If zipkin_attrs is still not set then we're not in a trace context
    if not zipkin_attrs:
        return {}

    if new_span_id:
        span_id = generate_random_64bit_string()
        parent_span_id = zipkin_attrs.span_id
    else:
        span_id = zipkin_attrs.span_id
        parent_span_id = zipkin_attrs.parent_span_id

    return {
        "X-B3-TraceId": zipkin_attrs.trace_id,
        "X-B3-SpanId": span_id,
        "X-B3-ParentSpanId": parent_span_id,
        "X-B3-Flags": "0",
        "X-B3-Sampled": "1" if zipkin_attrs.is_sampled else "0",
    }
예제 #11
0
def test_has_default_tracer(mock_contextvar, mock_tracer, mock_tl):
    # shut up the py2 "yes" answer while testing the py3.7+ cases
    del mock_tl.tracer

    # We're in python 3.7+
    mock_contextvar.get.side_effect = LookupError
    assert not storage.has_default_tracer()
    mock_contextvar.get.side_effect = None
    mock_contextvar.get.return_value = "does not matter"

    assert storage.get_default_tracer() == storage._contextvars_tracer.get()
    assert storage.has_default_tracer()

    storage._contextvars_tracer = None

    # We're in python 2.7 to 3.6
    assert not storage.has_default_tracer()

    tracer = storage._get_thread_local_tracer()

    assert storage.has_default_tracer()
    assert mock_tracer.call_count == 1
    assert tracer == mock_tracer.return_value
예제 #12
0
def test_push_zipkin_attrs_adds_new_zipkin_attrs_to_list():
    tracer = storage.get_default_tracer()
    with mock.patch.object(tracer._context_stack, "_storage", ["foo"]):
        assert "foo" == thread_local.get_zipkin_attrs()
        thread_local.push_zipkin_attrs("bar")
        assert "bar" == thread_local.get_zipkin_attrs()
예제 #13
0
# -*- coding: utf-8 -*-
import json
from threading import Thread

from py_zipkin import Encoding
from py_zipkin.storage import get_default_tracer
from py_zipkin.zipkin import zipkin_span
from tests.test_helpers import MockTransportHandler

tracer = get_default_tracer()


@zipkin_span(service_name='service1', span_name='service1_do_stuff')
def do_stuff():
    return 'OK'


def run_inside_another_thread(transport):
    """Run this function inside a different thread.

    :param transport: transport handler. We need to pass it in since any
        assertion we do inside this thread gets silently swallowed, so we
        need a way to return the results to the main thread.
    :type transport: MockTransportHandler
    """
    with get_default_tracer().zipkin_span(
            service_name='webapp',
            span_name='index',
            transport_handler=transport,
            sample_rate=100.0,
            encoding=Encoding.V2_JSON,
예제 #14
0
def _Thread_pre_start(self):
    self._orig_tracer = None
    if storage.has_default_tracer():
        self._orig_tracer = storage.get_default_tracer().copy()
예제 #15
0
def test_pop_zipkin_attrs_removes_the_last_zipkin_attrs():
    tracer = storage.get_default_tracer()
    with mock.patch.object(tracer._context_stack, '_storage', ['foo', 'bar']):
        assert 'bar' == thread_local.pop_zipkin_attrs()
        assert 'foo' == thread_local.get_zipkin_attrs()
예제 #16
0
import mock
import pytest
from py_zipkin.storage import get_default_tracer
from py_zipkin.storage import Stack

from pyramid_zipkin import tween
from tests.acceptance.test_helper import MockTransport

DummyRequestContext = collections.namedtuple(
    'RequestContext',
    ['zipkin_context'],
)


@pytest.mark.parametrize('is_tracing', [True, False])
@mock.patch.object(get_default_tracer(), 'zipkin_span', autospec=True)
def test_zipkin_tween_sampling(
    mock_span,
    dummy_request,
    dummy_response,
    is_tracing,
):
    """
    We should enter py_zipkin context manager and
    generate a trace id regardless of whether we are sampling
    """
    dummy_request.registry.settings = {
        'zipkin.is_tracing': lambda _: is_tracing,
        'zipkin.transport_handler': MockTransport(),
    }
    handler = mock.Mock()
예제 #17
0
def test_push_zipkin_attrs_adds_new_zipkin_attrs_to_list():
    tracer = storage.get_default_tracer()
    with mock.patch.object(tracer._context_stack, '_storage', ['foo']):
        assert 'foo' == thread_local.get_zipkin_attrs()
        thread_local.push_zipkin_attrs('bar')
        assert 'bar' == thread_local.get_zipkin_attrs()
예제 #18
0
def test_get_thread_local_span_storage_present():
    tracer = storage.get_default_tracer()
    with mock.patch.object(tracer, "_span_storage", SpanStorage(["foo"])):
        assert thread_local.get_thread_local_span_storage() == SpanStorage(
            ["foo"])
예제 #19
0
def test_get_zipkin_attrs_returns_the_last_of_the_list():
    tracer = storage.get_default_tracer()
    with mock.patch.object(tracer._context_stack, "_storage", ["foo"]):
        assert "foo" == thread_local.get_zipkin_attrs()
예제 #20
0
def test_create_headers_for_new_span_empty_if_no_active_request():
    with mock.patch.object(get_default_tracer(), 'get_zipkin_attrs') as mock_ctx:
        mock_ctx.return_value = None
        assert {} == zipkin.create_http_headers_for_new_span()
예제 #21
0
def test_pop_zipkin_attrs_removes_the_last_zipkin_attrs():
    tracer = storage.get_default_tracer()
    with mock.patch.object(tracer._context_stack, "_storage", ["foo", "bar"]):
        assert "bar" == thread_local.pop_zipkin_attrs()
        assert "foo" == thread_local.get_zipkin_attrs()
예제 #22
0
 def get_tracer(self):
     if self._tracer is not None:
         return self._tracer
     else:
         return get_default_tracer()
예제 #23
0
def test_get_thread_local_zipkin_attrs_returns_back_zipkin_attrs_if_present():
    tracer = storage.get_default_tracer()
    with mock.patch.object(tracer._context_stack, "_storage", ["foo"]):
        assert thread_local.get_thread_local_zipkin_attrs() == ["foo"]