Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query Analysis #6515

Merged
merged 49 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
ee1b9a7
Return Query Analysis in API
nishchay-veer Jul 10, 2023
3a66c9b
Added analyze checkbox in Thanos UI
nishchay-veer Jul 28, 2023
a9c8cfb
Merge branch 'main' into query-analyze
nishchay-veer Jul 28, 2023
f804a76
Return Query Analysis in API
nishchay-veer Jul 10, 2023
cf54bc7
Added analyze checkbox in Thanos UI
nishchay-veer Jul 28, 2023
2bcefbe
Add query explain API
saswatamcode Aug 4, 2023
c9de0a6
Merge branch 'main' into query-analyze
saswatamcode Aug 4, 2023
797c1fe
Merge branch 'query-analyze' into analyze
nishchay-veer Aug 13, 2023
3934fdd
Merge pull request #1 from saswatamcode/analyze
nishchay-veer Aug 13, 2023
47778cf
Hooked queryTelemetry data into UI
nishchay-veer Aug 14, 2023
d3293be
Merge branch 'main' into query-analyze
nishchay-veer Aug 14, 2023
b69a546
/query_explain and /query_range_explain for explain-tree
nishchay-veer Aug 14, 2023
5fabf3b
Merge remote-tracking branch 'origin/query-analyze' into query-analyze
nishchay-veer Aug 14, 2023
9a1b811
update promql-engine
nishchay-veer Aug 16, 2023
00e7bad
Execution time shows 0s
nishchay-veer Aug 16, 2023
91deb46
Merge branch 'main' into query-analyze
nishchay-veer Aug 16, 2023
5b3612e
Show execution time of operators
nishchay-veer Aug 17, 2023
c8a1568
Merge branch 'main' into query-analyze
nishchay-veer Aug 17, 2023
7f80303
Removing QueryExplainParam from query api
nishchay-veer Aug 17, 2023
932c827
Merge branch 'main' into query-analyze
nishchay-veer Aug 19, 2023
902a42e
bad request format in Explain
nishchay-veer Aug 20, 2023
ab2d6bf
Merge remote-tracking branch 'origin/query-analyze' into query-analyze
nishchay-veer Aug 20, 2023
abfd8a1
Showing Expalin and Analyze Output
nishchay-veer Aug 20, 2023
0891d53
Merge branch 'main' into query-analyze
nishchay-veer Aug 24, 2023
77193fb
Merge branch 'main' into query-analyze
nishchay-veer Aug 24, 2023
ad49d3b
Added tooltip and different enpoints for table and graph queries
nishchay-veer Aug 24, 2023
86ab544
Linters pass
nishchay-veer Aug 25, 2023
91f2513
Merge branch 'main' into query-analyze
nishchay-veer Aug 31, 2023
da5de39
disable Explain when engine is 'prometheus'
nishchay-veer Aug 31, 2023
c1bc461
passing query params to explain endpoints
nishchay-veer Aug 31, 2023
703d29f
Merge branch 'main' into query-analyze
nishchay-veer Aug 31, 2023
bea3c8b
fixed react test case failing
nishchay-veer Aug 31, 2023
75cd9d1
Merge branch 'main' into query-analyze
nishchay-veer Sep 1, 2023
e7138d2
Merge branch 'main' into query-analyze
nishchay-veer Sep 4, 2023
91c8f6f
fix ui tests
nishchay-veer Sep 4, 2023
4c88f5d
Merge remote-tracking branch 'origin/query-analyze' into query-analyze
nishchay-veer Sep 4, 2023
bf0a91c
fix some e2e test fails
nishchay-veer Sep 5, 2023
3857d19
Merge branch 'main' into query-analyze
nishchay-veer Sep 7, 2023
c6926d5
added customised tooltip in place of Tooltip component
nishchay-veer Sep 7, 2023
1550af9
removed Tooltip from Panel
nishchay-veer Sep 8, 2023
674cab9
Linters pass
nishchay-veer Sep 8, 2023
58587e2
4 arguments in QueryInstant
nishchay-veer Sep 11, 2023
9fcba42
resolving conflicts -2
nishchay-veer Sep 11, 2023
e5ee652
resolving conflicts in Panel.tsx
nishchay-veer Sep 12, 2023
bc05b36
adding checkbox
nishchay-veer Sep 12, 2023
d9d7c68
Merge remote-tracking branch 'origin/main' into query-analyze
nishchay-veer Sep 13, 2023
e520a81
Merge branch 'main' into query-analyze
nishchay-veer Sep 13, 2023
02c0bc8
Merge branch 'main' into query-analyze
nishchay-veer Oct 10, 2023
10261d4
fixing linters fail
nishchay-veer Oct 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
340 changes: 298 additions & 42 deletions pkg/api/query/v1.go

Large diffs are not rendered by default.

148 changes: 148 additions & 0 deletions pkg/api/query/v1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (
"github.com/prometheus/prometheus/tsdb/tsdbutil"
promgate "github.com/prometheus/prometheus/util/gate"
"github.com/prometheus/prometheus/util/stats"
"github.com/thanos-io/promql-engine/engine"
baseAPI "github.com/thanos-io/thanos/pkg/api"
"github.com/thanos-io/thanos/pkg/compact"
"github.com/thanos-io/thanos/pkg/component"
Expand Down Expand Up @@ -337,6 +338,7 @@ func TestQueryEndpoints(t *testing.T) {
},
},
},

// Query endpoint with single deduplication label.
{
endpoint: api.query,
Expand Down Expand Up @@ -628,6 +630,152 @@ func TestQueryEndpoints(t *testing.T) {
}
}

func TestQueryExplainEndpoints(t *testing.T) {
db, err := e2eutil.NewTSDB()
defer func() { testutil.Ok(t, db.Close()) }()
testutil.Ok(t, err)

now := time.Now()
timeout := 100 * time.Second
ef := NewQueryEngineFactory(promql.EngineOpts{
Logger: nil,
Reg: nil,
MaxSamples: 10000,
Timeout: timeout,
}, nil)
api := &QueryAPI{
baseAPI: &baseAPI.BaseAPI{
Now: func() time.Time { return now },
},
queryableCreate: query.NewQueryableCreator(nil, nil, newProxyStoreWithTSDBStore(db), 2, timeout),
engineFactory: ef,
defaultEngine: PromqlEnginePrometheus,
lookbackDeltaCreate: func(m int64) time.Duration { return time.Duration(0) },
gate: gate.New(nil, 4, gate.Queries),
defaultRangeQueryStep: time.Second,
queryRangeHist: promauto.With(prometheus.NewRegistry()).NewHistogram(prometheus.HistogramOpts{
Name: "query_range_hist",
}),
seriesStatsAggregatorFactory: &store.NoopSeriesStatsAggregatorFactory{},
tenantHeader: "thanos-tenant",
defaultTenant: "default-tenant",
}

var tests = []endpointTestCase{
{
endpoint: api.queryExplain,
query: url.Values{
"query": []string{"2"},
"time": []string{"123.4"},
"engine": []string{"thanos"},
},
response: &engine.ExplainOutputNode{
OperatorName: "[*numberLiteralSelector] 2",
},
},
{
endpoint: api.queryRangeExplain,
query: url.Values{
"query": []string{"time()"},
"start": []string{"0"},
"end": []string{"500"},
"step": []string{"1"},
"engine": []string{"thanos"},
},
response: &engine.ExplainOutputNode{
OperatorName: "[*noArgFunctionOperator] time()",
},
},
}
for i, test := range tests {
if ok := testEndpoint(t, test, fmt.Sprintf("#%d %s", i, test.query.Encode()), reflect.DeepEqual); !ok {
return
}
}
}

func TestQueryAnalyzeEndpoints(t *testing.T) {
db, err := e2eutil.NewTSDB()
defer func() { testutil.Ok(t, db.Close()) }()
testutil.Ok(t, err)

now := time.Now()
timeout := 100 * time.Second
ef := NewQueryEngineFactory(promql.EngineOpts{
Logger: nil,
Reg: nil,
MaxSamples: 10000,
Timeout: timeout,
}, nil)
api := &QueryAPI{
baseAPI: &baseAPI.BaseAPI{
Now: func() time.Time { return now },
},
queryableCreate: query.NewQueryableCreator(nil, nil, newProxyStoreWithTSDBStore(db), 2, timeout),
engineFactory: ef,
defaultEngine: PromqlEnginePrometheus,
lookbackDeltaCreate: func(m int64) time.Duration { return time.Duration(0) },
gate: gate.New(nil, 4, gate.Queries),
defaultRangeQueryStep: time.Second,
queryRangeHist: promauto.With(prometheus.NewRegistry()).NewHistogram(prometheus.HistogramOpts{
Name: "query_range_hist",
}),
seriesStatsAggregatorFactory: &store.NoopSeriesStatsAggregatorFactory{},
tenantHeader: "thanos-tenant",
defaultTenant: "default-tenant",
}
start := time.Unix(0, 0)

var tests = []endpointTestCase{
{
endpoint: api.query,
query: url.Values{
"query": []string{"2"},
"time": []string{"123.4"},
"engine": []string{"thanos"},
},
response: &queryData{
ResultType: parser.ValueTypeScalar,
Result: promql.Scalar{
V: 2,
T: timestamp.FromTime(start.Add(123*time.Second + 400*time.Millisecond)),
},
QueryAnalysis: queryTelemetry{},
},
},
{
endpoint: api.queryRange,
query: url.Values{
"query": []string{"time()"},
"start": []string{"0"},
"end": []string{"500"},
"step": []string{"1"},
},
response: &queryData{
ResultType: parser.ValueTypeMatrix,
Result: promql.Matrix{
promql.Series{
Floats: func(end, step float64) []promql.FPoint {
var res []promql.FPoint
for v := float64(0); v <= end; v += step {
res = append(res, promql.FPoint{F: v, T: timestamp.FromTime(start.Add(time.Duration(v) * time.Second))})
}
return res
}(500, 1),
Metric: nil,
},
},
QueryAnalysis: queryTelemetry{},
},
},
}
for i, test := range tests {
if ok := testEndpoint(t, test, fmt.Sprintf("#%d %s", i, test.query.Encode()), reflect.DeepEqual); !ok {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a third argument to responeCompareFunction testing.T and then use that to perform validation on queryTelemetry - check that Execution field is not zero.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I need to pass the argument in reflect.deepequal.go as well then ?

return
}
}
}

