Skip to content

Commit f06a166

Browse files
Merge branch 'main' into controls/range-slider
2 parents ea0ee1d + 1daa7ee commit f06a166

41 files changed

Lines changed: 956 additions & 318 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

x-pack/plugins/alerting/server/usage/alerting_telemetry.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,16 @@ Object {
151151
'logs.alert.document.count': 1675765,
152152
'document.test.': 17687687,
153153
},
154+
ruleTypesEsSearchDuration: {
155+
'.index-threshold': 23,
156+
'logs.alert.document.count': 526,
157+
'document.test.': 534,
158+
},
159+
ruleTypesTotalSearchDuration: {
160+
'.index-threshold': 62,
161+
'logs.alert.document.count': 588,
162+
'document.test.': 637,
163+
},
154164
},
155165
},
156166
failuresByReason: {
@@ -165,6 +175,12 @@ Object {
165175
},
166176
},
167177
avgDuration: { value: 10 },
178+
avgEsSearchDuration: {
179+
value: 25.785714285714285,
180+
},
181+
avgTotalSearchDuration: {
182+
value: 30.642857142857142,
183+
},
168184
},
169185
hits: {
170186
hits: [],
@@ -177,12 +193,24 @@ Object {
177193
expect(mockEsClient.search).toHaveBeenCalledTimes(1);
178194

179195
expect(telemetry).toStrictEqual({
196+
avgEsSearchDuration: 26,
197+
avgEsSearchDurationByType: {
198+
'__index-threshold': 12,
199+
document__test__: 534,
200+
logs__alert__document__count: 526,
201+
},
180202
avgExecutionTime: 0,
181203
avgExecutionTimeByType: {
182204
'__index-threshold': 1043934,
183205
document__test__: 17687687,
184206
logs__alert__document__count: 1675765,
185207
},
208+
avgTotalSearchDuration: 31,
209+
avgTotalSearchDurationByType: {
210+
'__index-threshold': 31,
211+
document__test__: 637,
212+
logs__alert__document__count: 588,
213+
},
186214
countByType: {
187215
'__index-threshold': 2,
188216
document__test__: 1,

x-pack/plugins/alerting/server/usage/alerting_telemetry.ts

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,17 @@ const ruleTypeMetric = {
4040

4141
const ruleTypeExecutionsWithDurationMetric = {
4242
scripted_metric: {
43-
init_script: 'state.ruleTypes = [:]; state.ruleTypesDuration = [:];',
43+
init_script:
44+
'state.ruleTypes = [:]; state.ruleTypesDuration = [:]; state.ruleTypesEsSearchDuration = [:]; state.ruleTypesTotalSearchDuration = [:];',
4445
map_script: `
4546
String ruleType = doc['rule.category'].value;
4647
long duration = doc['event.duration'].value / (1000 * 1000);
48+
long esSearchDuration = doc['kibana.alert.rule.execution.metrics.es_search_duration_ms'].empty ? 0 : doc['kibana.alert.rule.execution.metrics.es_search_duration_ms'].value;
49+
long totalSearchDuration = doc['kibana.alert.rule.execution.metrics.total_search_duration_ms'].empty ? 0 : doc['kibana.alert.rule.execution.metrics.total_search_duration_ms'].value;
4750
state.ruleTypes.put(ruleType, state.ruleTypes.containsKey(ruleType) ? state.ruleTypes.get(ruleType) + 1 : 1);
4851
state.ruleTypesDuration.put(ruleType, state.ruleTypesDuration.containsKey(ruleType) ? state.ruleTypesDuration.get(ruleType) + duration : duration);
52+
state.ruleTypesEsSearchDuration.put(ruleType, state.ruleTypesEsSearchDuration.containsKey(ruleType) ? state.ruleTypesEsSearchDuration.get(ruleType) + esSearchDuration : esSearchDuration);
53+
state.ruleTypesTotalSearchDuration.put(ruleType, state.ruleTypesTotalSearchDuration.containsKey(ruleType) ? state.ruleTypesTotalSearchDuration.get(ruleType) + totalSearchDuration : totalSearchDuration);
4954
`,
5055
// Combine script is executed per cluster, but we already have a key-value pair per cluster.
5156
// Despite docs that say this is optional, this script can't be blank.
@@ -398,13 +403,24 @@ export async function getExecutionsPerDayCount(
398403
byRuleTypeId: ruleTypeExecutionsWithDurationMetric,
399404
failuresByReason: ruleTypeFailureExecutionsMetric,
400405
avgDuration: { avg: { field: 'event.duration' } },
406+
avgEsSearchDuration: {
407+
avg: { field: 'kibana.alert.rule.execution.metrics.es_search_duration_ms' },
408+
},
409+
avgTotalSearchDuration: {
410+
avg: { field: 'kibana.alert.rule.execution.metrics.total_search_duration_ms' },
411+
},
401412
},
402413
},
403414
});
404415

405416
const executionsAggregations = searchResult.aggregations as {
406417
byRuleTypeId: {
407-
value: { ruleTypes: Record<string, string>; ruleTypesDuration: Record<string, number> };
418+
value: {
419+
ruleTypes: Record<string, string>;
420+
ruleTypesDuration: Record<string, number>;
421+
ruleTypesEsSearchDuration: Record<string, number>;
422+
ruleTypesTotalSearchDuration: Record<string, number>;
423+
};
408424
};
409425
};
410426

@@ -414,6 +430,15 @@ export async function getExecutionsPerDayCount(
414430
searchResult.aggregations.avgDuration.value / (1000 * 1000)
415431
);
416432

433+
const aggsAvgEsSearchDuration = Math.round(
434+
// @ts-expect-error aggegation type is not specified
435+
searchResult.aggregations.avgEsSearchDuration.value
436+
);
437+
const aggsAvgTotalSearchDuration = Math.round(
438+
// @ts-expect-error aggegation type is not specified
439+
searchResult.aggregations.avgTotalSearchDuration.value
440+
);
441+
417442
const executionFailuresAggregations = searchResult.aggregations as {
418443
failuresByReason: { value: { reasons: Record<string, Record<string, string>> } };
419444
};
@@ -482,6 +507,36 @@ export async function getExecutionsPerDayCount(
482507
}),
483508
{}
484509
),
510+
avgEsSearchDuration: aggsAvgEsSearchDuration,
511+
avgEsSearchDurationByType: Object.keys(
512+
executionsAggregations.byRuleTypeId.value.ruleTypes
513+
).reduce(
514+
// ES DSL aggregations are returned as `any` by esClient.search
515+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
516+
(obj: any, key: string) => ({
517+
...obj,
518+
[replaceDotSymbols(key)]: Math.round(
519+
executionsAggregations.byRuleTypeId.value.ruleTypesEsSearchDuration[key] /
520+
parseInt(executionsAggregations.byRuleTypeId.value.ruleTypes[key], 10)
521+
),
522+
}),
523+
{}
524+
),
525+
avgTotalSearchDuration: aggsAvgTotalSearchDuration,
526+
avgTotalSearchDurationByType: Object.keys(
527+
executionsAggregations.byRuleTypeId.value.ruleTypes
528+
).reduce(
529+
// ES DSL aggregations are returned as `any` by esClient.search
530+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
531+
(obj: any, key: string) => ({
532+
...obj,
533+
[replaceDotSymbols(key)]: Math.round(
534+
executionsAggregations.byRuleTypeId.value.ruleTypesTotalSearchDuration[key] /
535+
parseInt(executionsAggregations.byRuleTypeId.value.ruleTypes[key], 10)
536+
),
537+
}),
538+
{}
539+
),
485540
};
486541
}
487542

x-pack/plugins/alerting/server/usage/alerting_usage_collector.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ export function createAlertingUsageCollector(
156156
count_failed_and_unrecognized_rule_tasks_by_status_by_type_per_day: {},
157157
avg_execution_time_per_day: 0,
158158
avg_execution_time_by_type_per_day: {},
159+
avg_es_search_duration_per_day: 0,
160+
avg_es_search_duration_by_type_per_day: {},
161+
avg_total_search_duration_per_day: 0,
162+
avg_total_search_duration_by_type_per_day: {},
159163
};
160164
}
161165
},
@@ -203,6 +207,10 @@ export function createAlertingUsageCollector(
203207
count_failed_and_unrecognized_rule_tasks_by_status_by_type_per_day: byTaskStatusSchemaByType,
204208
avg_execution_time_per_day: { type: 'long' },
205209
avg_execution_time_by_type_per_day: byTypeSchema,
210+
avg_es_search_duration_per_day: { type: 'long' },
211+
avg_es_search_duration_by_type_per_day: byTypeSchema,
212+
avg_total_search_duration_per_day: { type: 'long' },
213+
avg_total_search_duration_by_type_per_day: byTypeSchema,
206214
},
207215
});
208216
}

