Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add http.server.response.size metric to ASGI implementation. #1789

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
fed3fe2
Add http.server.response.size metric to ASGI implementation.
imanshafiei540 May 8, 2023
54f9cbe
Update changelog.
imanshafiei540 May 8, 2023
8dd9381
Fix linting by disabling too-many-nested-blocks
imanshafiei540 May 9, 2023
fb3c287
Put new logic in a new method
imanshafiei540 May 9, 2023
c9579b7
Refactor the placement of new logic.
imanshafiei540 May 9, 2023
fcb9222
Merge branch 'main' into Add-response-size-histogram-metric-to-ASGI-i…
shalevr May 16, 2023
e429dd2
Merge branch 'open-telemetry:main' into Add-response-size-histogram-m…
imanshafiei540 May 17, 2023
ba4a244
Fixed the unit tests in FastAPI and Starlette
imanshafiei540 May 17, 2023
1a50c15
Update changelog.
imanshafiei540 May 17, 2023
604dac1
Merge branch 'main' into Add-response-size-histogram-metric-to-ASGI-i…
shalevr May 23, 2023
050e69c
FIx lint errors.
imanshafiei540 May 23, 2023
6e447b2
Merge branch 'main' into Add-response-size-histogram-metric-to-ASGI-i…
shalevr May 24, 2023
ebae427
Merge branch 'main' into Add-response-size-histogram-metric-to-ASGI-i…
ocelotl Jun 9, 2023
8f4ca60
Merge branch 'main' into Add-response-size-histogram-metric-to-ASGI-i…
imanshafiei540 Jun 13, 2023
56da463
Merge branch 'main' into Add-response-size-histogram-metric-to-ASGI-i…
imanshafiei540 Jun 17, 2023
a552ee0
Merge branch 'main' into Add-response-size-histogram-metric-to-ASGI-i…
imanshafiei540 Jun 18, 2023
be70c8b
Refactor getting content-length header
imanshafiei540 Jun 19, 2023
edf0f92
Refactor getting content-length header
imanshafiei540 Jun 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#1407](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1407))
- `opentelemetry-instrumentation-logging` Add `otelTraceSampled` to instrumetation-logging
([#1773](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1773))
- `opentelemetry-instrumentation-asgi` Add `http.server.response.size` metric
imanshafiei540 marked this conversation as resolved.
Show resolved Hide resolved
([#1789](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1789))


### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,11 @@ def __init__(
unit="ms",
description="measures the duration of the inbound HTTP request",
)
self.server_response_size_histogram = self.meter.create_histogram(
name=MetricInstruments.HTTP_SERVER_RESPONSE_SIZE,
unit="By",
description="measures the size of HTTP response messages (compressed).",
)
self.active_requests_counter = self.meter.create_up_down_counter(
name=MetricInstruments.HTTP_SERVER_ACTIVE_REQUESTS,
unit="requests",
Expand Down Expand Up @@ -615,6 +620,18 @@ def _get_otel_send(
):
@wraps(send)
async def otel_send(message):
if message.get("headers"):
imanshafiei540 marked this conversation as resolved.
Show resolved Hide resolved
headers = {
_key.decode("utf8"): _value.decode("utf8")
for (_key, _value) in message.get("headers")
}
if headers.get("content-length"):
target = _collect_target_attribute(scope)
if target:
duration_attrs[SpanAttributes.HTTP_TARGET] = target
self.server_response_size_histogram.record(
int(headers.get("content-length")), duration_attrs
)
with self.tracer.start_as_current_span(
" ".join((server_span_name, scope["type"], "send"))
) as send_span:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,12 @@
_expected_metric_names = [
"http.server.active_requests",
"http.server.duration",
"http.server.response.size",
]
_recommended_attrs = {
"http.server.active_requests": _active_requests_count_attrs,
"http.server.duration": _duration_attrs,
"http.server.response.size": _duration_attrs,
}


Expand All @@ -61,7 +63,10 @@ async def http_app(scope, receive, send):
{
"type": "http.response.start",
"status": 200,
"headers": [[b"Content-Type", b"text/plain"]],
"headers": [
[b"Content-Type", b"text/plain"],
[b"content-length", b"1024"],
],
}
)
await send({"type": "http.response.body", "body": b"*"})
Expand Down Expand Up @@ -103,7 +108,10 @@ async def error_asgi(scope, receive, send):
{
"type": "http.response.start",
"status": 200,
"headers": [[b"Content-Type", b"text/plain"]],
"headers": [
[b"Content-Type", b"text/plain"],
[b"content-length", b"1024"],
],
}
)
await send({"type": "http.response.body", "body": b"*"})
Expand All @@ -126,7 +134,8 @@ def validate_outputs(self, outputs, error=None, modifiers=None):
# Check http response start
self.assertEqual(response_start["status"], 200)
self.assertEqual(
response_start["headers"], [[b"Content-Type", b"text/plain"]]
response_start["headers"],
[[b"Content-Type", b"text/plain"], [b"content-length", b"1024"]],
)

exc_info = self.scope.get("hack_exc_info")
Expand Down Expand Up @@ -352,6 +361,7 @@ def test_traceresponse_header(self):
response_start["headers"],
[
[b"Content-Type", b"text/plain"],
[b"content-length", b"1024"],
[b"traceresponse", f"{traceresponse}".encode()],
[b"access-control-expose-headers", b"traceresponse"],
],
Expand Down Expand Up @@ -575,9 +585,12 @@ def test_basic_metric_success(self):
dict(point.attributes),
)
self.assertEqual(point.count, 1)
self.assertAlmostEqual(
duration, point.sum, delta=5
)
if metric.name == "http.server.duration":
self.assertAlmostEqual(
duration, point.sum, delta=5
)
elif metric.name == "http.server.response.size":
self.assertEqual(1024, point.sum)
elif isinstance(point, NumberDataPoint):
self.assertDictEqual(
expected_requests_count_attributes,
Expand All @@ -602,13 +615,12 @@ async def target_asgi(scope, receive, send):
app = otel_asgi.OpenTelemetryMiddleware(target_asgi)
self.seed_app(app)
self.send_default_request()

metrics_list = self.memory_metrics_reader.get_metrics_data()
assertions = 0
for resource_metric in metrics_list.resource_metrics:
for scope_metrics in resource_metric.scope_metrics:
for metric in scope_metrics.metrics:
if metric.name != "http.server.duration":
if metric.name == "http.server.active_requests":
imanshafiei540 marked this conversation as resolved.
Show resolved Hide resolved
continue
for point in metric.data.data_points:
if isinstance(point, HistogramDataPoint):
Expand All @@ -617,7 +629,7 @@ async def target_asgi(scope, receive, send):
expected_target,
)
assertions += 1
self.assertEqual(assertions, 1)
self.assertEqual(assertions, 2)

def test_no_metric_for_websockets(self):
self.scope = {
Expand Down