Skip to content

Commit 5f00479

Browse files
committed
tests
1 parent f299243 commit 5f00479

File tree

3 files changed

+265
-45
lines changed

3 files changed

+265
-45
lines changed

instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
http_status_to_status_code,
7171
)
7272
from opentelemetry.instrumentation._semconv import (
73+
_filter_duration_attrs,
7374
_report_old,
7475
_report_new,
7576
_set_http_hostname,
@@ -80,6 +81,9 @@
8081
_set_http_scheme,
8182
_set_http_url,
8283
_set_http_status_code,
84+
_SPAN_ATTRIBUTES_ERROR_TYPE,
85+
_SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS,
86+
_SPAN_ATTRIBUTES_NETWORK_PEER_PORT,
8387
_OpenTelemetrySemanticConventionStability,
8488
_OpenTelemetryStabilityMode,
8589
_OpenTelemetryStabilitySignalType,
@@ -105,11 +109,6 @@
105109
_RequestHookT = Optional[Callable[[Span, PreparedRequest], None]]
106110
_ResponseHookT = Optional[Callable[[Span, PreparedRequest], None]]
107111

108-
# TODO: will come through semconv package once updated
109-
_SPAN_ATTRIBUTES_ERROR_TYPE = "error.type"
110-
_SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS ="network.peer.address"
111-
_SPAN_ATTRIBUTES_NETWORK_PEER_PORT = "network.peer.port"
112-
113112

114113
# pylint: disable=unused-argument
115114
# pylint: disable=R0915
@@ -177,11 +176,13 @@ def get_or_create_headers():
177176
_set_http_net_peer_name(metric_labels, parsed_url.hostname, sem_conv_opt_in_mode)
178177
if _report_new(sem_conv_opt_in_mode):
179178
_set_http_hostname(span_attributes, parsed_url.hostname, sem_conv_opt_in_mode)
179+
# Use semconv library when available
180180
span_attributes[_SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS] = parsed_url.hostname
181181
if parsed_url.port:
182182
_set_http_port(metric_labels, parsed_url.port, sem_conv_opt_in_mode)
183183
if _report_new(sem_conv_opt_in_mode):
184184
_set_http_port(span_attributes, parsed_url.port, sem_conv_opt_in_mode)
185+
# Use semconv library when available
185186
span_attributes[_SPAN_ATTRIBUTES_NETWORK_PEER_PORT] = parsed_url.port
186187
except ValueError:
187188
pass
@@ -229,20 +230,23 @@ def get_or_create_headers():
229230
_set_http_network_protocol_version(metric_labels, version_text, sem_conv_opt_in_mode)
230231
if _report_new(sem_conv_opt_in_mode):
231232
_set_http_network_protocol_version(span_attributes, version_text, sem_conv_opt_in_mode)
232-
if exception is not None:
233-
if _report_new(sem_conv_opt_in_mode):
234-
span_attributes[_SPAN_ATTRIBUTES_ERROR_TYPE] = type(exception).__name__
235-
metric_labels[_SPAN_ATTRIBUTES_ERROR_TYPE] = type(exception).__name__
236233
for k, v in span_attributes.items():
237234
span.set_attribute(k, v)
238235

239236
if callable(response_hook):
240237
response_hook(span, request, result)
241238

242-
if _report_old(sem_conv_opt_in_mode) and duration_histogram_old is not None:
243-
duration_histogram_old.record(max(round(elapsed_time * 1000), 0), attributes=metric_labels)
244-
# duration_histogram_new.record(elapsed_time, attributes=metric_labels)
245-
239+
if exception is not None and _report_new(sem_conv_opt_in_mode):
240+
span.set_attribute(_SPAN_ATTRIBUTES_ERROR_TYPE, type(exception).__name__)
241+
metric_labels[_SPAN_ATTRIBUTES_ERROR_TYPE] = type(exception).__name__
242+
243+
if duration_histogram_old is not None:
244+
duration_attrs_old = _filter_duration_attrs(metric_labels, _OpenTelemetryStabilityMode.DEFAULT)
245+
duration_histogram_old.record(max(round(elapsed_time * 1000), 0), attributes=duration_attrs_old)
246+
if duration_histogram_new is not None:
247+
duration_attrs_new = _filter_duration_attrs(metric_labels, _OpenTelemetryStabilityMode.HTTP)
248+
duration_histogram_new.record(elapsed_time, attributes=duration_attrs_new)
249+
246250
if exception is not None:
247251
raise exception.with_traceback(exception.__traceback__)
248252

instrumentation/opentelemetry-instrumentation-requests/tests/test_requests_integration.py

Lines changed: 211 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
from opentelemetry.instrumentation.requests import RequestsInstrumentor
2929
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
3030
from opentelemetry.instrumentation._semconv import (
31+
_SPAN_ATTRIBUTES_ERROR_TYPE,
32+
_SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS,
3133
_OTEL_SEMCONV_STABILITY_OPT_IN_KEY,
3234
_OpenTelemetrySemanticConventionStability,
3335
)
@@ -68,7 +70,7 @@ class RequestsIntegrationTestBase(abc.ABC):
6870
# pylint: disable=too-many-public-methods
6971

7072
URL = "http://mock/status/200"
71-
HOST = "mock/status"
73+
HOST = "mock"
7274

7375
# pylint: disable=invalid-name
7476
def setUp(self):
@@ -150,33 +152,62 @@ def test_basic(self):
150152
span, opentelemetry.instrumentation.requests
151153
)
152154

