Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[APM] Add error grouping key filter in error count rule type #155410

Merged
merged 7 commits into from
Apr 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions x-pack/plugins/apm/common/rules/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const errorCountParamsSchema = schema.object({
threshold: schema.number(),
serviceName: schema.maybe(schema.string()),
environment: schema.string(),
errorGroupingKey: schema.maybe(schema.string()),
});

export const transactionDurationParamsSchema = schema.object({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { createCallApmApi } from '../../../../services/rest/create_call_apm_api'
import { ChartPreview } from '../../ui_components/chart_preview';
import {
EnvironmentField,
ErrorGroupingKeyField,
IsAboveField,
ServiceField,
} from '../../utils/fields';
Expand All @@ -33,6 +34,7 @@ export interface RuleParams {
threshold?: number;
serviceName?: string;
environment?: string;
errorGroupingKey?: string;
}

interface Props {
Expand Down Expand Up @@ -74,6 +76,7 @@ export function ErrorCountRuleType(props: Props) {
query: {
environment: params.environment,
serviceName: params.serviceName,
errorGroupingKey: params.errorGroupingKey,
interval,
start,
end,
Expand All @@ -88,6 +91,7 @@ export function ErrorCountRuleType(props: Props) {
params.windowUnit,
params.environment,
params.serviceName,
params.errorGroupingKey,
]
);

Expand All @@ -98,6 +102,7 @@ export function ErrorCountRuleType(props: Props) {
if (value !== params.serviceName) {
setRuleParams('serviceName', value);
setRuleParams('environment', ENVIRONMENT_ALL.value);
setRuleParams('errorGroupingKey', undefined);
}
}}
/>,
Expand All @@ -106,6 +111,12 @@ export function ErrorCountRuleType(props: Props) {
onChange={(value) => setRuleParams('environment', value)}
serviceName={params.serviceName}
/>,
<ErrorGroupingKeyField
currentValue={params.errorGroupingKey}
onChange={(value) => setRuleParams('errorGroupingKey', value)}
serviceName={params.serviceName}
/>,

<IsAboveField
value={params.threshold}
unit={i18n.translate('xpack.apm.errorCountRuleType.errors', {
Expand Down
40 changes: 40 additions & 0 deletions x-pack/plugins/apm/public/components/alerting/utils/fields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { EuiFieldNumber } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import {
ERROR_GROUP_ID,
SERVICE_ENVIRONMENT,
SERVICE_NAME,
TRANSACTION_TYPE,
Expand Down Expand Up @@ -178,6 +179,45 @@ export function TransactionTypeField({
);
}

export function ErrorGroupingKeyField({
currentValue,
onChange,
serviceName,
}: {
currentValue?: string;
onChange: (value?: string) => void;
serviceName?: string;
}) {
const label = i18n.translate('xpack.apm.alerting.fields.error.group.id', {
defaultMessage: 'Error grouping key',
});
return (
<PopoverExpression value={currentValue || allOptionText} title={label}>
<SuggestionsSelect
customOptions={[{ label: allOptionText, value: undefined }]}
customOptionText={i18n.translate(
'xpack.apm.errorKeySelectCustomOptionText',
{
defaultMessage: 'Add \\{searchValue\\} as a new error grouping key',
}
)}
defaultValue={currentValue}
fieldName={ERROR_GROUP_ID}
onChange={onChange}
placeholder={i18n.translate(
'xpack.apm.errorGroupingKeySelectPlaceholder',
{
defaultMessage: 'Select error grouping key',
}
)}
start={moment().subtract(24, 'h').toISOString()}
end={moment().toISOString()}
serviceName={serviceName}
/>
</PopoverExpression>
);
}

export function IsAboveField({
value,
unit,
Expand Down
9 changes: 9 additions & 0 deletions x-pack/plugins/apm/server/routes/alerts/action_variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,13 @@ export const apmActionVariables = {
name: 'viewInAppUrl' as const,
usesPublicBaseUrl: true,
},
errorGroupingKey: {
description: i18n.translate(
'xpack.apm.alerts.action_variables.errorGroupingKey',
{
defaultMessage: 'The error grouping key the alert is created for',
}
),
name: 'errorGroupingKey' as const,
},
};
1 change: 1 addition & 0 deletions x-pack/plugins/apm/server/routes/alerts/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const alertParamsRt = t.intersection([
t.literal(AggregationType.P99),
]),
serviceName: t.string,
errorGroupingKey: t.string,
transactionType: t.string,
transactionName: t.string,
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@

import { rangeQuery, termQuery } from '@kbn/observability-plugin/server';
import { ProcessorEvent } from '@kbn/observability-plugin/common';
import { SERVICE_NAME } from '../../../../../common/es_fields/apm';
import {
ERROR_GROUP_ID,
SERVICE_NAME,
} from '../../../../../common/es_fields/apm';
import { AlertParams } from '../../route';
import { environmentQuery } from '../../../../../common/utils/environment_query';
import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client';
Expand All @@ -24,12 +27,14 @@ export async function getTransactionErrorCountChartPreview({
apmEventClient: APMEventClient;
alertParams: AlertParams;
}): Promise<TransactionErrorCountChartPreviewResponse> {
const { serviceName, environment, interval, start, end } = alertParams;
const { serviceName, environment, errorGroupingKey, interval, start, end } =
alertParams;

const query = {
bool: {
filter: [
...termQuery(SERVICE_NAME, serviceName),
...termQuery(ERROR_GROUP_ID, errorGroupingKey),
...rangeQuery(start, end),
...environmentQuery(environment),
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
getEnvironmentLabel,
} from '../../../../../common/environment_filter_values';
import {
ERROR_GROUP_ID,
PROCESSOR_EVENT,
SERVICE_ENVIRONMENT,
SERVICE_NAME,
Expand Down Expand Up @@ -77,6 +78,7 @@ export function registerErrorCountRuleType({
apmActionVariables.interval,
apmActionVariables.reason,
apmActionVariables.serviceName,
apmActionVariables.errorGroupingKey,
apmActionVariables.threshold,
apmActionVariables.triggerValue,
apmActionVariables.viewInAppUrl,
Expand Down Expand Up @@ -112,6 +114,7 @@ export function registerErrorCountRuleType({
},
{ term: { [PROCESSOR_EVENT]: ProcessorEvent.error } },
...termQuery(SERVICE_NAME, ruleParams.serviceName),
...termQuery(ERROR_GROUP_ID, ruleParams.errorGroupingKey),
...environmentQuery(ruleParams.environment),
],
},
Expand Down Expand Up @@ -164,7 +167,12 @@ export function registerErrorCountRuleType({
windowUnit: ruleParams.windowUnit,
});

const id = [ApmRuleType.ErrorCount, serviceName, environment]
const id = [
ApmRuleType.ErrorCount,
serviceName,
environment,
ruleParams.errorGroupingKey,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kpatticha do we need ruleParams.errorGroupingKey to be added in alert ID? It will always be same value for a given rule as it is coming from the filter. Is it ok if we keep this implementation?

Copy link
Contributor Author

@kpatticha kpatticha Apr 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it ok if we keep this implementation?

@benakansara Yes, let's keep what you've implemented regarding the IDs.

do we need ruleParams.errorGroupingKey to be added in alert ID?
No, we don't since we're planning to add the error.grouping_key as a grouping field

]
.filter((name) => name)
.join('_');

Expand All @@ -188,6 +196,7 @@ export function registerErrorCountRuleType({
[PROCESSOR_EVENT]: ProcessorEvent.error,
[ALERT_EVALUATION_VALUE]: errorCount,
[ALERT_EVALUATION_THRESHOLD]: ruleParams.threshold,
[ERROR_GROUP_ID]: ruleParams.errorGroupingKey,
[ALERT_REASON]: alertReason,
...sourceFields,
},
Expand All @@ -201,6 +210,7 @@ export function registerErrorCountRuleType({
reason: alertReason,
serviceName,
threshold: ruleParams.threshold,
errorGroupingKey: ruleParams.errorGroupingKey,
triggerValue: errorCount,
viewInAppUrl,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,33 @@ export default function ApiTest({ getService }: FtrProviderContext) {
).to.equal(true);
});

it('error_count with error grouping key', async () => {
const options = {
params: {
query: {
start,
end,
serviceName: 'opbeans-java',
errorGroupingKey: 'd16d39e7fa133b8943cea035430a7b4e',
environment: 'ENVIRONMENT_ALL',
interval: '5m',
},
},
};

const response = await apmApiClient.readUser({
endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview',
...options,
});

expect(response.status).to.be(200);
expect(response.body.errorCountChartPreview).to.eql([
{ x: 1627974600000, y: 4 },
{ x: 1627974900000, y: 2 },
{ x: 1627975200000, y: 0 },
]);
});

it('transaction_duration (with data)', async () => {
const options = getOptions();
const response = await apmApiClient.readUser({
Expand Down