From b9c08bac92f60495a87149f6a49624aef49ce137 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Thu, 9 Nov 2023 08:26:25 -0700 Subject: [PATCH] [SLO] Add support for document count to custom metric indicator (#170913) ## :cherries: Summary This PR fixes #170905 by adding the aggregation menu to the Custom Metric indicator to allow the user to pick either `doc_count` or `sum` for the aggregation. image --- .../kbn-slo-schema/src/schema/indicators.ts | 39 +++--- .../custom_metric/metric_indicator.tsx | 121 +++++++++++++++--- .../timeslice_metric/metric_input.tsx | 2 +- .../slo_edit/helpers/aggregation_options.ts | 4 + .../hooks/use_section_form_validation.ts | 24 +++- ..._metric_indicator_aggregation.test.ts.snap | 12 +- ...get_custom_metric_indicator_aggregation.ts | 23 +++- .../__snapshots__/metric_custom.test.ts.snap | 74 ++++++++--- .../metric_custom.test.ts | 42 ++++++ .../translations/translations/fr-FR.json | 2 - .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - 12 files changed, 274 insertions(+), 73 deletions(-) diff --git a/x-pack/packages/kbn-slo-schema/src/schema/indicators.ts b/x-pack/packages/kbn-slo-schema/src/schema/indicators.ts index f8d795275acc6..c6748eba37968 100644 --- a/x-pack/packages/kbn-slo-schema/src/schema/indicators.ts +++ b/x-pack/packages/kbn-slo-schema/src/schema/indicators.ts @@ -136,22 +136,29 @@ const timesliceMetricIndicatorSchema = t.type({ ]), }); -const metricCustomValidAggregations = t.keyof({ - sum: true, -}); +const metricCustomDocCountMetric = t.intersection([ + t.type({ + name: t.string, + aggregation: t.literal('doc_count'), + }), + t.partial({ + filter: t.string, + }), +]); + +const metricCustomBasicMetric = t.intersection([ + t.type({ + name: t.string, + aggregation: t.literal('sum'), + field: t.string, + }), + t.partial({ + filter: t.string, + }), +]); + const metricCustomMetricDef = t.type({ - metrics: t.array( - t.intersection([ - t.type({ - name: t.string, - aggregation: metricCustomValidAggregations, - field: t.string, - }), - t.partial({ - filter: t.string, - }), - ]) - ), + metrics: t.array(t.union([metricCustomBasicMetric, metricCustomDocCountMetric])), equation: t.string, }); const metricCustomIndicatorTypeSchema = t.literal('sli.metric.custom'); @@ -267,6 +274,8 @@ export { kqlCustomIndicatorTypeSchema, metricCustomIndicatorSchema, metricCustomIndicatorTypeSchema, + metricCustomDocCountMetric, + metricCustomBasicMetric, timesliceMetricComparatorMapping, timesliceMetricIndicatorSchema, timesliceMetricIndicatorTypeSchema, diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/metric_indicator.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/metric_indicator.tsx index ec413f46df5dd..262e6e6d2249a 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/metric_indicator.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/metric_indicator.tsx @@ -22,6 +22,10 @@ import { first, range, xor } from 'lodash'; import React, { useEffect, useState } from 'react'; import { Controller, useFieldArray, useFormContext } from 'react-hook-form'; import { Field } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; +import { + aggValueToLabel, + CUSTOM_METRIC_AGGREGATION_OPTIONS, +} from '../../helpers/aggregation_options'; import { createOptionsFromFields, Option } from '../../helpers/create_options'; import { CreateSLOForm } from '../../types'; import { QueryBuilder } from '../common/query_builder'; @@ -62,7 +66,8 @@ const metricTooltip = ( content={i18n.translate( 'xpack.observability.slo.sloEdit.sliType.customMetric.totalMetric.tooltip', { - defaultMessage: 'This data from this field will be aggregated with the "sum" aggregation.', + defaultMessage: + 'This data from this field will be aggregated with the "sum" aggregation or document count.', } )} position="top" @@ -89,6 +94,7 @@ const equationTooltip = ( export function MetricIndicator({ type, metricFields, isLoadingIndex }: MetricIndicatorProps) { const { control, watch, setValue, register, getFieldState } = useFormContext(); const [options, setOptions] = useState(createOptionsFromFields(metricFields)); + const [aggregationOptions, setAggregationOptions] = useState(CUSTOM_METRIC_AGGREGATION_OPTIONS); useEffect(() => { setOptions(createOptionsFromFields(metricFields)); @@ -131,20 +137,25 @@ export function MetricIndicator({ type, metricFields, isLoadingIndex }: MetricIn {fields?.map((metric, index) => ( - - {metricLabel} {metric.name} {metricTooltip} + {i18n.translate( + 'xpack.observability.slo.sloEdit.customMetric.aggregationLabel', + { defaultMessage: 'Aggregation' } + )}{' '} + {metric.name} } > ( @@ -153,17 +164,13 @@ export function MetricIndicator({ type, metricFields, isLoadingIndex }: MetricIn async fullWidth singleSelection={{ asPlainText: true }} - prepend={i18n.translate( - 'xpack.observability.slo.sloEdit.sliType.customMetric.sumLabel', - { defaultMessage: 'Sum of' } - )} placeholder={i18n.translate( - 'xpack.observability.slo.sloEdit.sliType.customMetric.metricField.placeholder', - { defaultMessage: 'Select a metric field' } + 'xpack.observability.slo.sloEdit.sliType.customMetric.aggregation.placeholder', + { defaultMessage: 'Select an aggregation' } )} aria-label={i18n.translate( - 'xpack.observability.slo.sloEdit.sliType.customMetric.metricField.placeholder', - { defaultMessage: 'Select a metric field' } + 'xpack.observability.slo.sloEdit.sliType.customMetric.aggregation.placeholder', + { defaultMessage: 'Select an aggregation' } )} isClearable isInvalid={fieldState.invalid} @@ -178,40 +185,112 @@ export function MetricIndicator({ type, metricFields, isLoadingIndex }: MetricIn selectedOptions={ !!indexPattern && !!field.value && - metricFields.some((metricField) => metricField.name === field.value) + CUSTOM_METRIC_AGGREGATION_OPTIONS.some((agg) => agg.value === field.value) ? [ { value: field.value, - label: field.value, + label: aggValueToLabel(field.value), }, ] : [] } onSearchChange={(searchValue: string) => { - setOptions( - createOptionsFromFields(metricFields, ({ value }) => + setAggregationOptions( + CUSTOM_METRIC_AGGREGATION_OPTIONS.filter(({ value }) => value.includes(searchValue) ) ); }} - options={options} + options={aggregationOptions} /> )} /> + {watch(`indicator.params.${type}.metrics.${index}.aggregation`) !== 'doc_count' && ( + + + {metricLabel} {metric.name} {metricTooltip} + + } + > + ( + { + if (selected.length) { + return field.onChange(selected[0].value); + } + field.onChange(''); + }} + selectedOptions={ + !!indexPattern && + !!field.value && + metricFields.some((metricField) => metricField.name === field.value) + ? [ + { + value: field.value, + label: field.value, + }, + ] + : [] + } + onSearchChange={(searchValue: string) => { + setOptions( + createOptionsFromFields(metricFields, ({ value }) => + value.includes(searchValue) + ) + ); + }} + options={options} + /> + )} + /> + + + )} agg.value === agg.value) + AGGREGATION_OPTIONS.some((agg) => agg.value === field.value) ? [ { value: field.value, diff --git a/x-pack/plugins/observability/public/pages/slo_edit/helpers/aggregation_options.ts b/x-pack/plugins/observability/public/pages/slo_edit/helpers/aggregation_options.ts index 4a3a5fb9cf28a..ab27dcd68efe5 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/helpers/aggregation_options.ts +++ b/x-pack/plugins/observability/public/pages/slo_edit/helpers/aggregation_options.ts @@ -75,6 +75,10 @@ export const AGGREGATION_OPTIONS = [ }, ]; +export const CUSTOM_METRIC_AGGREGATION_OPTIONS = AGGREGATION_OPTIONS.filter((option) => + ['doc_count', 'sum'].includes(option.value) +); + export function aggValueToLabel(value: string) { const aggregation = AGGREGATION_OPTIONS.find((agg) => agg.value === value); if (aggregation) { diff --git a/x-pack/plugins/observability/public/pages/slo_edit/hooks/use_section_form_validation.ts b/x-pack/plugins/observability/public/pages/slo_edit/hooks/use_section_form_validation.ts index 6fede4552d6f8..e8cabe602e7cc 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/hooks/use_section_form_validation.ts +++ b/x-pack/plugins/observability/public/pages/slo_edit/hooks/use_section_form_validation.ts @@ -6,6 +6,8 @@ */ import { + metricCustomBasicMetric, + metricCustomDocCountMetric, MetricCustomIndicator, timesliceMetricBasicMetricWithField, TimesliceMetricIndicator, @@ -31,7 +33,16 @@ export function useSectionFormValidation({ getFieldState, getValues, formState, const data = getValues('indicator.params.good') as MetricCustomIndicator['params']['good']; const isEquationValid = !getFieldState('indicator.params.good.equation').invalid; const areMetricsValid = - isObject(data) && (data.metrics ?? []).every((metric) => Boolean(metric.field)); + isObject(data) && + (data.metrics ?? []).every((metric) => { + if (metricCustomDocCountMetric.is(metric)) { + return true; + } + if (metricCustomBasicMetric.is(metric) && metric.field != null) { + return true; + } + return false; + }); return isEquationValid && areMetricsValid; }; @@ -41,7 +52,16 @@ export function useSectionFormValidation({ getFieldState, getValues, formState, ) as MetricCustomIndicator['params']['total']; const isEquationValid = !getFieldState('indicator.params.total.equation').invalid; const areMetricsValid = - isObject(data) && (data.metrics ?? []).every((metric) => Boolean(metric.field)); + isObject(data) && + (data.metrics ?? []).every((metric) => { + if (metricCustomDocCountMetric.is(metric)) { + return true; + } + if (metricCustomBasicMetric.is(metric) && metric.field != null) { + return true; + } + return false; + }); return isEquationValid && areMetricsValid; }; diff --git a/x-pack/plugins/observability/server/services/slo/aggregations/__snapshots__/get_custom_metric_indicator_aggregation.test.ts.snap b/x-pack/plugins/observability/server/services/slo/aggregations/__snapshots__/get_custom_metric_indicator_aggregation.test.ts.snap index f5558a33f1981..6bf8f0ad13e56 100644 --- a/x-pack/plugins/observability/server/services/slo/aggregations/__snapshots__/get_custom_metric_indicator_aggregation.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/aggregations/__snapshots__/get_custom_metric_indicator_aggregation.test.ts.snap @@ -4,7 +4,7 @@ exports[`GetHistogramIndicatorAggregation should generate a aggregation for good Object { "_good_A": Object { "aggs": Object { - "sum": Object { + "metric": Object { "sum": Object { "field": "total", }, @@ -16,7 +16,7 @@ Object { }, "_good_B": Object { "aggs": Object { - "sum": Object { + "metric": Object { "sum": Object { "field": "processed", }, @@ -29,8 +29,8 @@ Object { "goodEvents": Object { "bucket_script": Object { "buckets_path": Object { - "A": "_good_A>sum", - "B": "_good_B>sum", + "A": "_good_A>metric", + "B": "_good_B>metric", }, "script": Object { "lang": "painless", @@ -45,7 +45,7 @@ exports[`GetHistogramIndicatorAggregation should generate a aggregation for tota Object { "_total_A": Object { "aggs": Object { - "sum": Object { + "metric": Object { "sum": Object { "field": "total", }, @@ -58,7 +58,7 @@ Object { "totalEvents": Object { "bucket_script": Object { "buckets_path": Object { - "A": "_total_A>sum", + "A": "_total_A>metric", }, "script": Object { "lang": "painless", diff --git a/x-pack/plugins/observability/server/services/slo/aggregations/get_custom_metric_indicator_aggregation.ts b/x-pack/plugins/observability/server/services/slo/aggregations/get_custom_metric_indicator_aggregation.ts index 73bbb91b1041f..6c3439eb9a146 100644 --- a/x-pack/plugins/observability/server/services/slo/aggregations/get_custom_metric_indicator_aggregation.ts +++ b/x-pack/plugins/observability/server/services/slo/aggregations/get_custom_metric_indicator_aggregation.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { MetricCustomIndicator } from '@kbn/slo-schema'; +import { metricCustomDocCountMetric, MetricCustomIndicator } from '@kbn/slo-schema'; import { getElastichsearchQueryOrThrow } from '../transform_generators'; type MetricCustomMetricDef = @@ -20,12 +20,22 @@ export class GetCustomMetricIndicatorAggregation { const filter = metric.filter ? getElastichsearchQueryOrThrow(metric.filter) : { match_all: {} }; + + if (metricCustomDocCountMetric.is(metric)) { + return { + ...acc, + [`_${type}_${metric.name}`]: { + filter, + }, + }; + } + return { ...acc, [`_${type}_${metric.name}`]: { filter, aggs: { - sum: { + metric: { [metric.aggregation]: { field: metric.field }, }, }, @@ -42,10 +52,11 @@ export class GetCustomMetricIndicatorAggregation { } private buildMetricEquation(type: 'good' | 'total', metricDef: MetricCustomMetricDef) { - const bucketsPath = metricDef.metrics.reduce( - (acc, metric) => ({ ...acc, [metric.name]: `_${type}_${metric.name}>sum` }), - {} - ); + const bucketsPath = metricDef.metrics.reduce((acc, metric) => { + const path = metricCustomDocCountMetric.is(metric) ? '_count' : 'metric'; + return { ...acc, [metric.name]: `_${type}_${metric.name}>${path}` }; + }, {}); + return { bucket_script: { buckets_path: bucketsPath, diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/metric_custom.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/metric_custom.test.ts.snap index 7c1765953d154..55ed414bd2ec7 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/metric_custom.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/metric_custom.test.ts.snap @@ -1,10 +1,38 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Metric Custom Transform Generator aggregates using doc_count for the denominator equation with filter 1`] = ` +Object { + "bucket_script": Object { + "buckets_path": Object { + "A": "_total_A>_count", + }, + "script": Object { + "lang": "painless", + "source": "params.A / 100", + }, + }, +} +`; + +exports[`Metric Custom Transform Generator aggregates using doc_count the numerator equation with filter 1`] = ` +Object { + "bucket_script": Object { + "buckets_path": Object { + "A": "_good_A>_count", + }, + "script": Object { + "lang": "painless", + "source": "params.A * 100", + }, + }, +} +`; + exports[`Metric Custom Transform Generator aggregates using the denominator equation 1`] = ` Object { "bucket_script": Object { "buckets_path": Object { - "A": "_total_A>sum", + "A": "_total_A>metric", }, "script": Object { "lang": "painless", @@ -18,7 +46,7 @@ exports[`Metric Custom Transform Generator aggregates using the denominator equa Object { "bucket_script": Object { "buckets_path": Object { - "A": "_total_A>sum", + "A": "_total_A>metric", }, "script": Object { "lang": "painless", @@ -32,7 +60,7 @@ exports[`Metric Custom Transform Generator aggregates using the numerator equati Object { "bucket_script": Object { "buckets_path": Object { - "A": "_good_A>sum", + "A": "_good_A>metric", }, "script": Object { "lang": "painless", @@ -46,7 +74,7 @@ exports[`Metric Custom Transform Generator aggregates using the numerator equati Object { "bucket_script": Object { "buckets_path": Object { - "A": "_good_A>sum", + "A": "_good_A>metric", }, "script": Object { "lang": "painless", @@ -101,7 +129,7 @@ Object { "aggregations": Object { "_good_A": Object { "aggs": Object { - "sum": Object { + "metric": Object { "sum": Object { "field": "total", }, @@ -113,7 +141,7 @@ Object { }, "_good_B": Object { "aggs": Object { - "sum": Object { + "metric": Object { "sum": Object { "field": "processed", }, @@ -125,7 +153,7 @@ Object { }, "_total_A": Object { "aggs": Object { - "sum": Object { + "metric": Object { "sum": Object { "field": "total", }, @@ -138,7 +166,7 @@ Object { "slo.denominator": Object { "bucket_script": Object { "buckets_path": Object { - "A": "_total_A>sum", + "A": "_total_A>metric", }, "script": Object { "lang": "painless", @@ -158,8 +186,8 @@ Object { "slo.numerator": Object { "bucket_script": Object { "buckets_path": Object { - "A": "_good_A>sum", - "B": "_good_B>sum", + "A": "_good_A>metric", + "B": "_good_B>metric", }, "script": Object { "lang": "painless", @@ -384,7 +412,7 @@ Object { "aggregations": Object { "_good_A": Object { "aggs": Object { - "sum": Object { + "metric": Object { "sum": Object { "field": "total", }, @@ -396,7 +424,7 @@ Object { }, "_good_B": Object { "aggs": Object { - "sum": Object { + "metric": Object { "sum": Object { "field": "processed", }, @@ -408,7 +436,7 @@ Object { }, "_total_A": Object { "aggs": Object { - "sum": Object { + "metric": Object { "sum": Object { "field": "total", }, @@ -421,7 +449,7 @@ Object { "slo.denominator": Object { "bucket_script": Object { "buckets_path": Object { - "A": "_total_A>sum", + "A": "_total_A>metric", }, "script": Object { "lang": "painless", @@ -432,8 +460,8 @@ Object { "slo.numerator": Object { "bucket_script": Object { "buckets_path": Object { - "A": "_good_A>sum", - "B": "_good_B>sum", + "A": "_good_A>metric", + "B": "_good_B>metric", }, "script": Object { "lang": "painless", @@ -629,3 +657,17 @@ Object { "transform_id": Any, } `; + +exports[`Metric Custom Transform Generator support the same field used twice in the equation 1`] = ` +Object { + "bucket_script": Object { + "buckets_path": Object { + "A": "_good_A>metric", + }, + "script": Object { + "lang": "painless", + "source": "params.A + params.A * 100", + }, + }, +} +`; diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/metric_custom.test.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/metric_custom.test.ts index beea8164b1c99..69685bad0c09e 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/metric_custom.test.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/metric_custom.test.ts @@ -142,6 +142,20 @@ describe('Metric Custom Transform Generator', () => { expect(transform.pivot!.aggregations!['slo.numerator']).toMatchSnapshot(); }); + it('support the same field used twice in the equation', async () => { + const anSLO = createSLO({ + indicator: createMetricCustomIndicator({ + good: { + metrics: [{ name: 'A', aggregation: 'sum', field: 'good' }], + equation: 'A + A * 100', + }, + }), + }); + const transform = generator.getTransformParams(anSLO); + + expect(transform.pivot!.aggregations!['slo.numerator']).toMatchSnapshot(); + }); + it('aggregates using the numerator equation with filter', async () => { const anSLO = createSLO({ indicator: createMetricCustomIndicator({ @@ -158,6 +172,20 @@ describe('Metric Custom Transform Generator', () => { expect(transform.pivot!.aggregations!['slo.numerator']).toMatchSnapshot(); }); + it('aggregates using doc_count the numerator equation with filter', async () => { + const anSLO = createSLO({ + indicator: createMetricCustomIndicator({ + good: { + metrics: [{ name: 'A', aggregation: 'doc_count', filter: 'outcome: "success" ' }], + equation: 'A * 100', + }, + }), + }); + const transform = generator.getTransformParams(anSLO); + + expect(transform.pivot!.aggregations!['slo.numerator']).toMatchSnapshot(); + }); + it('aggregates using the denominator equation', async () => { const anSLO = createSLO({ indicator: createMetricCustomIndicator({ @@ -185,4 +213,18 @@ describe('Metric Custom Transform Generator', () => { expect(transform.pivot!.aggregations!['slo.denominator']).toMatchSnapshot(); }); + + it('aggregates using doc_count for the denominator equation with filter', async () => { + const anSLO = createSLO({ + indicator: createMetricCustomIndicator({ + total: { + metrics: [{ name: 'A', aggregation: 'doc_count', filter: 'outcome: *' }], + equation: 'A / 100', + }, + }), + }); + const transform = generator.getTransformParams(anSLO); + + expect(transform.pivot!.aggregations!['slo.denominator']).toMatchSnapshot(); + }); }); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index d00b542c58131..6c64ec463940e 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -29682,12 +29682,10 @@ "xpack.observability.slo.sloEdit.sliType.customMetric.equationHelpText": "Accepte les équations mathématiques de base, les caractères valides sont : A-Z, +, -, /, *, (, ), ?, !, &, :, |, >, <, =", "xpack.observability.slo.sloEdit.sliType.customMetric.equationLabel": "Équation", "xpack.observability.slo.sloEdit.sliType.customMetric.filterLabel": "Filtre", - "xpack.observability.slo.sloEdit.sliType.customMetric.goodQuery.tooltip": "Cette requête KQL doit renvoyer un sous-ensemble d'événements.", "xpack.observability.slo.sloEdit.sliType.customMetric.goodTitle": "Bons événements", "xpack.observability.slo.sloEdit.sliType.customMetric.metricField.placeholder": "Sélectionner un champ d’indicateur", "xpack.observability.slo.sloEdit.sliType.customMetric.metricLabel": "Indicateur", "xpack.observability.slo.sloEdit.sliType.customMetric.queryFilter": "Filtre de requête", - "xpack.observability.slo.sloEdit.sliType.customMetric.sumLabel": "Somme de", "xpack.observability.slo.sloEdit.sliType.customMetric.totalEquation.tooltip": "Ceci est compatible avec des calculs de base (A + B / C) et la logique booléenne (A < B ? A : B).", "xpack.observability.slo.sloEdit.sliType.customMetric.totalMetric.tooltip": "Les données de ce champ seront agrégées avec l’agréation de \"somme\".", "xpack.observability.slo.sloEdit.sliType.customMetric.totalTitle": "Total des événements", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 1ce0c2df38db5..a24d4d8cc7c10 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -29681,12 +29681,10 @@ "xpack.observability.slo.sloEdit.sliType.customMetric.equationHelpText": "基本的な数式をサポートします。有効な文字:A-Z、+、-、/、*、(、)、?、!、&、:、|、>、<、=", "xpack.observability.slo.sloEdit.sliType.customMetric.equationLabel": "式", "xpack.observability.slo.sloEdit.sliType.customMetric.filterLabel": "フィルター", - "xpack.observability.slo.sloEdit.sliType.customMetric.goodQuery.tooltip": "このKQLクエリはイベントのサブセットを返します。", "xpack.observability.slo.sloEdit.sliType.customMetric.goodTitle": "良好なイベント数", "xpack.observability.slo.sloEdit.sliType.customMetric.metricField.placeholder": "メトリックフィールドを選択", "xpack.observability.slo.sloEdit.sliType.customMetric.metricLabel": "メトリック", "xpack.observability.slo.sloEdit.sliType.customMetric.queryFilter": "クエリのフィルター", - "xpack.observability.slo.sloEdit.sliType.customMetric.sumLabel": "の合計", "xpack.observability.slo.sloEdit.sliType.customMetric.totalEquation.tooltip": "これは基本的な数学ロジック(A + B / C)とブールロジック(A < B ?A :B)をサポートします。", "xpack.observability.slo.sloEdit.sliType.customMetric.totalMetric.tooltip": "このフィールドのデータは「sum」集計で集約されます。", "xpack.observability.slo.sloEdit.sliType.customMetric.totalTitle": "合計イベント数", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 2fd8d38a579a5..d9aaa9c724465 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -29679,12 +29679,10 @@ "xpack.observability.slo.sloEdit.sliType.customMetric.equationHelpText": "支持基本数学方程,有效字符包括:A-Z、+、-、/、*、(、)、?、!、&、:、|、>、<、=", "xpack.observability.slo.sloEdit.sliType.customMetric.equationLabel": "方程", "xpack.observability.slo.sloEdit.sliType.customMetric.filterLabel": "筛选", - "xpack.observability.slo.sloEdit.sliType.customMetric.goodQuery.tooltip": "此 KQL 查询应返回一个事件子集。", "xpack.observability.slo.sloEdit.sliType.customMetric.goodTitle": "良好事件", "xpack.observability.slo.sloEdit.sliType.customMetric.metricField.placeholder": "选择指标字段", "xpack.observability.slo.sloEdit.sliType.customMetric.metricLabel": "指标", "xpack.observability.slo.sloEdit.sliType.customMetric.queryFilter": "查询筛选", - "xpack.observability.slo.sloEdit.sliType.customMetric.sumLabel": "求和", "xpack.observability.slo.sloEdit.sliType.customMetric.totalEquation.tooltip": "这支持基本数学 (A + B / C) 和布尔逻辑 (A < B ?A :B)。", "xpack.observability.slo.sloEdit.sliType.customMetric.totalMetric.tooltip": "来自该字段的此类数据将使用“求和”聚合进行汇总。", "xpack.observability.slo.sloEdit.sliType.customMetric.totalTitle": "事件合计",