Commit 347343f5 by Ivana Huckova Committed by GitHub

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
parent 80294b2d
......@@ -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)
......
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) {
......
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) => {
......
// 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;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment