Like Prometheus, but for logs.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
loki/pkg/querier/queryrange/stats_test.go

125 lines
4.1 KiB

package queryrange
import (
"context"
"errors"
"testing"
"time"
"github.com/cortexproject/cortex/pkg/querier/queryrange"
"github.com/stretchr/testify/require"
"github.com/grafana/loki/pkg/loghttp"
"github.com/grafana/loki/pkg/logql"
"github.com/grafana/loki/pkg/logql/stats"
)
func TestStatsMiddleware(t *testing.T) {
for name, test := range map[string]struct {
queryrange.Handler
queryrange.Request
expect func(t *testing.T, status, query string, rangeType logql.QueryRangeType, stats stats.Result)
}{
"Prometheus instant query nil": {
Handler: queryrange.HandlerFunc(func(c context.Context, r queryrange.Request) (queryrange.Response, error) {
return &LokiPromResponse{}, nil
}),
Request: &LokiRequest{
Query: "foo",
},
expect: func(t *testing.T, status, query string, rangeType logql.QueryRangeType, stats stats.Result) {
require.Equal(t, "", status)
require.Equal(t, "foo", query)
require.Equal(t, logql.InstantType, rangeType)
require.NotEmpty(t, stats.Summary.ExecTime)
},
},
"Prometheus instant query": {
Handler: queryrange.HandlerFunc(func(c context.Context, r queryrange.Request) (queryrange.Response, error) {
return &LokiPromResponse{
Response: &queryrange.PrometheusResponse{
Status: loghttp.QueryStatusSuccess,
},
}, nil
}),
Request: &LokiRequest{
Query: "foo",
},
expect: func(t *testing.T, status, query string, rangeType logql.QueryRangeType, stats stats.Result) {
require.Equal(t, loghttp.QueryStatusSuccess, status)
require.Equal(t, "foo", query)
require.Equal(t, logql.InstantType, rangeType)
require.NotEmpty(t, stats.Summary.ExecTime)
},
},
"Loki range query": {
Handler: queryrange.HandlerFunc(func(c context.Context, r queryrange.Request) (queryrange.Response, error) {
return &LokiResponse{
Status: loghttp.QueryStatusFail,
Statistics: stats.Result{
Store: stats.Store{
DecompressedBytes: 20 * 1024,
},
},
}, nil
}),
Request: &LokiRequest{
Query: "foo",
EndTs: time.Now(),
},
expect: func(t *testing.T, status, query string, rangeType logql.QueryRangeType, stats stats.Result) {
require.Equal(t, loghttp.QueryStatusFail, status)
require.Equal(t, "foo", query)
require.Equal(t, logql.RangeType, rangeType)
require.NotEmpty(t, stats.Summary.ExecTime)
require.Equal(t, int64(20*1024), stats.Store.DecompressedBytes)
},
},
"error": {
Handler: queryrange.HandlerFunc(func(c context.Context, r queryrange.Request) (queryrange.Response, error) {
return nil, errors.New("")
}),
Request: &LokiRequest{
Query: "foo",
EndTs: time.Now(),
},
expect: func(t *testing.T, status, query string, rangeType logql.QueryRangeType, stats stats.Result) {
require.Equal(t, loghttp.QueryStatusFail, status)
require.Equal(t, "foo", query)
require.Equal(t, logql.RangeType, rangeType)
require.NotEmpty(t, stats.Summary.ExecTime)
},
},
"invalid response type": {
Handler: queryrange.HandlerFunc(func(c context.Context, r queryrange.Request) (queryrange.Response, error) {
return &queryrange.PrometheusResponse{}, nil
}),
Request: &queryrange.PrometheusRequest{
Query: "foo",
},
expect: func(t *testing.T, status, query string, rangeType logql.QueryRangeType, stats stats.Result) {
t.Error("should not have been recorded")
},
},
} {
t.Run(name, func(t *testing.T) {
md := statsMiddleware(metricRecorderFn(func(status, query string, rangeType logql.QueryRangeType, stats stats.Result) {
test.expect(t, status, query, rangeType, stats)
}))
_, _ = md.Wrap(test.Handler).Do(context.Background(), test.Request)
})
}
}
func Test_StatsUpdateResult(t *testing.T) {
resp, err := StatsMiddleware().Wrap(queryrange.HandlerFunc(func(c context.Context, r queryrange.Request) (queryrange.Response, error) {
time.Sleep(20 * time.Millisecond)
return &LokiResponse{}, nil
})).Do(context.Background(), &LokiRequest{
Query: "foo",
EndTs: time.Now(),
})
require.NoError(t, err)
require.GreaterOrEqual(t, resp.(*LokiResponse).Statistics.Summary.ExecTime, (20 * time.Millisecond).Seconds())
}