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

Add customizable context window for logs #654

Merged
merged 1 commit into from
Nov 4, 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
3 changes: 1 addition & 2 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
"extends": "./.config/.eslintrc",
"rules": {
"array-element-newline": ["error", {
"ArrayExpression": "consistent",
"ArrayPattern": { "minItems": 3 }
}],
"object-curly-newline": ["error", {
"ObjectPattern": { "multiline": true, "minProperties": 3 }
"ObjectPattern": { "multiline": true, "minProperties": 10 }
}]
}
}
14 changes: 6 additions & 8 deletions src/datasource/datasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,29 +159,28 @@ export
const requestOptions = {...options, range: this.options.range}

const originalQuery = this.createQuery(requestOptions, query)

let scanner = new Scanner(originalQuery.stmt.replace(/\r\n|\r|\n/g, ' '));
let { select } = scanner.toAST();

const generateQueryForTraceID = (traceId, select) => {
return `SELECT ${select.join(',')} FROM $table WHERE $timeFilter AND trace_id=${traceId}`
}

const generateQueryForTimestampBackward = (inputTimestampColumn, inputTimestampValue) => {
const generateQueryForTimestampBackward = (inputTimestampColumn, inputTimestampValue, contextWindowSize) => {
return `SELECT timestamp FROM (
SELECT
${inputTimestampColumn},
FIRST_VALUE(${inputTimestampColumn}) OVER (ORDER BY ${inputTimestampColumn} ROWS BETWEEN 10 PRECEDING AND CURRENT ROW) AS timestamp
FIRST_VALUE(${inputTimestampColumn}) OVER (ORDER BY ${inputTimestampColumn} ROWS BETWEEN ${contextWindowSize || 10} PRECEDING AND CURRENT ROW) AS timestamp
FROM $table
ORDER BY ${inputTimestampColumn}
) WHERE ${inputTimestampColumn} = '${inputTimestampValue}'`
}

const generateQueryForTimestampForward = (inputTimestampColumn, inputTimestampValue) => {
const generateQueryForTimestampForward = (inputTimestampColumn, inputTimestampValue, contextWindowSize) => {
return `SELECT timestamp FROM (
SELECT
${inputTimestampColumn},
LAST_VALUE(${inputTimestampColumn}) OVER (ORDER BY ${inputTimestampColumn} ROWS BETWEEN CURRENT ROW AND 10 FOLLOWING) AS timestamp
LAST_VALUE(${inputTimestampColumn}) OVER (ORDER BY ${inputTimestampColumn} ROWS BETWEEN CURRENT ROW AND ${contextWindowSize || 10} FOLLOWING) AS timestamp
FROM $table
ORDER BY ${inputTimestampColumn}
) WHERE ${inputTimestampColumn} = '${inputTimestampValue}'`
Expand Down Expand Up @@ -219,11 +218,10 @@ export
const timestampColumn = query?.dateTimeColDataType

const getLogsTimeBoundaries = async () => {

const boundariesRequest =
options?.direction === LogRowContextQueryDirection.Backward ?
generateQueryForTimestampBackward(timestampColumn, row.timeUtc):
generateQueryForTimestampForward(timestampColumn, row.timeUtc)
generateQueryForTimestampBackward(timestampColumn, row.timeUtc, query?.contextWindowSize):
generateQueryForTimestampForward(timestampColumn, row.timeUtc, query?.contextWindowSize)

const {
stmt,
Expand Down
1 change: 1 addition & 0 deletions src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export interface CHQuery extends DataQuery {
intervalFactor?: number;
interval?: string;
formattedQuery?: string;
contextWindowSize?: number;
}

/**
Expand Down
11 changes: 3 additions & 8 deletions src/views/QueryEditor/QueryEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,7 @@ import { initializeQueryDefaults } from './helpers/initializeQueryDefaults';
import './QueryEditor.css';

export function QueryEditor(props: QueryEditorProps<CHDataSource, CHQuery, CHDataSourceOptions>) {
const {
datasource,
query,
onChange,
onRunQuery
} = props;
const { datasource, query, onChange, onRunQuery } = props;

const isAnnotationView = !props.app;
const initializedQuery = initializeQueryDefaults(query, isAnnotationView, datasource, onChange);
Expand All @@ -26,12 +21,12 @@ export function QueryEditor(props: QueryEditorProps<CHDataSource, CHQuery, CHDat
useQueryState(query, onChange, datasource);

const onSqlChange = (sql: string) => onChange({ ...initializedQuery, query: sql });
const onFieldChange = (field: any) => onChange({ ...initializedQuery, [field.fieldName]: field.value })
const onFieldChange = (field: any) => onChange({ ...initializedQuery, [field.fieldName]: field.value });
const onTriggerQuery = () => onRunQuery();

// @ts-ignore
const adHocFilters = datasource.templateSrv.getAdhocFilters(datasource.name);
const areAdHocFiltersAvailable = !!adHocFilters.length
const areAdHocFiltersAvailable = !!adHocFilters.length;

if (adHocFilters?.length) {
// eslint-disable-next-line
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { InlineField, Select } from '@grafana/ui';
import React, { useState, useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import { SelectableValue } from '@grafana/data';

type UniversalSelectFieldProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ export const QueryTextEditor = ({
onFieldChange({ fieldName: 'format', value: value });
};

const handleContextWindowChange = (value: string | undefined) => {
onFieldChange({ fieldName: 'contextWindowSize', value: value });
};

const handleToggleField = (fieldName: string) => {
onFieldChange({ fieldName: fieldName, value: !query[fieldName] });
};
Expand All @@ -83,24 +87,26 @@ export const QueryTextEditor = ({
onEditorMount={onEditorMount}
onRunQuery={onRunQuery}
/>
{!areAdHocFiltersAvailable && <TagsInput
className={'adhoc-filters-tags'}
tags={adhocFilters.map((filter: any, index: number) => `${filter.key} ${filter.operator} ${filter.value}`)}
onChange={(tagsList) => {
onFieldChange({
fieldName: 'adHocFilters',
value: tagsList.map((item: string) => {
const [
key,
operator,
value
] = item.split(' ');
{!areAdHocFiltersAvailable && (
<TagsInput
className={'adhoc-filters-tags'}
tags={adhocFilters.map((filter: any, index: number) => `${filter.key} ${filter.operator} ${filter.value}`)}
onChange={(tagsList) => {
onFieldChange({
fieldName: 'adHocFilters',
value: tagsList.map((item: string) => {
const [
key,
operator,
value
] = item.split(' ');

return { key, operator, value };
}),
});
}}
/>}
return { key, operator, value };
}),
});
}}
/>
)}
<div className="gf-form" style={{ display: 'flex', flexDirection: 'column', marginTop: '10px' }}>
<InlineFieldRow>
<InlineField
Expand Down Expand Up @@ -149,6 +155,17 @@ export const QueryTextEditor = ({
/>
</InlineField>
)}
{query.format === 'logs' && (
<InlineField label={<InlineLabel width={'auto'}>Context window</InlineLabel>}>
<Select
width={'auto'}
data-testid="context-window-size-select"
onChange={(e) => handleContextWindowChange(e.value)}
options={[10, 20, 50, 100].map((value) => ({ label: value + ' entries', value }))}
value={query.contextWindowSize}
/>
</InlineField>
)}
</InlineFieldRow>
<InlineFieldRow>
<InlineField
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ const MONACO_EDITOR_OPTIONS: any = {
overviewRulerLanes: 0,
};

export const SQLCodeEditor = ({
query, onSqlChange, onRunQuery, datasource
}: any) => {
export const SQLCodeEditor = ({ query, onSqlChange, onRunQuery, datasource }: any) => {
const [initialized, setInitialized] = useState(false);
const [updatedSQLQuery, setUpdatedSQLQuery] = useState(query.query);
const autocompletionData = useAutocompleteData(datasource);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ export const initiateEditor = (
autocompletionData: any,
systemDatabasesData: any
) => {
const {
Method, Variable, Constant, Keyword, TypeParameter, Text
} = monacoInstance.languages.CompletionItemKind;
const { Method, Variable, Constant, Keyword, TypeParameter, Text } = monacoInstance.languages.CompletionItemKind;

let dynamicIdentifier: string[];
let dynamicKeyword: string[];
Expand Down
38 changes: 28 additions & 10 deletions src/views/QueryEditor/helpers/initializeQueryDefaults.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import {CHQuery, EditorMode, TimestampFormat} from "../../../types/types";
import {DEFAULT_FORMAT, DEFAULT_INTERVAL_FACTOR, DEFAULT_ROUND, defaultQuery} from "../constants";
import { CHQuery, EditorMode, TimestampFormat } from '../../../types/types';
import { DEFAULT_FORMAT, DEFAULT_INTERVAL_FACTOR, DEFAULT_ROUND, defaultQuery } from '../constants';

export const initializeQueryDefaults = (query: CHQuery, isAnnotationView: boolean, datasource: any, onChange: any): CHQuery => {
export const initializeQueryDefaults = (
query: CHQuery,
isAnnotationView: boolean,
datasource: any,
onChange: any
): CHQuery => {
const initializedQuery = {
...query,
format: query.format || DEFAULT_FORMAT,
Expand All @@ -15,36 +20,49 @@ export const initializeQueryDefaults = (query: CHQuery, isAnnotationView: boole
adHocFilters: query.adHocFilters || [],
query: query.query || defaultQuery,
formattedQuery: query.formattedQuery || query.query,
editorMode: (query.database && query.table) ? EditorMode.SQL : EditorMode.Builder,
editorMode: query.database && query.table ? EditorMode.SQL : EditorMode.Builder,
contextWindowSize: query.contextWindowSize || 10,
};

if (datasource.defaultValues && !query.initialized) {
if (datasource.defaultValues.defaultDateTimeType && !initializedQuery.dateTimeType) {
initializedQuery.dateTimeType = datasource.defaultValues.defaultDateTimeType;
}

if (datasource.defaultValues.dateTime.defaultDateTime && initializedQuery.dateTimeType === TimestampFormat.DateTime && !initializedQuery.dateTimeColDataType) {
if (
datasource.defaultValues.dateTime.defaultDateTime &&
initializedQuery.dateTimeType === TimestampFormat.DateTime &&
!initializedQuery.dateTimeColDataType
) {
initializedQuery.dateTimeColDataType = datasource.defaultValues.dateTime.defaultDateTime;
}

if (datasource.defaultValues.dateTime.defaultDateTime64 && initializedQuery.dateTimeType === TimestampFormat.DateTime64 && !initializedQuery.dateTimeColDataType) {
if (
datasource.defaultValues.dateTime.defaultDateTime64 &&
initializedQuery.dateTimeType === TimestampFormat.DateTime64 &&
!initializedQuery.dateTimeColDataType
) {
initializedQuery.dateTimeColDataType = datasource.defaultValues.dateTime.defaultDateTime64;
}

if (datasource.defaultValues.dateTime.defaultDateDate32 && !initializedQuery.dateColDataType) {
initializedQuery.dateColDataType = datasource.defaultValues.dateTime.defaultDateDate32;
}

if (datasource.defaultValues.dateTime.defaultUint32 && initializedQuery.dateTimeType === TimestampFormat.TimeStamp && !initializedQuery.dateTimeColDataType) {
if (
datasource.defaultValues.dateTime.defaultUint32 &&
initializedQuery.dateTimeType === TimestampFormat.TimeStamp &&
!initializedQuery.dateTimeColDataType
) {
initializedQuery.dateTimeColDataType = datasource.defaultValues.dateTime.defaultUint32;
}

onChange({ ...query, ...initializedQuery, initialized: true });
}

if (isAnnotationView) {
initializedQuery.format = 'ANNOTATION'
initializedQuery.format = 'ANNOTATION';
}

return initializedQuery
}
return initializedQuery;
};
10 changes: 4 additions & 6 deletions src/views/QueryEditor/hooks/useSystemDatabases.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {useEffect, useState} from "react";
import { useEffect, useState } from 'react';

const GET_DATABASES_QUERY =
'SELECT name FROM system.tables\n' +
Expand Down Expand Up @@ -28,11 +28,11 @@ export const useSystemDatabases = (datasource) => {
try {
const result = await datasource.metricFindQuery(GET_DATABASES_QUERY);
const expiry = now.getTime() + 10 * 60 * 1000;
localStorage.setItem(storageKey, JSON.stringify({ expiry, result: result.map(item => item.text) }));
setData( result.map(item => item.text));
localStorage.setItem(storageKey, JSON.stringify({ expiry, result: result.map((item) => item.text) }));
setData(result.map((item) => item.text));
} catch (error) {
setData([]);
console.error("Failed to fetch data:", error)
console.error('Failed to fetch data:', error);
}
};

Expand All @@ -41,5 +41,3 @@ export const useSystemDatabases = (datasource) => {

return data;
};


Loading