[v10.0.x] Alerting: Add limit query parameter to Loki-based ASH api, drop default limit from 5000 to 1000, extend visible time range for new ASH UI (#70857)

Alerting: Add limit query parameter to Loki-based ASH api, drop default limit from 5000 to 1000, extend visible time range for new ASH UI (#70769)

* Add limit query parameter

* Drop copy paste comment

* Extend history query limit to 30 days and 250 entries

* Fix history log entries ordering

* Update no history message, add empty history test

---------

Co-authored-by: Konrad Lalik <konrad.lalik@grafana.com>
(cherry picked from commit f94fb765b5)

Co-authored-by: Alexander Weaver <weaver.alex.d@gmail.com>
This commit is contained in:
grafana-delivery-bot[bot]
2023-06-28 15:11:17 -05:00
committed by GitHub
co-authored by Alexander Weaver
parent 05154b8d06
commit bf80197015
9 changed files with 142 additions and 30 deletions
@@ -27,6 +27,7 @@ const labelQueryPrefix = "labels_"
func (srv *HistorySrv) RouteQueryStateHistory(c *contextmodel.ReqContext) response.Response {
from := c.QueryInt64("from")
to := c.QueryInt64("to")
limit := c.QueryInt("limit")
ruleUID := c.Query("ruleUID")
labels := make(map[string]string)
@@ -42,6 +43,7 @@ func (srv *HistorySrv) RouteQueryStateHistory(c *contextmodel.ReqContext) respon
SignedInUser: c.SignedInUser,
From: time.Unix(from, 0),
To: time.Unix(to, 0),
Limit: limit,
Labels: labels,
}
frame, err := srv.hist.Query(c.Req.Context(), query)
+1
View File
@@ -13,5 +13,6 @@ type HistoryQuery struct {
Labels map[string]string
From time.Time
To time.Time
Limit int
SignedInUser *user.SignedInUser
}
+2 -2
View File
@@ -43,7 +43,7 @@ const defaultQueryRange = 6 * time.Hour
type remoteLokiClient interface {
ping(context.Context) error
push(context.Context, []stream) error
rangeQuery(ctx context.Context, logQL string, start, end int64) (queryRes, error)
rangeQuery(ctx context.Context, logQL string, start, end, limit int64) (queryRes, error)
}
// RemoteLokibackend is a state.Historian that records state history to an external Loki instance.
@@ -126,7 +126,7 @@ func (h *RemoteLokiBackend) Query(ctx context.Context, query models.HistoryQuery
}
// Timestamps are expected in RFC3339Nano.
res, err := h.client.rangeQuery(ctx, logQL, query.From.UnixNano(), query.To.UnixNano())
res, err := h.client.rangeQuery(ctx, logQL, query.From.UnixNano(), query.To.UnixNano(), int64(query.Limit))
if err != nil {
return nil, err
}
@@ -17,7 +17,8 @@ import (
"github.com/weaveworks/common/http/client"
)
const defaultPageSize = 5000
const defaultPageSize = 1000
const maximumPageSize = 5000
func NewRequester() client.Requester {
return &http.Client{}
@@ -225,11 +226,17 @@ func (c *httpLokiClient) setAuthAndTenantHeaders(req *http.Request) {
}
}
func (c *httpLokiClient) rangeQuery(ctx context.Context, logQL string, start, end int64) (queryRes, error) {
func (c *httpLokiClient) rangeQuery(ctx context.Context, logQL string, start, end, limit int64) (queryRes, error) {
// Run the pre-flight checks for the query.
if start > end {
return queryRes{}, fmt.Errorf("start time cannot be after end time")
}
if limit < 1 {
limit = defaultPageSize
}
if limit > maximumPageSize {
limit = maximumPageSize
}
queryURL := c.cfg.ReadPathURL.JoinPath("/loki/api/v1/query_range")
@@ -237,7 +244,7 @@ func (c *httpLokiClient) rangeQuery(ctx context.Context, logQL string, start, en
values.Set("query", logQL)
values.Set("start", fmt.Sprintf("%d", start))
values.Set("end", fmt.Sprintf("%d", end))
values.Set("limit", fmt.Sprintf("%d", defaultPageSize))
values.Set("limit", fmt.Sprintf("%d", limit))
queryURL.RawQuery = values.Encode()
@@ -131,13 +131,73 @@ func TestLokiHTTPClient(t *testing.T) {
now := time.Now().UTC().UnixNano()
q := `{from="state-history"}`
_, err := client.rangeQuery(context.Background(), q, now-100, now)
_, err := client.rangeQuery(context.Background(), q, now-100, now, 1100)
require.NoError(t, err)
params := req.lastRequest.URL.Query()
require.True(t, params.Has("limit"), "query params did not contain 'limit': %#v", params)
require.Equal(t, fmt.Sprint(1100), params.Get("limit"))
})
t.Run("uses default page size if limit not provided", func(t *testing.T) {
req := NewFakeRequester().WithResponse(&http.Response{
Status: "200 OK",
StatusCode: 200,
Body: io.NopCloser(bytes.NewBufferString(`{}`)),
ContentLength: int64(0),
Header: make(http.Header, 0),
})
client := createTestLokiClient(req)
now := time.Now().UTC().UnixNano()
q := `{from="state-history"}`
_, err := client.rangeQuery(context.Background(), q, now-100, now, 0)
require.NoError(t, err)
params := req.lastRequest.URL.Query()
require.True(t, params.Has("limit"), "query params did not contain 'limit': %#v", params)
require.Equal(t, fmt.Sprint(defaultPageSize), params.Get("limit"))
})
t.Run("uses default page size if limit invalid", func(t *testing.T) {
req := NewFakeRequester().WithResponse(&http.Response{
Status: "200 OK",
StatusCode: 200,
Body: io.NopCloser(bytes.NewBufferString(`{}`)),
ContentLength: int64(0),
Header: make(http.Header, 0),
})
client := createTestLokiClient(req)
now := time.Now().UTC().UnixNano()
q := `{from="state-history"}`
_, err := client.rangeQuery(context.Background(), q, now-100, now, -100)
require.NoError(t, err)
params := req.lastRequest.URL.Query()
require.True(t, params.Has("limit"), "query params did not contain 'limit': %#v", params)
require.Equal(t, fmt.Sprint(defaultPageSize), params.Get("limit"))
})
t.Run("uses maximum page size if limit too big", func(t *testing.T) {
req := NewFakeRequester().WithResponse(&http.Response{
Status: "200 OK",
StatusCode: 200,
Body: io.NopCloser(bytes.NewBufferString(`{}`)),
ContentLength: int64(0),
Header: make(http.Header, 0),
})
client := createTestLokiClient(req)
now := time.Now().UTC().UnixNano()
q := `{from="state-history"}`
_, err := client.rangeQuery(context.Background(), q, now-100, now, maximumPageSize+1000)
require.NoError(t, err)
params := req.lastRequest.URL.Query()
require.True(t, params.Has("limit"), "query params did not contain 'limit': %#v", params)
require.Equal(t, fmt.Sprint(maximumPageSize), params.Get("limit"))
})
})
}
@@ -194,7 +254,7 @@ func TestLokiHTTPClient_Manual(t *testing.T) {
end := time.Now().UnixNano()
// Authorized request should not fail against Grafana Cloud.
res, err := client.rangeQuery(context.Background(), logQL, start, end)
res, err := client.rangeQuery(context.Background(), logQL, start, end, defaultPageSize)
require.NoError(t, err)
require.NotNil(t, res)
})