diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 0b749d90f7152..0b7bf32b92a25 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -203,6 +203,7 @@ export { isEsError, SearchSessionState, SortDirection, + handleResponse, } from './search'; export type { diff --git a/src/plugins/data/public/search/index.ts b/src/plugins/data/public/search/index.ts index 821f16e0cf68a..d963e08f8477b 100644 --- a/src/plugins/data/public/search/index.ts +++ b/src/plugins/data/public/search/index.ts @@ -52,6 +52,7 @@ export { waitUntilNextSessionCompletes$, } from './session'; export { getEsPreference } from './es_search'; +export { handleResponse } from './fetch'; export type { SearchInterceptorDeps } from './search_interceptor'; export { SearchInterceptor } from './search_interceptor'; diff --git a/src/plugins/inspector/common/adapters/request/request_responder.ts b/src/plugins/inspector/common/adapters/request/request_responder.ts index 1b8da2e57e7f2..1d3a999e4834d 100644 --- a/src/plugins/inspector/common/adapters/request/request_responder.ts +++ b/src/plugins/inspector/common/adapters/request/request_responder.ts @@ -51,7 +51,7 @@ export class RequestResponder { } public finish(status: RequestStatus, response: Response): void { - this.request.time = Date.now() - this.request.startTime; + this.request.time = response.time ?? Date.now() - this.request.startTime; this.request.status = status; this.request.response = response; this.onChange(); diff --git a/src/plugins/inspector/common/adapters/request/types.ts b/src/plugins/inspector/common/adapters/request/types.ts index a204a7aa00a4a..4e6a8d324559f 100644 --- a/src/plugins/inspector/common/adapters/request/types.ts +++ b/src/plugins/inspector/common/adapters/request/types.ts @@ -53,4 +53,5 @@ export interface RequestStatistic { export interface Response { json?: object; + time?: number; } diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts index 98362bfe4f560..3b76a01382039 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -288,6 +288,10 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'long', _meta: { description: 'Non-default value of setting.' }, }, + 'metrics:allowCheckingForFailedShards': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, 'query:allowLeadingWildcards': { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts index 7a527e911ddce..7aec93e9f22b6 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -95,6 +95,7 @@ export interface UsageStats { 'savedObjects:listingLimit': number; 'query:queryString:options': string; 'metrics:max_buckets': number; + 'metrics:allowCheckingForFailedShards': boolean; 'query:allowLeadingWildcards': boolean; metaFields: string[]; 'indexPattern:placeholder': string; diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index 54032badcd8e0..d78adb7e22958 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -7577,6 +7577,12 @@ "description": "Non-default value of setting." } }, + "metrics:allowCheckingForFailedShards": { + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } + }, "query:allowLeadingWildcards": { "type": "boolean", "_meta": { diff --git a/src/plugins/vis_types/timeseries/common/constants.ts b/src/plugins/vis_types/timeseries/common/constants.ts index bddbf095e895e..fec7272093ea3 100644 --- a/src/plugins/vis_types/timeseries/common/constants.ts +++ b/src/plugins/vis_types/timeseries/common/constants.ts @@ -7,6 +7,7 @@ */ export const MAX_BUCKETS_SETTING = 'metrics:max_buckets'; +export const ALLOW_CHECKING_FOR_FAILED_SHARDS = 'metrics:allowCheckingForFailedShards'; export const INDEXES_SEPARATOR = ','; export const AUTO_INTERVAL = 'auto'; export const ROUTES = { diff --git a/src/plugins/vis_types/timeseries/common/types/index.ts b/src/plugins/vis_types/timeseries/common/types/index.ts index 5e04fee0d015c..6266a4c2bc997 100644 --- a/src/plugins/vis_types/timeseries/common/types/index.ts +++ b/src/plugins/vis_types/timeseries/common/types/index.ts @@ -10,7 +10,15 @@ import { Filter, IndexPattern, Query } from '../../../../data/common'; import { Panel } from './panel_model'; export type { Metric, Series, Panel, MetricType } from './panel_model'; -export type { TimeseriesVisData, PanelData, SeriesData, TableData } from './vis_data'; +export type { + TimeseriesVisData, + PanelData, + SeriesData, + TableData, + DataResponseMeta, + TrackedEsSearches, + PanelSeries, +} from './vis_data'; export interface FetchedIndexPattern { indexPattern: IndexPattern | undefined | null; diff --git a/src/plugins/vis_types/timeseries/common/types/vis_data.ts b/src/plugins/vis_types/timeseries/common/types/vis_data.ts index 1a7be0b467004..07c078a6e8aae 100644 --- a/src/plugins/vis_types/timeseries/common/types/vis_data.ts +++ b/src/plugins/vis_types/timeseries/common/types/vis_data.ts @@ -7,30 +7,38 @@ */ import { PANEL_TYPES } from '../enums'; -import { TimeseriesUIRestrictions } from '../ui_restrictions'; +import type { TimeseriesUIRestrictions } from '../ui_restrictions'; export type TimeseriesVisData = SeriesData | TableData; -export interface TableData { - type: PANEL_TYPES.TABLE; +export type TrackedEsSearches = Record< + string, + { + body: Record; + label?: string; + time: number; + response?: Record; + } +>; + +export interface DataResponseMeta { + type: PANEL_TYPES; uiRestrictions: TimeseriesUIRestrictions; + trackedEsSearches: TrackedEsSearches; +} + +export interface TableData extends DataResponseMeta { series?: PanelData[]; pivot_label?: string; } // series data is not fully typed yet -export type SeriesData = { - type: Exclude; - uiRestrictions: TimeseriesUIRestrictions; +export type SeriesData = DataResponseMeta & { error?: string; -} & { - [key: string]: PanelSeries; -}; +} & Record; export interface PanelSeries { - annotations: { - [key: string]: Annotation[]; - }; + annotations: Record; id: string; series: PanelData[]; error?: string; diff --git a/src/plugins/vis_types/timeseries/kibana.json b/src/plugins/vis_types/timeseries/kibana.json index 5cc425e4edf71..d97bee71424e7 100644 --- a/src/plugins/vis_types/timeseries/kibana.json +++ b/src/plugins/vis_types/timeseries/kibana.json @@ -4,7 +4,7 @@ "kibanaVersion": "kibana", "server": true, "ui": true, - "requiredPlugins": ["charts", "data", "expressions", "visualizations", "visualize"], + "requiredPlugins": ["charts", "data", "expressions", "visualizations", "visualize", "inspector"], "optionalPlugins": ["usageCollection"], "requiredBundles": ["kibanaUtils", "kibanaReact", "fieldFormats"], "owner": { diff --git a/src/plugins/vis_types/timeseries/public/application/components/annotation_row.tsx b/src/plugins/vis_types/timeseries/public/application/components/annotation_row.tsx index 734bdfecac673..9bed61721ae67 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/annotation_row.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/annotation_row.tsx @@ -80,7 +80,9 @@ export const AnnotationRow = ({ try { fetchedIndexPattern = index - ? await fetchIndexPattern(index, indexPatterns) + ? await fetchIndexPattern(index, indexPatterns, { + fetchKibanaIndexForStringIndexes: true, + }) : { ...fetchedIndexPattern, defaultIndex: await indexPatterns.getDefault(), diff --git a/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/field_text_select.tsx b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/field_text_select.tsx index 86d1758932301..682279d5639e5 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/field_text_select.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/field_text_select.tsx @@ -37,7 +37,7 @@ export const FieldTextSelect = ({ useDebounce( () => { - if (inputValue !== indexPatternString) { + if ((inputValue ?? '') !== (indexPatternString ?? '')) { onIndexChange(inputValue); } }, diff --git a/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx index 1029ac67cc43c..0c63fddc440fe 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx @@ -108,7 +108,7 @@ export const IndexPatternSelect = ({ defaultIndexPatternHelpText + (!useKibanaIndices ? queryAllIndexesHelpText : '') } labelAppend={ - fetchedIndex.indexPatternString && !fetchedIndex.indexPattern ? ( + !useKibanaIndices && fetchedIndex.indexPatternString && !fetchedIndex.indexPattern ? ( ({ help: '', }, }, - async fn(input, args, { getSearchSessionId, isSyncColorsEnabled, getExecutionContext }) { + async fn( + input, + args, + { getSearchSessionId, isSyncColorsEnabled, getExecutionContext, inspectorAdapters } + ) { const visParams: TimeseriesVisParams = JSON.parse(args.params); const uiState = JSON.parse(args.uiState); const syncColors = isSyncColorsEnabled?.() ?? false; @@ -65,6 +69,7 @@ export const createMetricsFn = (): TimeseriesExpressionFunctionDefinition => ({ uiState, searchSessionId: getSearchSessionId(), executionContext: getExecutionContext(), + inspectorAdapters, }); return { diff --git a/src/plugins/vis_types/timeseries/public/metrics_type.ts b/src/plugins/vis_types/timeseries/public/metrics_type.ts index 30474758e2799..505f8f88d38fe 100644 --- a/src/plugins/vis_types/timeseries/public/metrics_type.ts +++ b/src/plugins/vis_types/timeseries/public/metrics_type.ts @@ -22,6 +22,7 @@ import { } from '../../../visualizations/public'; import { getDataStart } from './services'; import type { TimeseriesVisDefaultParams, TimeseriesVisParams } from './types'; +import { RequestAdapter } from '../../../inspector/public'; export const withReplacedIds = ( vis: Vis @@ -118,7 +119,9 @@ export const metricsVisDefinition: VisTypeDefinition< } return []; }, - inspectorAdapters: {}, + inspectorAdapters: () => ({ + requests: new RequestAdapter(), + }), requiresSearch: true, getUsedIndexPattern: async (params: VisParams) => { const { indexPatterns } = getDataStart(); diff --git a/src/plugins/vis_types/timeseries/public/request_handler.ts b/src/plugins/vis_types/timeseries/public/request_handler.ts index e9037c0b84a5e..94e370233778a 100644 --- a/src/plugins/vis_types/timeseries/public/request_handler.ts +++ b/src/plugins/vis_types/timeseries/public/request_handler.ts @@ -6,13 +6,14 @@ * Side Public License, v 1. */ import type { KibanaExecutionContext } from 'src/core/public'; +import type { Adapters } from 'src/plugins/inspector'; import { getTimezone } from './application/lib/get_timezone'; import { getUISettings, getDataStart, getCoreStart } from './services'; -import { ROUTES } from '../common/constants'; +import { ROUTES, ALLOW_CHECKING_FOR_FAILED_SHARDS } from '../common/constants'; +import { KibanaContext, handleResponse } from '../../../data/public'; import type { TimeseriesVisParams } from './types'; import type { TimeseriesVisData } from '../common/types'; -import type { KibanaContext } from '../../../data/public'; interface MetricsRequestHandlerParams { input: KibanaContext | null; @@ -20,6 +21,7 @@ interface MetricsRequestHandlerParams { visParams: TimeseriesVisParams; searchSessionId?: string; executionContext?: KibanaExecutionContext; + inspectorAdapters?: Adapters; } export const metricsRequestHandler = async ({ @@ -28,6 +30,7 @@ export const metricsRequestHandler = async ({ visParams, searchSessionId, executionContext, + inspectorAdapters, }: MetricsRequestHandlerParams): Promise => { const config = getUISettings(); const data = getDataStart(); @@ -48,7 +51,8 @@ export const metricsRequestHandler = async ({ try { const searchSessionOptions = dataSearch.session.getSearchOptions(searchSessionId); - return await getCoreStart().http.post(ROUTES.VIS_DATA, { + + const visData: TimeseriesVisData = await getCoreStart().http.post(ROUTES.VIS_DATA, { body: JSON.stringify({ timerange: { timezone, @@ -64,6 +68,21 @@ export const metricsRequestHandler = async ({ }), context: executionContext, }); + + inspectorAdapters?.requests?.reset(); + + Object.entries(visData.trackedEsSearches || {}).forEach(([key, query]) => { + inspectorAdapters?.requests + ?.start(query.label ?? key, { searchSessionId }) + .json(query.body) + .ok({ time: query.time }); + + if (query.response && config.get(ALLOW_CHECKING_FOR_FAILED_SHARDS)) { + handleResponse({ body: query.body }, { rawResponse: query.response }); + } + }); + + return visData; } finally { if (untrackSearch && dataSearch.session.isCurrentSession(searchSessionId)) { // untrack if this search still belongs to current session diff --git a/src/plugins/vis_types/timeseries/server/lib/search_strategies/index.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/index.ts index ca0c50a79564a..721e1dad473f0 100644 --- a/src/plugins/vis_types/timeseries/server/lib/search_strategies/index.ts +++ b/src/plugins/vis_types/timeseries/server/lib/search_strategies/index.ts @@ -11,6 +11,7 @@ import { AbstractSearchStrategy } from './strategies'; export { SearchStrategyRegistry } from './search_strategy_registry'; export { AbstractSearchStrategy, RollupSearchStrategy, DefaultSearchStrategy } from './strategies'; +export type { EsSearchRequest } from './strategies/abstract_search_strategy'; export type SearchCapabilities = DefaultSearchCapabilities; export type SearchStrategy = AbstractSearchStrategy; diff --git a/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts index 6216bce00fc7d..1a52132612f71 100644 --- a/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts +++ b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.test.ts @@ -9,7 +9,7 @@ import { IndexPatternsService } from '../../../../../../data/common'; import { from } from 'rxjs'; -import { AbstractSearchStrategy } from './abstract_search_strategy'; +import { AbstractSearchStrategy, EsSearchRequest } from './abstract_search_strategy'; import type { FieldSpec } from '../../../../../../data/common'; import type { CachedIndexPatternFetcher } from '../lib/cached_index_pattern_fetcher'; import type { @@ -64,7 +64,7 @@ describe('AbstractSearchStrategy', () => { }); test('should return response', async () => { - const searches = [{ body: 'body', index: 'index' }]; + const searches: EsSearchRequest[] = [{ body: {}, index: 'index' }]; const responses = await abstractSearchStrategy.search( requestContext, @@ -84,7 +84,7 @@ describe('AbstractSearchStrategy', () => { expect(requestContext.search.search).toHaveBeenCalledWith( { params: { - body: 'body', + body: {}, index: 'index', }, indexType: undefined, diff --git a/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts index bce07d2cdb300..1d3650ccedbd3 100644 --- a/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts +++ b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts @@ -6,40 +6,67 @@ * Side Public License, v 1. */ +import { tap } from 'rxjs/operators'; +import { omit } from 'lodash'; import { IndexPatternsService } from '../../../../../../data/server'; import { toSanitizedFieldType } from '../../../../common/fields_utils'; -import type { FetchedIndexPattern } from '../../../../common/types'; +import type { FetchedIndexPattern, TrackedEsSearches } from '../../../../common/types'; import type { VisTypeTimeseriesRequest, VisTypeTimeseriesRequestHandlerContext, VisTypeTimeseriesVisDataRequest, } from '../../../types'; +export interface EsSearchRequest { + body: Record; + index?: string; + trackingEsSearchMeta?: { + requestId: string; + requestLabel?: string; + }; +} + export abstract class AbstractSearchStrategy { async search( requestContext: VisTypeTimeseriesRequestHandlerContext, req: VisTypeTimeseriesVisDataRequest, - bodies: any[], + esRequests: EsSearchRequest[], + trackedEsSearches?: TrackedEsSearches, indexType?: string ) { const requests: any[] = []; - bodies.forEach((body) => { + esRequests.forEach(({ body, index, trackingEsSearchMeta }) => { + const startTime = Date.now(); requests.push( requestContext.search .search( { indexType, params: { - ...body, + body, + index, }, }, req.body.searchSession ) + .pipe( + tap((data) => { + if (trackingEsSearchMeta?.requestId && trackedEsSearches) { + trackedEsSearches[trackingEsSearchMeta.requestId] = { + body, + time: Date.now() - startTime, + label: trackingEsSearchMeta.requestLabel, + response: omit(data.rawResponse, 'aggregations'), + }; + } + }) + ) .toPromise() ); }); + return Promise.all(requests); } diff --git a/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts index 903e7f239f824..ef665b176be42 100644 --- a/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts +++ b/src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/rollup_search_strategy.ts @@ -10,10 +10,10 @@ import { getCapabilitiesForRollupIndices, IndexPatternsService, } from '../../../../../../data/server'; -import { AbstractSearchStrategy } from './abstract_search_strategy'; +import { AbstractSearchStrategy, EsSearchRequest } from './abstract_search_strategy'; import { RollupSearchCapabilities } from '../capabilities/rollup_search_capabilities'; -import type { FetchedIndexPattern } from '../../../../common/types'; +import type { FetchedIndexPattern, TrackedEsSearches } from '../../../../common/types'; import type { CachedIndexPatternFetcher } from '../lib/cached_index_pattern_fetcher'; import type { VisTypeTimeseriesRequest, @@ -29,9 +29,10 @@ export class RollupSearchStrategy extends AbstractSearchStrategy { async search( requestContext: VisTypeTimeseriesRequestHandlerContext, req: VisTypeTimeseriesVisDataRequest, - bodies: any[] + esRequests: EsSearchRequest[], + trackedEsSearches?: TrackedEsSearches ) { - return super.search(requestContext, req, bodies, 'rollup'); + return super.search(requestContext, req, esRequests, trackedEsSearches, 'rollup'); } async getRollupData( diff --git a/src/plugins/vis_types/timeseries/server/lib/vis_data/annotations/get_request_params.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/annotations/get_request_params.ts index 1973e3b85b966..41f7e7c86708f 100644 --- a/src/plugins/vis_types/timeseries/server/lib/vis_data/annotations/get_request_params.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/annotations/get_request_params.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - +import { i18n } from '@kbn/i18n'; import type { Annotation, Panel } from '../../../../common/types'; import { buildAnnotationRequest } from './build_request_body'; import type { @@ -13,7 +13,7 @@ import type { VisTypeTimeseriesRequestServices, VisTypeTimeseriesVisDataRequest, } from '../../../types'; -import type { SearchStrategy, SearchCapabilities } from '../../search_strategies'; +import type { SearchStrategy, SearchCapabilities, EsSearchRequest } from '../../search_strategies'; export type AnnotationServices = VisTypeTimeseriesRequestServices & { capabilities: SearchCapabilities; @@ -32,7 +32,7 @@ export async function getAnnotationRequestParams( uiSettings, cachedIndexPatternFetcher, }: AnnotationServices -) { +): Promise { const annotationIndex = await cachedIndexPatternFetcher(annotation.index_pattern); const request = await buildAnnotationRequest({ @@ -52,5 +52,14 @@ export async function getAnnotationRequestParams( runtime_mappings: annotationIndex.indexPattern?.getComputedFields().runtimeFields ?? {}, timeout: esShardTimeout > 0 ? `${esShardTimeout}ms` : undefined, }, + trackingEsSearchMeta: { + requestId: annotation.id, + requestLabel: i18n.translate('visTypeTimeseries.annotationRequest.label', { + defaultMessage: 'Annotation: {id}', + values: { + id: annotation.id, + }, + }), + }, }; } diff --git a/src/plugins/vis_types/timeseries/server/lib/vis_data/get_annotations.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_annotations.ts index 8a005deccaea9..481ddc7891817 100644 --- a/src/plugins/vis_types/timeseries/server/lib/vis_data/get_annotations.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_annotations.ts @@ -10,8 +10,7 @@ import { handleAnnotationResponse } from './response_processors/annotations'; import { AnnotationServices, getAnnotationRequestParams } from './annotations/get_request_params'; import { getLastSeriesTimestamp } from './helpers/timestamp'; import type { VisTypeTimeseriesVisDataRequest } from '../../types'; -import type { Annotation, Panel } from '../../../common/types'; -import type { PanelSeries } from '../../../common/types/vis_data'; +import type { Annotation, Panel, TrackedEsSearches, PanelSeries } from '../../../common/types'; function validAnnotation(annotation: Annotation) { return annotation.fields && annotation.icon && annotation.template && !annotation.hidden; @@ -22,26 +21,33 @@ interface GetAnnotationsParams { panel: Panel; series: Array; services: AnnotationServices; + trackedEsSearches: TrackedEsSearches; } -export async function getAnnotations({ req, panel, series, services }: GetAnnotationsParams) { +export async function getAnnotations({ + req, + panel, + series, + services, + trackedEsSearches, +}: GetAnnotationsParams) { const annotations = panel.annotations!.filter(validAnnotation); const lastSeriesTimestamp = getLastSeriesTimestamp(series); const handleAnnotationResponseBy = handleAnnotationResponse(lastSeriesTimestamp); - const bodiesPromises = annotations.map((annotation) => - getAnnotationRequestParams(req, panel, annotation, services) - ); - - const searches = (await Promise.all(bodiesPromises)).reduce( - (acc, items) => acc.concat(items as any), - [] + const searches = await Promise.all( + annotations.map((annotation) => getAnnotationRequestParams(req, panel, annotation, services)) ); if (!searches.length) return { responses: [] }; try { - const data = await services.searchStrategy.search(services.requestContext, req, searches); + const data = await services.searchStrategy.search( + services.requestContext, + req, + searches, + trackedEsSearches + ); return annotations.reduce((acc, annotation, index) => { acc[annotation.id] = handleAnnotationResponseBy(data[index].rawResponse, annotation); diff --git a/src/plugins/vis_types/timeseries/server/lib/vis_data/get_series_data.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_series_data.ts index 3428124033acf..82ad8f75e2541 100644 --- a/src/plugins/vis_types/timeseries/server/lib/vis_data/get_series_data.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_series_data.ts @@ -20,7 +20,7 @@ import type { VisTypeTimeseriesVisDataRequest, VisTypeTimeseriesRequestServices, } from '../../types'; -import type { Panel } from '../../../common/types'; +import type { Panel, DataResponseMeta } from '../../../common/types'; import { PANEL_TYPES } from '../../../common/enums'; export async function getSeriesData( @@ -49,13 +49,14 @@ export async function getSeriesData( } const { searchStrategy, capabilities } = strategy; - const meta = { + const handleError = handleErrorResponse(panel); + + const meta: DataResponseMeta = { type: panel.type, uiRestrictions: capabilities.uiRestrictions, + trackedEsSearches: {}, }; - const handleError = handleErrorResponse(panel); - try { const bodiesPromises = getActiveSeries(panel).map((series) => { if (isEntireTimeRangeMode(panel, series)) { @@ -80,7 +81,7 @@ export async function getSeriesData( ); const searches = await Promise.all(bodiesPromises); - const data = await searchStrategy.search(requestContext, req, searches); + const data = await searchStrategy.search(requestContext, req, searches, meta.trackedEsSearches); const series = await Promise.all( data.map( @@ -101,6 +102,7 @@ export async function getSeriesData( searchStrategy, capabilities, }, + trackedEsSearches: meta.trackedEsSearches, }); } diff --git a/src/plugins/vis_types/timeseries/server/lib/vis_data/get_table_data.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_table_data.ts index e604f7473ce69..54acb55e79fc5 100644 --- a/src/plugins/vis_types/timeseries/server/lib/vis_data/get_table_data.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/get_table_data.ts @@ -23,7 +23,8 @@ import type { VisTypeTimeseriesRequestServices, VisTypeTimeseriesVisDataRequest, } from '../../types'; -import type { Panel } from '../../../common/types'; +import type { Panel, DataResponseMeta } from '../../../common/types'; +import type { EsSearchRequest } from '../search_strategies'; export async function getTableData( requestContext: VisTypeTimeseriesRequestHandlerContext, @@ -65,11 +66,11 @@ export async function getTableData( return panel.pivot_id; }; - const meta = { + const meta: DataResponseMeta = { type: panel.type, uiRestrictions: capabilities.uiRestrictions, + trackedEsSearches: {}, }; - const handleError = handleErrorResponse(panel); try { @@ -79,29 +80,38 @@ export async function getTableData( }); } - const body = await buildTableRequest({ - req, - panel, - esQueryConfig: services.esQueryConfig, - seriesIndex: panelIndex, - capabilities, - uiSettings: services.uiSettings, - buildSeriesMetaParams: () => - services.buildSeriesMetaParams(panelIndex, Boolean(panel.use_kibana_indexes)), - }); - - const [resp] = await searchStrategy.search(requestContext, req, [ + const searches: EsSearchRequest[] = [ { + index: panelIndex.indexPatternString, body: { - ...body, + ...(await buildTableRequest({ + req, + panel, + esQueryConfig: services.esQueryConfig, + seriesIndex: panelIndex, + capabilities, + uiSettings: services.uiSettings, + buildSeriesMetaParams: () => + services.buildSeriesMetaParams(panelIndex, Boolean(panel.use_kibana_indexes)), + })), runtime_mappings: panelIndex.indexPattern?.getComputedFields().runtimeFields ?? {}, }, - index: panelIndex.indexPatternString, + trackingEsSearchMeta: { + requestId: panel.id, + requestLabel: i18n.translate('visTypeTimeseries.tableRequest.label', { + defaultMessage: 'Table: {id}', + values: { + id: panel.id, + }, + }), + }, }, - ]); + ]; + + const data = await searchStrategy.search(requestContext, req, searches, meta.trackedEsSearches); const buckets = get( - resp.rawResponse ? resp.rawResponse : resp, + data[0].rawResponse ? data[0].rawResponse : data[0], 'aggregations.pivot.buckets', [] ); diff --git a/src/plugins/vis_types/timeseries/server/lib/vis_data/series/get_request_params.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/series/get_request_params.ts index 046b207050ca0..d176eb8b99392 100644 --- a/src/plugins/vis_types/timeseries/server/lib/vis_data/series/get_request_params.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/series/get_request_params.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - +import { i18n } from '@kbn/i18n'; import { buildRequestBody } from './build_request_body'; import type { FetchedIndexPattern, Panel, Series } from '../../../../common/types'; @@ -13,7 +13,7 @@ import type { VisTypeTimeseriesRequestServices, VisTypeTimeseriesVisDataRequest, } from '../../../types'; -import type { SearchCapabilities } from '../../search_strategies'; +import type { SearchCapabilities, EsSearchRequest } from '../../search_strategies'; export async function getSeriesRequestParams( req: VisTypeTimeseriesVisDataRequest, @@ -28,7 +28,7 @@ export async function getSeriesRequestParams( cachedIndexPatternFetcher, buildSeriesMetaParams, }: VisTypeTimeseriesRequestServices -) { +): Promise { let seriesIndex = panelIndex; if (series.override_index_pattern) { @@ -53,5 +53,14 @@ export async function getSeriesRequestParams( runtime_mappings: seriesIndex.indexPattern?.getComputedFields().runtimeFields ?? {}, timeout: esShardTimeout > 0 ? `${esShardTimeout}ms` : undefined, }, + trackingEsSearchMeta: { + requestId: series.id, + requestLabel: i18n.translate('visTypeTimeseries.seriesRequest.label', { + defaultMessage: 'Series: {id}', + values: { + id: series.id, + }, + }), + }, }; } diff --git a/src/plugins/vis_types/timeseries/server/ui_settings.ts b/src/plugins/vis_types/timeseries/server/ui_settings.ts index e61635058cee0..5bee1bd08e211 100644 --- a/src/plugins/vis_types/timeseries/server/ui_settings.ts +++ b/src/plugins/vis_types/timeseries/server/ui_settings.ts @@ -11,7 +11,7 @@ import { schema } from '@kbn/config-schema'; import { UiSettingsParams } from 'kibana/server'; -import { MAX_BUCKETS_SETTING } from '../common/constants'; +import { MAX_BUCKETS_SETTING, ALLOW_CHECKING_FOR_FAILED_SHARDS } from '../common/constants'; export const getUiSettings: () => Record = () => ({ [MAX_BUCKETS_SETTING]: { @@ -25,4 +25,18 @@ export const getUiSettings: () => Record = () => ({ }), schema: schema.number(), }, + [ALLOW_CHECKING_FOR_FAILED_SHARDS]: { + name: i18n.translate('visTypeTimeseries.advancedSettings.allowCheckingForFailedShardsTitle', { + defaultMessage: 'Show TSVB request shard failures', + }), + value: true, + description: i18n.translate( + 'visTypeTimeseries.advancedSettings.allowCheckingForFailedShardsText', + { + defaultMessage: + 'Show warning message for partial data in TSVB charts if the request succeeds for some shards but fails for others.', + } + ), + schema: schema.boolean(), + }, }); diff --git a/test/functional/apps/visualize/_tsvb_chart.ts b/test/functional/apps/visualize/_tsvb_chart.ts index ae18874491288..1759b07581e07 100644 --- a/test/functional/apps/visualize/_tsvb_chart.ts +++ b/test/functional/apps/visualize/_tsvb_chart.ts @@ -51,8 +51,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visualBuilder.clickDataTab('metric'); }); - it('should not have inspector enabled', async () => { - await inspector.expectIsNotEnabled(); + it('should have inspector enabled', async () => { + await inspector.expectIsEnabled(); }); it('should show correct data', async () => { diff --git a/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts index 730da9511dc38..a61697bd23c86 100644 --- a/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts @@ -6,8 +6,8 @@ */ import { i18n } from '@kbn/i18n'; -import { flatten, get } from 'lodash'; import { KibanaRequest } from 'src/core/server'; +import { flatten, get } from 'lodash'; import { NodeDetailsMetricData } from '../../../../common/http_api/node_details_api'; import { KibanaFramework } from '../framework/kibana_framework_adapter'; import { InfraMetricsAdapter, InfraMetricsRequestOptions } from './adapter_types'; @@ -62,7 +62,7 @@ export class KibanaMetricsAdapter implements InfraMetricsAdapter { .then((results) => { return results.filter(isVisSeriesData).map((result) => { const metricIds = Object.keys(result).filter( - (k) => !['type', 'uiRestrictions'].includes(k) + (k) => !['type', 'uiRestrictions', 'trackedEsSearches'].includes(k) ); return metricIds.map((id: string) => {