Skip to content

Commit

Permalink
[Monitoring][Alerting] Large shard alert (#89410) (#90197)
Browse files Browse the repository at this point in the history
* Shards alert draft

* Added index pattern validation

* Fixed ui/ux

* Optimizing the response

* CR feedback

* import fix

* Increased size limit
# Conflicts:
#	packages/kbn-optimizer/limits.yml
#	x-pack/plugins/monitoring/public/components/elasticsearch/index/advanced.js
  • Loading branch information
igoristic authored Feb 3, 2021
1 parent 25428f3 commit 1bc6c1c
Show file tree
Hide file tree
Showing 32 changed files with 931 additions and 171 deletions.
2 changes: 1 addition & 1 deletion packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pageLoadAssetSize:
mapsLegacy: 116961
mapsLegacyLicensing: 20214
ml: 82187
monitoring: 50000
monitoring: 80000
navigation: 37413
newsfeed: 42228
observability: 89709
Expand Down
27 changes: 27 additions & 0 deletions x-pack/plugins/monitoring/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ export const ALERT_MISSING_MONITORING_DATA = `${ALERT_PREFIX}alert_missing_monit
export const ALERT_THREAD_POOL_SEARCH_REJECTIONS = `${ALERT_PREFIX}alert_thread_pool_search_rejections`;
export const ALERT_THREAD_POOL_WRITE_REJECTIONS = `${ALERT_PREFIX}alert_thread_pool_write_rejections`;
export const ALERT_CCR_READ_EXCEPTIONS = `${ALERT_PREFIX}ccr_read_exceptions`;
export const ALERT_LARGE_SHARD_SIZE = `${ALERT_PREFIX}shard_size`;

/**
* Legacy alerts details/label for server and public use
Expand Down Expand Up @@ -471,6 +472,30 @@ export const ALERT_DETAILS = {
defaultMessage: 'Alert if any CCR read exceptions have been detected.',
}),
},
[ALERT_LARGE_SHARD_SIZE]: {
paramDetails: {
threshold: {
label: i18n.translate('xpack.monitoring.alerts.shardSize.paramDetails.threshold.label', {
defaultMessage: `Notify when a shard exceeds this size`,
}),
type: AlertParamType.Number,
append: 'GB',
},
indexPattern: {
label: i18n.translate('xpack.monitoring.alerts.shardSize.paramDetails.indexPattern.label', {
defaultMessage: `Check the following index patterns`,
}),
placeholder: 'eg: data-*, *prod-data, -.internal-data*',
type: AlertParamType.TextField,
},
},
label: i18n.translate('xpack.monitoring.alerts.shardSize.label', {
defaultMessage: 'Shard size',
}),
description: i18n.translate('xpack.monitoring.alerts.shardSize.description', {
defaultMessage: 'Alert if an index (primary) shard is oversize.',
}),
},
};

export const ALERT_PANEL_MENU = [
Expand All @@ -494,6 +519,7 @@ export const ALERT_PANEL_MENU = [
{ alertName: ALERT_CPU_USAGE },
{ alertName: ALERT_DISK_USAGE },
{ alertName: ALERT_MEMORY_USAGE },
{ alertName: ALERT_LARGE_SHARD_SIZE },
],
},
{
Expand Down Expand Up @@ -527,6 +553,7 @@ export const ALERTS = [
ALERT_THREAD_POOL_SEARCH_REJECTIONS,
ALERT_THREAD_POOL_WRITE_REJECTIONS,
ALERT_CCR_READ_EXCEPTIONS,
ALERT_LARGE_SHARD_SIZE,
];

/**
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/monitoring/common/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export enum AlertMessageTokenType {
}

export enum AlertParamType {
TextField = 'textfield',
Duration = 'duration',
Percentage = 'percentage',
Number = 'number',
Expand Down
58 changes: 58 additions & 0 deletions x-pack/plugins/monitoring/common/es_glob_patterns.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export interface RegExPatterns {
contains?: string | RegExp;
negate?: string | RegExp;
}

const valid = /.*/;

export class ESGlobPatterns {
public static createRegExPatterns(globPattern: string) {
if (globPattern === '*') {
return { contains: valid, negate: valid };
}

globPattern = globPattern.toLowerCase();
globPattern = globPattern.replace(/[ \\\/?"<>|#]/g, '');
const patternsArr = globPattern.split(',');
const containPatterns: string[] = [];
const negatePatterns: string[] = [];
patternsArr.forEach((pattern) => {
if (pattern.charAt(0) === '-') {
negatePatterns.push(ESGlobPatterns.createESGlobRegExStr(pattern.slice(1)));
} else {
containPatterns.push(ESGlobPatterns.createESGlobRegExStr(pattern));
}
});
const contains = containPatterns.length ? new RegExp(containPatterns.join('|'), 'gi') : valid;
const negate = negatePatterns.length
? new RegExp(`^((?!(${negatePatterns.join('|')})).)*$`, 'gi')
: valid;
return { contains, negate };
}

public static isValid(value: string, patterns: RegExPatterns) {
const { contains = valid, negate = valid } = patterns;
return new RegExp(contains).test(value) && new RegExp(negate).test(value);
}

private static createESGlobRegExStr(pattern: string) {
const patternsArr = pattern.split('*');
const firstItem = patternsArr.shift();
const lastItem = patternsArr.pop();
const start = firstItem?.length ? `(^${ESGlobPatterns.escapeStr(firstItem)})` : '';
const mid = patternsArr.map((group) => `(.*${ESGlobPatterns.escapeStr(group)})`);
const end = lastItem?.length ? `(.*${ESGlobPatterns.escapeStr(lastItem)}$)` : '';
const regExArr = ['(^', start, ...mid, end, ')'];
return regExArr.join('');
}

private static escapeStr(str: string) {
return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}
}
14 changes: 14 additions & 0 deletions x-pack/plugins/monitoring/common/types/alerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface CommonAlertFilter {
export interface CommonAlertParamDetail {
label: string;
type?: AlertParamType;
[name: string]: unknown | undefined;
}

export interface CommonAlertParamDetails {
Expand All @@ -38,6 +39,7 @@ export interface CommonAlertParams {
duration: string;
threshold?: number;
limit?: string;
[key: string]: unknown;
}

export interface ThreadPoolRejectionsAlertParams {
Expand Down Expand Up @@ -182,6 +184,18 @@ export interface CCRReadExceptionsUIMeta extends CCRReadExceptionsStats {
itemLabel: string;
}

export interface IndexShardSizeStats extends AlertNodeStats {
shardIndex: string;
shardSize: number;
}

export interface IndexShardSizeUIMeta extends IndexShardSizeStats {
shardIndex: string;
shardSize: number;
instanceId: string;
itemLabel: string;
}

export interface AlertData {
nodeName?: string;
nodeId?: string;
Expand Down
46 changes: 24 additions & 22 deletions x-pack/plugins/monitoring/common/types/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,29 @@ export interface ElasticsearchNodeStats {
};
}

export interface ElasticsearchIndexStats {
index?: string;
primaries?: {
docs?: {
count?: number;
};
store?: {
size_in_bytes?: number;
};
indexing?: {
index_total?: number;
};
};
total?: {
store?: {
size_in_bytes?: number;
};
search?: {
query_total?: number;
};
};
}

export interface ElasticsearchLegacySource {
timestamp: string;
cluster_uuid: string;
Expand Down Expand Up @@ -243,28 +266,7 @@ export interface ElasticsearchLegacySource {
name?: string;
};
};
index_stats?: {
index?: string;
primaries?: {
docs?: {
count?: number;
};
store?: {
size_in_bytes?: number;
};
indexing?: {
index_total?: number;
};
};
total?: {
store?: {
size_in_bytes?: number;
};
search?: {
query_total?: number;
};
};
};
index_stats?: ElasticsearchIndexStats;
node_stats?: ElasticsearchNodeStats;
service?: {
address?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import React from 'react';
import { i18n } from '@kbn/i18n';
import { Expression, Props } from '../components/duration/expression';
import { Expression, Props } from '../components/param_details_form/expression';
import { AlertTypeModel, ValidationResult } from '../../../../triggers_actions_ui/public';
import { ALERT_CCR_READ_EXCEPTIONS, ALERT_DETAILS } from '../../../common/constants';
import { AlertTypeParams } from '../../../../alerts/common';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { AlertParamDuration } from '../../flyout_expressions/alert_param_duratio
import { AlertParamType } from '../../../../common/enums';
import { AlertParamPercentage } from '../../flyout_expressions/alert_param_percentage';
import { AlertParamNumber } from '../../flyout_expressions/alert_param_number';
import { AlertParamTextField } from '../../flyout_expressions/alert_param_textfield';

export interface Props {
alertParams: { [property: string]: any };
Expand All @@ -23,7 +24,7 @@ export interface Props {
export const Expression: React.FC<Props> = (props) => {
const { alertParams, paramDetails, setAlertParams, errors } = props;

const alertParamsUi = Object.keys(alertParams).map((alertParamName) => {
const alertParamsUi = Object.keys(paramDetails).map((alertParamName) => {
const details = paramDetails[alertParamName];
const value = alertParams[alertParamName];

Expand Down Expand Up @@ -53,6 +54,17 @@ export const Expression: React.FC<Props> = (props) => {
case AlertParamType.Number:
return (
<AlertParamNumber
key={alertParamName}
name={alertParamName}
details={details}
value={value}
errors={errors[alertParamName]}
setAlertParams={setAlertParams}
/>
);
case AlertParamType.TextField:
return (
<AlertParamTextField
key={alertParamName}
name={alertParamName}
label={details?.label}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import React from 'react';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { AlertTypeModel } from '../../../../triggers_actions_ui/public/types';
import { ALERT_CPU_USAGE, ALERT_DETAILS } from '../../../common/constants';
import { validate, MonitoringAlertTypeParams } from '../components/duration/validation';
import { Expression, Props } from '../components/duration/expression';
import { validate, MonitoringAlertTypeParams } from '../components/param_details_form/validation';
import { Expression, Props } from '../components/param_details_form/expression';

export function createCpuUsageAlertType(): AlertTypeModel<MonitoringAlertTypeParams> {
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
*/

import React from 'react';
import { validate, MonitoringAlertTypeParams } from '../components/duration/validation';
import { Expression, Props } from '../components/duration/expression';
import { validate, MonitoringAlertTypeParams } from '../components/param_details_form/validation';
import { Expression, Props } from '../components/param_details_form/expression';

// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { AlertTypeModel } from '../../../../triggers_actions_ui/public/types';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,19 @@ import { EuiFormRow, EuiFieldNumber } from '@elastic/eui';
interface Props {
name: string;
value: number;
label: string;
details: { [key: string]: unknown };
errors: string[];
setAlertParams: (property: string, value: number) => void;
}
export const AlertParamNumber: React.FC<Props> = (props: Props) => {
const { name, label, setAlertParams, errors } = props;
const { name, details, setAlertParams, errors } = props;
const [value, setValue] = useState(props.value);
return (
<EuiFormRow label={label} error={errors} isInvalid={errors?.length > 0}>
<EuiFormRow label={details.label as string} error={errors} isInvalid={errors?.length > 0}>
<EuiFieldNumber
compressed
value={value}
append={details.append as string}
onChange={(e) => {
let newValue = Number(e.target.value);
if (isNaN(newValue)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useState } from 'react';
import { EuiFormRow, EuiFieldText } from '@elastic/eui';

interface Props {
name: string;
value: string;
placeholder?: string;
label: string;
errors: string[];
setAlertParams: (property: string, value: string) => void;
}
export const AlertParamTextField: React.FC<Props> = (props: Props) => {
const { name, label, setAlertParams, errors, placeholder } = props;
const [value, setValue] = useState(props.value);
return (
<EuiFormRow label={label} error={errors} isInvalid={errors?.length > 0}>
<EuiFieldText
compressed
placeholder={placeholder}
value={value}
onChange={(e) => {
const newValue = e.target.value;
setValue(newValue);
setAlertParams(name, newValue);
}}
/>
</EuiFormRow>
);
};
Loading

0 comments on commit 1bc6c1c

Please sign in to comment.