Skip to content

Commit c33abc5

Browse files
committed
feat: add datasource pre-filter
1 parent d1347d1 commit c33abc5

12 files changed

Lines changed: 66 additions & 5 deletions

File tree

CONTRIBUTING.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ $ go test -v ./pkg/...
6161
$ npm run storybook
6262
```
6363

64+
## Reset grafana password
65+
66+
```shell
67+
docker exec -it grafana-quickwit-datasource bash
68+
grafana-cli admin reset-admin-password <new_password>
69+
```
70+
6471
## Release
6572

6673
TODO

build_and_start.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
npm install
44
npm run build
55
~/go/bin/mage -v
6-
#docker compose up --build --force-recreate
6+
docker compose up --build --force-recreate

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/configuration/ConfigEditor.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ describe('ConfigEditor', () => {
2626

2727
// Check ElasticDetails are rendered
2828
expect(screen.getByText('Index settings')).toBeInTheDocument();
29+
expect(screen.getByLabelText('Forced query filter')).toBeInTheDocument();
2930
});
3031

3132
it('should not apply default if values are set', () => {

src/configuration/ConfigEditor.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,21 @@ export const QuickwitDetails = ({ value, onChange }: DetailsProps) => {
109109
width={40}
110110
/>
111111
</InlineField>
112+
<InlineField
113+
label="Forced query filter"
114+
labelWidth={26}
115+
tooltip="Lucene filter added to every query. Combined with AND when query is not empty."
116+
>
117+
<Input
118+
id="quickwit_forced_query_filter"
119+
value={value.jsonData.forcedQueryFilter}
120+
onChange={(event) =>
121+
onChange({ ...value, jsonData: { ...value.jsonData, forcedQueryFilter: event.currentTarget.value } })
122+
}
123+
placeholder="service:frontend"
124+
width={40}
125+
/>
126+
</InlineField>
112127
</FieldSet>
113128
<FieldSet label="Editor settings">
114129
<InlineField label="Default logs limit" labelWidth={26} tooltip="The log level field must be a fast field">

src/configuration/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export const coerceOptions = (
1414
...options.jsonData,
1515
logMessageField: options.jsonData.logMessageField || '',
1616
logLevelField: options.jsonData.logLevelField || '',
17+
forcedQueryFilter: options.jsonData.forcedQueryFilter || '',
1718
filterAutocompleteLimit: options.jsonData.filterAutocompleteLimit ?? '1000',
1819
filterAutocompleteChainMode,
1920
filterAutocompleteUseFilterChains: filterAutocompleteChainMode !== 'none',

0 commit comments

Comments
 (0)