From 284037b6d533cd2f73715cdb2335e06334971683 Mon Sep 17 00:00:00 2001 From: Jason Woods Date: Sun, 16 Feb 2020 11:50:27 +0000 Subject: [PATCH] Utilise index in log item flyout to prevent scanning of all available indices on getLogItem which can bring down small clusters --- .../graphql/shared/fragments.gql_query.ts | 1 + x-pack/plugins/infra/common/graphql/types.ts | 6 ++++ .../common/http_api/log_entries/entries.ts | 1 + .../infra/common/http_api/log_entries/item.ts | 1 + .../logging/log_text_stream/log_entry_row.tsx | 5 +-- .../scrollable_log_text_stream_view.tsx | 6 ++-- .../containers/logs/log_entries/types.ts | 2 ++ .../public/containers/logs/log_flyout.tsx | 36 +++++++++++-------- .../infra/public/graphql/introspection.json | 12 +++++++ x-pack/plugins/infra/public/graphql/types.ts | 6 ++++ .../pages/logs/stream/page_logs_content.tsx | 4 +-- x-pack/plugins/infra/server/graphql/types.ts | 9 +++++ .../log_entries/kibana_log_entries_adapter.ts | 4 ++- .../log_entries_domain/log_entries_domain.ts | 5 ++- .../infra/server/routes/log_entries/item.ts | 9 +++-- 15 files changed, 81 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/infra/common/graphql/shared/fragments.gql_query.ts b/x-pack/plugins/infra/common/graphql/shared/fragments.gql_query.ts index c324813b65efb..615f5d211121f 100644 --- a/x-pack/plugins/infra/common/graphql/shared/fragments.gql_query.ts +++ b/x-pack/plugins/infra/common/graphql/shared/fragments.gql_query.ts @@ -24,6 +24,7 @@ export const sharedFragments = { InfraLogEntryFields: gql` fragment InfraLogEntryFields on InfraLogEntry { gid + index key { time tiebreaker diff --git a/x-pack/plugins/infra/common/graphql/types.ts b/x-pack/plugins/infra/common/graphql/types.ts index bb089bf8bf8ad..4f9c211ec9357 100644 --- a/x-pack/plugins/infra/common/graphql/types.ts +++ b/x-pack/plugins/infra/common/graphql/types.ts @@ -159,6 +159,8 @@ export interface InfraLogEntry { key: InfraTimeKey; /** The log entry's id */ gid: string; + /** The log entry's index */ + index: string; /** The source id */ source: string; /** The columns used for rendering the log entry */ @@ -993,6 +995,8 @@ export namespace InfraLogEntryFields { gid: string; + index: string; + key: Key; columns: Columns[]; @@ -1062,6 +1066,8 @@ export namespace InfraLogEntryHighlightFields { gid: string; + index: string; + key: Key; columns: Columns[]; diff --git a/x-pack/plugins/infra/common/http_api/log_entries/entries.ts b/x-pack/plugins/infra/common/http_api/log_entries/entries.ts index d532c079e3e9c..a3b83bc159de3 100644 --- a/x-pack/plugins/infra/common/http_api/log_entries/entries.ts +++ b/x-pack/plugins/infra/common/http_api/log_entries/entries.ts @@ -76,6 +76,7 @@ export const logColumnRT = rt.union([logTimestampColumnRT, logFieldColumnRT, log export const logEntryRT = rt.type({ id: rt.string, + index: rt.string, cursor: logEntriesCursorRT, columns: rt.array(logColumnRT), context: rt.partial({ diff --git a/x-pack/plugins/infra/common/http_api/log_entries/item.ts b/x-pack/plugins/infra/common/http_api/log_entries/item.ts index 02335d68402c0..7d6e7021bbd17 100644 --- a/x-pack/plugins/infra/common/http_api/log_entries/item.ts +++ b/x-pack/plugins/infra/common/http_api/log_entries/item.ts @@ -12,6 +12,7 @@ export const LOG_ENTRIES_ITEM_PATH = '/api/log_entries/item'; export const logEntriesItemRequestRT = rt.type({ sourceId: rt.string, id: rt.string, + index: rt.string, }); export type LogEntriesItemRequest = rt.TypeOf; diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx index 7d7df796d13ad..7d1003e6695c4 100644 --- a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_row.tsx @@ -31,7 +31,7 @@ interface LogEntryRowProps { isActiveHighlight: boolean; isHighlighted: boolean; logEntry: LogEntry; - openFlyoutWithItem?: (id: string) => void; + openFlyoutWithItem?: (id: string, index: string) => void; scale: TextScale; wrap: boolean; } @@ -58,9 +58,10 @@ export const LogEntryRow = memo( const setItemIsHovered = useCallback(() => setIsHovered(true), []); const setItemIsNotHovered = useCallback(() => setIsHovered(false), []); - const openFlyout = useCallback(() => openFlyoutWithItem?.(logEntry.id), [ + const openFlyout = useCallback(() => openFlyoutWithItem?.(logEntry.id, logEntry.index), [ openFlyoutWithItem, logEntry.id, + logEntry.index, ]); const logEntryColumnsById = useMemo( diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx index 2c389b47fa6cf..6153be1de2a15 100644 --- a/x-pack/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx @@ -50,7 +50,7 @@ interface ScrollableLogTextStreamViewProps { }) => any; loadNewerItems: () => void; reloadItems: () => void; - setFlyoutItem: (id: string) => void; + setFlyoutRef: (ref: { id: string; index: string }) => void; setFlyoutVisibility: (visible: boolean) => void; highlightedItem: string | null; currentHighlightKey: UniqueTimeKey | null; @@ -286,8 +286,8 @@ export class ScrollableLogTextStreamView extends React.PureComponent< ); } - private handleOpenFlyout = (id: string) => { - this.props.setFlyoutItem(id); + private handleOpenFlyout = (id: string, index: string) => { + this.props.setFlyoutRef({ id, index }); this.props.setFlyoutVisibility(true); }; diff --git a/x-pack/plugins/infra/public/containers/logs/log_entries/types.ts b/x-pack/plugins/infra/public/containers/logs/log_entries/types.ts index 75aea8c415eee..c216cfb3c5de3 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_entries/types.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_entries/types.ts @@ -68,6 +68,8 @@ export interface InfraLogEntry { key: InfraTimeKey; /** The log entry's id */ gid: string; + /** The log entry's index */ + index: string; /** The source id */ source: string; /** The columns used for rendering the log entry */ diff --git a/x-pack/plugins/infra/public/containers/logs/log_flyout.tsx b/x-pack/plugins/infra/public/containers/logs/log_flyout.tsx index 267abe631c142..d750b02d975fc 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_flyout.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_flyout.tsx @@ -21,6 +21,7 @@ export enum FlyoutVisibility { export interface FlyoutOptionsUrlState { flyoutId?: string | null; + flyoutIndex?: string | null; flyoutVisibility?: string | null; surroundingLogsId?: string | null; } @@ -28,7 +29,7 @@ export interface FlyoutOptionsUrlState { export const useLogFlyout = () => { const { sourceId } = useContext(Source.Context); const [flyoutVisible, setFlyoutVisibility] = useState(false); - const [flyoutId, setFlyoutId] = useState(null); + const [flyoutRef, setFlyoutRef] = useState<{ id: string; index: string } | null>(null); const [flyoutItem, setFlyoutItem] = useState(null); const [surroundingLogsId, setSurroundingLogsId] = useState(null); @@ -36,10 +37,10 @@ export const useLogFlyout = () => { { cancelPreviousOn: 'creation', createPromise: async () => { - if (!flyoutId) { + if (!flyoutRef) { return; } - return await fetchLogEntriesItem({ sourceId, id: flyoutId }); + return await fetchLogEntriesItem({ sourceId, id: flyoutRef.id, index: flyoutRef.index }); }, onResolve: response => { if (response) { @@ -48,7 +49,7 @@ export const useLogFlyout = () => { } }, }, - [sourceId, flyoutId] + [sourceId, flyoutRef] ); const isLoading = useMemo(() => { @@ -56,16 +57,16 @@ export const useLogFlyout = () => { }, [loadFlyoutItemRequest.state]); useEffect(() => { - if (flyoutId) { + if (flyoutRef) { loadFlyoutItem(); } - }, [loadFlyoutItem, flyoutId]); + }, [loadFlyoutItem, flyoutRef]); return { flyoutVisible, setFlyoutVisibility, - flyoutId, - setFlyoutId, + flyoutRef, + setFlyoutRef, surroundingLogsId, setSurroundingLogsId, isLoading, @@ -79,8 +80,8 @@ export const WithFlyoutOptionsUrlState = () => { const { flyoutVisible, setFlyoutVisibility, - flyoutId, - setFlyoutId, + flyoutRef, + setFlyoutRef, surroundingLogsId, setSurroundingLogsId, } = useContext(LogFlyout.Context); @@ -89,14 +90,15 @@ export const WithFlyoutOptionsUrlState = () => { { - if (newUrlState && newUrlState.flyoutId) { - setFlyoutId(newUrlState.flyoutId); + if (newUrlState && newUrlState.flyoutId && newUrlState.flyoutIndex) { + setFlyoutRef({ id: newUrlState.flyoutId, index: newUrlState.flyoutIndex }); } if (newUrlState && newUrlState.surroundingLogsId) { setSurroundingLogsId(newUrlState.surroundingLogsId); @@ -109,8 +111,8 @@ export const WithFlyoutOptionsUrlState = () => { } }} onInitialize={initialUrlState => { - if (initialUrlState && initialUrlState.flyoutId) { - setFlyoutId(initialUrlState.flyoutId); + if (initialUrlState && initialUrlState.flyoutId && initialUrlState.flyoutIndex) { + setFlyoutRef({ id: initialUrlState.flyoutId, index: initialUrlState.flyoutIndex }); } if (initialUrlState && initialUrlState.surroundingLogsId) { setSurroundingLogsId(initialUrlState.surroundingLogsId); @@ -130,6 +132,7 @@ const mapToUrlState = (value: any): FlyoutOptionsUrlState | undefined => value ? { flyoutId: mapToFlyoutIdState(value.flyoutId), + flyoutIndex: mapToFlyoutIndexState(value.flyoutIndex), flyoutVisibility: mapToFlyoutVisibilityState(value.flyoutVisibility), surroundingLogsId: mapToSurroundingLogsIdState(value.surroundingLogsId), } @@ -138,6 +141,9 @@ const mapToUrlState = (value: any): FlyoutOptionsUrlState | undefined => const mapToFlyoutIdState = (subject: any) => { return subject && isString(subject) ? subject : undefined; }; +const mapToFlyoutIndexState = (subject: any) => { + return subject && isString(subject) ? subject : undefined; +}; const mapToSurroundingLogsIdState = (subject: any) => { return subject && isString(subject) ? subject : undefined; }; diff --git a/x-pack/plugins/infra/public/graphql/introspection.json b/x-pack/plugins/infra/public/graphql/introspection.json index 5d351f3259ac5..370ea5a1bdbfb 100644 --- a/x-pack/plugins/infra/public/graphql/introspection.json +++ b/x-pack/plugins/infra/public/graphql/introspection.json @@ -1185,6 +1185,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "index", + "description": "The log entry's index", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "source", "description": "The source id", diff --git a/x-pack/plugins/infra/public/graphql/types.ts b/x-pack/plugins/infra/public/graphql/types.ts index 79351d8dc16cd..5b71128cfb36d 100644 --- a/x-pack/plugins/infra/public/graphql/types.ts +++ b/x-pack/plugins/infra/public/graphql/types.ts @@ -161,6 +161,8 @@ export interface InfraLogEntry { key: InfraTimeKey; /** The log entry's id */ gid: string; + /** The log entry's index */ + index: string; /** The source id */ source: string; /** The columns used for rendering the log entry */ @@ -995,6 +997,8 @@ export namespace InfraLogEntryFields { gid: string; + index: string; + key: Key; columns: Columns[]; @@ -1064,6 +1068,8 @@ export namespace InfraLogEntryHighlightFields { gid: string; + index: string; + key: Key; columns: Columns[]; diff --git a/x-pack/plugins/infra/public/pages/logs/stream/page_logs_content.tsx b/x-pack/plugins/infra/public/pages/logs/stream/page_logs_content.tsx index b6061203a1c72..65aff37b9b430 100644 --- a/x-pack/plugins/infra/public/pages/logs/stream/page_logs_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/stream/page_logs_content.tsx @@ -34,7 +34,7 @@ export const LogsPageLogsContent: React.FunctionComponent = () => { const { setFlyoutVisibility, flyoutVisible, - setFlyoutId, + setFlyoutRef, surroundingLogsId, setSurroundingLogsId, flyoutItem, @@ -102,7 +102,7 @@ export const LogsPageLogsContent: React.FunctionComponent = () => { scale={textScale} target={targetPosition} wrap={textWrap} - setFlyoutItem={setFlyoutId} + setFlyoutRef={setFlyoutRef} setFlyoutVisibility={setFlyoutVisibility} highlightedItem={surroundingLogsId ? surroundingLogsId : null} currentHighlightKey={currentHighlightKey} diff --git a/x-pack/plugins/infra/server/graphql/types.ts b/x-pack/plugins/infra/server/graphql/types.ts index 1d6b03ac7bffb..9e8efb2d786ee 100644 --- a/x-pack/plugins/infra/server/graphql/types.ts +++ b/x-pack/plugins/infra/server/graphql/types.ts @@ -187,6 +187,8 @@ export interface InfraLogEntry { key: InfraTimeKey; /** The log entry's id */ gid: string; + /** The log entry's index */ + index: string; /** The source id */ source: string; /** The columns used for rendering the log entry */ @@ -1137,6 +1139,8 @@ export namespace InfraLogEntryResolvers { key?: KeyResolver; /** The log entry's id */ gid?: GidResolver; + /** The log entry's index */ + index?: IndexResolver; /** The source id */ source?: SourceResolver; /** The columns used for rendering the log entry */ @@ -1153,6 +1157,11 @@ export namespace InfraLogEntryResolvers { Parent, Context >; + export type IndexResolver = Resolver< + R, + Parent, + Context + >; export type SourceResolver = Resolver< R, Parent, diff --git a/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts index b8513541be7ae..7b2d16a8405e2 100644 --- a/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts @@ -195,13 +195,14 @@ export class InfraKibanaLogEntriesAdapter implements LogEntriesAdapter { public async getLogItem( requestContext: RequestHandlerContext, id: string, + index: string, sourceConfiguration: InfraSourceConfiguration ) { const search = (searchOptions: object) => this.framework.callWithRequest(requestContext, 'search', searchOptions); const params = { - index: sourceConfiguration.logAlias, + index, terminate_after: 1, body: { size: 1, @@ -240,6 +241,7 @@ function mapHitsToLogEntryDocuments(hits: SortedSearchHit[], fields: string[]): return { id: hit._id, + index: hit._index, cursor: { time: hit.sort[0], tiebreaker: hit.sort[1] }, fields: logFields, highlights: hit.highlight || {}, diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts index 528b9a69327fa..b8ba43a47a00a 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts @@ -242,9 +242,10 @@ export class InfraLogEntriesDomain { public async getLogItem( requestContext: RequestHandlerContext, id: string, + index: string, sourceConfiguration: InfraSourceConfiguration ): Promise { - const document = await this.adapter.getLogItem(requestContext, id, sourceConfiguration); + const document = await this.adapter.getLogItem(requestContext, id, index, sourceConfiguration); const defaultFields = [ { field: '_index', value: document._index }, { field: '_id', value: document._id }, @@ -292,6 +293,7 @@ export interface LogEntriesAdapter { getLogItem( requestContext: RequestHandlerContext, id: string, + index: string, source: InfraSourceConfiguration ): Promise; } @@ -300,6 +302,7 @@ export type LogEntryQuery = JsonObject; export interface LogEntryDocument { id: string; + index: string; fields: Fields; highlights: Highlights; cursor: LogEntriesCursor; diff --git a/x-pack/plugins/infra/server/routes/log_entries/item.ts b/x-pack/plugins/infra/server/routes/log_entries/item.ts index 3a6bdaf3804e3..adb8b97c59d17 100644 --- a/x-pack/plugins/infra/server/routes/log_entries/item.ts +++ b/x-pack/plugins/infra/server/routes/log_entries/item.ts @@ -36,11 +36,16 @@ export const initLogEntriesItemRoute = ({ framework, sources, logEntries }: Infr fold(throwErrors(Boom.badRequest), identity) ); - const { id, sourceId } = payload; + const { id, index, sourceId } = payload; const sourceConfiguration = (await sources.getSourceConfiguration(requestContext, sourceId)) .configuration; - const logEntry = await logEntries.getLogItem(requestContext, id, sourceConfiguration); + const logEntry = await logEntries.getLogItem( + requestContext, + id, + index, + sourceConfiguration + ); return response.ok({ body: logEntriesItemResponseRT.encode({