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

Make log limits configurable #115

Merged
merged 1 commit into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 24 additions & 5 deletions src/components/QueryEditor/ElasticsearchQueryContext.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { createContext, PropsWithChildren, useCallback, useEffect, useState } from 'react';
import React, { createContext, PropsWithChildren, useCallback, useEffect, useState, FunctionComponent } from 'react';

import { CoreApp, TimeRange } from '@grafana/data';

Expand All @@ -10,6 +10,9 @@ import { createReducer as createBucketAggsReducer } from './BucketAggregationsEd
import { reducer as metricsReducer } from './MetricAggregationsEditor/state/reducer';
import { aliasPatternReducer, queryReducer, initQuery, initExploreQuery } from './state';
import { getHook } from '@/utils/context';
import { Provider, useDispatch } from "react-redux";
import { initDefaults } from '@/store/defaults';
import { store } from "@/store"

export const RangeContext = createContext<TimeRange | undefined>(undefined);
export const useRange = getHook(RangeContext);
Expand All @@ -29,15 +32,31 @@ interface Props {
range: TimeRange;
}

export const ElasticsearchProvider = ({
function withStore<P extends PropsWithChildren<Props>>(Component: FunctionComponent<P>): FunctionComponent<P>{
const newComp = (props: P) => (
<Provider store={store}>
<Component {...props}/>
</Provider>
)
newComp.displayName = Component.displayName
return newComp
}

export const ElasticsearchProvider = withStore(({
children,
onChange,
onRunQuery,
query,
app,
datasource,
range,
}: PropsWithChildren<Props>) => {
}: PropsWithChildren<Props>): JSX.Element => {

const storeDispatch = useDispatch();
useEffect(()=>{
storeDispatch(initDefaults(datasource.queryEditorConfig?.defaults))
}, [storeDispatch, datasource])

const onStateChange = useCallback(
(query: ElasticsearchQuery) => {
onChange(query);
Expand Down Expand Up @@ -77,7 +96,7 @@ export const ElasticsearchProvider = ({
}, [shouldRunInit, dispatch, isUninitialized, app]);

if (isUninitialized) {
return null;
return (<></>);
}

return (
Expand All @@ -89,4 +108,4 @@ export const ElasticsearchProvider = ({
</QueryContext.Provider>
</DatasourceContext.Provider>
);
};
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Action } from '@reduxjs/toolkit';
import { defaultLogsAgg, defaultMetricAgg } from '@/queryDef';
import { defaultMetricAgg } from '@/queryDef';
import { ElasticsearchQuery, MetricAggregation } from '@/types';
import { removeEmpty } from '@/utils';
import { initExploreQuery, initQuery } from '../../state';
Expand All @@ -17,7 +17,11 @@ import {
toggleMetricVisibility,
} from './actions';

import { store } from "@/store"

export const reducer = (state: ElasticsearchQuery['metrics'], action: Action): ElasticsearchQuery['metrics'] => {
const defaultsMetricAggregation = store.getState().defaults.metricAggregation;

if (addMetric.match(action)) {
return [...state!, defaultMetricAgg(action.payload)];
}
Expand Down Expand Up @@ -55,7 +59,7 @@ export const reducer = (state: ElasticsearchQuery['metrics'], action: Action): E
return {
id: metric.id,
type: action.payload.type,
...metricAggregationConfig[action.payload.type].defaults,
...defaultsMetricAggregation[action.payload.type as keyof typeof defaultsMetricAggregation],
} as MetricAggregation;
});
}
Expand Down Expand Up @@ -164,7 +168,7 @@ export const reducer = (state: ElasticsearchQuery['metrics'], action: Action): E
if (state && state.length > 0) {
return state;
}
return [defaultLogsAgg('3')];
return [{ type: 'logs', id: '3', ...defaultsMetricAggregation.logs }];
}

return state;
Expand Down
1 change: 1 addition & 0 deletions src/components/QueryEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export const ElasticSearchQueryField = ({ value, onChange, onSubmit }: ElasticSe
};

const QueryEditorForm = ({ value, onRunQuery }: Props) => {

const dispatch = useDispatch();
const nextId = useNextId();
const styles = useStyles2(getStyles);
Expand Down
12 changes: 12 additions & 0 deletions src/configuration/ConfigEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { QuickwitOptions } from '../quickwit';
import { coerceOptions } from './utils';
import { Divider } from '../components/Divider';
import { DataLinks } from './DataLinks';
import _ from 'lodash';

interface Props extends DataSourcePluginOptionsEditorProps<QuickwitOptions> {}

Expand Down Expand Up @@ -92,6 +93,17 @@ export const QuickwitDetails = ({ value, onChange }: DetailsProps) => {
/>
</InlineField>
</FieldSet>
<FieldSet label="Editor settings">
<InlineField label="Default logs limit" labelWidth={26} tooltip="The log level field must be a fast field">
<Input
id="quickwit_defaults_metricaggregation_logs_limit"
value={value.jsonData.queryEditorConfig?.defaults?.['metricAggregation.logs.settings.limit']}
onChange={(event) => onChange(_.merge(value, {jsonData:{queryEditorConfig:{defaults:{'metricAggregation.logs.settings.limit':event.currentTarget.value}}}}))}
placeholder="100"
width={40}
/>
</InlineField>
</FieldSet>
</div>
</>
);
Expand Down
5 changes: 5 additions & 0 deletions src/datasource/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { SECOND } from 'utils/time';
import { GConstructor } from 'utils/mixins';
import { LuceneQuery } from '@/utils/lucene';
import { uidMaker } from "@/utils/uid"
import { DefaultsConfigOverrides } from 'store/defaults/conf';

export type BaseQuickwitDataSourceConstructor = GConstructor<BaseQuickwitDataSource>

Expand All @@ -59,6 +60,9 @@ export class BaseQuickwitDataSource
logMessageField?: string;
logLevelField?: string;
dataLinks: DataLinkConfig[];
queryEditorConfig?: {
defaults?: DefaultsConfigOverrides
};
languageProvider: ElasticsearchLanguageProvider;


Expand All @@ -73,6 +77,7 @@ export class BaseQuickwitDataSource
this.logMessageField = settingsData.logMessageField || '';
this.logLevelField = settingsData.logLevelField || '';
this.dataLinks = settingsData.dataLinks || [];
this.queryEditorConfig = settingsData.queryEditorConfig || {};
this.languageProvider = new ElasticsearchLanguageProvider(this);
this.annotations = {};
}
Expand Down
4 changes: 0 additions & 4 deletions src/queryDef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ export function defaultMetricAgg(id = '1'): MetricAggregation {
return { type: 'count', id };
}

export function defaultLogsAgg(id = '1'): MetricAggregation {
return { type: 'logs', id, ...metricAggregationConfig['logs'].defaults };
}

export function defaultBucketAgg(id = '1'): DateHistogram {
return { type: 'date_histogram', id, settings: { interval: 'auto' } };
}
Expand Down
4 changes: 4 additions & 0 deletions src/quickwit.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { DataSourceJsonData } from "@grafana/data";
import { DataLinkConfig } from "./types";
import { DefaultsConfigOverrides } from "store/defaults/conf";

export interface QuickwitOptions extends DataSourceJsonData {
timeField: string;
Expand All @@ -8,4 +9,7 @@ export interface QuickwitOptions extends DataSourceJsonData {
logLevelField?: string;
dataLinks?: DataLinkConfig[];
index: string;
queryEditorConfig?: {
defaults?: DefaultsConfigOverrides
}
}
40 changes: 40 additions & 0 deletions src/store/defaults/conf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {
MetricAggregation,
MetricAggregationType,
Logs as SchemaLogs,
} from '@/dataquery.gen';
import { Logs, LogsSortDirection } from "@/types";

export type QuickwitMetricAggregationType = Extract<'count' | 'avg' | 'sum' | 'min' | 'max' | 'percentiles' | 'raw_data' | 'logs', MetricAggregationType >

export type MetricsDefaultSettings = Partial<{
[T in QuickwitMetricAggregationType]: Omit<Extract<Exclude<MetricAggregation,SchemaLogs>|Logs, { type: T }>, 'id' | 'type'>;
}>;


export const defaultMetricAggregationConfig: MetricsDefaultSettings = {
percentiles: {
settings: {
percents: ['25', '50', '75', '95', '99'],
},
},
raw_data: {
settings: {
size: '100',
},
},
logs: {
settings: {
limit: '100',
sortDirection:'desc' as LogsSortDirection
},
},
};

export const defaultConfig = {
metricAggregation: defaultMetricAggregationConfig
};

export type DefaultsConfig = typeof defaultConfig

export type DefaultsConfigOverrides = {[key: string]: any};
33 changes: 33 additions & 0 deletions src/store/defaults/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { defaultConfig , DefaultsConfigOverrides } from "./conf";
import _ from "lodash";

export const initialState = defaultConfig

const defaultsSlice = createSlice({
name: "defaults",
initialState: defaultConfig,
reducers: {
initDefaults(_s, action: PayloadAction<DefaultsConfigOverrides | undefined>) {
// Initialize from default state, dont keep the old one
let newState = _.cloneDeep(defaultConfig);
// override values with payload
if (action.payload) {
const overrides = action.payload;
for (const key in overrides) {
// XXX : this is very not type-safe. Can do better ?
const value = overrides[key];
newState = _.set(newState, key, value);
}
}
return newState
}
}
})

const {actions, reducer} = defaultsSlice
export const {
initDefaults,
} = actions

export default reducer;
13 changes: 13 additions & 0 deletions src/store/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { configureStore } from "@reduxjs/toolkit";
import defaultsReducer from "./defaults"

export const store = configureStore({
reducer: {
defaults: defaultsReducer,
}
})

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
Loading