Skip to content

Commit

Permalink
Merge branch 'master' into task/hide-KQL-bar-when-not-compatible
Browse files Browse the repository at this point in the history
  • Loading branch information
elasticmachine authored Sep 20, 2020
2 parents 25e1430 + 496152e commit 1cf12ea
Show file tree
Hide file tree
Showing 120 changed files with 3,413 additions and 528 deletions.
87 changes: 32 additions & 55 deletions src/plugins/data/public/search/expressions/esaggs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import { get, hasIn } from 'lodash';
import { i18n } from '@kbn/i18n';
import { KibanaDatatable, KibanaDatatableColumn } from 'src/plugins/expressions/public';
import { calculateObjectHash } from '../../../../../plugins/kibana_utils/public';
import { PersistedState } from '../../../../../plugins/visualizations/public';
import { Adapters } from '../../../../../plugins/inspector/public';

Expand Down Expand Up @@ -60,7 +59,6 @@ export interface RequestHandlerParams {
indexPattern?: IIndexPattern;
query?: Query;
filters?: Filter[];
forceFetch: boolean;
filterManager: FilterManager;
uiState?: PersistedState;
partialRows?: boolean;
Expand All @@ -80,7 +78,6 @@ const handleCourierRequest = async ({
indexPattern,
query,
filters,
forceFetch,
partialRows,
metricsAtAllLevels,
inspectorAdapters,
Expand Down Expand Up @@ -137,46 +134,35 @@ const handleCourierRequest = async ({
requestSearchSource.setField('filter', filters);
requestSearchSource.setField('query', query);

const reqBody = await requestSearchSource.getSearchRequestBody();

const queryHash = calculateObjectHash(reqBody);
// We only need to reexecute the query, if forceFetch was true or the hash of the request body has changed
// since the last request
const shouldQuery = forceFetch || (searchSource as any).lastQuery !== queryHash;

if (shouldQuery) {
inspectorAdapters.requests.reset();
const request = inspectorAdapters.requests.start(
i18n.translate('data.functions.esaggs.inspector.dataRequest.title', {
defaultMessage: 'Data',
inspectorAdapters.requests.reset();
const request = inspectorAdapters.requests.start(
i18n.translate('data.functions.esaggs.inspector.dataRequest.title', {
defaultMessage: 'Data',
}),
{
description: i18n.translate('data.functions.esaggs.inspector.dataRequest.description', {
defaultMessage:
'This request queries Elasticsearch to fetch the data for the visualization.',
}),
{
description: i18n.translate('data.functions.esaggs.inspector.dataRequest.description', {
defaultMessage:
'This request queries Elasticsearch to fetch the data for the visualization.',
}),
}
);
request.stats(getRequestInspectorStats(requestSearchSource));

try {
const response = await requestSearchSource.fetch({ abortSignal });

(searchSource as any).lastQuery = queryHash;

request.stats(getResponseInspectorStats(response, searchSource)).ok({ json: response });

(searchSource as any).rawResponse = response;
} catch (e) {
// Log any error during request to the inspector
request.error({ json: e });
throw e;
} finally {
// Add the request body no matter if things went fine or not
requestSearchSource.getSearchRequestBody().then((req: unknown) => {
request.json(req);
});
}
);
request.stats(getRequestInspectorStats(requestSearchSource));

try {
const response = await requestSearchSource.fetch({ abortSignal });

request.stats(getResponseInspectorStats(response, searchSource)).ok({ json: response });

(searchSource as any).rawResponse = response;
} catch (e) {
// Log any error during request to the inspector
request.error({ json: e });
throw e;
} finally {
// Add the request body no matter if things went fine or not
requestSearchSource.getSearchRequestBody().then((req: unknown) => {
request.json(req);
});
}

// Note that rawResponse is not deeply cloned here, so downstream applications using courier
Expand Down Expand Up @@ -207,19 +193,11 @@ const handleCourierRequest = async ({
: undefined,
};

const tabifyCacheHash = calculateObjectHash({ tabifyAggs: aggs, ...tabifyParams });
// We only need to reexecute tabify, if either we did a new request or some input params to tabify changed
const shouldCalculateNewTabify =
shouldQuery || (searchSource as any).lastTabifyHash !== tabifyCacheHash;

if (shouldCalculateNewTabify) {
(searchSource as any).lastTabifyHash = tabifyCacheHash;
(searchSource as any).tabifiedResponse = tabifyAggResponse(
aggs,
(searchSource as any).finalResponse,
tabifyParams
);
}
(searchSource as any).tabifiedResponse = tabifyAggResponse(
aggs,
(searchSource as any).finalResponse,
tabifyParams
);

inspectorAdapters.data.setTabularLoader(
() =>
Expand Down Expand Up @@ -294,7 +272,6 @@ export const esaggs = (): EsaggsExpressionFunctionDefinition => ({
query: get(input, 'query', undefined) as any,
filters: get(input, 'filters', undefined),
timeFields: args.timeFields,
forceFetch: true,
metricsAtAllLevels: args.metricsAtAllLevels,
partialRows: args.partialRows,
inspectorAdapters: inspectorAdapters as Adapters,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ export function getTimelionRequestHandler({
filters: Filter[];
query: Query;
visParams: VisParams;
forceFetch?: boolean;
}): Promise<TimelionSuccessResponse> {
const expression = visParams.expression;

Expand Down
1 change: 0 additions & 1 deletion src/plugins/vis_type_timelion/public/timelion_vis_fn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ export const getTimelionVisualizationConfig = (
query: get(input, 'query') as Query,
filters: get(input, 'filters') as Filter[],
visParams,
forceFetch: true,
});

response.visType = TIMELION_VIS_NAME;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ export const visualization = (): ExpressionFunctionVisualization => ({
uiState,
inspectorAdapters,
queryFilter: getFilterManager(),
forceFetch: true,
aggs,
});
}
Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugins/infra/common/alerting/metrics/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ const baseAlertRequestParamsRT = rt.intersection([
]),
criteria: rt.array(rt.any),
alertInterval: rt.string,
alertThrottle: rt.string,
alertOnNoData: rt.boolean,
}),
]);

Expand Down Expand Up @@ -91,6 +93,7 @@ export const alertPreviewSuccessResponsePayloadRT = rt.type({
fired: rt.number,
noData: rt.number,
error: rt.number,
notifications: rt.number,
}),
});
export type AlertPreviewSuccessResponsePayload = rt.TypeOf<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { getAlertPreview, PreviewableAlertTypes } from './get_alert_preview';

interface Props {
alertInterval: string;
alertThrottle: string;
alertType: PreviewableAlertTypes;
fetch: HttpSetup['fetch'];
alertParams: { criteria: any[]; sourceId: string } & Record<string, any>;
Expand All @@ -45,6 +46,7 @@ export const AlertPreview: React.FC<Props> = (props) => {
const {
alertParams,
alertInterval,
alertThrottle,
fetch,
alertType,
validate,
Expand Down Expand Up @@ -73,16 +75,27 @@ export const AlertPreview: React.FC<Props> = (props) => {
...alertParams,
lookback: previewLookbackInterval as 'h' | 'd' | 'w' | 'M',
alertInterval,
alertThrottle,
alertOnNoData: showNoDataResults ?? false,
} as AlertPreviewRequestParams,
alertType,
});
setPreviewResult({ ...result, groupByDisplayName, previewLookbackInterval });
setPreviewResult({ ...result, groupByDisplayName, previewLookbackInterval, alertThrottle });
} catch (e) {
setPreviewError(e);
} finally {
setIsPreviewLoading(false);
}
}, [alertParams, alertInterval, fetch, alertType, groupByDisplayName, previewLookbackInterval]);
}, [
alertParams,
alertInterval,
fetch,
alertType,
groupByDisplayName,
previewLookbackInterval,
alertThrottle,
showNoDataResults,
]);

const previewIntervalError = useMemo(() => {
const intervalInSeconds = getIntervalInSeconds(alertInterval);
Expand All @@ -101,6 +114,13 @@ export const AlertPreview: React.FC<Props> = (props) => {
return hasValidationErrors || previewIntervalError;
}, [alertParams.criteria, previewIntervalError, validate]);

const showNumberOfNotifications = useMemo(() => {
if (!previewResult) return false;
const { notifications, fired, noData, error } = previewResult.resultTotals;
const unthrottledNotifications = fired + (showNoDataResults ? noData + error : 0);
return unthrottledNotifications > notifications;
}, [previewResult, showNoDataResults]);

return (
<EuiFormRow
label={i18n.translate('xpack.infra.metrics.alertFlyout.previewLabel', {
Expand Down Expand Up @@ -136,19 +156,22 @@ export const AlertPreview: React.FC<Props> = (props) => {
<>
<EuiSpacer size={'s'} />
<EuiCallOut
iconType="iInCircle"
size="s"
title={
<>
<FormattedMessage
id="xpack.infra.metrics.alertFlyout.alertPreviewResult"
defaultMessage="This alert would have occurred {firedTimes}"
defaultMessage="There were {firedTimes}"
values={{
firedTimes: (
<strong>
{previewResult.resultTotals.fired}{' '}
{previewResult.resultTotals.fired === 1
? firedTimeLabel
: firedTimesLabel}
<FormattedMessage
id="xpack.infra.metrics.alertFlyout.firedTimes"
defaultMessage="{fired, plural, one {# instance} other {# instances}}"
values={{
fired: previewResult.resultTotals.fired,
}}
/>
</strong>
),
}}
Expand All @@ -173,7 +196,7 @@ export const AlertPreview: React.FC<Props> = (props) => {
) : null}
<FormattedMessage
id="xpack.infra.metrics.alertFlyout.alertPreviewResultLookback"
defaultMessage="in the last {lookback}."
defaultMessage="that satisfied the conditions of this alert in the last {lookback}."
values={{
lookback: previewOptions.find(
(e) => e.value === previewResult.previewLookbackInterval
Expand Down Expand Up @@ -211,13 +234,40 @@ export const AlertPreview: React.FC<Props> = (props) => {
defaultMessage="An error occurred when trying to evaluate some of the data."
/>
) : null}
{showNumberOfNotifications ? (
<>
<EuiSpacer size={'s'} />
<FormattedMessage
id="xpack.infra.metrics.alertFlyout.alertPreviewTotalNotifications"
defaultMessage='As a result, this alert would have sent {notifications} based on the selected "notify every" setting of "{alertThrottle}."'
values={{
alertThrottle: previewResult.alertThrottle,
notifications: (
<strong>
{i18n.translate(
'xpack.infra.metrics.alertFlyout.alertPreviewTotalNotificationsNumber',
{
defaultMessage:
'{notifs, plural, one {# notification} other {# notifications}}',
values: {
notifs: previewResult.resultTotals.notifications,
},
}
)}
</strong>
),
}}
/>
</>
) : null}{' '}
</EuiCallOut>
</>
)}
{previewIntervalError && (
<>
<EuiSpacer size={'s'} />
<EuiCallOut
size="s"
title={
<FormattedMessage
id="xpack.infra.metrics.alertFlyout.previewIntervalTooShortTitle"
Expand All @@ -242,6 +292,7 @@ export const AlertPreview: React.FC<Props> = (props) => {
<EuiSpacer size={'s'} />
{previewError.body?.statusCode === 508 ? (
<EuiCallOut
size="s"
title={
<FormattedMessage
id="xpack.infra.metrics.alertFlyout.tooManyBucketsErrorTitle"
Expand All @@ -264,6 +315,7 @@ export const AlertPreview: React.FC<Props> = (props) => {
</EuiCallOut>
) : (
<EuiCallOut
size="s"
title={
<FormattedMessage
id="xpack.infra.metrics.alertFlyout.alertPreviewError"
Expand Down Expand Up @@ -349,10 +401,3 @@ const previewOptions = [
const previewDOMOptions: Array<{ text: string; value: string }> = previewOptions.map((o) =>
omit(o, 'shortText')
);

const firedTimeLabel = i18n.translate('xpack.infra.metrics.alertFlyout.firedTime', {
defaultMessage: 'time',
});
const firedTimesLabel = i18n.translate('xpack.infra.metrics.alertFlyout.firedTimes', {
defaultMessage: 'times',
});
7 changes: 0 additions & 7 deletions x-pack/plugins/infra/public/alerting/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,3 @@ export const previewOptions = [
}),
},
];

export const firedTimeLabel = i18n.translate('xpack.infra.metrics.alertFlyout.firedTime', {
defaultMessage: 'time',
});
export const firedTimesLabel = i18n.translate('xpack.infra.metrics.alertFlyout.firedTimes', {
defaultMessage: 'times',
});
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ describe('Expression', () => {
<Expressions
alertsContext={context}
alertInterval="1m"
alertThrottle="1m"
alertParams={alertParams as any}
errors={[]}
setAlertParams={(key, value) => Reflect.set(alertParams, key, value)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ interface Props {
alertOnNoData?: boolean;
};
alertInterval: string;
alertThrottle: string;
alertsContext: AlertsContextValue<AlertContextMeta>;
setAlertParams(key: string, value: any): void;
setAlertProperty(key: string, value: any): void;
Expand All @@ -104,7 +105,14 @@ const defaultExpression = {
} as InventoryMetricConditions;

export const Expressions: React.FC<Props> = (props) => {
const { setAlertParams, alertParams, errors, alertsContext, alertInterval } = props;
const {
setAlertParams,
alertParams,
errors,
alertsContext,
alertInterval,
alertThrottle,
} = props;
const { source, createDerivedIndexPattern } = useSourceViaHttp({
sourceId: 'default',
type: 'metrics',
Expand Down Expand Up @@ -378,6 +386,7 @@ export const Expressions: React.FC<Props> = (props) => {
<EuiSpacer size={'m'} />
<AlertPreview
alertInterval={alertInterval}
alertThrottle={alertThrottle}
alertType={METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID}
alertParams={pick(alertParams, 'criteria', 'nodeType', 'sourceId', 'filterQuery')}
validate={validateMetricThreshold}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ describe('Expression', () => {
<Expressions
alertsContext={context}
alertInterval="1m"
alertThrottle="1m"
alertParams={alertParams}
errors={[]}
setAlertParams={(key, value) => Reflect.set(alertParams, key, value)}
Expand Down
Loading

0 comments on commit 1cf12ea

Please sign in to comment.