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
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()
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', }
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
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
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()
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
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
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
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", }
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
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()
# -*- 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,
def _Thread_pre_start(self): self._orig_tracer = None if storage.has_default_tracer(): self._orig_tracer = storage.get_default_tracer().copy()
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()
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()
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()
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"])
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()
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()
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()
def get_tracer(self): if self._tracer is not None: return self._tracer else: return get_default_tracer()
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"]