fix(observability-proxy): cap the hits groups when fields_limit is absent

The fields_limit cap applied only when the client sent the parameter.
vlselect returns every group when it is absent, as it does for 0, so
leaving it out bypassed the cap. The capped value is now always sent.

Assisted-by: LLM
Signed-off-by: ZverGuy <maximbel2003@gmail.com>
This commit is contained in:
ZverGuy committed 2026-11-10 00:45:07 +07:00
1 parent 1ef10537f6
commit 38f9837f14
2 files changed
+12 -7

No files matched your search

+6 -6
View File
@@ -103,13 +103,13 @@ func BuildLogsParams(endpoint string, in url.Values, namespace string, now time.
out.Add("field", f)
}
}
if in.Has("fields_limit") {
// setLimit reads an empty value as the default, which here is 0.
if in.Get("fields_limit") == "" {
return nil, errorf(http.StatusBadRequest, "invalid fields_limit \"\"")
}
herr = setLimit(out, in, "fields_limit", 0, lim.MaxLimit)
// vlselect returns every group without fields_limit or with 0, so
// the cap is sent either way; an empty value is malformed rather
// than a request for the default.
if in.Has("fields_limit") && in.Get("fields_limit") == "" {
return nil, errorf(http.StatusBadRequest, "invalid fields_limit \"\"")
}
herr = setLimit(out, in, "fields_limit", lim.MaxLimit, lim.MaxLimit)
case "stats_query_range":
herr = setStep(out, in, start, end, lim)
case "field_values", "stream_field_values":
@@ -116,7 +116,7 @@ func TestBuildLogsParamsRejects(t *testing.T) {
code int
}{
{"unknown endpoint", "tenant_ids", url.Values{}, http.StatusNotFound},
// An empty value used to reach vlselect as fields_limit=0.
// vlselect reads fields_limit=0 as no limit on the groups.
{"empty fields_limit", "hits", url.Values{"field": {"level"}, "fields_limit": {""}}, http.StatusBadRequest},
{"stats_query is not proxied", "stats_query", url.Values{}, http.StatusNotFound},
{"ignore_global_time_filter", "query", url.Values{"query": {`* options(ignore_global_time_filter=true)`}}, http.StatusBadRequest},
@@ -264,6 +264,11 @@ func TestBuildLogsParamsStepAndLimit(t *testing.T) {
if facets.Get("max_values_per_field") != "5000" || facets.Get("max_value_len") != "5000" {
t.Errorf("facets caps not clamped: %v", facets)
}
// Without fields_limit vlselect returns every group, so the cap is
// sent even when the client sends none.
if got := build(t, "hits", url.Values{"field": {"level"}}).Get("fields_limit"); got != "5000" {
t.Errorf("hits without fields_limit forwards %q, want the 5000 cap", got)
}
hits := build(t, "hits", url.Values{"field": {"b", "a"}, "fields_limit": {"99999"}})
fields := hits["field"]
sort.Strings(fields)