155+
def test_basic_new_semconv(self):
156+
result = self.perform_request(self.URL)
157+
self.assertEqual(result.text, "Hello!")
158+
span = self.assert_span()
153159

154-
# def test_basic_new_semconv(self):
155-
# print("here2")
156-
# result = self.perform_request(self.URL)
157-
# self.assertEqual(result.text, "Hello!")
158-
# span = self.assert_span()
160+
self.assertIs(span.kind, trace.SpanKind.CLIENT)
161+
self.assertEqual(span.name, "GET")
159162

160-
# self.assertIs(span.kind, trace.SpanKind.CLIENT)
161-
# self.assertEqual(span.name, "GET")
163+
self.assertEqual(
164+
span.attributes,
165+
{
166+
SpanAttributes.HTTP_REQUEST_METHOD: "GET",
167+
SpanAttributes.URL_FULL: self.URL,
168+
SpanAttributes.SERVER_ADDRESS: self.HOST,
169+
_SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS: "mock",
170+
SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 200,
171+
SpanAttributes.NET_PROTOCOL_VERSION: "1.1",
172+
},
173+
)
174+
175+
self.assertIs(span.status.status_code, trace.StatusCode.UNSET)
176+
177+
self.assertEqualSpanInstrumentationScope(
178+
span, opentelemetry.instrumentation.requests
179+
)
180+
181+
def test_basic_both_semconv(self):
182+
result = self.perform_request(self.URL)
183+
self.assertEqual(result.text, "Hello!")
184+
span = self.assert_span()
162185

163-
# self.assertEqual(
164-
# span.attributes,
165-
# {
166-
# SpanAttributes.HTTP_REQUEST_METHOD: "GET",
167-
# SpanAttributes.HTTP_REQUEST_METHOD_ORIGINAL: "GET",
168-
# SpanAttributes.URL_FULL: self.URL,
169-
# SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 200,
170-
# SpanAttributes.SERVER_ADDRESS: self.HOST,
171-
# },
172-
# )
186+
self.assertIs(span.kind, trace.SpanKind.CLIENT)
187+
self.assertEqual(span.name, "GET")
173188

174-
# self.assertIs(span.status.status_code, trace.StatusCode.UNSET)
189+
self.assertEqual(
190+
span.attributes,
191+
{
192+
SpanAttributes.HTTP_METHOD: "GET",
193+
SpanAttributes.HTTP_REQUEST_METHOD: "GET",
194+
SpanAttributes.HTTP_URL: self.URL,
195+
SpanAttributes.URL_FULL: self.URL,
196+
SpanAttributes.HTTP_HOST: self.HOST,
197+
SpanAttributes.SERVER_ADDRESS: self.HOST,
198+
_SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS: "mock",
199+
SpanAttributes.HTTP_STATUS_CODE: 200,
200+
SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 200,
201+
SpanAttributes.HTTP_FLAVOR: "1.1",
202+
SpanAttributes.NET_PROTOCOL_VERSION: "1.1",
203+
},
204+
)
175205

176-
# self.assertEqualSpanInstrumentationInfo(
177-
# span, opentelemetry.instrumentation.requests
178-
# )
206+
self.assertIs(span.status.status_code, trace.StatusCode.UNSET)
179207

208+
self.assertEqualSpanInstrumentationScope(
209+
span, opentelemetry.instrumentation.requests
210+
)
180211

