def test_with_nested_nonrecording_span(self): tracer = trace.get_tracer(__name__) with tracer.start_as_current_span( "requests HTTP GET" ) as span, set_ip_on_next_http_connection(span): with trace.use_span(INVALID_SPAN), set_ip_on_next_http_connection( INVALID_SPAN ): resp, body = self.perform_request() assert resp.status == 200 assert body == b"Hello!" span = self.assert_span(num_spans=1) self.assertEqual(span.attributes, {"net.peer.ip": "127.0.0.1"})
def test_with_nested_span(self): tracer = trace.get_tracer(__name__) with tracer.start_as_current_span( "requests HTTP GET" ) as span, set_ip_on_next_http_connection(span): with tracer.start_as_current_span( "urllib3 HTTP GET" ) as span2, set_ip_on_next_http_connection(span2): resp, body = self.perform_request() assert resp.status == 200 assert body == b"Hello!" for span in self.assert_span(num_spans=2): self.assertEqual(span.attributes, {"net.peer.ip": "127.0.0.1"})
def instrumented_urlopen(wrapped, instance, args, kwargs): if _is_instrumentation_suppressed(): return wrapped(*args, **kwargs) method = _get_url_open_arg("method", args, kwargs).upper() url = _get_url(instance, args, kwargs, url_filter) headers = _prepare_headers(kwargs) body = _get_url_open_arg("body", args, kwargs) span_name = f"HTTP {method.strip()}" span_attributes = { SpanAttributes.HTTP_METHOD: method, SpanAttributes.HTTP_URL: url, } with tracer.start_as_current_span( span_name, kind=SpanKind.CLIENT, attributes=span_attributes ) as span, set_ip_on_next_http_connection(span): if callable(request_hook): request_hook(span, instance, headers, body) inject(headers) with _suppress_further_instrumentation(): response = wrapped(*args, **kwargs) _apply_response(span, response) if callable(response_hook): response_hook(span, instance, response) return response
def test_with_only_nonrecording_span(self): with trace.use_span(INVALID_SPAN), set_ip_on_next_http_connection( INVALID_SPAN ): resp, body = self.perform_request() assert resp.status == 200 assert body == b"Hello!" self.assert_span(num_spans=0)
def _instrumented_requests_call(method: str, url: str, call_wrapped, get_or_create_headers): if context.get_value( _SUPPRESS_INSTRUMENTATION_KEY) or context.get_value( _SUPPRESS_HTTP_INSTRUMENTATION_KEY): return call_wrapped() # See # https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#http-client method = method.upper() span_name = "" if name_callback is not None: span_name = name_callback(method, url) if not span_name or not isinstance(span_name, str): span_name = get_default_span_name(method) url = remove_url_credentials(url) with tracer.start_as_current_span( span_name, kind=SpanKind.CLIENT) as span, set_ip_on_next_http_connection( span): exception = None if span.is_recording(): span.set_attribute(SpanAttributes.HTTP_METHOD, method) span.set_attribute(SpanAttributes.HTTP_URL, url) headers = get_or_create_headers() inject(headers) token = context.attach( context.set_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY, True)) try: result = call_wrapped() # *** PROCEED except Exception as exc: # pylint: disable=W0703 exception = exc result = getattr(exc, "response", None) finally: context.detach(token) if isinstance(result, Response): if span.is_recording(): span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, result.status_code) span.set_status( Status(http_status_to_status_code(result.status_code))) if span_callback is not None: span_callback(span, result) if exception is not None: raise exception.with_traceback(exception.__traceback__) return result
def test_uninstrument(self): HttpClientInstrumentor().uninstrument() tracer = trace.get_tracer(__name__) with tracer.start_as_current_span( "HTTP GET" ) as span, set_ip_on_next_http_connection(span): body = self.perform_request()[1] self.assertEqual(b"Hello!", body) # We should have a span, but it should have no attributes self.assertFalse(self.assert_span(num_spans=1).attributes) # instrument again to avoid warning message on tearDown HttpClientInstrumentor().instrument()
def instrumented_urlopen(wrapped, instance, args, kwargs): if _is_instrumentation_suppressed(): return wrapped(*args, **kwargs) method = _get_url_open_arg("method", args, kwargs).upper() url = _get_url(instance, args, kwargs, url_filter) headers = _prepare_headers(kwargs) body = _get_url_open_arg("body", args, kwargs) span_name = f"HTTP {method.strip()}" span_attributes = { SpanAttributes.HTTP_METHOD: method, SpanAttributes.HTTP_URL: url, } with tracer.start_as_current_span( span_name, kind=SpanKind.CLIENT, attributes=span_attributes ) as span, set_ip_on_next_http_connection(span): if callable(request_hook): request_hook(span, instance, headers, body) inject(headers) with _suppress_further_instrumentation(): start_time = default_timer() response = wrapped(*args, **kwargs) elapsed_time = round((default_timer() - start_time) * 1000) _apply_response(span, response) if callable(response_hook): response_hook(span, instance, response) request_size = 0 if body is None else len(body) response_size = int(response.headers.get("Content-Length", 0)) metric_attributes = _create_metric_attributes( instance, response, method) duration_histogram.record(elapsed_time, attributes=metric_attributes) request_size_histogram.record(request_size, attributes=metric_attributes) response_size_histogram.record(response_size, attributes=metric_attributes) return response
def _instrumented_requests_call(method: str, url: str, call_wrapped, get_or_create_headers): if context.get_value( _SUPPRESS_INSTRUMENTATION_KEY) or context.get_value( _SUPPRESS_HTTP_INSTRUMENTATION_KEY): return call_wrapped() # See # https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#http-client method = method.upper() span_name = "" if name_callback is not None: span_name = name_callback(method, url) if not span_name or not isinstance(span_name, str): span_name = get_default_span_name(method) url = remove_url_credentials(url) span_attributes = { SpanAttributes.HTTP_METHOD: method, SpanAttributes.HTTP_URL: url, } metric_labels = { SpanAttributes.HTTP_METHOD: method, } try: parsed_url = urlparse(url) metric_labels[SpanAttributes.HTTP_SCHEME] = parsed_url.scheme if parsed_url.hostname: metric_labels[SpanAttributes.HTTP_HOST] = parsed_url.hostname metric_labels[ SpanAttributes.NET_PEER_NAME] = parsed_url.hostname if parsed_url.port: metric_labels[SpanAttributes.NET_PEER_PORT] = parsed_url.port except ValueError: pass with tracer.start_as_current_span( span_name, kind=SpanKind.CLIENT, attributes=span_attributes ) as span, set_ip_on_next_http_connection(span): exception = None headers = get_or_create_headers() inject(headers) token = context.attach( context.set_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY, True)) start_time = default_timer() try: result = call_wrapped() # *** PROCEED except Exception as exc: # pylint: disable=W0703 exception = exc result = getattr(exc, "response", None) finally: elapsed_time = max( round((default_timer() - start_time) * 1000), 0) context.detach(token) if isinstance(result, Response): if span.is_recording(): span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, result.status_code) span.set_status( Status(http_status_to_status_code(result.status_code))) metric_labels[ SpanAttributes.HTTP_STATUS_CODE] = result.status_code if result.raw is not None: version = getattr(result.raw, "version", None) if version: metric_labels[SpanAttributes.HTTP_FLAVOR] = ( "1.1" if version == 11 else "1.0") if span_callback is not None: span_callback(span, result) duration_histogram.record(elapsed_time, attributes=metric_labels) if exception is not None: raise exception.with_traceback(exception.__traceback__) return result