Skip to content

Commit 1b53e15

Browse files
authored
Merge branch 'main' into emptyroute
2 parents c28c672 + f9f7b01 commit 1b53e15

File tree

51 files changed

+474
-381
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+474
-381
lines changed

Diff for: CHANGELOG.md

+13-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- `opentelemetry-instrumentation-django` Fix empty span name when using
1313
`path("", ...)` ([#1788](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1788)
14+
- Fix falcon instrumentation's usage of Span Status to only set the description if the status code is ERROR.
15+
([#1840](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1840))
16+
- Instrument all httpx versions >= 0.18. ([#1748](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1748))
1417

1518
## Version 1.18.0/0.39b0 (2023-05-10)
1619

@@ -26,9 +29,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2629
([#1778](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1778))
2730
- Add `excluded_urls` functionality to `urllib` and `urllib3` instrumentations
2831
([#1733](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1733))
29-
- Make Django request span attributes available for `start_span`.
32+
- Make Django request span attributes available for `start_span`.
3033
([#1730](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1730))
31-
- Make ASGI request span attributes available for `start_span`.
34+
- Make ASGI request span attributes available for `start_span`.
3235
([#1762](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1762))
3336
- `opentelemetry-instrumentation-celery` Add support for anonymous tasks.
3437
([#1407](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1407))
@@ -43,12 +46,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4346

4447
### Fixed
4548

49+
- Fix redis db.statements to be sanitized by default
50+
([#1778](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1778))
4651
- Fix elasticsearch db.statement attribute to be sanitized by default
4752
([#1758](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1758))
4853
- Fix `AttributeError` when AWS Lambda handler receives a list event
4954
([#1738](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1738))
5055
- Fix `None does not implement middleware` error when there are no middlewares registered
5156
([#1766](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1766))
57+
- Fix Flask instrumentation to only close the span if it was created by the same request context.
58+
([#1692](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1692))
59+
60+
### Changed
61+
- Update HTTP server/client instrumentation span names to comply with spec
62+
([#1759](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1759)
5263

5364
## Version 1.17.0/0.38b0 (2023-03-22)
5465

Diff for: dev-requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ bleach==4.1.0 # transient dependency for readme-renderer
1414
grpcio-tools==1.29.0
1515
mypy-protobuf>=1.23
1616
protobuf~=3.13
17-
markupsafe==2.0.1
17+
markupsafe>=2.0.1
1818
codespell==2.1.0
1919
requests==2.28.1
2020
ruamel.yaml==0.17.21

Diff for: instrumentation/opentelemetry-instrumentation-aiohttp-client/pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ instruments = [
3838
]
3939
test = [
4040
"opentelemetry-instrumentation-aiohttp-client[instruments]",
41+
"http-server-mock"
4142
]
4243

4344
[project.entry-points.opentelemetry_instrumentor]

Diff for: instrumentation/opentelemetry-instrumentation-aiohttp-client/src/opentelemetry/instrumentation/aiohttp_client/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ async def on_request_start(
179179
return
180180

181181
http_method = params.method.upper()
182-
request_span_name = f"HTTP {http_method}"
182+
request_span_name = f"{http_method}"
183183
request_url = (
184184
remove_url_credentials(trace_config_ctx.url_filter(params.url))
185185
if callable(trace_config_ctx.url_filter)

Diff for: instrumentation/opentelemetry-instrumentation-aiohttp-client/tests/test_aiohttp_client_integration.py

+29-17
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import aiohttp
2424
import aiohttp.test_utils
2525
import yarl
26+
from http_server_mock import HttpServerMock
2627
from pkg_resources import iter_entry_points
2728

2829
from opentelemetry import context
@@ -118,7 +119,7 @@ def test_status_codes(self):
118119
self.assert_spans(
119120
[
120121
(
121-
"HTTP GET",
122+
"GET",
122123
(span_status, None),
123124
{
124125
SpanAttributes.HTTP_METHOD: "GET",
@@ -212,7 +213,7 @@ def strip_query_params(url: yarl.URL) -> str:
212213
self.assert_spans(
213214
[
214215
(
215-
"HTTP GET",
216+
"GET",
216217
(StatusCode.UNSET, None),
217218
{
218219
SpanAttributes.HTTP_METHOD: "GET",
@@ -246,7 +247,7 @@ async def do_request(url):
246247
self.assert_spans(
247248
[
248249
(
249-
"HTTP GET",
250+
"GET",
250251
(expected_status, None),
251252
{
252253
SpanAttributes.HTTP_METHOD: "GET",
@@ -273,7 +274,7 @@ async def request_handler(request):
273274
self.assert_spans(
274275
[
275276
(
276-
"HTTP GET",
277+
"GET",
277278
(StatusCode.ERROR, None),
278279
{
279280
SpanAttributes.HTTP_METHOD: "GET",
@@ -300,7 +301,7 @@ async def request_handler(request):
300301
self.assert_spans(
301302
[
302303
(
303-
"HTTP GET",
304+
"GET",
304305
(StatusCode.ERROR, None),
305306
{
306307
SpanAttributes.HTTP_METHOD: "GET",
@@ -313,27 +314,37 @@ async def request_handler(request):
313314
def test_credential_removal(self):
314315
trace_configs = [aiohttp_client.create_trace_config()]
315316

316-
url = "http://username:[email protected]/status/200"
317-
with self.subTest(url=url):
317+
app = HttpServerMock("test_credential_removal")
318318

319-
async def do_request(url):
320-
async with aiohttp.ClientSession(
321-
trace_configs=trace_configs,
322-
) as session:
323-
async with session.get(url):
324-
pass
319+
@app.route("/status/200")
320+
def index():
321+
return "hello"
325322

326-
loop = asyncio.get_event_loop()
327-
loop.run_until_complete(do_request(url))
323+
url = "http://username:password@localhost:5000/status/200"
324+
325+
with app.run("localhost", 5000):
326+
with self.subTest(url=url):
327+
328+
async def do_request(url):
329+
async with aiohttp.ClientSession(
330+
trace_configs=trace_configs,
331+
) as session:
332+
async with session.get(url):
333+
pass
334+
335+
loop = asyncio.get_event_loop()
336+
loop.run_until_complete(do_request(url))
328337

329338
self.assert_spans(
330339
[
331340
(
332-
"HTTP GET",
341+
"GET",
333342
(StatusCode.UNSET, None),
334343
{
335344
SpanAttributes.HTTP_METHOD: "GET",
336-
SpanAttributes.HTTP_URL: "http://httpbin.org/status/200",
345+
SpanAttributes.HTTP_URL: (
346+
"http://localhost:5000/status/200"
347+
),
337348
SpanAttributes.HTTP_STATUS_CODE: int(HTTPStatus.OK),
338349
},
339350
)
@@ -380,6 +391,7 @@ def test_instrument(self):
380391
self.get_default_request(), self.URL, self.default_handler
381392
)
382393
span = self.assert_spans(1)
394+
self.assertEqual("GET", span.name)
383395
self.assertEqual("GET", span.attributes[SpanAttributes.HTTP_METHOD])
384396
self.assertEqual(
385397
f"http://{host}:{port}/test-path",

Diff for: instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py

+12-7
Original file line numberDiff line numberDiff line change
@@ -415,18 +415,23 @@ def set_status_code(span, status_code):
415415

416416

417417
def get_default_span_details(scope: dict) -> Tuple[str, dict]:
418-
"""Default implementation for get_default_span_details
418+
"""
419+
Default span name is the HTTP method and URL path, or just the method.
420+
https://github.com/open-telemetry/opentelemetry-specification/pull/3165
421+
https://opentelemetry.io/docs/reference/specification/trace/semantic_conventions/http/#name
422+
419423
Args:
420424
scope: the ASGI scope dictionary
421425
Returns:
422426
a tuple of the span name, and any attributes to attach to the span.
423427
"""
424-
span_name = (
425-
scope.get("path", "").strip()
426-
or f"HTTP {scope.get('method', '').strip()}"
427-
)
428-
429-
return span_name, {}
428+
path = scope.get("path", "").strip()
429+
method = scope.get("method", "").strip()
430+
if method and path: # http
431+
return f"{method} {path}", {}
432+
if path: # websocket
433+
return path, {}
434+
return method, {} # http with no path
430435

431436

432437
def _collect_target_attribute(

Diff for: instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_middleware.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -142,25 +142,25 @@ def validate_outputs(self, outputs, error=None, modifiers=None):
142142
self.assertEqual(len(span_list), 4)
143143
expected = [
144144
{
145-
"name": "/ http receive",
145+
"name": "GET / http receive",
146146
"kind": trace_api.SpanKind.INTERNAL,
147147
"attributes": {"type": "http.request"},
148148
},
149149
{
150-
"name": "/ http send",
150+
"name": "GET / http send",
151151
"kind": trace_api.SpanKind.INTERNAL,
152152
"attributes": {
153153
SpanAttributes.HTTP_STATUS_CODE: 200,
154154
"type": "http.response.start",
155155
},
156156
},
157157
{
158-
"name": "/ http send",
158+
"name": "GET / http send",
159159
"kind": trace_api.SpanKind.INTERNAL,
160160
"attributes": {"type": "http.response.body"},
161161
},
162162
{
163-
"name": "/",
163+
"name": "GET /",
164164
"kind": trace_api.SpanKind.SERVER,
165165
"attributes": {
166166
SpanAttributes.HTTP_METHOD: "GET",
@@ -231,7 +231,7 @@ def update_expected_span_name(expected):
231231
entry["name"] = span_name
232232
else:
233233
entry["name"] = " ".join(
234-
[span_name] + entry["name"].split(" ")[1:]
234+
[span_name] + entry["name"].split(" ")[2:]
235235
)
236236
return expected
237237

@@ -493,9 +493,9 @@ def update_expected_hook_results(expected):
493493
for entry in expected:
494494
if entry["kind"] == trace_api.SpanKind.SERVER:
495495
entry["name"] = "name from server hook"
496-
elif entry["name"] == "/ http receive":
496+
elif entry["name"] == "GET / http receive":
497497
entry["name"] = "name from client request hook"
498-
elif entry["name"] == "/ http send":
498+
elif entry["name"] == "GET / http send":
499499
entry["attributes"].update({"attr-from-hook": "value"})
500500
return expected
501501

@@ -705,11 +705,11 @@ def test_response_attributes_invalid_status_code(self):
705705
self.assertEqual(self.span.set_status.call_count, 1)
706706

707707
def test_credential_removal(self):
708-
self.scope["server"] = ("username:password@httpbin.org", 80)
708+
self.scope["server"] = ("username:password@mock", 80)
709709
self.scope["path"] = "/status/200"
710710
attrs = otel_asgi.collect_request_attributes(self.scope)
711711
self.assertEqual(
712-
attrs[SpanAttributes.HTTP_URL], "http://httpbin.org/status/200"
712+
attrs[SpanAttributes.HTTP_URL], "http://mock/status/200"
713713
)
714714

715715
def test_collect_target_attribute_missing(self):

Diff for: instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py

+3-9
Original file line numberDiff line numberDiff line change
@@ -173,18 +173,12 @@ def _get_span_name(request):
173173
match = resolve(request.path)
174174

175175
if hasattr(match, "route") and match.route:
176-
return match.route
176+
return f"{request.method} {match.route}"
177177

178-
# Instead of using `view_name`, better to use `_func_name` as some applications can use similar
179-
# view names in different modules
180-
if hasattr(match, "_func_name"):
181-
return match._func_name # pylint: disable=protected-access
182-
183-
# Fallback for safety as `_func_name` private field
184-
return match.view_name
178+
return request.method
185179

186180
except Resolver404:
187-
return f"HTTP {request.method}"
181+
return request.method
188182

189183
# pylint: disable=too-many-locals
190184
def process_request(self, request):

Diff for: instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py

+8-18
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,9 @@ def test_templated_route_get(self):
154154

155155
self.assertEqual(
156156
span.name,
157-
"^route/(?P<year>[0-9]{4})/template/$"
157+
"GET ^route/(?P<year>[0-9]{4})/template/$"
158158
if DJANGO_2_2
159-
else "tests.views.traced_template",
159+
else "GET",
160160
)
161161
self.assertEqual(span.kind, SpanKind.SERVER)
162162
self.assertEqual(span.status.status_code, StatusCode.UNSET)
@@ -181,9 +181,7 @@ def test_traced_get(self):
181181

182182
span = spans[0]
183183

184-
self.assertEqual(
185-
span.name, "^traced/" if DJANGO_2_2 else "tests.views.traced"
186-
)
184+
self.assertEqual(span.name, "GET ^traced/" if DJANGO_2_2 else "GET")
187185
self.assertEqual(span.kind, SpanKind.SERVER)
188186
self.assertEqual(span.status.status_code, StatusCode.UNSET)
189187
self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "GET")
@@ -229,9 +227,7 @@ def test_traced_post(self):
229227

230228
span = spans[0]
231229

232-
self.assertEqual(
233-
span.name, "^traced/" if DJANGO_2_2 else "tests.views.traced"
234-
)
230+
self.assertEqual(span.name, "POST ^traced/" if DJANGO_2_2 else "POST")
235231
self.assertEqual(span.kind, SpanKind.SERVER)
236232
self.assertEqual(span.status.status_code, StatusCode.UNSET)
237233
self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "POST")
@@ -255,9 +251,7 @@ def test_error(self):
255251

256252
span = spans[0]
257253

258-
self.assertEqual(
259-
span.name, "^error/" if DJANGO_2_2 else "tests.views.error"
260-
)
254+
self.assertEqual(span.name, "GET ^error/" if DJANGO_2_2 else "GET")
261255
self.assertEqual(span.kind, SpanKind.SERVER)
262256
self.assertEqual(span.status.status_code, StatusCode.ERROR)
263257
self.assertEqual(span.attributes[SpanAttributes.HTTP_METHOD], "GET")
@@ -321,9 +315,7 @@ def test_span_name(self):
321315
span = span_list[0]
322316
self.assertEqual(
323317
span.name,
324-
"^span_name/([0-9]{4})/$"
325-
if DJANGO_2_2
326-
else "tests.views.route_span_name",
318+
"GET ^span_name/([0-9]{4})/$" if DJANGO_2_2 else "GET",
327319
)
328320

329321
def test_span_name_for_query_string(self):
@@ -337,9 +329,7 @@ def test_span_name_for_query_string(self):
337329
span = span_list[0]
338330
self.assertEqual(
339331
span.name,
340-
"^span_name/([0-9]{4})/$"
341-
if DJANGO_2_2
342-
else "tests.views.route_span_name",
332+
"GET ^span_name/([0-9]{4})/$" if DJANGO_2_2 else "GET",
343333
)
344334

345335
def test_span_name_404(self):
@@ -348,7 +338,7 @@ def test_span_name_404(self):
348338
self.assertEqual(len(span_list), 1)
349339

350340
span = span_list[0]
351-
self.assertEqual(span.name, "HTTP GET")
341+
self.assertEqual(span.name, "GET")
352342

353343
def test_traced_request_attrs(self):
354344
Client().get("/span_name/1234/", CONTENT_TYPE="test/ct")

0 commit comments

Comments
 (0)