Skip to content

No span emitted when client_max_body_size is exceeded #115

@tommilligan

Description

@tommilligan

Describe the bug

When a location is configured with the client_max_body_size directive and the limit is exceeded, no telemetry span is emitted for the request.

To reproduce

This diff reproduces the issue as a unit test. You can also check out the commit here

diff --git a/tests/test_otel.py b/tests/test_otel.py
index fef771a..d32f217 100644
--- a/tests/test_otel.py
+++ b/tests/test_otel.py
@@ -42,6 +42,7 @@ http {
         server_name  localhost;
 
         location /ok {
+            client_max_body_size 1K;
             return 200 "OK";
         }
 
@@ -329,3 +330,35 @@ def test_tls_export(client, trace_service):
     assert client.get("http://127.0.0.1:18080/ok").status_code == 200
 
     assert trace_service.get_span().name == "/ok"
+
+
+@pytest.mark.parametrize(
+    ("body_size", "status"),
+    [(20, 200), (2000, 413)],
+)
+def test_error_page_emits_telemetry(client, trace_service, body_size, status):
+    http_ver = "1.1"
+    scheme = "http"
+    path = "/ok"
+    port = 18080
+    r = client.post(
+        f"{scheme}://127.0.0.1:{port}{path}", verify=False, data="A" * body_size
+    )
+    assert r.status_code == status
+
+    span = trace_service.get_span()
+    assert span.name == path
+
+    assert get_attr(span, "http.method") == "POST"
+    assert get_attr(span, "http.target") == path
+    assert get_attr(span, "http.route") == path
+    assert get_attr(span, "http.scheme") == scheme
+    assert get_attr(span, "http.flavor") == http_ver
+    assert get_attr(span, "http.user_agent") == (f"niquests/{niquests.__version__}")
+    assert get_attr(span, "http.request_content_length") == 0
+    assert get_attr(span, "http.response_content_length") == len(r.text)
+    assert get_attr(span, "http.status_code") == status
+    assert get_attr(span, "net.host.name") == "localhost"
+    assert get_attr(span, "net.host.port") == port
+    assert get_attr(span, "net.sock.peer.addr") == "127.0.0.1"
+    assert get_attr(span, "net.sock.peer.port") in range(1024, 65536)

Expected behavior

Telemetry span to be emitted on a standard HTTP error case for the request.

Your environment

Latest version of the nginx-otel repo, checked out locally. Originally seen in nginx:1.29.6-otel docker image from docker hub.

Additional context

It looks as though the body size limit is checked in the find_config phase here: https://github.com/nginx/nginx/blob/9fd94af4ddfca2f1f725744d6e4a578efef776e4/src/http/ngx_http_core_module.c#L1164

nginx-otel hooks into the request lifecycle in the http_rewrite phase: https://github.com/nginxinc/nginx-otel/blob/6eb28d7452f6ce2e009cc25470aec091826503b3/src/http_module.cpp#L554

So it looks as though any handling prior to the http_rewrite phase will never be traced currently.

Happy to help resolve this, but I'd want to agree the design of the solution first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status

    New

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions