Skip to content

Commit c6a6d09

Browse files
committed
feat/filter-datasource: implement backend part
1 parent 9112444 commit c6a6d09

7 files changed

Lines changed: 41 additions & 81 deletions

File tree

pkg/quickwit/client/client.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type DatasourceInfo struct {
2424
ID int64
2525
UID string
2626
Name string
27+
ForcedQueryFilter string
2728
LogsDatasourceUID string
2829
LogsDatasourceName string
2930
TracesDatasourceUID string

pkg/quickwit/data_query.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const (
1414
defaultSize = 100
1515
)
1616

17-
func buildMSR(queries []*Query, defaultTimeField string) ([]*es.SearchRequest, error) {
17+
func buildMSR(queries []*Query, defaultTimeField string, forcedQueryFilter string) ([]*es.SearchRequest, error) {
1818
ms := es.NewMultiSearchRequestBuilder()
1919

2020
for _, q := range queries {
@@ -31,7 +31,7 @@ func buildMSR(queries []*Query, defaultTimeField string) ([]*es.SearchRequest, e
3131
// trace_id lookups go from "scan every split" to "scan a few" — the
3232
// same speedup the native Jaeger endpoint gets via auto-derived bounds.
3333
filters.AddDateRangeFilter(defaultTimeField, q.RangeTo, q.RangeFrom)
34-
filters.AddQueryStringFilter(q.RawQuery, true, "AND")
34+
filters.AddQueryStringFilter(applyForcedQueryFilter(q.RawQuery, forcedQueryFilter), true, "AND")
3535
if isTraceSearchQuery(q) {
3636
filters.AddQueryStringFilter(traceSearchSettingsQuery(q), true, "AND")
3737
}
@@ -53,6 +53,20 @@ func buildMSR(queries []*Query, defaultTimeField string) ([]*es.SearchRequest, e
5353
return ms.Build()
5454
}
5555

56+
func applyForcedQueryFilter(rawQuery string, forcedQueryFilter string) string {
57+
query := strings.TrimSpace(rawQuery)
58+
forced := strings.TrimSpace(forcedQueryFilter)
59+
60+
if forced == "" {
61+
return query
62+
}
63+
if query == "" {
64+
return forced
65+
}
66+
67+
return query + " AND " + forced
68+
}
69+
5670
func setFloatPath(settings *simplejson.Json, path ...string) {
5771
if stringValue, err := settings.GetPath(path...).String(); err == nil {
5872
if value, err := strconv.ParseFloat(stringValue, 64); err == nil {

pkg/quickwit/data_query_test.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,20 @@ func TestQueryTypeHelpersDoNotPanicWithoutMetrics(t *testing.T) {
2424
})
2525
}
2626

27+
func TestApplyForcedQueryFilter(t *testing.T) {
28+
t.Run("adds AND when query is not empty", func(t *testing.T) {
29+
assert.Equal(t, "service:api AND tenant:acme", applyForcedQueryFilter("service:api", "tenant:acme"))
30+
})
31+
32+
t.Run("uses only forced filter when query is empty", func(t *testing.T) {
33+
assert.Equal(t, "tenant:acme", applyForcedQueryFilter("", "tenant:acme"))
34+
})
35+
36+
t.Run("keeps original query when forced filter is empty", func(t *testing.T) {
37+
assert.Equal(t, "service:api", applyForcedQueryFilter("service:api", ""))
38+
})
39+
}
40+
2741
func TestExecuteElasticsearchDataQuery(t *testing.T) {
2842
from := time.Date(2018, 5, 15, 17, 50, 0, 0, time.UTC)
2943
to := time.Date(2018, 5, 15, 17, 55, 0, 0, time.UTC)
@@ -1801,7 +1815,7 @@ func executeElasticsearchDataQuery(c es.Client, body string, from, to time.Time)
18011815
if err != nil {
18021816
return nil, err
18031817
}
1804-
req, err := buildMSR(queries, configuredFields.TimeField)
1818+
req, err := buildMSR(queries, configuredFields.TimeField, "")
18051819
if err != nil {
18061820
return &backend.QueryDataResponse{}, err
18071821
}

pkg/quickwit/elasticsearch.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func queryData(ctx context.Context, dataQueries []backend.DataQuery, dsInfo *es.
2525

2626
// Create a request
2727
// NODE : Params should probably be assembled in a dedicated structure to be reused by parseResponse
28-
req, err := buildMSR(queries, dsInfo.ConfiguredFields.TimeField)
28+
req, err := buildMSR(queries, dsInfo.ConfiguredFields.TimeField, dsInfo.ForcedQueryFilter)
2929
if err != nil {
3030
return &backend.QueryDataResponse{}, err
3131
}

pkg/quickwit/quickwit.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ func NewQuickwitDatasource(ctx context.Context, settings backend.DataSourceInsta
6767
logMessageField = ""
6868
}
6969

70+
forcedQueryFilter, ok := jsonData["forcedQueryFilter"].(string)
71+
if !ok {
72+
forcedQueryFilter = ""
73+
}
74+
7075
logsDatasourceUID, ok := jsonData["logsDatasourceUid"].(string)
7176
if !ok {
7277
logsDatasourceUID = ""
@@ -121,6 +126,7 @@ func NewQuickwitDatasource(ctx context.Context, settings backend.DataSourceInsta
121126
ID: settings.ID,
122127
UID: settings.UID,
123128
Name: settings.Name,
129+
ForcedQueryFilter: forcedQueryFilter,
124130
LogsDatasourceUID: logsDatasourceUID,
125131
LogsDatasourceName: logsDatasourceName,
126132
TracesDatasourceUID: tracesDatasourceUID,

src/datasource/base.test.ts

Lines changed: 0 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -706,72 +706,4 @@ describe('BaseQuickwitDataSource', () => {
706706
});
707707
});
708708

709-
describe('forced query filter', () => {
710-
const datasourceContext = (overrides: Record<string, unknown>) =>
711-
Object.assign(Object.create(BaseQuickwitDataSource.prototype), overrides);
712-
713-
const applyTemplateVariables = (
714-
query: ElasticsearchQuery,
715-
overrides: Record<string, unknown> = {},
716-
filters?: AdHocVariableFilter[]
717-
) => {
718-
const context = datasourceContext({
719-
fieldTypes: {},
720-
forcedQueryFilter: '',
721-
getRef: () => ({ type: 'quickwit-quickwit-datasource', uid: 'test' }),
722-
templateSrv: {
723-
replace: (value: string) => value,
724-
},
725-
...overrides,
726-
});
727-
728-
return (BaseQuickwitDataSource.prototype as any).applyTemplateVariables.call(context, query, {}, filters);
729-
};
730-
731-
it('appends forced filter with AND when query is not empty', () => {
732-
const result = applyTemplateVariables(
733-
{
734-
refId: 'A',
735-
query: 'service:"api"',
736-
metrics: [],
737-
bucketAggs: [],
738-
filters: [],
739-
} as ElasticsearchQuery,
740-
{ forcedQueryFilter: 'severity_text:error' }
741-
);
742-
743-
expect(result.query).toBe('service:"api" AND severity_text:error');
744-
});
745-
746-
it('uses only forced filter when query is empty', () => {
747-
const result = applyTemplateVariables(
748-
{
749-
refId: 'A',
750-
query: '',
751-
metrics: [],
752-
bucketAggs: [],
753-
filters: [],
754-
} as ElasticsearchQuery,
755-
{ forcedQueryFilter: 'severity_text:error' }
756-
);
757-
758-
expect(result.query).toBe('severity_text:error');
759-
});
760-
761-
it('still applies forced filter for single trace lookups', () => {
762-
const result = applyTemplateVariables(
763-
{
764-
refId: 'A',
765-
query: 'trace_id:abc123',
766-
metrics: [{ id: '1', type: 'traces', settings: { limit: '1000' } }] as any,
767-
bucketAggs: [],
768-
filters: [],
769-
} as ElasticsearchQuery,
770-
{ forcedQueryFilter: 'tenant:acme' },
771-
[{ key: 'service', operator: '=', value: 'frontend' }]
772-
);
773-
774-
expect(result.query).toBe('trace_id:abc123 AND tenant:acme');
775-
});
776-
});
777709
});

src/datasource/base.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import { fieldTypeMap, hasWhiteSpace, isSimpleToken } from 'utils';
3333
import { addAddHocFilter } from 'modifyQuery';
3434
import { getQueryResponseProcessor } from 'datasource/processResponse';
3535
import { normalizeInternalLinkQuery } from '@/queryModel';
36-
import { concatenate } from '@/utils/lucene';
3736

3837
import { SECOND } from 'utils/time';
3938
import { GConstructor } from 'utils/mixins';
@@ -92,7 +91,6 @@ export class BaseQuickwitDataSource
9291
timeField: string;
9392
logMessageField?: string;
9493
logLevelField?: string;
95-
forcedQueryFilter?: string;
9694
logsDatasourceUid?: string;
9795
logsDatasourceName?: string;
9896
tracesDatasourceUid?: string;
@@ -122,7 +120,6 @@ export class BaseQuickwitDataSource
122120
this.timeField = '';
123121
this.logMessageField = settingsData.logMessageField || '';
124122
this.logLevelField = settingsData.logLevelField || '';
125-
this.forcedQueryFilter = settingsData.forcedQueryFilter || '';
126123
this.logsDatasourceUid = settingsData.logsDatasourceUid || '';
127124
this.logsDatasourceName = settingsData.logsDatasourceName || '';
128125
this.tracesDatasourceUid = settingsData.tracesDatasourceUid || '';
@@ -669,7 +666,7 @@ export class BaseQuickwitDataSource
669666
const renderedQuery = (() => {
670667
let q = this.interpolateLuceneQuery(query.query || '', scopedVars);
671668
if (isSingleTraceLookup) {
672-
return this.addForcedQueryFilter(q);
669+
return q;
673670
}
674671
const queryFilters = query.filters
675672
?.filter((f) => {
@@ -685,7 +682,7 @@ export class BaseQuickwitDataSource
685682
.map((f) => f.filter);
686683
q = this.addAdHocFilters(q, queryFilters);
687684
q = this.addAdHocFilters(q, filters);
688-
return this.addForcedQueryFilter(q);
685+
return q;
689686
})();
690687

691688
const expandedQuery = {
@@ -699,10 +696,6 @@ export class BaseQuickwitDataSource
699696
return normalizeInternalLinkQuery(finalQuery);
700697
}
701698

702-
private addForcedQueryFilter(query: string) {
703-
return concatenate(query, this.forcedQueryFilter || '', 'AND');
704-
}
705-
706699
addAdHocFilters(query: string, adhocFilters?: AdHocVariableFilter[]) {
707700
if (!adhocFilters) {
708701
return query;

0 commit comments

Comments
 (0)