181212
def test_hooks(self):
182213
def request_hook(span, request_obj):
@@ -259,6 +290,51 @@ def test_not_foundbasic(self):
259290
trace.StatusCode.ERROR,
260291
)
261292

293+
def test_not_foundbasic_new_semconv(self):
294+
url_404 = "http://mock/status/404"
295+
httpretty.register_uri(
296+
httpretty.GET,
297+
url_404,
298+
status=404,
299+
)
300+
result = self.perform_request(url_404)
301+
self.assertEqual(result.status_code, 404)
302+
303+
span = self.assert_span()
304+
305+
self.assertEqual(
306+
span.attributes.get(SpanAttributes.HTTP_RESPONSE_STATUS_CODE), 404
307+
)
308+
309+
self.assertIs(
310+
span.status.status_code,
311+
trace.StatusCode.ERROR,
312+
)
313+
314+
def test_not_foundbasic_both_semconv(self):
315+
url_404 = "http://mock/status/404"
316+
httpretty.register_uri(
317+
httpretty.GET,
318+
url_404,
319+
status=404,
320+
)
321+
result = self.perform_request(url_404)
322+
self.assertEqual(result.status_code, 404)
323+
324+
span = self.assert_span()
325+
326+
self.assertEqual(
327+
span.attributes.get(SpanAttributes.HTTP_STATUS_CODE), 404
328+
)
329+
self.assertEqual(
330+
span.attributes.get(SpanAttributes.HTTP_RESPONSE_STATUS_CODE), 404
331+
)
332+
333+
self.assertIs(
334+
span.status.status_code,
335+
trace.StatusCode.ERROR,
336+
)
337+
262338
def test_uninstrument(self):
263339
RequestsInstrumentor().uninstrument()
264340
result = self.perform_request(self.URL)
@@ -413,6 +489,27 @@ def test_requests_exception_without_response(self, *_, **__):
413489
)
414490
self.assertEqual(span.status.status_code, StatusCode.ERROR)
415491

492+
@mock.patch(
493+
"requests.adapters.HTTPAdapter.send",
494+
side_effect=requests.RequestException,
495+
)
496+
def test_requests_exception_new_semconv(self, *_, **__):
497+
with self.assertRaises(requests.RequestException):
498+
self.perform_request(self.URL)
499+
500+
span = self.assert_span()
501+
self.assertEqual(
502+
span.attributes,
503+
{
504+
SpanAttributes.HTTP_REQUEST_METHOD: "GET",
505+
SpanAttributes.URL_FULL: self.URL,
506+
SpanAttributes.SERVER_ADDRESS: self.HOST,
507+
_SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS: "mock",
508+
_SPAN_ATTRIBUTES_ERROR_TYPE: "RequestException",
509+
},
510+
)
511+
self.assertEqual(span.status.status_code, StatusCode.ERROR)
512+
416513
mocked_response = requests.Response()
417514
mocked_response.status_code = 500
418515
mocked_response.reason = "Internal Server Error"
@@ -534,13 +631,30 @@ class TestRequestsIntergrationMetric(TestBase):
534631

535632
def setUp(self):
536633
super().setUp()
634+
test_name = ""
635+
if hasattr(self, "_testMethodName"):
636+
test_name = self._testMethodName
637+
sem_conv_mode = "default"
638+
if "new_semconv" in test_name:
639+
sem_conv_mode = "http"
640+
elif "both_semconv" in test_name:
641+
sem_conv_mode = "http/dup"
642+
self.env_patch = mock.patch.dict(
643+
"os.environ",
644+
{
645+
_OTEL_SEMCONV_STABILITY_OPT_IN_KEY: sem_conv_mode,
646+
},
647+
)
648+
self.env_patch.start()
649+
_OpenTelemetrySemanticConventionStability._initialized = False
537650
RequestsInstrumentor().instrument(meter_provider=self.meter_provider)
538651

539652
httpretty.enable()
540653
httpretty.register_uri(httpretty.GET, self.URL, body="Hello!")
541654

542655
def tearDown(self):
543656
super().tearDown()
657+
self.env_patch.stop()
544658
RequestsInstrumentor().uninstrument()
545659
httpretty.disable()
546660

@@ -552,22 +666,90 @@ def test_basic_metric_success(self):
552666
self.perform_request(self.URL)
553667

