github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/querier/queryrange/stats_test.go (about)

     1  package queryrange
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	strings "strings"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/stretchr/testify/require"
    13  
    14  	"github.com/grafana/loki/pkg/logproto"
    15  	"github.com/grafana/loki/pkg/logqlmodel/stats"
    16  	"github.com/grafana/loki/pkg/querier/queryrange/queryrangebase"
    17  )
    18  
    19  func TestStatsCollectorMiddleware(t *testing.T) {
    20  	// no stats
    21  	var (
    22  		data = &queryData{}
    23  		now  = time.Now()
    24  	)
    25  	ctx := context.WithValue(context.Background(), ctxKey, data)
    26  	_, _ = StatsCollectorMiddleware().Wrap(queryrangebase.HandlerFunc(func(ctx context.Context, r queryrangebase.Request) (queryrangebase.Response, error) {
    27  		return nil, nil
    28  	})).Do(ctx, &LokiRequest{
    29  		Query:   "foo",
    30  		StartTs: now,
    31  	})
    32  	require.Equal(t, "foo", data.params.Query())
    33  	require.Equal(t, true, data.recorded)
    34  	require.Equal(t, now, data.params.Start())
    35  	require.Nil(t, data.statistics)
    36  
    37  	// no context.
    38  	data = &queryData{}
    39  	_, _ = StatsCollectorMiddleware().Wrap(queryrangebase.HandlerFunc(func(ctx context.Context, r queryrangebase.Request) (queryrangebase.Response, error) {
    40  		return nil, nil
    41  	})).Do(context.Background(), &LokiRequest{
    42  		Query:   "foo",
    43  		StartTs: now,
    44  	})
    45  	require.Equal(t, false, data.recorded)
    46  
    47  	// stats
    48  	data = &queryData{}
    49  	ctx = context.WithValue(context.Background(), ctxKey, data)
    50  	_, _ = StatsCollectorMiddleware().Wrap(queryrangebase.HandlerFunc(func(ctx context.Context, r queryrangebase.Request) (queryrangebase.Response, error) {
    51  		return &LokiPromResponse{
    52  			Statistics: stats.Result{
    53  				Ingester: stats.Ingester{
    54  					TotalReached: 10,
    55  				},
    56  			},
    57  		}, nil
    58  	})).Do(ctx, &LokiRequest{
    59  		Query:   "foo",
    60  		StartTs: now,
    61  	})
    62  	require.Equal(t, "foo", data.params.Query())
    63  	require.Equal(t, true, data.recorded)
    64  	require.Equal(t, now, data.params.Start())
    65  	require.Equal(t, int32(10), data.statistics.Ingester.TotalReached)
    66  }
    67  
    68  func Test_StatsHTTP(t *testing.T) {
    69  	for _, test := range []struct {
    70  		name   string
    71  		next   http.Handler
    72  		expect func(t *testing.T, data *queryData)
    73  	}{
    74  		{
    75  			"should not record metric if nothing is recorded",
    76  			http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    77  				data := r.Context().Value(ctxKey).(*queryData)
    78  				data.recorded = false
    79  			}),
    80  			func(t *testing.T, data *queryData) {
    81  				t.Fail()
    82  			},
    83  		},
    84  		{
    85  			"empty statistics success",
    86  			http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    87  				data := r.Context().Value(ctxKey).(*queryData)
    88  				data.recorded = true
    89  				data.params, _ = paramsFromRequest(&LokiRequest{
    90  					Query:     "foo",
    91  					Direction: logproto.BACKWARD,
    92  					Limit:     100,
    93  				})
    94  				data.statistics = nil
    95  			}),
    96  			func(t *testing.T, data *queryData) {
    97  				require.Equal(t, fmt.Sprintf("%d", http.StatusOK), data.status)
    98  				require.Equal(t, "foo", data.params.Query())
    99  				require.Equal(t, logproto.BACKWARD, data.params.Direction())
   100  				require.Equal(t, uint32(100), data.params.Limit())
   101  				require.Equal(t, stats.Result{}, *data.statistics)
   102  			},
   103  		},
   104  		{
   105  			"statuscode",
   106  			http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   107  				data := r.Context().Value(ctxKey).(*queryData)
   108  				data.recorded = true
   109  				data.params, _ = paramsFromRequest(&LokiRequest{
   110  					Query:     "foo",
   111  					Direction: logproto.BACKWARD,
   112  					Limit:     100,
   113  				})
   114  				data.statistics = &statsResult
   115  				w.WriteHeader(http.StatusTeapot)
   116  			}),
   117  			func(t *testing.T, data *queryData) {
   118  				require.Equal(t, fmt.Sprintf("%d", http.StatusTeapot), data.status)
   119  				require.Equal(t, "foo", data.params.Query())
   120  				require.Equal(t, logproto.BACKWARD, data.params.Direction())
   121  				require.Equal(t, uint32(100), data.params.Limit())
   122  				require.Equal(t, statsResult, *data.statistics)
   123  			},
   124  		},
   125  		{
   126  			"result",
   127  			http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   128  				data := r.Context().Value(ctxKey).(*queryData)
   129  				data.recorded = true
   130  				data.params, _ = paramsFromRequest(&LokiRequest{
   131  					Query:     "foo",
   132  					Direction: logproto.BACKWARD,
   133  					Limit:     100,
   134  				})
   135  				data.statistics = &statsResult
   136  				data.result = streams
   137  				w.WriteHeader(http.StatusTeapot)
   138  			}),
   139  			func(t *testing.T, data *queryData) {
   140  				require.Equal(t, fmt.Sprintf("%d", http.StatusTeapot), data.status)
   141  				require.Equal(t, "foo", data.params.Query())
   142  				require.Equal(t, logproto.BACKWARD, data.params.Direction())
   143  				require.Equal(t, uint32(100), data.params.Limit())
   144  				require.Equal(t, statsResult, *data.statistics)
   145  				require.Equal(t, streams, data.result)
   146  			},
   147  		},
   148  	} {
   149  		t.Run(test.name, func(t *testing.T) {
   150  			statsHTTPMiddleware(metricRecorderFn(func(data *queryData) {
   151  				test.expect(t, data)
   152  			})).Wrap(test.next).ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/foo", strings.NewReader("")))
   153  		})
   154  	}
   155  }
   156  
   157  func Test_StatsUpdateResult(t *testing.T) {
   158  	resp, err := StatsCollectorMiddleware().Wrap(queryrangebase.HandlerFunc(func(c context.Context, r queryrangebase.Request) (queryrangebase.Response, error) {
   159  		time.Sleep(20 * time.Millisecond)
   160  		return &LokiResponse{}, nil
   161  	})).Do(context.Background(), &LokiRequest{
   162  		Query: "foo",
   163  		EndTs: time.Now(),
   164  	})
   165  	require.NoError(t, err)
   166  	require.GreaterOrEqual(t, resp.(*LokiResponse).Statistics.Summary.ExecTime, (20 * time.Millisecond).Seconds())
   167  }