Skip to content

Commit

Permalink
[SIEM] [Detection Engine] Fixes histogram intervals (#55969) (#56085)
Browse files Browse the repository at this point in the history
## Summary

This PR wraps up the remaining `Detection Engine` meta tickets: #55585, #54935, and elastic/siem-team#498
- [x] Histogram bar interval (bar counts and widths) consistency (#55585)
  - [x] Make the bar intervals a consistent 32 bars across the board
  * Enabled `extended_bounds`, `min_doc_count: 0`, and now setting consistent `fixed_interval` when querying to ensure the entire daterange is displayed across all histograms.
- [x] Filter out the "untitled" timelines from both timeline selection options during rule creation (elastic/siem-team#498)
  - [ ] ~Import query from saved timeline~
    * For 7.7 tracking ticket here: #56079
  - [x] `Investigate detections using this timeline template` 
- [x] Everywhere we use "Alerts" (Overview page, Host Tab, Network Tab) we should change the term to "External Alerts"
  - [x] Updated Host Page Tab/Table/Histogram/Breadcrumbs
  - [x] Updated Network Page Tab/Table/Histogram/Breadcrumbs
- [x] Updated DE permission/index  error doc links to go to [corresponding DE docs section](https://www.elastic.co/guide/en/siem/guide/7.6/detection-engine-overview.html#detections-permissions)
- [x] Removed `frequency` in favor of `count` for remaining histograms

##### Inconsistent Histogram intervals
![image](https://user-images.githubusercontent.com/2946766/73161560-04a82300-40a9-11ea-950f-ea56f9a5bfd7.png)


##### Consistent Histogram Intervals
![image](https://user-images.githubusercontent.com/2946766/73159564-fefc0e80-40a3-11ea-9b9d-4d15899dabd2.png)


cc @MichaelMarcialis @cwurm @MikePaquette 

### Checklist

Use ~~strikethroughs~~ to remove checklist items you don't feel are applicable to this PR.

- [ ] ~This was checked for cross-browser compatibility, [including a check against IE11](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility)~
- [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/master/packages/kbn-i18n/README.md)
- [ ] ~[Documentation](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#writing-documentation) was added for features that require explanation or tutorials~
- [ ] ~[Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios~
- [ ] ~This was checked for [keyboard-only and screenreader accessibility](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Accessibility_testing_checklist)~

### For maintainers

- [ ] ~This was checked for breaking API changes and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process)~
- [ ] ~This includes a feature addition or change that requires a release note and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process)~
  • Loading branch information
spong authored Jan 28, 2020
1 parent 0c5c054 commit 99de5ee
Show file tree
Hide file tree
Showing 17 changed files with 118 additions and 104 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
import { noop } from 'lodash/fp';
import React, { useEffect, useCallback } from 'react';
import { EuiSpacer } from '@elastic/eui';
import numeral from '@elastic/numeral';

import { AlertsComponentsQueryProps } from './types';
import { AlertsTable } from './alerts_table';
import * as i18n from './translations';
import { MatrixHistogramOption } from '../matrix_histogram/types';
import { MatrixHistogramContainer } from '../../containers/matrix_histogram';
import { MatrixHistogramGqlQuery } from '../../containers/matrix_histogram/index.gql_query';
import { useUiSetting$ } from '../../lib/kibana';
import { DEFAULT_NUMBER_FORMAT } from '../../../common/constants';
const ID = 'alertsOverTimeQuery';
export const alertsStackByOptions: MatrixHistogramOption[] = [
{
Expand All @@ -37,6 +40,8 @@ export const AlertsView = ({
type,
updateDateRange = noop,
}: AlertsComponentsQueryProps) => {
const [defaultNumberFormat] = useUiSetting$<string>(DEFAULT_NUMBER_FORMAT);

useEffect(() => {
return () => {
if (deleteQuery) {
Expand All @@ -46,7 +51,10 @@ export const AlertsView = ({
}, []);

const getSubtitle = useCallback(
(totalCount: number) => `${i18n.SHOWING}: ${totalCount} ${i18n.UNIT(totalCount)}`,
(totalCount: number) =>
`${i18n.SHOWING}: ${numeral(totalCount).format(defaultNumberFormat)} ${i18n.UNIT(
totalCount
)}`,
[]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@
import { i18n } from '@kbn/i18n';

export const ALERTS_DOCUMENT_TYPE = i18n.translate('xpack.siem.alertsView.alertsDocumentType', {
defaultMessage: 'Alerts',
defaultMessage: 'External alerts',
});

export const TOTAL_COUNT_OF_ALERTS = i18n.translate('xpack.siem.alertsView.totalCountOfAlerts', {
defaultMessage: 'alerts match the search criteria',
defaultMessage: 'external alerts match the search criteria',
});

export const ALERTS_TABLE_TITLE = i18n.translate('xpack.siem.alertsView.alertsTableTitle', {
defaultMessage: 'Alerts',
defaultMessage: 'External alerts',
});

export const ALERTS_GRAPH_TITLE = i18n.translate('xpack.siem.alertsView.alertsGraphTitle', {
defaultMessage: 'Alert detection frequency',
defaultMessage: 'External alerts count',
});

export const ALERTS_STACK_BY_MODULE = i18n.translate(
Expand All @@ -36,7 +36,7 @@ export const SHOWING = i18n.translate('xpack.siem.alertsView.showing', {
export const UNIT = (totalCount: number) =>
i18n.translate('xpack.siem.alertsView.unit', {
values: { totalCount },
defaultMessage: `{totalCount, plural, =1 {alert} other {alerts}}`,
defaultMessage: `external {totalCount, plural, =1 {alert} other {alerts}}`,
});

export const ERROR_FETCHING_ALERTS_DATA = i18n.translate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ const MyEuiFlexGroup = styled(EuiFlexGroup)`

interface SearchTimelineSuperSelectProps {
isDisabled: boolean;
hideUntitled?: boolean;
timelineId: string | null;
timelineTitle: string | null;
onTimelineChange: (timelineTitle: string, timelineId: string | null) => void;
Expand Down Expand Up @@ -101,6 +102,7 @@ const POPOVER_HEIGHT = 260;
const TIMELINE_ITEM_HEIGHT = 50;
const SearchTimelineSuperSelectComponent: React.FC<SearchTimelineSuperSelectProps> = ({
isDisabled,
hideUntitled = false,
timelineId,
timelineTitle,
onTimelineChange,
Expand Down Expand Up @@ -287,7 +289,11 @@ const SearchTimelineSuperSelectComponent: React.FC<SearchTimelineSuperSelectProp
rowHeight: TIMELINE_ITEM_HEIGHT,
showIcons: false,
virtualizedProps: ({
onScroll: handleOnScroll.bind(null, timelines.length, totalCount),
onScroll: handleOnScroll.bind(
null,
timelines.filter(t => !hideUntitled || t.title !== '').length,
totalCount
),
} as unknown) as ListProps,
}}
renderOption={renderTimelineOption}
Expand All @@ -308,18 +314,20 @@ const SearchTimelineSuperSelectComponent: React.FC<SearchTimelineSuperSelectProp
...(!onlyFavorites && searchTimelineValue === ''
? getBasicSelectableOptions(timelineId == null ? '-1' : timelineId)
: []),
...timelines.map(
(t, index) =>
({
description: t.description,
favorite: t.favorite,
label: t.title,
id: t.savedObjectId,
key: `${t.title}-${index}`,
title: t.title,
checked: t.savedObjectId === timelineId ? 'on' : undefined,
} as Option)
),
...timelines
.filter(t => !hideUntitled || t.title !== '')
.map(
(t, index) =>
({
description: t.description,
favorite: t.favorite,
label: t.title,
id: t.savedObjectId,
key: `${t.title}-${index}`,
title: t.title,
checked: t.savedObjectId === timelineId ? 'on' : undefined,
} as Option)
),
]}
>
{(list, search) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,14 @@ export const getSignalsHistogramQuery = (
},
aggs: {
signals: {
auto_date_histogram: {
date_histogram: {
field: '@timestamp',
buckets: 36,
fixed_interval: `${Math.floor((to - from) / 32)}ms`,
min_doc_count: 0,
extended_bounds: {
min: from,
max: to,
},
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export const STACK_BY_USERS = i18n.translate(
export const HISTOGRAM_HEADER = i18n.translate(
'xpack.siem.detectionEngine.signals.histogram.headerTitle',
{
defaultMessage: 'Signal count',
defaultMessage: 'Signals count',
}
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,24 @@
*/

import React from 'react';
import chrome from 'ui/chrome';

import { EmptyPage } from '../../components/empty_page';
import * as i18n from './translations';
import { useKibana } from '../../lib/kibana';

const basePath = chrome.getBasePath();

export const DetectionEngineNoIndex = React.memo(() => (
<EmptyPage
actionPrimaryIcon="documents"
actionPrimaryLabel={i18n.GO_TO_DOCUMENTATION}
actionPrimaryUrl={`${basePath}/app/kibana#/home/tutorial_directory/siem`}
actionPrimaryTarget="_blank"
message={i18n.NO_INDEX_MSG_BODY}
data-test-subj="no_index"
title={i18n.NO_INDEX_TITLE}
/>
));
export const DetectionEngineNoIndex = React.memo(() => {
const docLinks = useKibana().services.docLinks;
return (
<EmptyPage
actionPrimaryIcon="documents"
actionPrimaryLabel={i18n.GO_TO_DOCUMENTATION}
actionPrimaryUrl={`${docLinks.ELASTIC_WEBSITE_URL}guide/en/siem/guide/${docLinks.DOC_LINK_VERSION}/detection-engine-overview.html#detections-permissions`}
actionPrimaryTarget="_blank"
message={i18n.NO_INDEX_MSG_BODY}
data-test-subj="no_index"
title={i18n.NO_INDEX_TITLE}
/>
);
});

DetectionEngineNoIndex.displayName = 'DetectionEngineNoIndex';
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,25 @@
*/

import React from 'react';
import chrome from 'ui/chrome';

import { EmptyPage } from '../../components/empty_page';
import * as i18n from './translations';
import { useKibana } from '../../lib/kibana';

const basePath = chrome.getBasePath();
export const DetectionEngineUserUnauthenticated = React.memo(() => {
const docLinks = useKibana().services.docLinks;

export const DetectionEngineUserUnauthenticated = React.memo(() => (
<EmptyPage
actionPrimaryIcon="documents"
actionPrimaryLabel={i18n.GO_TO_DOCUMENTATION}
actionPrimaryUrl={`${basePath}/app/kibana#/home/tutorial_directory/siem`}
actionPrimaryTarget="_blank"
message={i18n.USER_UNAUTHENTICATED_MSG_BODY}
data-test-subj="no_index"
title={i18n.USER_UNAUTHENTICATED_TITLE}
/>
));
return (
<EmptyPage
actionPrimaryIcon="documents"
actionPrimaryLabel={i18n.GO_TO_DOCUMENTATION}
actionPrimaryUrl={`${docLinks.ELASTIC_WEBSITE_URL}guide/en/siem/guide/${docLinks.DOC_LINK_VERSION}/detection-engine-overview.html#detections-permissions`}
actionPrimaryTarget="_blank"
message={i18n.USER_UNAUTHENTICATED_MSG_BODY}
data-test-subj="no_index"
title={i18n.USER_UNAUTHENTICATED_TITLE}
/>
);
});

DetectionEngineUserUnauthenticated.displayName = 'DetectionEngineUserUnauthenticated';
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export const PickTimeline = ({
>
<SearchTimelineSuperSelect
isDisabled={isDisabled}
hideUntitled={true}
timelineId={timelineId}
timelineTitle={timelineTitle}
onTimelineChange={handleOnTimelineChange}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const NAVIGATION_EVENTS_TITLE = i18n.translate('xpack.siem.hosts.navigati
});

export const NAVIGATION_ALERTS_TITLE = i18n.translate('xpack.siem.hosts.navigation.alertsTitle', {
defaultMessage: 'Alerts',
defaultMessage: 'External alerts',
});

export const ERROR_FETCHING_AUTHENTICATIONS_DATA = i18n.translate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const NAVIGATION_ANOMALIES_TITLE = i18n.translate(
);

export const NAVIGATION_ALERTS_TITLE = i18n.translate('xpack.siem.network.navigation.alertsTitle', {
defaultMessage: 'Alerts',
defaultMessage: 'External alerts',
});

export const DOMAINS_COUNT_BY = (groupByField: string) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const ALERTS_COUNT_BY = (groupByField: string) =>
});

export const ALERTS_GRAPH_TITLE = i18n.translate('xpack.siem.overview.alertsGraphTitle', {
defaultMessage: 'Alert detection frequency',
defaultMessage: 'External alerts count',
});

export const EVENTS_COUNT_BY = (groupByField: string) =>
Expand Down
19 changes: 9 additions & 10 deletions x-pack/legacy/plugins/siem/server/lib/alerts/query.dsl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { createQueryFilterClauses, calculateTimeseriesInterval } from '../../utils/build_query';
import { createQueryFilterClauses, calculateTimeSeriesInterval } from '../../utils/build_query';
import { buildTimelineQuery } from '../events/query.dsl';
import { RequestOptions, MatrixHistogramRequestOptions } from '../framework';

Expand Down Expand Up @@ -68,18 +68,17 @@ export const buildAlertsHistogramQuery = ({
];

const getHistogramAggregation = () => {
const interval = calculateTimeseriesInterval(from, to);
const interval = calculateTimeSeriesInterval(from, to);
const histogramTimestampField = '@timestamp';
const dateHistogram = {
date_histogram: {
field: histogramTimestampField,
fixed_interval: `${interval}s`,
},
};
const autoDateHistogram = {
auto_date_histogram: {
field: histogramTimestampField,
buckets: 36,
fixed_interval: interval,
min_doc_count: 0,
extended_bounds: {
min: from,
max: to,
},
},
};
return {
Expand All @@ -93,7 +92,7 @@ export const buildAlertsHistogramQuery = ({
size: 10,
},
aggs: {
alerts: interval ? dateHistogram : autoDateHistogram,
alerts: dateHistogram,
},
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { createQueryFilterClauses, calculateTimeseriesInterval } from '../../utils/build_query';
import { createQueryFilterClauses, calculateTimeSeriesInterval } from '../../utils/build_query';
import { MatrixHistogramRequestOptions } from '../framework';

export const buildAnomaliesOverTimeQuery = ({
Expand All @@ -26,18 +26,17 @@ export const buildAnomaliesOverTimeQuery = ({
];

const getHistogramAggregation = () => {
const interval = calculateTimeseriesInterval(from, to);
const interval = calculateTimeSeriesInterval(from, to);
const histogramTimestampField = 'timestamp';
const dateHistogram = {
date_histogram: {
field: histogramTimestampField,
fixed_interval: `${interval}s`,
},
};
const autoDateHistogram = {
auto_date_histogram: {
field: histogramTimestampField,
buckets: 36,
fixed_interval: interval,
min_doc_count: 0,
extended_bounds: {
min: from,
max: to,
},
},
};
return {
Expand All @@ -50,7 +49,7 @@ export const buildAnomaliesOverTimeQuery = ({
size: 10,
},
aggs: {
anomalies: interval ? dateHistogram : autoDateHistogram,
anomalies: dateHistogram,
},
},
};
Expand Down
Loading

0 comments on commit 99de5ee

Please sign in to comment.