x-pack/plugins/alerting/server/usage/task.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,12 @@ export function telemetryTaskRunner(
138138
dailyFailedAndUnrecognizedTasks.countByStatusByRuleType,
139139
avg_execution_time_per_day: dailyExecutionCounts.avgExecutionTime,
140140
avg_execution_time_by_type_per_day: dailyExecutionCounts.avgExecutionTimeByType,
141+
avg_es_search_duration_per_day: dailyExecutionCounts.avgEsSearchDuration,
142+
avg_es_search_duration_by_type_per_day:
143+
dailyExecutionCounts.avgEsSearchDurationByType,
144+
avg_total_search_duration_per_day: dailyExecutionCounts.avgTotalSearchDuration,
145+
avg_total_search_duration_by_type_per_day:
146+
dailyExecutionCounts.avgTotalSearchDurationByType,
141147
},
142148
runAt: getNextMidnight(),
143149
};

x-pack/plugins/alerting/server/usage/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ export interface AlertingUsage {
2727
>;
2828
avg_execution_time_per_day: number;
2929
avg_execution_time_by_type_per_day: Record<string, number>;
30+
avg_es_search_duration_per_day: number;
31+
avg_es_search_duration_by_type_per_day: Record<string, number>;
32+
avg_total_search_duration_per_day: number;
33+
avg_total_search_duration_by_type_per_day: Record<string, number>;
3034
throttle_time: {
3135
min: string;
3236
avg: string;

x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail.test.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import { DocumentDetail } from '.';
2424

2525
describe('DocumentDetail', () => {
2626
const values = {
27+
isMetaEngine: false,
28+
isElasticsearchEngine: false,
2729
dataLoading: false,
2830
fields: [],
2931
};
@@ -98,4 +100,22 @@ describe('DocumentDetail', () => {
98100

99101
expect(actions.deleteDocument).toHaveBeenCalledWith('1');
100102
});
103+
104+
it('hides delete button when the document is a part of a meta engine', () => {
105+
setMockValues({ ...values, isMetaEngine: true });
106+
const wrapper = shallow(<DocumentDetail />);
107+
108+
expect(
109+
getPageHeaderActions(wrapper).find('[data-test-subj="DeleteDocumentButton"]')
110+
).toHaveLength(0);
111+
});
112+
113+
it('hides delete button when the document is a part of an elasticsearch-indexed engine', () => {
114+
setMockValues({ ...values, isElasticsearchEngine: true });
115+
const wrapper = shallow(<DocumentDetail />);
116+
117+
expect(
118+
getPageHeaderActions(wrapper).find('[data-test-subj="DeleteDocumentButton"]')
119+
).toHaveLength(0);
120+
});
101121
});

x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail.tsx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { i18n } from '@kbn/i18n';
1515

1616
import { DELETE_BUTTON_LABEL } from '../../../shared/constants';
1717
import { useDecodedParams } from '../../utils/encode_path_params';
18-
import { getEngineBreadcrumbs } from '../engine';
18+
import { EngineLogic, getEngineBreadcrumbs } from '../engine';
1919
import { AppSearchPageTemplate } from '../layout';
2020
import { ResultFieldValue } from '../result';
2121

@@ -32,6 +32,8 @@ const DOCUMENT_DETAIL_TITLE = (documentId: string) =>
3232
export const DocumentDetail: React.FC = () => {
3333
const { dataLoading, fields } = useValues(DocumentDetailLogic);
3434
const { deleteDocument, getDocumentDetails, setFields } = useActions(DocumentDetailLogic);
35+
const { isMetaEngine, isElasticsearchEngine } = useValues(EngineLogic);
36+
const showDeleteButton = !isMetaEngine && !isElasticsearchEngine;
3537

3638
const { documentId } = useParams() as { documentId: string };
3739
const { documentId: documentTitle } = useDecodedParams();
@@ -60,21 +62,23 @@ export const DocumentDetail: React.FC = () => {
6062
},
6163
];
6264

65+
const deleteButton = (
66+
<EuiButton
67+
color="danger"
68+
iconType="trash"
69+
onClick={() => deleteDocument(documentId)}
70+
data-test-subj="DeleteDocumentButton"
71+
>
72+
{DELETE_BUTTON_LABEL}
73+
</EuiButton>
74+
);
75+
6376
return (
6477
<AppSearchPageTemplate
6578
pageChrome={getEngineBreadcrumbs([DOCUMENTS_TITLE, documentTitle])}
6679
pageHeader={{
6780
pageTitle: DOCUMENT_DETAIL_TITLE(documentTitle),
68-
rightSideItems: [
69-
<EuiButton
70-
color="danger"
71-
iconType="trash"
72-
onClick={() => deleteDocument(documentId)}
73-
data-test-subj="DeleteDocumentButton"
74-
>
75-
{DELETE_BUTTON_LABEL}
76-
</EuiButton>,
77-
],
81+
rightSideItems: showDeleteButton ? [deleteButton] : [],
7882
}}
7983
isLoading={dataLoading}
8084
>

x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.test.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ describe('Documents', () => {
2323
const values = {
2424
isMetaEngine: false,
2525
myRole: { canManageEngineDocuments: true },
26+
engine: { elasticsearchIndexName: 'my-elasticsearch-index' },
2627
};
2728

2829
beforeEach(() => {
@@ -66,6 +67,17 @@ describe('Documents', () => {
6667
const wrapper = shallow(<Documents />);
6768
expect(getPageHeaderActions(wrapper).find(DocumentCreationButton).exists()).toBe(false);
6869
});
70+
71+
it('does not render a DocumentCreationButton for elasticsearch engines even if the user can manage engine documents', () => {
72+
setMockValues({
73+
...values,
74+
myRole: { canManageEngineDocuments: true },
75+
isElasticsearchEngine: true,
76+
});
77+
78+
const wrapper = shallow(<Documents />);
79+
expect(getPageHeaderActions(wrapper).find(DocumentCreationButton).exists()).toBe(false);
80+
});
6981
});
7082

7183
describe('Meta Engines', () => {
@@ -89,4 +101,26 @@ describe('Documents', () => {
89101
expect(wrapper.find('[data-test-subj="MetaEnginesCallout"]').exists()).toBe(false);
90102
});
91103
});
104+
105+
describe('Elasticsearch indices', () => {
106+
it('renders an Elasticsearch indices message if this is an Elasticsearch index', () => {
107+
setMockValues({
108+
...values,
109+
isElasticsearchEngine: true,
110+
});
111+
112+
const wrapper = shallow(<Documents />);
113+
expect(wrapper.find('[data-test-subj="ElasticsearchEnginesCallout"]').exists()).toBe(true);
114+
});
115+
116+
it('does not render an Elasticsearch indices message if this is not an Elasticsearch index', () => {
117+
setMockValues({
118+
...values,
119+
isElasticsearchEngine: false,
120+
});
121+
122+
const wrapper = shallow(<Documents />);
123+
expect(wrapper.find('[data-test-subj="ElasticsearchEnginesCallout"]').exists()).toBe(false);
124+
});
125+
});
92126
});

x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.tsx

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,22 @@ import { DOCUMENTS_TITLE } from './constants';
2121
import { SearchExperience } from './search_experience';
2222

2323
export const Documents: React.FC = () => {
24-
const { isMetaEngine, hasNoDocuments } = useValues(EngineLogic);
24+
const {
25+
isMetaEngine,
26+
isElasticsearchEngine,
27+
hasNoDocuments,
28+
engine: { elasticsearchIndexName },
29+
} = useValues(EngineLogic);
2530
const { myRole } = useValues(AppLogic);
31+
const showDocumentCreationButton =
32+
myRole.canManageEngineDocuments && !isMetaEngine && !isElasticsearchEngine;
2633

2734
return (
2835
<AppSearchPageTemplate
2936
pageChrome={getEngineBreadcrumbs([DOCUMENTS_TITLE])}
3037
pageHeader={{
3138
pageTitle: DOCUMENTS_TITLE,
32-
rightSideItems:
33-
myRole.canManageEngineDocuments && !isMetaEngine ? [<DocumentCreationButton />] : [],
39+
rightSideItems: showDocumentCreationButton ? [<DocumentCreationButton />] : [],
3440
}}
3541
isEmptyState={hasNoDocuments}
3642
emptyState={<EmptyState />}
@@ -57,6 +63,32 @@ export const Documents: React.FC = () => {
5763
<EuiSpacer />
5864
</>
5965
)}
66+
{isElasticsearchEngine && (
67+
<>
68+
<EuiCallOut
69+
data-test-subj="ElasticsearchEnginesCallout"
70+
iconType="iInCircle"
71+
title={i18n.translate(
72+
'xpack.enterpriseSearch.appSearch.documents.elasticsearchEngineCallout.title',
73+
{
74+
defaultMessage: "This engine's data is managed by Elasticsearch.",
75+
}
76+
)}
77+
>
78+
<p>
79+
{i18n.translate(
80+
'xpack.enterpriseSearch.appSearch.documents.elasticsearchEngineCallout',
81+
{
82+
defaultMessage:
83+
"The engine is attached to {elasticsearchIndexName}. You can modify this index's data in Kibana.",
84+
values: { elasticsearchIndexName },
85+
}
86+
)}
87+
</p>
88+
</EuiCallOut>
89+
<EuiSpacer />
90+
</>
91+
)}
6092
<SearchExperience />
6193
</AppSearchPageTemplate>
6294
);

0 commit comments

Comments
 (0)