def test_trace_requests_span_extractor(monkeypatch): resp = Response() resp.status_code = 200 resp.url = "http://example.com/" recorder = Recorder() t = BasicTracer(recorder=recorder) t.register_required_propagators() opentracing.tracer = t top_span = opentracing.tracer.start_span(operation_name='top_span') def span_extractor(*args, **kwargs): return top_span trace_requests(span_extractor=span_extractor) monkeypatch.setattr( 'opentracing_utils.libs._requests.__requests_http_send', assert_send_request_mock(resp)) # disable getting the span from stack monkeypatch.setattr('opentracing_utils.span.inspect_span_from_stack', lambda: None) response = requests.get("http://example.com/") top_span.finish() assert len(recorder.spans) == 2 assert recorder.spans[0].context.trace_id == top_span.context.trace_id assert recorder.spans[0].parent_id == recorder.spans[1].context.span_id assert recorder.spans[0].operation_name == 'http_send_get' assert recorder.spans[-1].operation_name == 'top_span' assert response.status_code == resp.status_code
def test_trace_requests_session(monkeypatch): resp = Response() resp.status_code = 200 resp.url = URL monkeypatch.setattr( 'opentracing_utils.libs._requests.__requests_http_send', assert_send_reuqest_mock(resp)) recorder = Recorder() t = BasicTracer(recorder=recorder) t.register_required_propagators() opentracing.tracer = t top_span = opentracing.tracer.start_span(operation_name='top_span') with top_span: session = requests.Session() session.headers.update({CUSTOM_HEADER: CUSTOM_HEADER_VALUE}) response = session.get(URL) assert len(recorder.spans) == 2 assert recorder.spans[0].context.trace_id == top_span.context.trace_id assert recorder.spans[0].parent_id == recorder.spans[-1].context.span_id assert recorder.spans[-1].operation_name == 'top_span' assert response.status_code == resp.status_code assert recorder.spans[0].tags[tags.HTTP_STATUS_CODE] == resp.status_code assert recorder.spans[0].tags[tags.HTTP_URL] == URL assert recorder.spans[0].tags[tags.HTTP_METHOD] == 'GET' assert recorder.spans[0].tags[tags.SPAN_KIND] == tags.SPAN_KIND_RPC_CLIENT assert recorder.spans[0].tags[tags.PEER_HOSTNAME] == 'example.com'
def test_trace_requests_extract_span_fail(monkeypatch): resp = Response() resp.status_code = 200 resp.url = URL send_request_mock = MagicMock() send_request_mock.return_value = resp extract_span_mock = MagicMock() extract_span_mock.return_value = None, None monkeypatch.setattr('opentracing_utils.libs._requests.__requests_http_send', send_request_mock) monkeypatch.setattr('opentracing_utils.libs._requests.get_span_from_kwargs', extract_span_mock) logger = MagicMock() monkeypatch.setattr('opentracing_utils.libs._requests.logger', logger) recorder = Recorder() t = BasicTracer(recorder=recorder) t.register_required_propagators() opentracing.tracer = t session = requests.Session() session.headers.update({CUSTOM_HEADER: CUSTOM_HEADER_VALUE}) response = session.get(URL) assert response.status_code == resp.status_code logger.warn.assert_called_once()
def wrapper(*args, **kwargs): tracer = BasicTracer() tracer.register_required_propagators() #span_context = tracer.extract( # format=Format.HTTP_HEADERS, # carrier=request.headers, #) # terrible workaround, because the python opentracing libraries lack a reference implementation # https://github.com/opentracing/opentracing-python # (just no-op). I do not have time to write the reference implementation, so we'll manually extract the # headers here, possibly breaking forward compatibility. fault = request.headers.get("Ot-Baggage-Injectfault") if fault is not None: service, faults = fault.split("_") if service != name: return func(*args, **kwargs) else: print "FAULT is " + fault f, param = faults.split(":") if f == "delay": time.sleep(int(param)) return func(*args, **kwargs) else: return else: return func(*args, **kwargs)
def get_recorder(): recorder = Recorder() t = BasicTracer(recorder=recorder) t.register_required_propagators() opentracing.tracer = t return recorder
def test_trace_requests_no_parent_span(monkeypatch): resp = Response() resp.status_code = 200 resp.url = URL monkeypatch.setattr('opentracing_utils.libs._requests.__requests_http_send', assert_send_request_mock(resp)) recorder = Recorder() t = BasicTracer(recorder=recorder) t.register_required_propagators() opentracing.tracer = t session = requests.Session() session.headers.update({CUSTOM_HEADER: CUSTOM_HEADER_VALUE}) response = session.get(URL) assert len(recorder.spans) == 1 assert recorder.spans[0].tags[tags.HTTP_STATUS_CODE] == resp.status_code assert recorder.spans[0].tags[tags.HTTP_URL] == URL assert recorder.spans[0].tags[tags.HTTP_METHOD] == 'GET' assert recorder.spans[0].tags[tags.SPAN_KIND] == tags.SPAN_KIND_RPC_CLIENT assert recorder.spans[0].tags[tags.PEER_HOSTNAME] == 'example.com' assert recorder.spans[0].tags['timeout'] is None assert recorder.spans[0].tags[tags.COMPONENT] == 'requests' assert recorder.spans[0].operation_name == '{}_get'.format(OPERATION_NAME_PREFIX) assert response.status_code == resp.status_code
def tracer(asyncio_scope_manager): t = BasicTracer( recorder=InMemoryRecorder(), scope_manager=asyncio_scope_manager, ) t.register_required_propagators() return t
def test_trace_requests_no_error_tag(monkeypatch): resp = Response() resp.status_code = 400 resp.url = URL trace_requests(set_error_tag=False) monkeypatch.setattr('opentracing_utils.libs._requests.__requests_http_send', assert_send_request_mock(resp)) recorder = Recorder() t = BasicTracer(recorder=recorder) t.register_required_propagators() opentracing.tracer = t top_span = opentracing.tracer.start_span(operation_name='top_span') with top_span: response = requests.get(URL, headers={CUSTOM_HEADER: CUSTOM_HEADER_VALUE}) assert len(recorder.spans) == 2 assert recorder.spans[0].context.trace_id == top_span.context.trace_id assert recorder.spans[0].parent_id == recorder.spans[-1].context.span_id assert response.status_code == resp.status_code assert recorder.spans[0].tags[tags.HTTP_STATUS_CODE] == resp.status_code assert recorder.spans[0].tags[tags.HTTP_URL] == URL assert recorder.spans[0].tags[tags.HTTP_METHOD] == 'GET' assert recorder.spans[0].tags[tags.SPAN_KIND] == tags.SPAN_KIND_RPC_CLIENT assert recorder.spans[0].tags[tags.PEER_HOSTNAME] == 'example.com' assert recorder.spans[0].tags['timeout'] is None assert recorder.spans[0].tags[tags.COMPONENT] == 'requests' assert recorder.spans[0].operation_name == '{}_get'.format(OPERATION_NAME_PREFIX) assert 'error' not in recorder.spans[0].tags
def test_trace_requests_with_ignore_url_pattern_prune_kwargs(monkeypatch): """ In case there is a parent span already, the ignore url pattern must still be respected """ resp = Response() resp.status_code = 200 resp.url = URL trace_requests(ignore_url_patterns=[r".*{}.*".format(URL)]) monkeypatch.setattr('opentracing_utils.libs._requests.__requests_http_send', assert_send_request_mock_no_traces(resp)) @trace() def f1(): pass recorder = Recorder() t = BasicTracer(recorder=recorder) t.register_required_propagators() opentracing.tracer = t top_span = opentracing.tracer.start_span(operation_name='top_span') with top_span: response = requests.get(URL, headers={CUSTOM_HEADER: CUSTOM_HEADER_VALUE}) f1() # Top span, and @trace for f1() create spans. With the ignore pattern # in place, the call to requests.get should not add a span assert len(recorder.spans) == 2 assert recorder.spans[0].context.trace_id == top_span.context.trace_id assert recorder.spans[0].operation_name == 'f1' assert recorder.spans[1].operation_name == 'top_span' assert response.status_code == resp.status_code
def test_propagation(): tracer = BasicTracer() tracer.register_required_propagators() sp = tracer.start_span(operation_name='test') sp.context.sampled = False sp.set_baggage_item('foo', 'bar') # Test invalid types with pytest.raises(UnsupportedFormatException): tracer.inject(sp.context, 'invalid', {}) with pytest.raises(UnsupportedFormatException): tracer.extract('invalid', {}) tests = [(Format.BINARY, bytearray()), (Format.TEXT_MAP, {})] for format, carrier in tests: tracer.inject(sp.context, format, carrier) extracted_ctx = tracer.extract(format, carrier) assert extracted_ctx.trace_id == sp.context.trace_id assert extracted_ctx.span_id == sp.context.span_id assert extracted_ctx.sampled == sp.context.sampled assert extracted_ctx.baggage == sp.context.baggage # Test string value of sampled field headers = {} tracer.inject(sp.context, Format.HTTP_HEADERS, headers) headers['ot-tracer-sampled'] = '0' span_ctx0 = tracer.extract(Format.HTTP_HEADERS, headers) assert not span_ctx0.sampled headers['ot-tracer-sampled'] = '1' span_ctx1 = tracer.extract(Format.HTTP_HEADERS, headers) assert span_ctx1.sampled
def main(): # Setup BasicTracer to log to console logger = logging.getLogger('span_logging') logger.setLevel(logging.DEBUG) hndlr = logging.StreamHandler(sys.stdout) hndlr.setFormatter( logging.Formatter("[%(levelname)-8s] %(name)s: %(message)s")) logger.addHandler(hndlr) recorder = LogSpanRecorder(logger) tracer = BasicTracer(recorder=recorder) tracer.register_required_propagators() # Use tracer to create spans span = tracer.start_span(operation_name='main') for i in range(10): child_span = tracer.start_span(operation_name='loop', child_of=span) child_span.set_tag('i', i) child_span.log_kv({'message': "Sleeping for 1 second"}) time.sleep(1) child_span.finish() span.finish()
def test_propagation(): tracer = BasicTracer() tracer.register_required_propagators() sp = tracer.start_span(operation_name='test') sp.context.sampled = False sp.set_baggage_item('foo', 'bar') # Test invalid types with pytest.raises(UnsupportedFormatException): tracer.inject(sp.context, 'invalid', {}) with pytest.raises(UnsupportedFormatException): tracer.extract('invalid', {}) tests = [(Format.BINARY, bytearray()), (Format.TEXT_MAP, {})] for format, carrier in tests: tracer.inject(sp.context, format, carrier) extracted_ctx = tracer.extract(format, carrier) assert extracted_ctx.trace_id == sp.context.trace_id assert extracted_ctx.span_id == sp.context.span_id assert extracted_ctx.sampled == sp.context.sampled assert extracted_ctx.baggage == sp.context.baggage # Test string value of sampled field headers = {} tracer.inject(sp.context, Format.HTTP_HEADERS, headers) headers['ot-tracer-sampled'] = '0' span_ctx0 = tracer.extract(Format.HTTP_HEADERS, headers) assert not span_ctx0.sampled headers['ot-tracer-sampled'] = '1' span_ctx1 = tracer.extract(Format.HTTP_HEADERS, headers) assert span_ctx1.sampled
async def before_srver_start(app, loop): queue = asyncio.Queue() app.queue = queue loop.create_task(consume(queue, app.config.ZIPKIN_SERVER)) reporter = AioReporter(queue=queue) tracer = BasicTracer(recorder=reporter) tracer.register_required_propagators() opentracing.tracer = tracer app.db = await ConnectionPool(loop=loop).init(DB_CONFIG)
def tracer(): t = BasicTracer(recorder=InMemoryRecorder()) t.register_required_propagators() old_tracer = opentracing.tracer opentracing.tracer = t try: yield t except: opentracing.tracer = old_tracer
def tracer(): dummy_tracer = BasicTracer(recorder=InMemoryRecorder()) dummy_tracer.register_required_propagators() old_tracer = opentracing.tracer opentracing.tracer = dummy_tracer try: yield dummy_tracer finally: opentracing.tracer = old_tracer
def test_start_span(): """ Test in process child span creation.""" tracer = BasicTracer() tracer.register_required_propagators() sp = tracer.start_span(operation_name='test') sp.set_baggage_item('foo', 'bar') child = tracer.start_span(operation_name='child', child_of=sp.context) assert child.context.trace_id == sp.context.trace_id assert child.context.sampled == sp.context.sampled assert child.context.baggage == sp.context.baggage assert child.parent_id == sp.context.span_id
def test_span_missing_all_fields(): tracer = BasicTracer() tracer.register_required_propagators() # Given an empty carrier headers = {} # When .extract is called ctx = tracer.extract(Format.TEXT_MAP, headers) # Then it should return None assert ctx is None
def test_start_span(): """ Test in process child span creation.""" tracer = BasicTracer() tracer.register_required_propagators() sp = tracer.start_span(operation_name='test') sp.set_baggage_item('foo', 'bar') child = tracer.start_span( operation_name='child', child_of=sp.context) assert child.context.trace_id == sp.context.trace_id assert child.context.sampled == sp.context.sampled assert child.context.baggage == sp.context.baggage assert child.parent_id == sp.context.span_id
def tracer(): old_tracer = opentracing.tracer t = BasicTracer( recorder=InMemoryRecorder(), scope_manager=TornadoScopeManager(), ) t.register_required_propagators() opentracing.tracer = t try: yield t finally: opentracing.tracer = old_tracer
async def before_srver_start(app, loop): queue = asyncio.Queue() app.queue = queue loop.create_task(consume(queue, app.config['ZIPKIN_SERVER'])) reporter = AioReporter(queue=queue) tracer = BasicTracer(recorder=reporter) tracer.register_required_propagators() opentracing.tracer = tracer app.db = await ConnectionPool(loop=loop).init(app.config['DB_CONFIG']) service_names = app.config['SERVICES'] app.services = defaultdict(list) service = ServiceManager(loop=loop) for name in service_names: s = service.discovery_service(name) app.services[s].extend(s)
def test_span_missing_all_headers(): tracer = BasicTracer() tracer.register_required_propagators() # Given an carrier with no ot-headers headers = { 'Content-Type': 'text/html', 'Authorization': 'Digest 123456', } # When .extract is called ctx = tracer.extract(Format.TEXT_MAP, headers) # Then it should return None assert ctx is None
def test_span_with_baggage_only(): tracer = BasicTracer() tracer.register_required_propagators() # Given a carrier with only baggage: headers = { 'ot-baggage-example': 'ok', } # When .extract is called with pytest.raises(SpanContextCorruptedException) as exc: tracer.extract(Format.TEXT_MAP, headers) # Then it should raise SpanContextCorruptedException assert str(exc.value) == 'found baggage without required fields'
def test_span_missing_two_fields(): tracer = BasicTracer() tracer.register_required_propagators() # Given a carrier with only ot-tracer-traceid: headers = { 'ot-tracer-traceid': '1c3b00da', } # When .extract is called with pytest.raises(SpanContextCorruptedException) as exc: tracer.extract(Format.TEXT_MAP, headers) # Then it should raise SpanContextCorruptedException assert str(exc.value) == 'expected to parse 3 fields, but parsed 1 instead'
async def before_server_start(app, loop): queue = asyncio.Queue() app.queue = queue loop.create_task(consume(queue, app)) loop.create_task(service_watcher(app, loop)) reporter = AioReporter(queue=queue) tracer = BasicTracer(recorder=reporter) tracer.register_required_propagators() opentracing.tracer = tracer app.db = await ConnectionPool(loop=loop).init(app.config['DB_CONFIG']) service = ServiceManager(loop=loop, host=app.config['CONSUL_AGENT_HOST']) services = await service.discovery_services() app.services = defaultdict(list) for name in services[1].keys(): s = await service.discovery_service(name) app.services[name].extend(s)
async def before_server_start(app, loop): queue = asyncio.Queue() app.queue = queue if consul_enabled: app.service_manager = ServiceManager( consul_host=app.config['CONSUL_AGENT_HOST'], consul_port=app.config['CONSUL_AGENT_PORT'], loop=loop, ) loop.create_task(service_watcher(app, loop)) loop.create_task(consume(queue, app)) reporter = AioReporter(queue=queue) tracer = BasicTracer(recorder=reporter) tracer.register_required_propagators() opentracing.tracer = tracer app.db = await ConnectionPool(loop=loop).init(app.config['DB_CONFIG'])
def test_trace_requests_with_tags(monkeypatch): resp = Response() resp.status_code = 200 resp.url = URL trace_requests(default_tags={'tag1': 'value1'}) monkeypatch.setattr('opentracing_utils.libs._requests.__requests_http_send', assert_send_request_mock(resp)) @trace() def f1(): pass recorder = Recorder() t = BasicTracer(recorder=recorder) t.register_required_propagators() opentracing.tracer = t top_span = opentracing.tracer.start_span(operation_name='top_span') with top_span: response = requests.get(URL, headers={CUSTOM_HEADER: CUSTOM_HEADER_VALUE}) f1() assert len(recorder.spans) == 3 assert recorder.spans[0].context.trace_id == top_span.context.trace_id assert recorder.spans[0].parent_id == recorder.spans[-1].context.span_id assert recorder.spans[-1].operation_name == 'top_span' # ``requests`` default tags do not leak to other unrelated spans! assert recorder.spans[1].tags == {} assert recorder.spans[1].operation_name == 'f1' assert response.status_code == resp.status_code assert recorder.spans[0].tags[tags.HTTP_STATUS_CODE] == resp.status_code assert recorder.spans[0].tags[tags.HTTP_URL] == URL assert recorder.spans[0].tags[tags.HTTP_METHOD] == 'GET' assert recorder.spans[0].tags[tags.SPAN_KIND] == tags.SPAN_KIND_RPC_CLIENT assert recorder.spans[0].tags[tags.PEER_HOSTNAME] == 'example.com' assert recorder.spans[0].tags['timeout'] is None assert recorder.spans[0].tags[tags.COMPONENT] == 'requests' assert recorder.spans[0].operation_name == '{}_get'.format(OPERATION_NAME_PREFIX) assert recorder.spans[0].tags['tag1'] == 'value1'
def test_span_corrupted_invalid_traceid_value(): tracer = BasicTracer() tracer.register_required_propagators() # Given a carrier with invalid 'ot-tracer-traceid' value headers = { 'ot-tracer-traceid': 'nothex', 'ot-tracer-sampled': 'false', 'ot-tracer-spanid': '1c3b00da', } # When .extract is called with pytest.raises(SpanContextCorruptedException) as exc: tracer.extract(Format.TEXT_MAP, headers) # Then it should raise SpanContextCorruptedException assert str(exc.value) == ( "ot-tracer-traceid got an invalid hexadecimal value 'nothex'")
def test_trace_requests_nested(monkeypatch): resp = Response() resp.status_code = 200 resp.url = URL monkeypatch.setattr('opentracing_utils.libs._requests.__requests_http_send', assert_send_request_mock(resp)) recorder = Recorder() t = BasicTracer(recorder=recorder) t.register_required_propagators() opentracing.tracer = t top_span = opentracing.tracer.start_span(operation_name='top_span') @trace() def caller(): def child(): session = requests.Session() session.headers.update({CUSTOM_HEADER: CUSTOM_HEADER_VALUE}) return session.get(URL) # child is un-traced, but rquests will consume the current span! return child() with top_span: response = caller() assert len(recorder.spans) == 3 assert recorder.spans[0].context.trace_id == top_span.context.trace_id assert recorder.spans[0].parent_id == recorder.spans[1].context.span_id assert recorder.spans[-1].operation_name == 'top_span' assert response.status_code == resp.status_code assert recorder.spans[0].tags[tags.HTTP_STATUS_CODE] == resp.status_code assert recorder.spans[0].tags[tags.HTTP_URL] == URL assert recorder.spans[0].tags[tags.HTTP_METHOD] == 'GET' assert recorder.spans[0].tags[tags.SPAN_KIND] == tags.SPAN_KIND_RPC_CLIENT assert recorder.spans[0].tags[tags.PEER_HOSTNAME] == 'example.com' assert recorder.spans[0].tags['timeout'] is None assert recorder.spans[0].tags[tags.COMPONENT] == 'requests' assert recorder.spans[0].operation_name == '{}_get'.format(OPERATION_NAME_PREFIX)
def test_trace_requests_scope_active(monkeypatch, status_code): resp = Response() resp.status_code = status_code resp.url = URL monkeypatch.setattr('opentracing_utils.libs._requests.__requests_http_send', assert_send_request_mock(resp)) @trace() def f1(): pass recorder = Recorder() t = BasicTracer(recorder=recorder) t.register_required_propagators() opentracing.tracer = t top_span = None with opentracing.tracer.start_active_span(operation_name='top_span', finish_on_close=True) as top_scope: top_span = top_scope.span response = requests.get(URL, headers={CUSTOM_HEADER: CUSTOM_HEADER_VALUE}) f1() assert len(recorder.spans) == 3 assert recorder.spans[0].context.trace_id == top_span.context.trace_id assert recorder.spans[0].parent_id == recorder.spans[-1].context.span_id assert recorder.spans[-1].operation_name == 'top_span' assert response.status_code == resp.status_code assert recorder.spans[0].tags[tags.HTTP_STATUS_CODE] == resp.status_code assert recorder.spans[0].tags[tags.HTTP_URL] == URL assert recorder.spans[0].tags[tags.HTTP_METHOD] == 'GET' assert recorder.spans[0].tags[tags.SPAN_KIND] == tags.SPAN_KIND_RPC_CLIENT assert recorder.spans[0].tags[tags.PEER_HOSTNAME] == 'example.com' assert recorder.spans[0].tags['timeout'] is None assert recorder.spans[0].tags[tags.COMPONENT] == 'requests' assert recorder.spans[0].operation_name == '{}_get'.format(OPERATION_NAME_PREFIX) if status_code >= 400: assert recorder.spans[0].tags['error'] is True
def test_trace_requests(monkeypatch, status_code): resp = Response() resp.status_code = status_code resp.url = URL monkeypatch.setattr( 'opentracing_utils.libs._requests.__requests_http_send', assert_send_reuqest_mock(resp)) @trace() def f1(): pass recorder = Recorder() t = BasicTracer(recorder=recorder) t.register_required_propagators() opentracing.tracer = t top_span = opentracing.tracer.start_span(operation_name='top_span') with top_span: response = requests.get(URL, headers={CUSTOM_HEADER: CUSTOM_HEADER_VALUE}) f1() assert len(recorder.spans) == 3 assert recorder.spans[0].context.trace_id == top_span.context.trace_id assert recorder.spans[0].parent_id == recorder.spans[-1].context.span_id assert recorder.spans[-1].operation_name == 'top_span' assert response.status_code == resp.status_code assert recorder.spans[0].tags[tags.HTTP_STATUS_CODE] == resp.status_code assert recorder.spans[0].tags[tags.HTTP_URL] == URL assert recorder.spans[0].tags[tags.HTTP_METHOD] == 'GET' assert recorder.spans[0].tags[tags.SPAN_KIND] == tags.SPAN_KIND_RPC_CLIENT assert recorder.spans[0].tags[tags.PEER_HOSTNAME] == 'example.com' if status_code >= 400: assert recorder.spans[0].tags['error'] is True
def test_trace_requests_with_use_scope_manager(monkeypatch): resp = Response() resp.status_code = 200 resp.url = URL recorder = Recorder() t = BasicTracer(recorder=recorder) t.register_required_propagators() opentracing.tracer = t trace_requests(use_scope_manager=True) monkeypatch.setattr( 'opentracing_utils.libs._requests.__requests_http_send', assert_send_request_mock_scope_active(resp) ) response = requests.get(URL, headers={CUSTOM_HEADER: CUSTOM_HEADER_VALUE}) assert response.status_code == resp.status_code assert len(recorder.spans) == 1
def test_propagation(): tracer = BasicTracer() tracer.register_required_propagators() sp = tracer.start_span(operation_name='test') sp.context.sampled = False sp.set_baggage_item('foo', 'bar') # Test invalid types with pytest.raises(UnsupportedFormatException): tracer.inject(sp.context, 'invalid', {}) with pytest.raises(UnsupportedFormatException): tracer.extract('invalid', {}) tests = [(Format.BINARY, bytearray()), (Format.TEXT_MAP, {})] for format, carrier in tests: tracer.inject(sp.context, format, carrier) extracted_ctx = tracer.extract(format, carrier) assert extracted_ctx.trace_id == sp.context.trace_id assert extracted_ctx.span_id == sp.context.span_id assert extracted_ctx.sampled == sp.context.sampled assert extracted_ctx.baggage == sp.context.baggage
def tracer(self): t = BasicTracer() t.register_required_propagators() return t
def tracer(): t = BasicTracer(recorder=InMemoryRecorder()) t.register_required_propagators() return t