554668
expected_attributes = {
555-
"http.status_code": 200,
556-
"http.host": "examplehost",
557-
"net.peer.port": 8000,
558-
"net.peer.name": "examplehost",
559-
"http.method": "GET",
560-
"http.flavor": "1.1",
561-
"http.scheme": "http",
669+
SpanAttributes.HTTP_STATUS_CODE: 200,
670+
SpanAttributes.HTTP_HOST: "examplehost",
671+
SpanAttributes.NET_PEER_PORT: 8000,
672+
SpanAttributes.NET_PEER_NAME: "examplehost",
673+
SpanAttributes.HTTP_METHOD: "GET",
674+
SpanAttributes.HTTP_FLAVOR: "1.1",
675+
SpanAttributes.HTTP_SCHEME: "http",
562676
}
563677

564678
for (
565679
resource_metrics
566680
) in self.memory_metrics_reader.get_metrics_data().resource_metrics:
567681
for scope_metrics in resource_metrics.scope_metrics:
682+
self.assertEqual(len(scope_metrics.metrics), 1)
568683
for metric in scope_metrics.metrics:
684+
self.assertEqual(metric.unit, "ms")
685+
self.assertEqual(metric.description, "measures the duration of the outbound HTTP request")
569686
for data_point in metric.data.data_points:
570687
self.assertDictEqual(
571688
expected_attributes, dict(data_point.attributes)
572689
)
573690
self.assertEqual(data_point.count, 1)
691+
692+
def test_basic_metric_new_semconv(self):
693+
self.perform_request(self.URL)
694+
695+
expected_attributes = {
696+
SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 200,
697+
SpanAttributes.SERVER_ADDRESS: "examplehost",
698+
SpanAttributes.SERVER_PORT: 8000,
699+
SpanAttributes.SERVER_ADDRESS: "examplehost",
700+
SpanAttributes.HTTP_REQUEST_METHOD: "GET",
701+
SpanAttributes.NET_PROTOCOL_VERSION: "1.1",
702+
}
703+
704+
for (
705+
resource_metrics
706+
) in self.memory_metrics_reader.get_metrics_data().resource_metrics:
707+
for scope_metrics in resource_metrics.scope_metrics:
708+
self.assertEqual(len(scope_metrics.metrics), 1)
709+
for metric in scope_metrics.metrics:
710+
self.assertEqual(metric.unit, "s")
711+
self.assertEqual(metric.description, "Duration of HTTP client requests.")
712+
for data_point in metric.data.data_points:
713+
self.assertDictEqual(
714+
expected_attributes, dict(data_point.attributes)
715+
)
716+
self.assertEqual(data_point.count, 1)
717+
718+
def test_basic_metric_both_semconv(self):
719+
self.perform_request(self.URL)
720+
721+
expected_attributes_old = {
722+
SpanAttributes.HTTP_STATUS_CODE: 200,
723+
SpanAttributes.HTTP_HOST: "examplehost",
724+
SpanAttributes.NET_PEER_PORT: 8000,
725+
SpanAttributes.NET_PEER_NAME: "examplehost",
726+
SpanAttributes.HTTP_METHOD: "GET",
727+
SpanAttributes.HTTP_FLAVOR: "1.1",
728+
SpanAttributes.HTTP_SCHEME: "http",
729+
}
730+
731+
expected_attributes_new = {
732+
SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 200,
733+
SpanAttributes.SERVER_ADDRESS: "examplehost",
734+
SpanAttributes.SERVER_PORT: 8000,
735+
SpanAttributes.SERVER_ADDRESS: "examplehost",
736+
SpanAttributes.HTTP_REQUEST_METHOD: "GET",
737+
SpanAttributes.NET_PROTOCOL_VERSION: "1.1",
738+
}
739+
740+
for (
741+
resource_metrics
742+
) in self.memory_metrics_reader.get_metrics_data().resource_metrics:
743+
for scope_metrics in resource_metrics.scope_metrics:
744+
self.assertEqual(len(scope_metrics.metrics), 2)
745+
for metric in scope_metrics.metrics:
746+
for data_point in metric.data.data_points:
747+
if metric.unit == "ms":
748+
self.assertDictEqual(
749+
expected_attributes_old, dict(data_point.attributes)
750+
)
751+
else:
752+
self.assertDictEqual(
753+
expected_attributes_new, dict(data_point.attributes)
754+
)
755+
self.assertEqual(data_point.count, 1)

0 commit comments

Comments
 (0)