func newProxyStoreWithTSDBStore(db store.TSDBReader) *store.ProxyStore {
c := &storetestutil.TestClient{
Name: "1",
Expand Down
2 changes: 2 additions & 0 deletions pkg/promclient/promclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ type QueryOptions struct {
MaxSourceResolution string
Engine string
Explain bool
Analyze bool
}

func (p *QueryOptions) AddTo(values url.Values) error {
Expand All @@ -372,6 +373,7 @@ func (p *QueryOptions) AddTo(values url.Values) error {
}

values.Add("explain", fmt.Sprintf("%v", p.Explain))
values.Add("analyze", fmt.Sprintf("%v", p.Analyze))
values.Add("engine", p.Engine)

var partialResponseValue string
Expand Down
4 changes: 2 additions & 2 deletions pkg/queryfrontend/queryinstant_codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func (c queryInstantCodec) DecodeRequest(_ context.Context, r *http.Request, for

result.Query = r.FormValue("query")
result.Path = r.URL.Path
result.Explain = r.FormValue(queryv1.QueryExplainParam)
result.Analyze = r.FormValue("analyze")
result.Engine = r.FormValue("engine")

for _, header := range forwardHeaders {
Expand All @@ -176,7 +176,7 @@ func (c queryInstantCodec) EncodeRequest(ctx context.Context, r queryrange.Reque
"query": []string{thanosReq.Query},
queryv1.DedupParam: []string{strconv.FormatBool(thanosReq.Dedup)},
queryv1.PartialResponseParam: []string{strconv.FormatBool(thanosReq.PartialResponse)},
queryv1.QueryExplainParam: []string{thanosReq.Explain},
queryv1.QueryAnalyzeParam: []string{thanosReq.Analyze},
queryv1.EngineParam: []string{thanosReq.Engine},
queryv1.ReplicaLabelsParam: thanosReq.ReplicaLabels,
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/queryfrontend/queryrange_codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func (c queryRangeCodec) DecodeRequest(_ context.Context, r *http.Request, forwa
}

result.Query = r.FormValue("query")
result.Explain = r.FormValue(queryv1.QueryExplainParam)
result.Analyze = r.FormValue(queryv1.QueryAnalyzeParam)
result.Engine = r.FormValue(queryv1.EngineParam)
result.Path = r.URL.Path

Expand Down Expand Up @@ -161,7 +161,7 @@ func (c queryRangeCodec) EncodeRequest(ctx context.Context, r queryrange.Request
"end": []string{encodeTime(thanosReq.End)},
"step": []string{encodeDurationMillis(thanosReq.Step)},
"query": []string{thanosReq.Query},
queryv1.QueryExplainParam: []string{thanosReq.Explain},
queryv1.QueryAnalyzeParam: []string{thanosReq.Analyze},
queryv1.EngineParam: []string{thanosReq.Engine},
queryv1.DedupParam: []string{strconv.FormatBool(thanosReq.Dedup)},
queryv1.PartialResponseParam: []string{strconv.FormatBool(thanosReq.PartialResponse)},
Expand Down
4 changes: 2 additions & 2 deletions pkg/queryfrontend/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ type ThanosQueryRangeRequest struct {
Stats string
ShardInfo *storepb.ShardInfo
LookbackDelta int64
Explain string
Analyze string
Engine string
}

Expand Down Expand Up @@ -156,7 +156,7 @@ type ThanosQueryInstantRequest struct {
Stats string
ShardInfo *storepb.ShardInfo
LookbackDelta int64 // in milliseconds.
Explain string
Analyze string
Engine string
}

Expand Down
116 changes: 58 additions & 58 deletions pkg/ui/bindata.go

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions pkg/ui/react-app/src/components/ListTree.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import React, { useState } from 'react';
import { InputProps, Collapse, ListGroupItem, ListGroup } from 'reactstrap';
import { ExplainTree } from '../pages/graph/ExpressionInput';

export interface QueryTree {
name: string;
executionTime?: string;
children?: QueryTree[];
}

interface NodeProps extends InputProps {
node: QueryTree | null;
node: QueryTree | ExplainTree | null;
}

const ListTree: React.FC<NodeProps> = ({ id, node }) => {
Expand Down Expand Up @@ -41,7 +43,7 @@ const ListTree: React.FC<NodeProps> = ({ id, node }) => {
</div>
)}
<div id={id} style={{ cursor: `${node.children ? 'pointer' : 'inherit'}` }} onClick={toggle}>
{node.name}
{node.name} · {node.executionTime}
</div>
</div>
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/ui/react-app/src/pages/graph/ExpressionInput.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ describe('ExpressionInput', () => {
enableAutocomplete: true,
enableHighlighting: true,
enableLinter: true,
executeExplain: (): void => {
// Do nothing.
},
disableExplain: false,
};

let expressionInput: ReactWrapper;
Expand Down
12 changes: 11 additions & 1 deletion pkg/ui/react-app/src/pages/graph/ExpressionInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,16 @@ interface CMExpressionInputProps {
enableAutocomplete: boolean;
enableHighlighting: boolean;
enableLinter: boolean;
executeExplain: () => void;
disableExplain: boolean;
}

const dynamicConfigCompartment = new Compartment();

export interface ExplainTree {
name: string;
children?: ExplainTree[];
}
// Autocompletion strategy that wraps the main one and enriches
// it with past query items.
export class HistoryCompleteStrategy implements CompleteStrategy {
Expand Down Expand Up @@ -88,11 +94,12 @@ const ExpressionInput: FC<PathPrefixProps & CMExpressionInputProps> = ({
enableAutocomplete,
enableHighlighting,
enableLinter,
executeExplain,
disableExplain,
}) => {
const containerRef = useRef<HTMLDivElement>(null);
const viewRef = useRef<EditorView | null>(null);
const { theme } = useTheme();

// (Re)initialize editor based on settings / setting changes.
useEffect(() => {
// Build the dynamic part of the config.
Expand Down Expand Up @@ -205,6 +212,9 @@ const ExpressionInput: FC<PathPrefixProps & CMExpressionInputProps> = ({
Execute
</Button>
</InputGroupAddon>
<Button className="ml-2" color="info" onClick={executeExplain} disabled={disableExplain}>
Explain
</Button>
</InputGroup>
</>
);
Expand Down
8 changes: 4 additions & 4 deletions pkg/ui/react-app/src/pages/graph/Panel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ const defaultProps: PanelProps = {
usePartialResponse: false,
storeMatches: [],
engine: 'prometheus',
explain: false,
disableExplainCheckbox: false,
analyze: false,
disableAnalyzeCheckbox: false,
},
onOptionsChanged: (): void => {
// Do nothing.
Expand Down Expand Up @@ -97,8 +97,8 @@ describe('Panel', () => {
usePartialResponse: false,
storeMatches: [],
engine: 'prometheus',
explain: false,
disableExplainCheckbox: false,
analyze: false,
disableAnalyzeCheckbox: false,
};
const graphPanel = mount(<Panel {...defaultProps} options={options} />);
const controls = graphPanel.find(GraphControls);
Expand Down
Loading