diff --git a/public/app/features/explore/Logs.tsx b/public/app/features/explore/Logs.tsx index bcddbccbb28..7af6ff9f822 100644 --- a/public/app/features/explore/Logs.tsx +++ b/public/app/features/explore/Logs.tsx @@ -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 { 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) diff --git a/public/app/features/explore/LogsContainer.tsx b/public/app/features/explore/LogsContainer.tsx index b9451ea5352..79295872b68 100644 --- a/public/app/features/explore/LogsContainer.tsx +++ b/public/app/features/explore/LogsContainer.tsx @@ -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 { +export class LogsContainer extends PureComponent { onChangeTime = (absoluteRange: AbsoluteTimeRange) => { const { exploreId, updateTimeRange } = this.props; updateTimeRange({ exploreId, absoluteRange }); @@ -102,7 +69,8 @@ export class LogsContainer extends PureComponent { }; 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 { exploreId, } = this.props; + if (!logRows) { + return null; + } + return ( <> @@ -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; + +export default hot(module)(connector(LogsContainer)); diff --git a/public/app/features/explore/TraceView/TraceView.tsx b/public/app/features/explore/TraceView/TraceView.tsx index 03fab339b45..00618a8073d 100644 --- a/public/app/features/explore/TraceView/TraceView.tsx +++ b/public/app/features/explore/TraceView/TraceView.tsx @@ -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) { diff --git a/public/app/features/explore/TraceView/createSpanLink.tsx b/public/app/features/explore/TraceView/createSpanLink.tsx index 1d2ce0d62c9..b9d91b5c7ff 100644 --- a/public/app/features/explore/TraceView/createSpanLink.tsx +++ b/public/app/features/explore/TraceView/createSpanLink.tsx @@ -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; diff --git a/public/app/features/explore/utils/links.ts b/public/app/features/explore/utils/links.ts index 3373fad3568..18ac3c1f03e 100644 --- a/public/app/features/explore/utils/links.ts +++ b/public/app/features/explore/utils/links.ts @@ -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) => { diff --git a/public/app/plugins/datasource/loki/datasource.ts b/public/app/plugins/datasource/loki/datasource.ts index 1f9821fe4b4..70a6ad92363 100644 --- a/public/app/plugins/datasource/loki/datasource.ts +++ b/public/app/plugins/datasource/loki/datasource.ts @@ -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 { data: data || [], key: `loki-${liveTarget.refId}`, state: LoadingState.Streaming, - })) + })), + catchError((err: any) => { + return throwError(`Live tailing was stopped due to following error: ${err.reason}`); + }) ); }; diff --git a/public/app/plugins/datasource/loki/live_streams.ts b/public/app/plugins/datasource/loki/live_streams.ts index d286ddce86b..fd96048a707 100644 --- a/public/app/plugins/datasource/loki/live_streams.ts +++ b/public/app/plugins/datasource/loki/live_streams.ts @@ -60,7 +60,7 @@ export class LiveStreams { // Retry every 5s return timer(retryInterval); } - return throwError(`error: ${error.reason}`); + return throwError(error); }) ) ), diff --git a/public/app/types/explore.ts b/public/app/types/explore.ts index a23391fd55f..c2d9c2f35ec 100644 --- a/public/app/types/explore.ts +++ b/public/app/types/explore.ts @@ -221,3 +221,7 @@ export interface ExplorePanelData extends PanelData { tableResult: DataFrame | null; logsResult: LogsModel | null; } + +export type SplitOpen = ( + options?: { datasourceUid: string; query: T; range?: TimeRange } | undefined +) => void;