mirror of https://github.com/grafana/grafana.git
Logs: Add labels as variable for use in correlations/links (#103605)
This commit is contained in:
parent
08316103b5
commit
e45f2d0a18
|
@ -16,10 +16,8 @@ import {
|
||||||
RawTimeRange,
|
RawTimeRange,
|
||||||
DataQueryResponse,
|
DataQueryResponse,
|
||||||
LogRowContextOptions,
|
LogRowContextOptions,
|
||||||
LinkModel,
|
|
||||||
EventBus,
|
EventBus,
|
||||||
ExplorePanelsState,
|
ExplorePanelsState,
|
||||||
Field,
|
|
||||||
TimeRange,
|
TimeRange,
|
||||||
LogsDedupStrategy,
|
LogsDedupStrategy,
|
||||||
LogsSortOrder,
|
LogsSortOrder,
|
||||||
|
@ -62,6 +60,7 @@ import { LogLevelColor, dedupLogRows, filterLogLevels } from 'app/features/logs/
|
||||||
import { getLogLevelFromKey, getLogLevelInfo } from 'app/features/logs/utils';
|
import { getLogLevelFromKey, getLogLevelInfo } from 'app/features/logs/utils';
|
||||||
import { LokiQueryDirection } from 'app/plugins/datasource/loki/dataquery.gen';
|
import { LokiQueryDirection } from 'app/plugins/datasource/loki/dataquery.gen';
|
||||||
import { isLokiQuery } from 'app/plugins/datasource/loki/queryUtils';
|
import { isLokiQuery } from 'app/plugins/datasource/loki/queryUtils';
|
||||||
|
import { GetFieldLinksFn } from 'app/plugins/panel/logs/types';
|
||||||
import { getState } from 'app/store/store';
|
import { getState } from 'app/store/store';
|
||||||
import { ExploreItemState, useDispatch } from 'app/types';
|
import { ExploreItemState, useDispatch } from 'app/types';
|
||||||
|
|
||||||
|
@ -119,7 +118,7 @@ interface Props extends Themeable2 {
|
||||||
cacheFilters?: boolean
|
cacheFilters?: boolean
|
||||||
) => Promise<DataQuery | null>;
|
) => Promise<DataQuery | null>;
|
||||||
getLogRowContextUi?: (row: LogRowModel, runContextQuery?: () => void) => React.ReactNode;
|
getLogRowContextUi?: (row: LogRowModel, runContextQuery?: () => void) => React.ReactNode;
|
||||||
getFieldLinks: (field: Field, rowIndex: number, dataFrame: DataFrame) => Array<LinkModel<Field>>;
|
getFieldLinks: GetFieldLinksFn;
|
||||||
addResultsToCache: () => void;
|
addResultsToCache: () => void;
|
||||||
clearCache: () => void;
|
clearCache: () => void;
|
||||||
eventBus: EventBus;
|
eventBus: EventBus;
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { connect, ConnectedProps } from 'react-redux';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AbsoluteTimeRange,
|
AbsoluteTimeRange,
|
||||||
Field,
|
|
||||||
hasLogsContextSupport,
|
hasLogsContextSupport,
|
||||||
hasLogsContextUiSupport,
|
hasLogsContextUiSupport,
|
||||||
LoadingState,
|
LoadingState,
|
||||||
|
@ -27,6 +26,7 @@ import { DataQuery } from '@grafana/schema';
|
||||||
import { Collapse } from '@grafana/ui';
|
import { Collapse } from '@grafana/ui';
|
||||||
import { t } from 'app/core/internationalization';
|
import { t } from 'app/core/internationalization';
|
||||||
import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
|
import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
|
||||||
|
import { GetFieldLinksFn } from 'app/plugins/panel/logs/types';
|
||||||
import { StoreState } from 'app/types';
|
import { StoreState } from 'app/types';
|
||||||
import { ExploreItemState } from 'app/types/explore';
|
import { ExploreItemState } from 'app/types/explore';
|
||||||
|
|
||||||
|
@ -237,9 +237,9 @@ class LogsContainer extends PureComponent<LogsContainerProps, LogsContainerState
|
||||||
return hasLogsContextSupport(this.state.dsInstances[row.dataFrame.refId]);
|
return hasLogsContextSupport(this.state.dsInstances[row.dataFrame.refId]);
|
||||||
};
|
};
|
||||||
|
|
||||||
getFieldLinks = (field: Field, rowIndex: number, dataFrame: DataFrame) => {
|
getFieldLinks: GetFieldLinksFn = (field, rowIndex, dataFrame, vars) => {
|
||||||
const { splitOpenFn, range } = this.props;
|
const { splitOpenFn, range } = this.props;
|
||||||
return getFieldLinksForExplore({ field, rowIndex, splitOpenFn, range, dataFrame });
|
return getFieldLinksForExplore({ field, rowIndex, splitOpenFn, range, dataFrame, vars });
|
||||||
};
|
};
|
||||||
|
|
||||||
logDetailsFilterAvailable = () => {
|
logDetailsFilterAvailable = () => {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { cx } from '@emotion/css';
|
import { cx } from '@emotion/css';
|
||||||
import { PureComponent } from 'react';
|
import { PureComponent } from 'react';
|
||||||
|
|
||||||
import { CoreApp, DataFrame, DataFrameType, Field, LinkModel, LogRowModel } from '@grafana/data';
|
import { CoreApp, DataFrame, DataFrameType, LogRowModel } from '@grafana/data';
|
||||||
import { PopoverContent, Themeable2, withTheme2 } from '@grafana/ui';
|
import { PopoverContent, Themeable2, withTheme2 } from '@grafana/ui';
|
||||||
import { Trans, t } from 'app/core/internationalization';
|
import { Trans, t } from 'app/core/internationalization';
|
||||||
|
import { GetFieldLinksFn } from 'app/plugins/panel/logs/types';
|
||||||
|
|
||||||
import { calculateLogsLabelStats, calculateStats } from '../utils';
|
import { calculateLogsLabelStats, calculateStats } from '../utils';
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ export interface Props extends Themeable2 {
|
||||||
|
|
||||||
onClickFilterLabel?: (key: string, value: string, frame?: DataFrame) => void;
|
onClickFilterLabel?: (key: string, value: string, frame?: DataFrame) => void;
|
||||||
onClickFilterOutLabel?: (key: string, value: string, frame?: DataFrame) => void;
|
onClickFilterOutLabel?: (key: string, value: string, frame?: DataFrame) => void;
|
||||||
getFieldLinks?: (field: Field, rowIndex: number, dataFrame: DataFrame) => Array<LinkModel<Field>>;
|
getFieldLinks?: GetFieldLinksFn;
|
||||||
displayedFields?: string[];
|
displayedFields?: string[];
|
||||||
onClickShowField?: (key: string) => void;
|
onClickShowField?: (key: string) => void;
|
||||||
onClickHideField?: (key: string) => void;
|
onClickHideField?: (key: string) => void;
|
||||||
|
|
|
@ -1,20 +1,12 @@
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import { MouseEvent, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { MouseEvent, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import {
|
import { CoreApp, DataFrame, dateTimeFormat, LogRowContextOptions, LogRowModel, LogsSortOrder } from '@grafana/data';
|
||||||
CoreApp,
|
|
||||||
DataFrame,
|
|
||||||
dateTimeFormat,
|
|
||||||
Field,
|
|
||||||
LinkModel,
|
|
||||||
LogRowContextOptions,
|
|
||||||
LogRowModel,
|
|
||||||
LogsSortOrder,
|
|
||||||
} from '@grafana/data';
|
|
||||||
import { reportInteraction } from '@grafana/runtime';
|
import { reportInteraction } from '@grafana/runtime';
|
||||||
import { DataQuery, TimeZone } from '@grafana/schema';
|
import { DataQuery, TimeZone } from '@grafana/schema';
|
||||||
import { Icon, PopoverContent, Tooltip, useTheme2 } from '@grafana/ui';
|
import { Icon, PopoverContent, Tooltip, useTheme2 } from '@grafana/ui';
|
||||||
import { t } from 'app/core/internationalization';
|
import { t } from 'app/core/internationalization';
|
||||||
|
import { GetFieldLinksFn } from 'app/plugins/panel/logs/types';
|
||||||
|
|
||||||
import { checkLogsError, checkLogsSampled, escapeUnescapedString } from '../utils';
|
import { checkLogsError, checkLogsSampled, escapeUnescapedString } from '../utils';
|
||||||
|
|
||||||
|
@ -41,7 +33,7 @@ export interface Props {
|
||||||
onClickFilterLabel?: (key: string, value: string, frame?: DataFrame) => void;
|
onClickFilterLabel?: (key: string, value: string, frame?: DataFrame) => void;
|
||||||
onClickFilterOutLabel?: (key: string, value: string, frame?: DataFrame) => void;
|
onClickFilterOutLabel?: (key: string, value: string, frame?: DataFrame) => void;
|
||||||
onContextClick?: () => void;
|
onContextClick?: () => void;
|
||||||
getFieldLinks?: (field: Field, rowIndex: number, dataFrame: DataFrame) => Array<LinkModel<Field>>;
|
getFieldLinks?: GetFieldLinksFn;
|
||||||
showContextToggle?: (row: LogRowModel) => boolean;
|
showContextToggle?: (row: LogRowModel) => boolean;
|
||||||
onClickShowField?: (key: string) => void;
|
onClickShowField?: (key: string) => void;
|
||||||
onClickHideField?: (key: string) => void;
|
onClickHideField?: (key: string) => void;
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import { memo, ReactNode, useMemo } from 'react';
|
import { memo, ReactNode, useMemo } from 'react';
|
||||||
|
|
||||||
import { LogRowModel, Field, LinkModel, DataFrame } from '@grafana/data';
|
import { LogRowModel } from '@grafana/data';
|
||||||
|
import { GetFieldLinksFn } from 'app/plugins/panel/logs/types';
|
||||||
|
|
||||||
import { LOG_LINE_BODY_FIELD_NAME } from './LogDetailsBody';
|
import { LOG_LINE_BODY_FIELD_NAME } from './LogDetailsBody';
|
||||||
import { LogRowMenuCell } from './LogRowMenuCell';
|
import { LogRowMenuCell } from './LogRowMenuCell';
|
||||||
|
@ -12,7 +13,7 @@ export interface Props {
|
||||||
row: LogRowModel;
|
row: LogRowModel;
|
||||||
detectedFields: string[];
|
detectedFields: string[];
|
||||||
wrapLogMessage: boolean;
|
wrapLogMessage: boolean;
|
||||||
getFieldLinks?: (field: Field, rowIndex: number, dataFrame: DataFrame) => Array<LinkModel<Field>>;
|
getFieldLinks?: GetFieldLinksFn;
|
||||||
styles: LogRowStyles;
|
styles: LogRowStyles;
|
||||||
showContextToggle?: (row: LogRowModel) => boolean;
|
showContextToggle?: (row: LogRowModel) => boolean;
|
||||||
onOpenContext: (row: LogRowModel) => void;
|
onOpenContext: (row: LogRowModel) => void;
|
||||||
|
|
|
@ -5,8 +5,6 @@ import {
|
||||||
TimeZone,
|
TimeZone,
|
||||||
LogsDedupStrategy,
|
LogsDedupStrategy,
|
||||||
LogRowModel,
|
LogRowModel,
|
||||||
Field,
|
|
||||||
LinkModel,
|
|
||||||
LogsSortOrder,
|
LogsSortOrder,
|
||||||
CoreApp,
|
CoreApp,
|
||||||
DataFrame,
|
DataFrame,
|
||||||
|
@ -16,6 +14,7 @@ import { config } from '@grafana/runtime';
|
||||||
import { DataQuery } from '@grafana/schema';
|
import { DataQuery } from '@grafana/schema';
|
||||||
import { ConfirmModal, Icon, PopoverContent, useTheme2 } from '@grafana/ui';
|
import { ConfirmModal, Icon, PopoverContent, useTheme2 } from '@grafana/ui';
|
||||||
import { t, Trans } from 'app/core/internationalization';
|
import { t, Trans } from 'app/core/internationalization';
|
||||||
|
import { GetFieldLinksFn } from 'app/plugins/panel/logs/types';
|
||||||
|
|
||||||
import { PopoverMenu } from '../../explore/Logs/PopoverMenu';
|
import { PopoverMenu } from '../../explore/Logs/PopoverMenu';
|
||||||
import { UniqueKeyMaker } from '../UniqueKeyMaker';
|
import { UniqueKeyMaker } from '../UniqueKeyMaker';
|
||||||
|
@ -44,7 +43,7 @@ export interface Props {
|
||||||
showContextToggle?: (row: LogRowModel) => boolean;
|
showContextToggle?: (row: LogRowModel) => boolean;
|
||||||
onClickFilterLabel?: (key: string, value: string, frame?: DataFrame) => void;
|
onClickFilterLabel?: (key: string, value: string, frame?: DataFrame) => void;
|
||||||
onClickFilterOutLabel?: (key: string, value: string, frame?: DataFrame) => void;
|
onClickFilterOutLabel?: (key: string, value: string, frame?: DataFrame) => void;
|
||||||
getFieldLinks?: (field: Field, rowIndex: number, dataFrame: DataFrame) => Array<LinkModel<Field>>;
|
getFieldLinks?: GetFieldLinksFn;
|
||||||
onClickShowField?: (key: string) => void;
|
onClickShowField?: (key: string) => void;
|
||||||
onClickHideField?: (key: string) => void;
|
onClickHideField?: (key: string) => void;
|
||||||
onPinLine?: (row: LogRowModel, allowUnPin?: boolean) => void;
|
onPinLine?: (row: LogRowModel, allowUnPin?: boolean) => void;
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import { DataFrameType, Field, FieldType, LogRowModel, MutableDataFrame } from '@grafana/data';
|
import { DataFrameType, Field, FieldType, LogRowModel, MutableDataFrame } from '@grafana/data';
|
||||||
import { ExploreFieldLinkModel } from 'app/features/explore/utils/links';
|
import { mockTimeRange } from '@grafana/plugin-ui';
|
||||||
|
import { ExploreFieldLinkModel, getFieldLinksForExplore } from 'app/features/explore/utils/links';
|
||||||
|
import { GetFieldLinksFn } from 'app/plugins/panel/logs/types';
|
||||||
|
|
||||||
import { createLogRow } from './__mocks__/logRow';
|
import { createLogRow } from './__mocks__/logRow';
|
||||||
import { getAllFields, createLogLineLinks, FieldDef } from './logParser';
|
import { getAllFields, createLogLineLinks, FieldDef, getDataframeFields } from './logParser';
|
||||||
|
|
||||||
describe('logParser', () => {
|
describe('logParser', () => {
|
||||||
describe('getAllFields', () => {
|
describe('getAllFields', () => {
|
||||||
|
@ -462,6 +464,64 @@ describe('logParser', () => {
|
||||||
expect(fields.length).toBe(0);
|
expect(fields.length).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getDataframeFields', () => {
|
||||||
|
it('should add row labels as variables for links', () => {
|
||||||
|
const row = createLogRow({
|
||||||
|
labels: { service_name: 'checkout', service_namespace: 'prod' },
|
||||||
|
dataFrame: {
|
||||||
|
refId: 'A',
|
||||||
|
fields: [
|
||||||
|
testTimeField,
|
||||||
|
testLineField,
|
||||||
|
{
|
||||||
|
name: 'link',
|
||||||
|
type: FieldType.string,
|
||||||
|
config: {
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
title: 'link1',
|
||||||
|
url: 'https://service.com/${__labels.tags["service_namespace"]}/${__labels.tags["service_name"]}',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
values: ['some'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
length: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const getFieldLinks: GetFieldLinksFn = (field, rowIndex, dataFrame, vars) => {
|
||||||
|
return getFieldLinksForExplore({
|
||||||
|
field,
|
||||||
|
rowIndex,
|
||||||
|
range: mockTimeRange(),
|
||||||
|
dataFrame: dataFrame,
|
||||||
|
vars,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fields = getDataframeFields(row, getFieldLinks);
|
||||||
|
expect(fields).toHaveLength(1);
|
||||||
|
expect(fields[0].links).toHaveLength(1);
|
||||||
|
expect(fields[0].links).toMatchObject([
|
||||||
|
{
|
||||||
|
href: 'https://service.com/prod/checkout',
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
fieldPath: 'tags["service_namespace"]',
|
||||||
|
format: undefined,
|
||||||
|
found: true,
|
||||||
|
match: '${__labels.tags["service_namespace"]}',
|
||||||
|
value: 'prod',
|
||||||
|
variableName: '__labels',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const testTimeField = {
|
const testTimeField = {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { partition } from 'lodash';
|
import { partition } from 'lodash';
|
||||||
|
|
||||||
import { DataFrame, Field, FieldWithIndex, LinkModel, LogRowModel } from '@grafana/data';
|
import { DataFrame, Field, FieldWithIndex, LinkModel, LogRowModel, ScopedVars } from '@grafana/data';
|
||||||
import { safeStringifyValue } from 'app/core/utils/explore';
|
import { safeStringifyValue } from 'app/core/utils/explore';
|
||||||
import { ExploreFieldLinkModel } from 'app/features/explore/utils/links';
|
import { ExploreFieldLinkModel } from 'app/features/explore/utils/links';
|
||||||
|
import { GetFieldLinksFn } from 'app/plugins/panel/logs/types';
|
||||||
|
|
||||||
import { parseLogsFrame } from '../logsFrame';
|
import { parseLogsFrame } from '../logsFrame';
|
||||||
|
|
||||||
|
@ -17,14 +18,7 @@ export type FieldDef = {
|
||||||
* Returns all fields for log row which consists of fields we parse from the message itself and additional fields
|
* Returns all fields for log row which consists of fields we parse from the message itself and additional fields
|
||||||
* found in the dataframe (they may contain links).
|
* found in the dataframe (they may contain links).
|
||||||
*/
|
*/
|
||||||
export const getAllFields = (
|
export const getAllFields = (row: LogRowModel, getFieldLinks?: GetFieldLinksFn) => {
|
||||||
row: LogRowModel,
|
|
||||||
getFieldLinks?: (
|
|
||||||
field: Field,
|
|
||||||
rowIndex: number,
|
|
||||||
dataFrame: DataFrame
|
|
||||||
) => Array<LinkModel<Field>> | ExploreFieldLinkModel[]
|
|
||||||
) => {
|
|
||||||
return getDataframeFields(row, getFieldLinks);
|
return getDataframeFields(row, getFieldLinks);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,13 +60,18 @@ export const createLogLineLinks = (hiddenFieldsWithLinks: FieldDef[]): FieldDef[
|
||||||
/**
|
/**
|
||||||
* creates fields from the dataframe-fields, adding data-links, when field.config.links exists
|
* creates fields from the dataframe-fields, adding data-links, when field.config.links exists
|
||||||
*/
|
*/
|
||||||
export const getDataframeFields = (
|
export const getDataframeFields = (row: LogRowModel, getFieldLinks?: GetFieldLinksFn): FieldDef[] => {
|
||||||
row: LogRowModel,
|
|
||||||
getFieldLinks?: (field: Field, rowIndex: number, dataFrame: DataFrame) => Array<LinkModel<Field>>
|
|
||||||
): FieldDef[] => {
|
|
||||||
const nonEmptyVisibleFields = getNonEmptyVisibleFields(row);
|
const nonEmptyVisibleFields = getNonEmptyVisibleFields(row);
|
||||||
return nonEmptyVisibleFields.map((field) => {
|
return nonEmptyVisibleFields.map((field) => {
|
||||||
const links = getFieldLinks ? getFieldLinks(field, row.rowIndex, row.dataFrame) : [];
|
const vars: ScopedVars = {
|
||||||
|
__labels: {
|
||||||
|
text: 'Labels',
|
||||||
|
value: {
|
||||||
|
tags: { ...row.labels },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const links = getFieldLinks ? getFieldLinks(field, row.rowIndex, row.dataFrame, vars) : [];
|
||||||
const fieldVal = field.values[row.rowIndex];
|
const fieldVal = field.values[row.rowIndex];
|
||||||
const outputVal =
|
const outputVal =
|
||||||
typeof fieldVal === 'string' || typeof fieldVal === 'number' ? fieldVal.toString() : safeStringifyValue(fieldVal);
|
typeof fieldVal === 'string' || typeof fieldVal === 'number' ? fieldVal.toString() : safeStringifyValue(fieldVal);
|
||||||
|
|
|
@ -7,11 +7,8 @@ import { VariableSizeList } from 'react-window';
|
||||||
import {
|
import {
|
||||||
AbsoluteTimeRange,
|
AbsoluteTimeRange,
|
||||||
CoreApp,
|
CoreApp,
|
||||||
DataFrame,
|
|
||||||
EventBus,
|
EventBus,
|
||||||
EventBusSrv,
|
EventBusSrv,
|
||||||
Field,
|
|
||||||
LinkModel,
|
|
||||||
LogLevel,
|
LogLevel,
|
||||||
LogRowModel,
|
LogRowModel,
|
||||||
LogsDedupStrategy,
|
LogsDedupStrategy,
|
||||||
|
@ -21,6 +18,7 @@ import {
|
||||||
TimeRange,
|
TimeRange,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { PopoverContent, useTheme2 } from '@grafana/ui';
|
import { PopoverContent, useTheme2 } from '@grafana/ui';
|
||||||
|
import { GetFieldLinksFn } from 'app/plugins/panel/logs/types';
|
||||||
|
|
||||||
import { InfiniteScroll } from './InfiniteScroll';
|
import { InfiniteScroll } from './InfiniteScroll';
|
||||||
import { getGridTemplateColumns } from './LogLine';
|
import { getGridTemplateColumns } from './LogLine';
|
||||||
|
@ -38,8 +36,6 @@ import {
|
||||||
storeLogLineSize,
|
storeLogLineSize,
|
||||||
} from './virtualization';
|
} from './virtualization';
|
||||||
|
|
||||||
export type GetFieldLinksFn = (field: Field, rowIndex: number, dataFrame: DataFrame) => Array<LinkModel<Field>>;
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
app: CoreApp;
|
app: CoreApp;
|
||||||
containerElement: HTMLDivElement;
|
containerElement: HTMLDivElement;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import Prism, { Grammar } from 'prismjs';
|
import Prism, { Grammar } from 'prismjs';
|
||||||
|
|
||||||
import { dateTimeFormat, LogLevel, LogRowModel, LogsSortOrder } from '@grafana/data';
|
import { dateTimeFormat, LogLevel, LogRowModel, LogsSortOrder } from '@grafana/data';
|
||||||
|
import { GetFieldLinksFn } from 'app/plugins/panel/logs/types';
|
||||||
|
|
||||||
import { escapeUnescapedString, sortLogRows } from '../../utils';
|
import { escapeUnescapedString, sortLogRows } from '../../utils';
|
||||||
import { FieldDef, getAllFields } from '../logParser';
|
import { FieldDef, getAllFields } from '../logParser';
|
||||||
|
|
||||||
import { GetFieldLinksFn } from './LogList';
|
|
||||||
import { generateLogGrammar } from './grammar';
|
import { generateLogGrammar } from './grammar';
|
||||||
|
|
||||||
export interface LogListModel extends LogRowModel {
|
export interface LogListModel extends LogRowModel {
|
||||||
|
|
|
@ -13,7 +13,6 @@ import {
|
||||||
DataQueryResponse,
|
DataQueryResponse,
|
||||||
DataSourceApi,
|
DataSourceApi,
|
||||||
dateTimeForTimeZone,
|
dateTimeForTimeZone,
|
||||||
Field,
|
|
||||||
GrafanaTheme2,
|
GrafanaTheme2,
|
||||||
hasLogsContextSupport,
|
hasLogsContextSupport,
|
||||||
hasLogsContextUiSupport,
|
hasLogsContextUiSupport,
|
||||||
|
@ -45,6 +44,7 @@ import { LogRows } from '../../../features/logs/components/LogRows';
|
||||||
import { COMMON_LABELS, dataFrameToLogsModel, dedupLogRows } from '../../../features/logs/logsModel';
|
import { COMMON_LABELS, dataFrameToLogsModel, dedupLogRows } from '../../../features/logs/logsModel';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
GetFieldLinksFn,
|
||||||
isIsFilterLabelActive,
|
isIsFilterLabelActive,
|
||||||
isOnClickFilterLabel,
|
isOnClickFilterLabel,
|
||||||
isOnClickFilterOutLabel,
|
isOnClickFilterOutLabel,
|
||||||
|
@ -303,9 +303,15 @@ export const LogsPanel = ({
|
||||||
}
|
}
|
||||||
}, [panelData.request?.app, isAscending, scrollElement, logRows]);
|
}, [panelData.request?.app, isAscending, scrollElement, logRows]);
|
||||||
|
|
||||||
const getFieldLinks = useCallback(
|
const getFieldLinks: GetFieldLinksFn = useCallback(
|
||||||
(field: Field, rowIndex: number) => {
|
(field, rowIndex, dataFrame, vars) => {
|
||||||
return getFieldLinksForExplore({ field, rowIndex, range: panelData.timeRange });
|
return getFieldLinksForExplore({
|
||||||
|
field,
|
||||||
|
rowIndex,
|
||||||
|
range: panelData.timeRange,
|
||||||
|
dataFrame: dataFrame,
|
||||||
|
vars,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
[panelData]
|
[panelData]
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { ReactNode } from 'react';
|
import React, { ReactNode } from 'react';
|
||||||
|
|
||||||
import { DataFrame } from '@grafana/data';
|
import { DataFrame, Field, LinkModel, ScopedVars } from '@grafana/data';
|
||||||
|
|
||||||
export type { Options } from './panelcfg.gen';
|
export type { Options } from './panelcfg.gen';
|
||||||
|
|
||||||
|
@ -13,6 +13,13 @@ type isOnClickShowFieldType = (value: string) => void;
|
||||||
type isOnClickHideFieldType = (value: string) => void;
|
type isOnClickHideFieldType = (value: string) => void;
|
||||||
export type onNewLogsReceivedType = (allLogs: DataFrame[], newLogs: DataFrame[]) => void;
|
export type onNewLogsReceivedType = (allLogs: DataFrame[], newLogs: DataFrame[]) => void;
|
||||||
|
|
||||||
|
export type GetFieldLinksFn = (
|
||||||
|
field: Field,
|
||||||
|
rowIndex: number,
|
||||||
|
dataFrame: DataFrame,
|
||||||
|
vars: ScopedVars
|
||||||
|
) => Array<LinkModel<Field>>;
|
||||||
|
|
||||||
export function isOnClickFilterLabel(callback: unknown): callback is onClickFilterLabelType {
|
export function isOnClickFilterLabel(callback: unknown): callback is onClickFilterLabelType {
|
||||||
return typeof callback === 'function';
|
return typeof callback === 'function';
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue