Skip to content

Commit db85f97

Browse files
committed
Merge branch 'main' into emptyroute
2 parents 1b53e15 + ffc9334 commit db85f97

File tree

21 files changed

+298
-80
lines changed

21 files changed

+298
-80
lines changed

Diff for: CHANGELOG.md

+15
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,22 @@ 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+
- Update falcon instrumentation to follow semantic conventions
15+
([#1824](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1824))
16+
17+
### Added
18+
19+
- Make Flask request span attributes available for `start_span`.
20+
([#1784](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1784))
1421
- Fix falcon instrumentation's usage of Span Status to only set the description if the status code is ERROR.
1522
([#1840](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1840))
1623
- Instrument all httpx versions >= 0.18. ([#1748](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1748))
24+
- Fix `Invalid type NoneType for attribute X (opentelemetry-instrumentation-aws-lambda)` error when some attributes do not exist
25+
([#1780](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1780))
26+
- Add metric instrumentation for celery
27+
([#1679](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1679))
28+
- `opentelemetry-instrumentation-asgi` Add `http.server.response.size` metric
29+
([#1789](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1789))
1730

1831
## Version 1.18.0/0.39b0 (2023-05-10)
1932

@@ -22,6 +35,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2235
([#1706](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1706))
2336
- `opentelemetry-instrumentation-pymemcache` Update instrumentation to support pymemcache >4
2437
([#1764](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1764))
38+
- `opentelemetry-instrumentation-confluent-kafka` Add support for higher versions of confluent_kafka
39+
([#1815](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1815))
2540

2641
### Added
2742

Diff for: dev-requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ mypy-protobuf>=1.23
1616
protobuf~=3.13
1717
markupsafe>=2.0.1
1818
codespell==2.1.0
19-
requests==2.28.1
19+
requests==2.31.0
2020
ruamel.yaml==0.17.21

Diff for: docs-requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ boto~=2.0
2626
botocore~=1.0
2727
boto3~=1.0
2828
celery>=4.0
29-
confluent-kafka>= 1.8.2,< 2.0.0
29+
confluent-kafka>= 1.8.2,<= 2.2.0
3030
elasticsearch>=2.0,<9.0
3131
flask~=2.0
3232
falcon~=2.0

Diff for: instrumentation/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
| [opentelemetry-instrumentation-boto3sqs](./opentelemetry-instrumentation-boto3sqs) | boto3 ~= 1.0 | No
1212
| [opentelemetry-instrumentation-botocore](./opentelemetry-instrumentation-botocore) | botocore ~= 1.0 | No
1313
| [opentelemetry-instrumentation-celery](./opentelemetry-instrumentation-celery) | celery >= 4.0, < 6.0 | No
14-
| [opentelemetry-instrumentation-confluent-kafka](./opentelemetry-instrumentation-confluent-kafka) | confluent-kafka >= 1.8.2, < 2.0.0 | No
14+
| [opentelemetry-instrumentation-confluent-kafka](./opentelemetry-instrumentation-confluent-kafka) | confluent-kafka >= 1.8.2, <= 2.2.0 | No
1515
| [opentelemetry-instrumentation-dbapi](./opentelemetry-instrumentation-dbapi) | dbapi | No
1616
| [opentelemetry-instrumentation-django](./opentelemetry-instrumentation-django) | django >= 1.10 | Yes
1717
| [opentelemetry-instrumentation-elasticsearch](./opentelemetry-instrumentation-elasticsearch) | elasticsearch >= 2.0 | No

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

+17
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,11 @@ def __init__(
506506
unit="ms",
507507
description="measures the duration of the inbound HTTP request",
508508
)
509+
self.server_response_size_histogram = self.meter.create_histogram(
510+
name=MetricInstruments.HTTP_SERVER_RESPONSE_SIZE,
511+
unit="By",
512+
description="measures the size of HTTP response messages (compressed).",
513+
)
509514
self.active_requests_counter = self.meter.create_up_down_counter(
510515
name=MetricInstruments.HTTP_SERVER_ACTIVE_REQUESTS,
511516
unit="requests",
@@ -518,6 +523,7 @@ def __init__(
518523
self.server_request_hook = server_request_hook
519524
self.client_request_hook = client_request_hook
520525
self.client_response_hook = client_response_hook
526+
self.content_length_header = None
521527

522528
async def __call__(self, scope, receive, send):
523529
"""The ASGI application
@@ -593,6 +599,10 @@ async def __call__(self, scope, receive, send):
593599
self.active_requests_counter.add(
594600
-1, active_requests_count_attrs
595601
)
602+
if self.content_length_header:
603+
self.server_response_size_histogram.record(
604+
self.content_length_header, duration_attrs
605+
)
596606
if token:
597607
context.detach(token)
598608

@@ -660,6 +670,13 @@ async def otel_send(message):
660670
setter=asgi_setter,
661671
)
662672

673+
content_length = asgi_getter.get(message, "content-length")
674+
if content_length:
675+
try:
676+
self.content_length_header = int(content_length[0])
677+
except ValueError:
678+
pass
679+
663680
await send(message)
664681

665682
return otel_send

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

+22-9
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,12 @@
4646
_expected_metric_names = [
4747
"http.server.active_requests",
4848
"http.server.duration",
49+
"http.server.response.size",
4950
]
5051
_recommended_attrs = {
5152
"http.server.active_requests": _active_requests_count_attrs,
5253
"http.server.duration": _duration_attrs,
54+
"http.server.response.size": _duration_attrs,
5355
}
5456

5557

@@ -61,7 +63,10 @@ async def http_app(scope, receive, send):
6163
{
6264
"type": "http.response.start",
6365
"status": 200,
64-
"headers": [[b"Content-Type", b"text/plain"]],
66+
"headers": [
67+
[b"Content-Type", b"text/plain"],
68+
[b"content-length", b"1024"],
69+
],
6570
}
6671
)
6772
await send({"type": "http.response.body", "body": b"*"})
@@ -103,7 +108,10 @@ async def error_asgi(scope, receive, send):
103108
{
104109
"type": "http.response.start",
105110
"status": 200,
106-
"headers": [[b"Content-Type", b"text/plain"]],
111+
"headers": [
112+
[b"Content-Type", b"text/plain"],
113+
[b"content-length", b"1024"],
114+
],
107115
}
108116
)
109117
await send({"type": "http.response.body", "body": b"*"})
@@ -126,7 +134,8 @@ def validate_outputs(self, outputs, error=None, modifiers=None):
126134
# Check http response start
127135
self.assertEqual(response_start["status"], 200)
128136
self.assertEqual(
129-
response_start["headers"], [[b"Content-Type", b"text/plain"]]
137+
response_start["headers"],
138+
[[b"Content-Type", b"text/plain"], [b"content-length", b"1024"]],
130139
)
131140

132141
exc_info = self.scope.get("hack_exc_info")
@@ -352,6 +361,7 @@ def test_traceresponse_header(self):
352361
response_start["headers"],
353362
[
354363
[b"Content-Type", b"text/plain"],
364+
[b"content-length", b"1024"],
355365
[b"traceresponse", f"{traceresponse}".encode()],
356366
[b"access-control-expose-headers", b"traceresponse"],
357367
],
@@ -565,6 +575,7 @@ def test_basic_metric_success(self):
565575
"http.flavor": "1.0",
566576
}
567577
metrics_list = self.memory_metrics_reader.get_metrics_data()
578+
# pylint: disable=too-many-nested-blocks
568579
for resource_metric in metrics_list.resource_metrics:
569580
for scope_metrics in resource_metric.scope_metrics:
570581
for metric in scope_metrics.metrics:
@@ -575,9 +586,12 @@ def test_basic_metric_success(self):
575586
dict(point.attributes),
576587
)
577588
self.assertEqual(point.count, 1)
578-
self.assertAlmostEqual(
579-
duration, point.sum, delta=5
580-
)
589+
if metric.name == "http.server.duration":
590+
self.assertAlmostEqual(
591+
duration, point.sum, delta=5
592+
)
593+
elif metric.name == "http.server.response.size":
594+
self.assertEqual(1024, point.sum)
581595
elif isinstance(point, NumberDataPoint):
582596
self.assertDictEqual(
583597
expected_requests_count_attributes,
@@ -602,13 +616,12 @@ async def target_asgi(scope, receive, send):
602616
app = otel_asgi.OpenTelemetryMiddleware(target_asgi)
603617
self.seed_app(app)
604618
self.send_default_request()
605-
606619
metrics_list = self.memory_metrics_reader.get_metrics_data()
607620
assertions = 0
608621
for resource_metric in metrics_list.resource_metrics:
609622
for scope_metrics in resource_metric.scope_metrics:
610623
for metric in scope_metrics.metrics:
611-
if metric.name != "http.server.duration":
624+
if metric.name == "http.server.active_requests":
612625
continue
613626
for point in metric.data.data_points:
614627
if isinstance(point, HistogramDataPoint):
@@ -617,7 +630,7 @@ async def target_asgi(scope, receive, send):
617630
expected_target,
618631
)
619632
assertions += 1
620-
self.assertEqual(assertions, 1)
633+
self.assertEqual(assertions, 2)
621634

622635
def test_no_metric_for_websockets(self):
623636
self.scope = {

Diff for: instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py

+51-43
Original file line numberDiff line numberDiff line change
@@ -201,30 +201,35 @@ def _set_api_gateway_v1_proxy_attributes(
201201
span.set_attribute(
202202
SpanAttributes.HTTP_METHOD, lambda_event.get("httpMethod")
203203
)
204-
span.set_attribute(SpanAttributes.HTTP_ROUTE, lambda_event.get("resource"))
205204

206205
if lambda_event.get("headers"):
207-
span.set_attribute(
208-
SpanAttributes.HTTP_USER_AGENT,
209-
lambda_event["headers"].get("User-Agent"),
210-
)
211-
span.set_attribute(
212-
SpanAttributes.HTTP_SCHEME,
213-
lambda_event["headers"].get("X-Forwarded-Proto"),
214-
)
215-
span.set_attribute(
216-
SpanAttributes.NET_HOST_NAME, lambda_event["headers"].get("Host")
217-
)
206+
if "User-Agent" in lambda_event["headers"]:
207+
span.set_attribute(
208+
SpanAttributes.HTTP_USER_AGENT,
209+
lambda_event["headers"]["User-Agent"],
210+
)
211+
if "X-Forwarded-Proto" in lambda_event["headers"]:
212+
span.set_attribute(
213+
SpanAttributes.HTTP_SCHEME,
214+
lambda_event["headers"]["X-Forwarded-Proto"],
215+
)
216+
if "Host" in lambda_event["headers"]:
217+
span.set_attribute(
218+
SpanAttributes.NET_HOST_NAME,
219+
lambda_event["headers"]["Host"],
220+
)
221+
if "resource" in lambda_event:
222+
span.set_attribute(SpanAttributes.HTTP_ROUTE, lambda_event["resource"])
218223

219-
if lambda_event.get("queryStringParameters"):
220-
span.set_attribute(
221-
SpanAttributes.HTTP_TARGET,
222-
f"{lambda_event.get('resource')}?{urlencode(lambda_event.get('queryStringParameters'))}",
223-
)
224-
else:
225-
span.set_attribute(
226-
SpanAttributes.HTTP_TARGET, lambda_event.get("resource")
227-
)
224+
if lambda_event.get("queryStringParameters"):
225+
span.set_attribute(
226+
SpanAttributes.HTTP_TARGET,
227+
f"{lambda_event['resource']}?{urlencode(lambda_event['queryStringParameters'])}",
228+
)
229+
else:
230+
span.set_attribute(
231+
SpanAttributes.HTTP_TARGET, lambda_event["resource"]
232+
)
228233

229234
return span
230235

@@ -237,35 +242,38 @@ def _set_api_gateway_v2_proxy_attributes(
237242
More info:
238243
https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html
239244
"""
240-
span.set_attribute(
241-
SpanAttributes.NET_HOST_NAME,
242-
lambda_event["requestContext"].get("domainName"),
243-
)
244-
245-
if lambda_event["requestContext"].get("http"):
245+
if "domainName" in lambda_event["requestContext"]:
246246
span.set_attribute(
247-
SpanAttributes.HTTP_METHOD,
248-
lambda_event["requestContext"]["http"].get("method"),
249-
)
250-
span.set_attribute(
251-
SpanAttributes.HTTP_USER_AGENT,
252-
lambda_event["requestContext"]["http"].get("userAgent"),
253-
)
254-
span.set_attribute(
255-
SpanAttributes.HTTP_ROUTE,
256-
lambda_event["requestContext"]["http"].get("path"),
247+
SpanAttributes.NET_HOST_NAME,
248+
lambda_event["requestContext"]["domainName"],
257249
)
258250

259-
if lambda_event.get("rawQueryString"):
251+
if lambda_event["requestContext"].get("http"):
252+
if "method" in lambda_event["requestContext"]["http"]:
260253
span.set_attribute(
261-
SpanAttributes.HTTP_TARGET,
262-
f"{lambda_event['requestContext']['http'].get('path')}?{lambda_event.get('rawQueryString')}",
254+
SpanAttributes.HTTP_METHOD,
255+
lambda_event["requestContext"]["http"]["method"],
263256
)
264-
else:
257+
if "userAgent" in lambda_event["requestContext"]["http"]:
265258
span.set_attribute(
266-
SpanAttributes.HTTP_TARGET,
267-
lambda_event["requestContext"]["http"].get("path"),
259+
SpanAttributes.HTTP_USER_AGENT,
260+
lambda_event["requestContext"]["http"]["userAgent"],
261+
)
262+
if "path" in lambda_event["requestContext"]["http"]:
263+
span.set_attribute(
264+
SpanAttributes.HTTP_ROUTE,
265+
lambda_event["requestContext"]["http"]["path"],
268266
)
267+
if lambda_event.get("rawQueryString"):
268+
span.set_attribute(
269+
SpanAttributes.HTTP_TARGET,
270+
f"{lambda_event['requestContext']['http']['path']}?{lambda_event['rawQueryString']}",
271+
)
272+
else:
273+
span.set_attribute(
274+
SpanAttributes.HTTP_TARGET,
275+
lambda_event["requestContext"]["http"]["path"],
276+
)
269277

270278
return span
271279

0 commit comments

Comments
 (0)