mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki: Improve live tailing errors and fix Explore's logs container type errors (#30517)
* If error - catch and show, if no logs - return null * Refactor LogsContainer to use ConnectedProps * Fix typescript error * Remove no logs check * Include review feedback * Add SplitOpen type to createSpanLink and TraceView
This commit is contained in:
@@ -56,7 +56,7 @@ function renderMetaItem(value: any, kind: LogsMetaKind) {
|
||||
}
|
||||
|
||||
interface Props {
|
||||
logRows?: LogRowModel[];
|
||||
logRows: LogRowModel[];
|
||||
logsMeta?: LogsMetaItem[];
|
||||
logsSeries?: GraphSeriesXY[];
|
||||
dedupedRows?: LogRowModel[];
|
||||
@@ -239,10 +239,6 @@ export class UnthemedLogs extends PureComponent<Props, State> {
|
||||
|
||||
const { showLabels, showTime, wrapLogMessage, logsSortOrder, isFlipping, showDetectedFields } = this.state;
|
||||
|
||||
if (!logRows) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const hasData = logRows && logRows.length > 0;
|
||||
const dedupCount = dedupedRows
|
||||
? dedupedRows.reduce((sum, row) => (row.duplicates ? sum + row.duplicates : sum), 0)
|
||||
|
||||
@@ -1,21 +1,9 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { connect } from 'react-redux';
|
||||
import { connect, ConnectedProps } from 'react-redux';
|
||||
import { Collapse } from '@grafana/ui';
|
||||
|
||||
import {
|
||||
AbsoluteTimeRange,
|
||||
DataSourceApi,
|
||||
Field,
|
||||
GraphSeriesXY,
|
||||
LogLevel,
|
||||
LogRowModel,
|
||||
LogsDedupStrategy,
|
||||
LogsMetaItem,
|
||||
RawTimeRange,
|
||||
TimeRange,
|
||||
TimeZone,
|
||||
} from '@grafana/data';
|
||||
import { AbsoluteTimeRange, Field, LogLevel, LogRowModel, LogsDedupStrategy, RawTimeRange } from '@grafana/data';
|
||||
|
||||
import { ExploreId, ExploreItemState } from 'app/types/explore';
|
||||
import { StoreState } from 'app/types';
|
||||
@@ -32,38 +20,17 @@ import { LiveTailControls } from './useLiveTailControls';
|
||||
import { getFieldLinksForExplore } from './utils/links';
|
||||
|
||||
interface LogsContainerProps {
|
||||
datasourceInstance?: DataSourceApi;
|
||||
exploreId: ExploreId;
|
||||
loading: boolean;
|
||||
|
||||
logsHighlighterExpressions?: string[];
|
||||
logRows?: LogRowModel[];
|
||||
logsMeta?: LogsMetaItem[];
|
||||
logsSeries?: GraphSeriesXY[];
|
||||
dedupedRows?: LogRowModel[];
|
||||
visibleRange?: AbsoluteTimeRange;
|
||||
|
||||
scanRange?: RawTimeRange;
|
||||
width: number;
|
||||
syncedTimes: boolean;
|
||||
onClickFilterLabel?: (key: string, value: string) => void;
|
||||
onClickFilterOutLabel?: (key: string, value: string) => void;
|
||||
onStartScanning: () => void;
|
||||
onStopScanning: () => void;
|
||||
timeZone: TimeZone;
|
||||
scanning?: boolean;
|
||||
scanRange?: RawTimeRange;
|
||||
toggleLogLevelAction: typeof toggleLogLevelAction;
|
||||
changeDedupStrategy: typeof changeDedupStrategy;
|
||||
dedupStrategy: LogsDedupStrategy;
|
||||
width: number;
|
||||
isLive: boolean;
|
||||
updateTimeRange: typeof updateTimeRange;
|
||||
range: TimeRange;
|
||||
syncedTimes: boolean;
|
||||
absoluteRange: AbsoluteTimeRange;
|
||||
isPaused: boolean;
|
||||
splitOpen: typeof splitOpen;
|
||||
}
|
||||
|
||||
export class LogsContainer extends PureComponent<LogsContainerProps> {
|
||||
export class LogsContainer extends PureComponent<PropsFromRedux & LogsContainerProps> {
|
||||
onChangeTime = (absoluteRange: AbsoluteTimeRange) => {
|
||||
const { exploreId, updateTimeRange } = this.props;
|
||||
updateTimeRange({ exploreId, absoluteRange });
|
||||
@@ -102,7 +69,8 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
|
||||
};
|
||||
|
||||
getFieldLinks = (field: Field, rowIndex: number) => {
|
||||
return getFieldLinksForExplore({ field, rowIndex, splitOpenFn: this.props.splitOpen, range: this.props.range });
|
||||
const { splitOpen: splitOpenFn, range } = this.props;
|
||||
return getFieldLinksForExplore({ field, rowIndex, splitOpenFn, range });
|
||||
};
|
||||
|
||||
render() {
|
||||
@@ -127,6 +95,10 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
|
||||
exploreId,
|
||||
} = this.props;
|
||||
|
||||
if (!logRows) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<LogsCrossFadeTransition visible={isLive}>
|
||||
@@ -195,16 +167,16 @@ function mapStateToProps(state: StoreState, { exploreId }: { exploreId: string }
|
||||
absoluteRange,
|
||||
dedupStrategy,
|
||||
} = item;
|
||||
const dedupedRows = deduplicatedRowsSelector(item);
|
||||
const dedupedRows = deduplicatedRowsSelector(item) || undefined;
|
||||
const timeZone = getTimeZone(state.user);
|
||||
|
||||
return {
|
||||
loading,
|
||||
logsHighlighterExpressions,
|
||||
logRows: logsResult && logsResult.rows,
|
||||
logsMeta: logsResult && logsResult.meta,
|
||||
logsSeries: logsResult && logsResult.series,
|
||||
visibleRange: logsResult && logsResult.visibleRange,
|
||||
logRows: logsResult?.rows,
|
||||
logsMeta: logsResult?.meta,
|
||||
logsSeries: logsResult?.series,
|
||||
visibleRange: logsResult?.visibleRange,
|
||||
scanning,
|
||||
timeZone,
|
||||
dedupStrategy,
|
||||
@@ -224,4 +196,7 @@ const mapDispatchToProps = {
|
||||
splitOpen,
|
||||
};
|
||||
|
||||
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(LogsContainer));
|
||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
type PropsFromRedux = ConnectedProps<typeof connector>;
|
||||
|
||||
export default hot(module)(connector(LogsContainer));
|
||||
|
||||
@@ -20,12 +20,13 @@ import { TraceViewData, Trace, TraceSpan, TraceKeyValuePair, TraceLink } from '@
|
||||
import { createSpanLinkFactory } from './createSpanLink';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { StoreState } from 'app/types';
|
||||
import { SplitOpen } from 'app/types/explore';
|
||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
import { TraceToLogsData } from 'app/core/components/TraceToLogsSettings';
|
||||
|
||||
type Props = {
|
||||
trace?: TraceViewData;
|
||||
splitOpenFn: (options: { datasourceUid: string; query: any }) => void;
|
||||
splitOpenFn: SplitOpen;
|
||||
};
|
||||
|
||||
export function TraceView(props: Props) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { DataLink, dateTime, Field, mapInternalLinkToExplore, TimeRange, TraceSpan } from '@grafana/data';
|
||||
import { getTemplateSrv } from '@grafana/runtime';
|
||||
import { Icon } from '@grafana/ui';
|
||||
import { SplitOpen } from 'app/types/explore';
|
||||
import { TraceToLogsOptions } from 'app/core/components/TraceToLogsSettings';
|
||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
import React from 'react';
|
||||
@@ -11,10 +12,7 @@ import { LokiQuery } from '../../../plugins/datasource/loki/types';
|
||||
* the trace view won't create any links and to capture the datasource and split function making it easier to memoize
|
||||
* with useMemo.
|
||||
*/
|
||||
export function createSpanLinkFactory(
|
||||
splitOpenFn: (options: { datasourceUid: string; query: any }) => void,
|
||||
traceToLogsOptions?: TraceToLogsOptions
|
||||
) {
|
||||
export function createSpanLinkFactory(splitOpenFn: SplitOpen, traceToLogsOptions?: TraceToLogsOptions) {
|
||||
// We should return if dataSourceUid is undefined otherwise getInstanceSettings would return testDataSource.
|
||||
if (!traceToLogsOptions?.datasourceUid) {
|
||||
return undefined;
|
||||
|
||||
@@ -9,9 +9,9 @@ import {
|
||||
DataFrame,
|
||||
getFieldDisplayValuesProxy,
|
||||
} from '@grafana/data';
|
||||
import { getLinkSrv } from '../../panel/panellinks/link_srv';
|
||||
import { config, getTemplateSrv } from '@grafana/runtime';
|
||||
import { splitOpen } from '../state/main';
|
||||
import { SplitOpen } from 'app/types/explore';
|
||||
import { getLinkSrv } from '../../panel/panellinks/link_srv';
|
||||
|
||||
/**
|
||||
* Get links from the field of a dataframe and in addition check if there is associated
|
||||
@@ -23,7 +23,7 @@ import { splitOpen } from '../state/main';
|
||||
export const getFieldLinksForExplore = (options: {
|
||||
field: Field;
|
||||
rowIndex: number;
|
||||
splitOpenFn?: typeof splitOpen;
|
||||
splitOpenFn?: SplitOpen;
|
||||
range: TimeRange;
|
||||
vars?: ScopedVars;
|
||||
dataFrame?: DataFrame;
|
||||
@@ -99,7 +99,7 @@ function getTitleFromHref(href: string): string {
|
||||
* all the fields so is useful for visualisation where the whole row is represented as single clickable item like a
|
||||
* service map.
|
||||
*/
|
||||
export function useLinks(range: TimeRange, splitOpenFn?: typeof splitOpen) {
|
||||
export function useLinks(range: TimeRange, splitOpenFn?: SplitOpen) {
|
||||
return useCallback(
|
||||
(dataFrame: DataFrame, rowIndex: number) => {
|
||||
return dataFrame.fields.flatMap((f) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Libraries
|
||||
import { cloneDeep, isEmpty, map as lodashMap } from 'lodash';
|
||||
import { merge, Observable, of } from 'rxjs';
|
||||
import { merge, Observable, of, throwError } from 'rxjs';
|
||||
import { catchError, map, switchMap } from 'rxjs/operators';
|
||||
import Prism from 'prismjs';
|
||||
|
||||
@@ -263,7 +263,10 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
|
||||
data: data || [],
|
||||
key: `loki-${liveTarget.refId}`,
|
||||
state: LoadingState.Streaming,
|
||||
}))
|
||||
})),
|
||||
catchError((err: any) => {
|
||||
return throwError(`Live tailing was stopped due to following error: ${err.reason}`);
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ export class LiveStreams {
|
||||
// Retry every 5s
|
||||
return timer(retryInterval);
|
||||
}
|
||||
return throwError(`error: ${error.reason}`);
|
||||
return throwError(error);
|
||||
})
|
||||
)
|
||||
),
|
||||
|
||||
@@ -221,3 +221,7 @@ export interface ExplorePanelData extends PanelData {
|
||||
tableResult: DataFrame | null;
|
||||
logsResult: LogsModel | null;
|
||||
}
|
||||
|
||||
export type SplitOpen = <T extends DataQuery = any>(
|
||||
options?: { datasourceUid: string; query: T; range?: TimeRange } | undefined
|
||||
) => void;
|
||||
|
||||
Reference in New Issue
Block a user