Skip to content

Commit 32d511f

Browse files
authored
Merge branch 'main' into issue_539
2 parents a0c3a84 + 9627f74 commit 32d511f

File tree

18 files changed

+1213
-21
lines changed

18 files changed

+1213
-21
lines changed

.github/component_owners.yml

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ components:
33
docs/instrumentation:
44
- nemoshlag
55

6+
67
instrumentation/opentelemetry-instrumentation-aio-pika:
78
- ofek1weiss
89

CHANGELOG.md

+8-1
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313

1414
### Fixed
1515

16-
- `opentelemetry-instrumentation-asgi` Fix UnboundLocalError local variable 'start' referenced before assignment
16+
- `opentelemetry-instrumentation-asgi` Fix UnboundLocalError local variable 'start' referenced before assignment
1717
([#1889](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1889))
18+
- Fixed union typing error not compatible with Python 3.7 introduced in `opentelemetry-util-http`, fix tests introduced by patch related to sanitize method for wsgi
19+
([#1913](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1913))
20+
21+
### Added
22+
23+
- `opentelemetry-resource-detector-azure` Add resource detectors for Azure App Service and VM
24+
([#1901](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1901))
1825

1926
## Version 1.19.0/0.40b0 (2023-07-13)
2027
- `opentelemetry-instrumentation-asgi` Add `http.server.request.size` metric

instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py

+77-17
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS,
4141
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST,
4242
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE,
43+
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE,
44+
OTEL_PYTHON_INSTRUMENTATION_HTTP_CAPTURE_ALL_METHODS,
4345
get_excluded_urls,
4446
)
4547

@@ -326,6 +328,25 @@ def test_flask_metric_values(self):
326328
if isinstance(point, NumberDataPoint):
327329
self.assertEqual(point.value, 0)
328330

331+
def _assert_basic_metric(self, expected_duration_attributes, expected_requests_count_attributes):
332+
metrics_list = self.memory_metrics_reader.get_metrics_data()
333+
for resource_metric in metrics_list.resource_metrics:
334+
for scope_metrics in resource_metric.scope_metrics:
335+
for metric in scope_metrics.metrics:
336+
for point in list(metric.data.data_points):
337+
if isinstance(point, HistogramDataPoint):
338+
self.assertDictEqual(
339+
expected_duration_attributes,
340+
dict(point.attributes),
341+
)
342+
self.assertEqual(point.count, 1)
343+
elif isinstance(point, NumberDataPoint):
344+
self.assertDictEqual(
345+
expected_requests_count_attributes,
346+
dict(point.attributes),
347+
)
348+
self.assertEqual(point.value, 0)
349+
329350
def test_basic_metric_success(self):
330351
self.client.get("/hello/756")
331352
expected_duration_attributes = {
@@ -344,23 +365,62 @@ def test_basic_metric_success(self):
344365
"http.flavor": "1.1",
345366
"http.server_name": "localhost",
346367
}
347-
metrics_list = self.memory_metrics_reader.get_metrics_data()
348-
for resource_metric in metrics_list.resource_metrics:
349-
for scope_metrics in resource_metric.scope_metrics:
350-
for metric in scope_metrics.metrics:
351-
for point in list(metric.data.data_points):
352-
if isinstance(point, HistogramDataPoint):
353-
self.assertDictEqual(
354-
expected_duration_attributes,
355-
dict(point.attributes),
356-
)
357-
self.assertEqual(point.count, 1)
358-
elif isinstance(point, NumberDataPoint):
359-
self.assertDictEqual(
360-
expected_requests_count_attributes,
361-
dict(point.attributes),
362-
)
363-
self.assertEqual(point.value, 0)
368+
self._assert_basic_metric(
369+
expected_duration_attributes,
370+
expected_requests_count_attributes,
371+
)
372+
373+
def test_basic_metric_nonstandard_http_method_success(self):
374+
self.client.open("/hello/756", method="NONSTANDARD")
375+
expected_duration_attributes = {
376+
"http.method": "UNKNOWN",
377+
"http.host": "localhost",
378+
"http.scheme": "http",
379+
"http.flavor": "1.1",
380+
"http.server_name": "localhost",
381+
"net.host.port": 80,
382+
"http.status_code": 405,
383+
}
384+
expected_requests_count_attributes = {
385+
"http.method": "UNKNOWN",
386+
"http.host": "localhost",
387+
"http.scheme": "http",
388+
"http.flavor": "1.1",
389+
"http.server_name": "localhost",
390+
}
391+
self._assert_basic_metric(
392+
expected_duration_attributes,
393+
expected_requests_count_attributes,
394+
)
395+
396+
@patch.dict(
397+
"os.environ",
398+
{
399+
OTEL_PYTHON_INSTRUMENTATION_HTTP_CAPTURE_ALL_METHODS: "1",
400+
},
401+
)
402+
def test_basic_metric_nonstandard_http_method_allowed_success(self):
403+
self.client.open("/hello/756", method="NONSTANDARD")
404+
expected_duration_attributes = {
405+
"http.method": "NONSTANDARD",
406+
"http.host": "localhost",
407+
"http.scheme": "http",
408+
"http.flavor": "1.1",
409+
"http.server_name": "localhost",
410+
"net.host.port": 80,
411+
"http.status_code": 405,
412+
}
413+
expected_requests_count_attributes = {
414+
"http.method": "NONSTANDARD",
415+
"http.host": "localhost",
416+
"http.scheme": "http",
417+
"http.flavor": "1.1",
418+
"http.server_name": "localhost",
419+
}
420+
self._assert_basic_metric(
421+
expected_duration_attributes,
422+
expected_requests_count_attributes,
423+
)
364424

365425
def test_metric_uninstrument(self):
366426
self.client.delete("/hello/756")

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

+9-2
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,12 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he
197197
Note:
198198
The environment variable names used to capture HTTP headers are still experimental, and thus are subject to change.
199199
200+
Sanitizing methods
201+
******************
202+
In order to prevent unbound cardinality for HTTP methods by default nonstandard ones are labeled as ``NONSTANDARD``.
203+
To record all of the names set the environment variable ``OTEL_PYTHON_INSTRUMENTATION_HTTP_CAPTURE_ALL_METHODS``
204+
to a value that evaluates to true, e.g. ``1``.
205+
200206
API
201207
---
202208
"""
@@ -226,6 +232,7 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he
226232
normalise_request_header_name,
227233
normalise_response_header_name,
228234
remove_url_credentials,
235+
sanitize_method,
229236
)
230237

231238
_HTTP_VERSION_PREFIX = "HTTP/"
@@ -295,7 +302,7 @@ def collect_request_attributes(environ):
295302
"""
296303

297304
result = {
298-
SpanAttributes.HTTP_METHOD: environ.get("REQUEST_METHOD"),
305+
SpanAttributes.HTTP_METHOD: sanitize_method(environ.get("REQUEST_METHOD")),
299306
SpanAttributes.HTTP_SERVER_NAME: environ.get("SERVER_NAME"),
300307
SpanAttributes.HTTP_SCHEME: environ.get("wsgi.url_scheme"),
301308
}
@@ -450,7 +457,7 @@ def get_default_span_name(environ):
450457
Returns:
451458
The span name.
452459
"""
453-
method = environ.get("REQUEST_METHOD", "").strip()
460+
method = sanitize_method(environ.get("REQUEST_METHOD", "").strip())
454461
path = environ.get("PATH_INFO", "").strip()
455462
if method and path:
456463
return f"{method} {path}"

instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py

+19
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS,
3434
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST,
3535
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE,
36+
OTEL_PYTHON_INSTRUMENTATION_HTTP_CAPTURE_ALL_METHODS,
3637
)
3738

3839

@@ -284,6 +285,24 @@ def test_wsgi_metrics(self):
284285
)
285286
self.assertTrue(number_data_point_seen and histogram_data_point_seen)
286287

288+
def test_nonstandard_http_method(self):
289+
self.environ["REQUEST_METHOD"]= "NONSTANDARD"
290+
app = otel_wsgi.OpenTelemetryMiddleware(simple_wsgi)
291+
response = app(self.environ, self.start_response)
292+
self.validate_response(response, span_name="UNKNOWN /", http_method="UNKNOWN")
293+
294+
@mock.patch.dict(
295+
"os.environ",
296+
{
297+
OTEL_PYTHON_INSTRUMENTATION_HTTP_CAPTURE_ALL_METHODS: "1",
298+
},
299+
)
300+
def test_nonstandard_http_method_allowed(self):
301+
self.environ["REQUEST_METHOD"]= "NONSTANDARD"
302+
app = otel_wsgi.OpenTelemetryMiddleware(simple_wsgi)
303+
response = app(self.environ, self.start_response)
304+
self.validate_response(response, span_name="NONSTANDARD /", http_method="NONSTANDARD")
305+
287306
def test_default_span_name_missing_path_info(self):
288307
"""Test that default span_names with missing path info."""
289308
self.environ.pop("PATH_INFO")

0 commit comments

Comments
 (0)