mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki/Explore: Add query type selector (#28817)
* Create query type switcher * Add and update tests * Add handling in datasource * Refactor * Update tests, when checking higlighting, suppy logs * Remove both option as redundant * Add tooltip, remove old comments * Remove unused importts * Remove console.log, update width * Update public/app/plugins/datasource/loki/components/LokiExploreExtraField.tsx Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com> * Update tests * Prettier fixes * Fix test Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com> Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com>
This commit is contained in:
parent
9ba8114bd4
commit
4c103663fb
@ -1,32 +1,35 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { LokiExploreExtraField, LokiExploreExtraFieldProps } from './LokiExploreExtraField';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { LokiExploreExtraFieldProps, LokiExploreExtraField } from './LokiExploreExtraField';
|
||||
|
||||
const setup = (propOverrides?: LokiExploreExtraFieldProps) => {
|
||||
const label = 'Loki Explore Extra Field';
|
||||
const value = '123';
|
||||
const type = 'number';
|
||||
const min = 0;
|
||||
const onChangeFunc = jest.fn();
|
||||
const queryType = 'range';
|
||||
const lineLimitValue = '1';
|
||||
const onLineLimitChange = jest.fn();
|
||||
const onQueryTypeChange = jest.fn();
|
||||
const onKeyDownFunc = jest.fn();
|
||||
|
||||
const props: any = {
|
||||
label,
|
||||
value,
|
||||
type,
|
||||
min,
|
||||
onChangeFunc,
|
||||
queryType,
|
||||
lineLimitValue,
|
||||
onLineLimitChange,
|
||||
onQueryTypeChange,
|
||||
onKeyDownFunc,
|
||||
};
|
||||
|
||||
Object.assign(props, propOverrides);
|
||||
|
||||
return shallow(<LokiExploreExtraField {...props} />);
|
||||
return render(<LokiExploreExtraField {...props} />);
|
||||
};
|
||||
|
||||
describe('LokiExploreExtraField', () => {
|
||||
it('should render component', () => {
|
||||
const wrapper = setup();
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
it('should render step field', () => {
|
||||
setup();
|
||||
expect(screen.getByTestId('lineLimitField')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render query type field', () => {
|
||||
setup();
|
||||
expect(screen.getByTestId('queryTypeField')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
@ -1,33 +1,68 @@
|
||||
// Libraries
|
||||
import React, { memo } from 'react';
|
||||
import { css, cx } from 'emotion';
|
||||
|
||||
// Types
|
||||
import { InlineFormLabel } from '@grafana/ui';
|
||||
import { InlineFormLabel, RadioButtonGroup } from '@grafana/ui';
|
||||
|
||||
export interface LokiExploreExtraFieldProps {
|
||||
label: string;
|
||||
onChangeFunc: (e: React.SyntheticEvent<HTMLInputElement>) => void;
|
||||
lineLimitValue: string;
|
||||
queryType: string;
|
||||
onLineLimitChange: (e: React.SyntheticEvent<HTMLInputElement>) => void;
|
||||
onKeyDownFunc: (e: React.KeyboardEvent<HTMLInputElement>) => void;
|
||||
value: string;
|
||||
type?: string;
|
||||
min?: number;
|
||||
onQueryTypeChange: (value: string) => void;
|
||||
}
|
||||
|
||||
export function LokiExploreExtraField(props: LokiExploreExtraFieldProps) {
|
||||
const { label, onChangeFunc, onKeyDownFunc, value, type, min } = props;
|
||||
const { onLineLimitChange, onKeyDownFunc, lineLimitValue, queryType, onQueryTypeChange } = props;
|
||||
|
||||
const rangeOptions = [
|
||||
{ value: 'range', label: 'Range' },
|
||||
{ value: 'instant', label: 'Instant' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<InlineFormLabel width={5}>{label}</InlineFormLabel>
|
||||
<div aria-label="Loki extra field" className="gf-form-inline">
|
||||
{/*Query type field*/}
|
||||
<div
|
||||
data-testid="queryTypeField"
|
||||
className={cx(
|
||||
'gf-form explore-input-margin',
|
||||
css`
|
||||
flex-wrap: nowrap;
|
||||
`
|
||||
)}
|
||||
aria-label="Query type field"
|
||||
>
|
||||
<InlineFormLabel
|
||||
tooltip="Choose the type of query you would like to run. An instant query queries against a single point in time. A range query queries over a range of time."
|
||||
width="auto"
|
||||
>
|
||||
Query type
|
||||
</InlineFormLabel>
|
||||
|
||||
<RadioButtonGroup options={rangeOptions} value={queryType} onChange={onQueryTypeChange} />
|
||||
</div>
|
||||
{/*Line limit field*/}
|
||||
<div
|
||||
data-testid="lineLimitField"
|
||||
className={cx(
|
||||
'gf-form',
|
||||
css`
|
||||
flex-wrap: nowrap;
|
||||
`
|
||||
)}
|
||||
aria-label="Line limit field"
|
||||
>
|
||||
<InlineFormLabel width={5}>Line limit</InlineFormLabel>
|
||||
<input
|
||||
type={type}
|
||||
type="number"
|
||||
className="gf-form-input width-4"
|
||||
placeholder={'auto'}
|
||||
onChange={onChangeFunc}
|
||||
min={0}
|
||||
onChange={onLineLimitChange}
|
||||
onKeyDown={onKeyDownFunc}
|
||||
min={min}
|
||||
value={value}
|
||||
value={lineLimitValue}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -20,6 +20,17 @@ export function LokiExploreQueryEditor(props: Props) {
|
||||
onChange(nextQuery);
|
||||
}
|
||||
|
||||
function onQueryTypeChange(value: string) {
|
||||
const { query, onChange } = props;
|
||||
let nextQuery;
|
||||
if (value === 'instant') {
|
||||
nextQuery = { ...query, instant: true, range: false };
|
||||
} else {
|
||||
nextQuery = { ...query, instant: false, range: true };
|
||||
}
|
||||
onChange(nextQuery);
|
||||
}
|
||||
|
||||
function preprocessMaxLines(value: string): number {
|
||||
if (value.length === 0) {
|
||||
// empty input - falls back to dataSource.maxLines limit
|
||||
@ -58,12 +69,11 @@ export function LokiExploreQueryEditor(props: Props) {
|
||||
range={range}
|
||||
ExtraFieldElement={
|
||||
<LokiExploreExtraField
|
||||
label={'Line limit'}
|
||||
onChangeFunc={onMaxLinesChange}
|
||||
queryType={query.instant ? 'instant' : 'range'}
|
||||
lineLimitValue={query?.maxLines?.toString() || ''}
|
||||
onQueryTypeChange={onQueryTypeChange}
|
||||
onLineLimitChange={onMaxLinesChange}
|
||||
onKeyDownFunc={onReturnKeyDown}
|
||||
value={query?.maxLines?.toString() || ''}
|
||||
type={'number'}
|
||||
min={0}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
@ -150,7 +150,7 @@ export class LokiQueryFieldForm extends React.PureComponent<LokiQueryFieldFormPr
|
||||
return (
|
||||
<>
|
||||
<div className="gf-form-inline gf-form-inline--xs-view-flex-column flex-grow-1">
|
||||
<div className="gf-form flex-shrink-0">
|
||||
<div className="gf-form flex-shrink-0 min-width-5">
|
||||
<ButtonCascader
|
||||
options={logLabelOptions || []}
|
||||
disabled={buttonDisabled}
|
||||
@ -161,7 +161,7 @@ export class LokiQueryFieldForm extends React.PureComponent<LokiQueryFieldFormPr
|
||||
{chooserText}
|
||||
</ButtonCascader>
|
||||
</div>
|
||||
<div className="gf-form gf-form--grow flex-shrink-1 min-width-15 explore-input-margin">
|
||||
<div className="gf-form gf-form--grow flex-shrink-1 min-width-15">
|
||||
<QueryField
|
||||
additionalPlugins={this.plugins}
|
||||
cleanText={cleanText}
|
||||
@ -176,8 +176,8 @@ export class LokiQueryFieldForm extends React.PureComponent<LokiQueryFieldFormPr
|
||||
syntaxLoaded={syntaxLoaded}
|
||||
/>
|
||||
</div>
|
||||
{ExtraFieldElement}
|
||||
</div>
|
||||
{ExtraFieldElement}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`LokiExploreExtraField should render component 1`] = `
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
width={5}
|
||||
>
|
||||
Loki Explore Extra Field
|
||||
</Component>
|
||||
<input
|
||||
className="gf-form-input width-4"
|
||||
min={0}
|
||||
onChange={[MockFunction]}
|
||||
onKeyDown={[MockFunction]}
|
||||
placeholder="auto"
|
||||
type="number"
|
||||
value="123"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
@ -4,12 +4,11 @@ exports[`LokiExploreQueryEditor should render component 1`] = `
|
||||
<Component
|
||||
ExtraFieldElement={
|
||||
<Memo(LokiExploreExtraField)
|
||||
label="Line limit"
|
||||
min={0}
|
||||
onChangeFunc={[Function]}
|
||||
lineLimitValue="0"
|
||||
onKeyDownFunc={[Function]}
|
||||
type="number"
|
||||
value="0"
|
||||
onLineLimitChange={[Function]}
|
||||
onQueryTypeChange={[Function]}
|
||||
queryType="range"
|
||||
/>
|
||||
}
|
||||
data={
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { of, throwError } from 'rxjs';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { omit } from 'lodash';
|
||||
import { AnnotationQueryRequest, CoreApp, DataFrame, dateTime, FieldCache, TimeRange } from '@grafana/data';
|
||||
import { AnnotationQueryRequest, CoreApp, DataFrame, dateTime, FieldCache, TimeRange, TimeSeries } from '@grafana/data';
|
||||
import { BackendSrvRequest, FetchResponse } from '@grafana/runtime';
|
||||
|
||||
import LokiDatasource from './datasource';
|
||||
@ -26,7 +25,7 @@ const timeSrvStub = {
|
||||
}),
|
||||
};
|
||||
|
||||
const testResponse: FetchResponse<LokiResponse> = {
|
||||
const testLogsResponse: FetchResponse<LokiResponse> = {
|
||||
data: {
|
||||
data: {
|
||||
resultType: LokiResultType.Stream,
|
||||
@ -49,6 +48,29 @@ const testResponse: FetchResponse<LokiResponse> = {
|
||||
config: ({} as unknown) as BackendSrvRequest,
|
||||
};
|
||||
|
||||
const testMetricsResponse: FetchResponse<LokiResponse> = {
|
||||
data: {
|
||||
data: {
|
||||
resultType: LokiResultType.Matrix,
|
||||
result: [
|
||||
{
|
||||
metric: {},
|
||||
values: [[1605715380, '1.1']],
|
||||
},
|
||||
],
|
||||
},
|
||||
status: 'success',
|
||||
},
|
||||
ok: true,
|
||||
headers: ({} as unknown) as Headers,
|
||||
redirected: false,
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
type: 'basic',
|
||||
url: '',
|
||||
config: ({} as unknown) as BackendSrvRequest,
|
||||
};
|
||||
|
||||
describe('LokiDatasource', () => {
|
||||
const fetchMock = jest.spyOn(backendSrv, 'fetch');
|
||||
|
||||
@ -96,7 +118,7 @@ describe('LokiDatasource', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when querying with limits', () => {
|
||||
describe('when doing logs queries with limits', () => {
|
||||
const runLimitTest = async ({
|
||||
maxDataPoints = 123,
|
||||
queryMaxLines,
|
||||
@ -121,7 +143,7 @@ describe('LokiDatasource', () => {
|
||||
const options = getQueryOptions<LokiQuery>({ targets: [{ expr, refId: 'B', maxLines: queryMaxLines }] });
|
||||
options.maxDataPoints = maxDataPoints;
|
||||
|
||||
fetchMock.mockImplementation(() => of(testResponse));
|
||||
fetchMock.mockImplementation(() => of(testLogsResponse));
|
||||
|
||||
await expect(ds.query(options).pipe(take(1))).toEmitValuesWith(() => {
|
||||
expect(fetchMock.mock.calls.length).toBe(1);
|
||||
@ -151,10 +173,10 @@ describe('LokiDatasource', () => {
|
||||
});
|
||||
|
||||
describe('when querying', () => {
|
||||
function setup(expr: string, app: CoreApp) {
|
||||
function setup(expr: string, app: CoreApp, instant?: boolean, range?: boolean) {
|
||||
const ds = createLokiDSForTests();
|
||||
const options = getQueryOptions<LokiQuery>({
|
||||
targets: [{ expr, refId: 'B' }],
|
||||
targets: [{ expr, refId: 'B', instant, range }],
|
||||
app,
|
||||
});
|
||||
ds.runInstantQuery = jest.fn(() => of({ data: [] }));
|
||||
@ -162,68 +184,95 @@ describe('LokiDatasource', () => {
|
||||
return { ds, options };
|
||||
}
|
||||
|
||||
it('should run range and instant query in Explore if running metric query', async () => {
|
||||
const { ds, options } = setup('rate({job="grafana"}[10m])', CoreApp.Explore);
|
||||
const metricsQuery = 'rate({job="grafana"}[10m])';
|
||||
const logsQuery = '{job="grafana"} |= "foo"';
|
||||
|
||||
it('should run logs instant if only instant is selected', async () => {
|
||||
const { ds, options } = setup(logsQuery, CoreApp.Explore, true, false);
|
||||
await ds.query(options).toPromise();
|
||||
expect(ds.runInstantQuery).toBeCalled();
|
||||
expect(ds.runRangeQuery).toBeCalled();
|
||||
expect(ds.runRangeQuery).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('should run only range query in Explore if running logs query', async () => {
|
||||
const { ds, options } = setup('{job="grafana"}', CoreApp.Explore);
|
||||
it('should run metrics instant if only instant is selected', async () => {
|
||||
const { ds, options } = setup(metricsQuery, CoreApp.Explore, true, false);
|
||||
await ds.query(options).toPromise();
|
||||
expect(ds.runInstantQuery).toBeCalled();
|
||||
expect(ds.runRangeQuery).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('should run only logs range query if only range is selected', async () => {
|
||||
const { ds, options } = setup(logsQuery, CoreApp.Explore, false, true);
|
||||
await ds.query(options).toPromise();
|
||||
expect(ds.runInstantQuery).not.toBeCalled();
|
||||
expect(ds.runRangeQuery).toBeCalled();
|
||||
});
|
||||
|
||||
it('should run only range query in Dashboard', async () => {
|
||||
const { ds, options } = setup('rate({job="grafana"}[10m])', CoreApp.Dashboard);
|
||||
it('should run only metrics range query if only range is selected', async () => {
|
||||
const { ds, options } = setup(metricsQuery, CoreApp.Explore, false, true);
|
||||
await ds.query(options).toPromise();
|
||||
expect(ds.runInstantQuery).not.toBeCalled();
|
||||
expect(ds.runRangeQuery).toBeCalled();
|
||||
});
|
||||
|
||||
it('should return series data for both queries in Explore if metrics query', async () => {
|
||||
it('should run only logs range query if no query type is selected in Explore', async () => {
|
||||
const { ds, options } = setup(logsQuery, CoreApp.Explore);
|
||||
await ds.query(options).toPromise();
|
||||
expect(ds.runInstantQuery).not.toBeCalled();
|
||||
expect(ds.runRangeQuery).toBeCalled();
|
||||
});
|
||||
|
||||
it('should run only metrics range query if no query type is selected in Explore', async () => {
|
||||
const { ds, options } = setup(metricsQuery, CoreApp.Explore);
|
||||
await ds.query(options).toPromise();
|
||||
expect(ds.runInstantQuery).not.toBeCalled();
|
||||
expect(ds.runRangeQuery).toBeCalled();
|
||||
});
|
||||
|
||||
it('should run only logs range query in Dashboard', async () => {
|
||||
const { ds, options } = setup(logsQuery, CoreApp.Dashboard);
|
||||
await ds.query(options).toPromise();
|
||||
expect(ds.runInstantQuery).not.toBeCalled();
|
||||
expect(ds.runRangeQuery).toBeCalled();
|
||||
});
|
||||
|
||||
it('should run only metrics range query in Dashboard', async () => {
|
||||
const { ds, options } = setup(metricsQuery, CoreApp.Dashboard);
|
||||
await ds.query(options).toPromise();
|
||||
expect(ds.runInstantQuery).not.toBeCalled();
|
||||
expect(ds.runRangeQuery).toBeCalled();
|
||||
});
|
||||
|
||||
it('should return series data for metrics range queries', async () => {
|
||||
const ds = createLokiDSForTests();
|
||||
const options = getQueryOptions<LokiQuery>({
|
||||
targets: [{ expr: 'rate({job="grafana"} |= "foo" [10m])', refId: 'B' }],
|
||||
targets: [{ expr: metricsQuery, refId: 'B', range: true }],
|
||||
app: CoreApp.Explore,
|
||||
});
|
||||
|
||||
fetchMock
|
||||
.mockImplementationOnce(() => of(testResponse))
|
||||
.mockImplementation(() => of(omit(testResponse, 'data.status')));
|
||||
fetchMock.mockImplementation(() => of(testMetricsResponse));
|
||||
|
||||
await expect(ds.query(options)).toEmitValuesWith(received => {
|
||||
// first result always comes from runInstantQuery
|
||||
const firstResult = received[0];
|
||||
expect(firstResult).toEqual({ data: [], key: 'B_instant' });
|
||||
const result = received[0];
|
||||
const timeSeries = result.data[0] as TimeSeries;
|
||||
|
||||
// second result always comes from runRangeQuery
|
||||
const secondResult = received[1];
|
||||
const dataFrame = secondResult.data[0] as DataFrame;
|
||||
const fieldCache = new FieldCache(dataFrame);
|
||||
|
||||
expect(fieldCache.getFieldByName('line')?.values.get(0)).toBe('hello');
|
||||
expect(dataFrame.meta?.limit).toBe(500);
|
||||
expect(dataFrame.meta?.searchWords).toEqual([]);
|
||||
expect(timeSeries.meta?.preferredVisualisationType).toBe('graph');
|
||||
expect(timeSeries.refId).toBe('B');
|
||||
expect(timeSeries.datapoints[0]).toEqual([1.1, 1605715380000]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return series data for range query in Dashboard', async () => {
|
||||
it('should return series data for logs range query', async () => {
|
||||
const ds = createLokiDSForTests();
|
||||
const options = getQueryOptions<LokiQuery>({
|
||||
targets: [{ expr: '{job="grafana"} |= "foo"', refId: 'B' }],
|
||||
targets: [{ expr: logsQuery, refId: 'B' }],
|
||||
});
|
||||
|
||||
fetchMock
|
||||
.mockImplementationOnce(() => of(testResponse))
|
||||
.mockImplementation(() => of(omit(testResponse, 'data.status')));
|
||||
fetchMock.mockImplementation(() => of(testLogsResponse));
|
||||
|
||||
await expect(ds.query(options)).toEmitValuesWith(received => {
|
||||
// first result will come from runRangeQuery
|
||||
const firstResult = received[0];
|
||||
const dataFrame = firstResult.data[0] as DataFrame;
|
||||
const result = received[0];
|
||||
const dataFrame = result.data[0] as DataFrame;
|
||||
const fieldCache = new FieldCache(dataFrame);
|
||||
|
||||
expect(fieldCache.getFieldByName('line')?.values.get(0)).toBe('hello');
|
||||
|
@ -24,13 +24,17 @@ import {
|
||||
QueryResultMeta,
|
||||
ScopedVars,
|
||||
TimeRange,
|
||||
CoreApp,
|
||||
} from '@grafana/data';
|
||||
import { getTemplateSrv, TemplateSrv, BackendSrvRequest, FetchError, getBackendSrv } from '@grafana/runtime';
|
||||
import { addLabelToQuery } from 'app/plugins/datasource/prometheus/add_label_to_query';
|
||||
import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||
import { convertToWebSocketUrl } from 'app/core/utils/explore';
|
||||
import { lokiResultsToTableModel, lokiStreamResultToDataFrame, processRangeQueryResponse } from './result_transformer';
|
||||
import {
|
||||
lokiResultsToTableModel,
|
||||
lokiStreamResultToDataFrame,
|
||||
lokiStreamsToDataFrames,
|
||||
processRangeQueryResponse,
|
||||
} from './result_transformer';
|
||||
import { getHighlighterExpressionsFromQuery } from './query_utils';
|
||||
|
||||
import {
|
||||
@ -99,12 +103,11 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
|
||||
}));
|
||||
|
||||
for (const target of filteredTargets) {
|
||||
// In explore we want to show result of metrics instant query in a table under the graph panel to mimic behaviour of prometheus.
|
||||
// We don't want to do that in dashboards though as user would have to pick the correct data frame.
|
||||
if (options.app === CoreApp.Explore && isMetricsQuery(target.expr)) {
|
||||
if (target.instant) {
|
||||
subQueries.push(this.runInstantQuery(target, options, filteredTargets.length));
|
||||
} else {
|
||||
subQueries.push(this.runRangeQuery(target, options, filteredTargets.length));
|
||||
}
|
||||
subQueries.push(this.runRangeQuery(target, options, filteredTargets.length));
|
||||
}
|
||||
|
||||
// No valid targets, return the empty result to save a round trip.
|
||||
@ -124,12 +127,14 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
|
||||
responseListLength: number
|
||||
): Observable<DataQueryResponse> => {
|
||||
const timeNs = this.getTime(options.range.to, true);
|
||||
const queryLimit = isMetricsQuery(target.expr) ? options.maxDataPoints : target.maxLines;
|
||||
const query = {
|
||||
query: target.expr,
|
||||
time: `${timeNs + (1e9 - (timeNs % 1e9))}`,
|
||||
limit: Math.min(options.maxDataPoints || Infinity, this.maxLines),
|
||||
limit: Math.min(queryLimit || Infinity, this.maxLines),
|
||||
};
|
||||
/** Show results of Loki instant queries only in table */
|
||||
|
||||
/** Used only for results of metrics instant queries */
|
||||
const meta: QueryResultMeta = {
|
||||
preferredVisualisationType: 'table',
|
||||
};
|
||||
@ -138,7 +143,14 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
|
||||
map((response: { data: LokiResponse }) => {
|
||||
if (response.data.data.resultType === LokiResultType.Stream) {
|
||||
return {
|
||||
data: [],
|
||||
data: response.data
|
||||
? lokiStreamsToDataFrames(
|
||||
response.data as LokiStreamResponse,
|
||||
target,
|
||||
query.limit,
|
||||
this.instanceSettings.jsonData
|
||||
)
|
||||
: [],
|
||||
key: `${target.refId}_instant`,
|
||||
};
|
||||
}
|
||||
|
@ -61,10 +61,10 @@ describe('loki result transformer', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('lokiStreamsToDataframes', () => {
|
||||
describe('lokiStreamsToDataFrames', () => {
|
||||
it('should enhance data frames', () => {
|
||||
jest.spyOn(ResultTransformer, 'enhanceDataFrame');
|
||||
const dataFrames = ResultTransformer.lokiStreamsToDataframes(lokiResponse, { refId: 'B' }, 500, {
|
||||
const dataFrames = ResultTransformer.lokiStreamsToDataFrames(lokiResponse, { refId: 'B' }, 500, {
|
||||
derivedFields: [
|
||||
{
|
||||
matcherRegex: 'trace=(w+)',
|
||||
|
@ -305,7 +305,7 @@ function lokiStatsToMetaStat(stats: LokiStats | undefined): QueryResultMetaStat[
|
||||
return result;
|
||||
}
|
||||
|
||||
export function lokiStreamsToDataframes(
|
||||
export function lokiStreamsToDataFrames(
|
||||
response: LokiStreamResponse,
|
||||
target: { refId: string; expr?: string },
|
||||
limit: number,
|
||||
@ -472,7 +472,7 @@ export function processRangeQueryResponse(
|
||||
switch (response.data.resultType) {
|
||||
case LokiResultType.Stream:
|
||||
return of({
|
||||
data: lokiStreamsToDataframes(response as LokiStreamResponse, target, limit, config, reverse),
|
||||
data: lokiStreamsToDataFrames(response as LokiStreamResponse, target, limit, config, reverse),
|
||||
key: `${target.refId}_log`,
|
||||
});
|
||||
|
||||
|
@ -30,6 +30,8 @@ export interface LokiQuery extends DataQuery {
|
||||
legendFormat?: string;
|
||||
valueWithRefId?: boolean;
|
||||
maxLines?: number;
|
||||
range?: boolean;
|
||||
instant?: boolean;
|
||||
}
|
||||
|
||||
export interface LokiOptions extends DataSourceJsonData {
|
||||
|
@ -23,7 +23,7 @@ export const PromExploreExtraField: React.FC<PromExploreExtraFieldProps> = memo(
|
||||
|
||||
return (
|
||||
<div aria-label="Prometheus extra field" className="gf-form-inline">
|
||||
{/*QueryTypeField */}
|
||||
{/*Query type field*/}
|
||||
<div
|
||||
data-testid="queryTypeField"
|
||||
className={cx(
|
||||
|
Loading…
Reference in New Issue
Block a user