mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[8.x] [Custom threshold/Metric threshold] [Preview chart] Sort groups by first metric and aggType combination (#199643) (#200534)
# Backport This will backport the following commits from `main` to `8.x`: - [[Custom threshold/Metric threshold] [Preview chart] Sort groups by first metric and aggType combination (#199643)](https://github.com/elastic/kibana/pull/199643) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Bena Kansara","email":"69037875+benakansara@users.noreply.github.com"},"sourceCommit":{"committedDate":"2024-11-18T10:45:35Z","message":"[Custom threshold/Metric threshold] [Preview chart] Sort groups by first metric and aggType combination (#199643)\n\nResolves https://github.com/elastic/kibana/issues/183491\r\n\r\nThis PR sorts the data in Preview chart of Custom threshold and Metric\r\nthreshold rules based on first metric and aggType combination used in\r\nthe rule equation. For `rate`, `percentile` and `last_value`\r\naggregations, I have used `max` aggregation as those aggregations\r\nrequire additional params to pass to `LensAttributesBuilder` which are\r\nnot supported currently. Also, sorting based on equation is not\r\nsupported right now.\r\n\r\n| Before | After |\r\n| --- | --- |\r\n| <img width=\"601\" alt=\"Screenshot 2024-11-11 at 17 07 47\"\r\nsrc=\"https://github.com/user-attachments/assets/0f22991f-fa82-4dcf-8f44-7c88d7f85d8e\">\r\n| <img width=\"596\" alt=\"Screenshot 2024-11-12 at 13 37 06\"\r\nsrc=\"https://github.com/user-attachments/assets/a4a53bac-ecd0-4cc7-9ba5-11c733cc8f88\">\r\n|\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"b87e47bdce25b2e560979d0ae532cbb4342ae2e7","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","backport:prev-minor","ci:project-deploy-observability","Team:obs-ux-management"],"title":"[Custom threshold/Metric threshold] [Preview chart] Sort groups by first metric and aggType combination","number":199643,"url":"https://github.com/elastic/kibana/pull/199643","mergeCommit":{"message":"[Custom threshold/Metric threshold] [Preview chart] Sort groups by first metric and aggType combination (#199643)\n\nResolves https://github.com/elastic/kibana/issues/183491\r\n\r\nThis PR sorts the data in Preview chart of Custom threshold and Metric\r\nthreshold rules based on first metric and aggType combination used in\r\nthe rule equation. For `rate`, `percentile` and `last_value`\r\naggregations, I have used `max` aggregation as those aggregations\r\nrequire additional params to pass to `LensAttributesBuilder` which are\r\nnot supported currently. Also, sorting based on equation is not\r\nsupported right now.\r\n\r\n| Before | After |\r\n| --- | --- |\r\n| <img width=\"601\" alt=\"Screenshot 2024-11-11 at 17 07 47\"\r\nsrc=\"https://github.com/user-attachments/assets/0f22991f-fa82-4dcf-8f44-7c88d7f85d8e\">\r\n| <img width=\"596\" alt=\"Screenshot 2024-11-12 at 13 37 06\"\r\nsrc=\"https://github.com/user-attachments/assets/a4a53bac-ecd0-4cc7-9ba5-11c733cc8f88\">\r\n|\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"b87e47bdce25b2e560979d0ae532cbb4342ae2e7"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/199643","number":199643,"mergeCommit":{"message":"[Custom threshold/Metric threshold] [Preview chart] Sort groups by first metric and aggType combination (#199643)\n\nResolves https://github.com/elastic/kibana/issues/183491\r\n\r\nThis PR sorts the data in Preview chart of Custom threshold and Metric\r\nthreshold rules based on first metric and aggType combination used in\r\nthe rule equation. For `rate`, `percentile` and `last_value`\r\naggregations, I have used `max` aggregation as those aggregations\r\nrequire additional params to pass to `LensAttributesBuilder` which are\r\nnot supported currently. Also, sorting based on equation is not\r\nsupported right now.\r\n\r\n| Before | After |\r\n| --- | --- |\r\n| <img width=\"601\" alt=\"Screenshot 2024-11-11 at 17 07 47\"\r\nsrc=\"https://github.com/user-attachments/assets/0f22991f-fa82-4dcf-8f44-7c88d7f85d8e\">\r\n| <img width=\"596\" alt=\"Screenshot 2024-11-12 at 13 37 06\"\r\nsrc=\"https://github.com/user-attachments/assets/a4a53bac-ecd0-4cc7-9ba5-11c733cc8f88\">\r\n|\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"b87e47bdce25b2e560979d0ae532cbb4342ae2e7"}}]}] BACKPORT--> Co-authored-by: Bena Kansara <69037875+benakansara@users.noreply.github.com>
This commit is contained in:
parent
702d5f96c5
commit
307acc756a
6 changed files with 288 additions and 63 deletions
|
@ -28,7 +28,7 @@ export type DateHistogramColumnParams = DateHistogramIndexPatternColumn['params'
|
|||
|
||||
export type TopValuesColumnParams = Pick<
|
||||
TermsIndexPatternColumn['params'],
|
||||
'size' | 'orderDirection' | 'orderBy' | 'secondaryFields' | 'accuracyMode'
|
||||
'size' | 'orderDirection' | 'orderBy' | 'secondaryFields' | 'accuracyMode' | 'orderAgg'
|
||||
>;
|
||||
|
||||
export const getHistogramColumn = ({
|
||||
|
|
|
@ -17,7 +17,11 @@ const useCases = [
|
|||
filter: '',
|
||||
name: '',
|
||||
},
|
||||
'sum(system.cpu.user.pct)',
|
||||
{
|
||||
operation: 'sum',
|
||||
operationWithField: 'sum(system.cpu.user.pct)',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
|
@ -26,7 +30,11 @@ const useCases = [
|
|||
filter: '',
|
||||
name: '',
|
||||
},
|
||||
'max(system.cpu.user.pct)',
|
||||
{
|
||||
operation: 'max',
|
||||
operationWithField: 'max(system.cpu.user.pct)',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
|
@ -35,7 +43,11 @@ const useCases = [
|
|||
filter: '',
|
||||
name: '',
|
||||
},
|
||||
'min(system.cpu.user.pct)',
|
||||
{
|
||||
operation: 'min',
|
||||
operationWithField: 'min(system.cpu.user.pct)',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
|
@ -44,16 +56,24 @@ const useCases = [
|
|||
filter: '',
|
||||
name: '',
|
||||
},
|
||||
'average(system.cpu.user.pct)',
|
||||
{
|
||||
operation: 'average',
|
||||
operationWithField: 'average(system.cpu.user.pct)',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
aggType: Aggregators.COUNT,
|
||||
field: 'system.cpu.user.pct',
|
||||
filter: '',
|
||||
field: '',
|
||||
filter: 'system.cpu.user.pct: *',
|
||||
name: '',
|
||||
},
|
||||
'count(___records___)',
|
||||
{
|
||||
operation: 'count',
|
||||
operationWithField: `count(kql='system.cpu.user.pct: *')`,
|
||||
sourceField: '',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
|
@ -62,7 +82,11 @@ const useCases = [
|
|||
filter: '',
|
||||
name: '',
|
||||
},
|
||||
'unique_count(system.cpu.user.pct)',
|
||||
{
|
||||
operation: 'unique_count',
|
||||
operationWithField: 'unique_count(system.cpu.user.pct)',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
|
@ -71,7 +95,11 @@ const useCases = [
|
|||
filter: '',
|
||||
name: '',
|
||||
},
|
||||
'percentile(system.cpu.user.pct, percentile=95)',
|
||||
{
|
||||
operation: 'percentile',
|
||||
operationWithField: 'percentile(system.cpu.user.pct, percentile=95)',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
|
@ -80,7 +108,11 @@ const useCases = [
|
|||
filter: '',
|
||||
name: '',
|
||||
},
|
||||
'percentile(system.cpu.user.pct, percentile=99)',
|
||||
{
|
||||
operation: 'percentile',
|
||||
operationWithField: 'percentile(system.cpu.user.pct, percentile=99)',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
|
@ -89,7 +121,11 @@ const useCases = [
|
|||
filter: '',
|
||||
name: '',
|
||||
},
|
||||
`counter_rate(max(system.network.in.bytes), kql='')`,
|
||||
{
|
||||
operation: 'counter_rate',
|
||||
operationWithField: `counter_rate(max(system.network.in.bytes), kql='')`,
|
||||
sourceField: 'system.network.in.bytes',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
|
@ -98,7 +134,11 @@ const useCases = [
|
|||
filter: 'host.name : "foo"',
|
||||
name: '',
|
||||
},
|
||||
`counter_rate(max(system.network.in.bytes), kql='host.name : foo')`,
|
||||
{
|
||||
operation: 'counter_rate',
|
||||
operationWithField: `counter_rate(max(system.network.in.bytes), kql='host.name : foo')`,
|
||||
sourceField: 'system.network.in.bytes',
|
||||
},
|
||||
],
|
||||
];
|
||||
|
||||
|
|
|
@ -8,14 +8,24 @@
|
|||
import { Aggregators } from '../../../common/custom_threshold_rule/types';
|
||||
import { GenericMetric } from './rule_condition_chart';
|
||||
|
||||
export const getLensOperationFromRuleMetric = (metric: GenericMetric): string => {
|
||||
export interface LensOperation {
|
||||
operation: string;
|
||||
operationWithField: string;
|
||||
sourceField: string;
|
||||
}
|
||||
|
||||
export const getLensOperationFromRuleMetric = (metric: GenericMetric): LensOperation => {
|
||||
const { aggType, field, filter } = metric;
|
||||
let operation: string = aggType;
|
||||
const operationArgs: string[] = [];
|
||||
const aggFilter = JSON.stringify(filter || '').replace(/"|\\/g, '');
|
||||
|
||||
if (aggType === Aggregators.RATE) {
|
||||
return `counter_rate(max(${field}), kql='${aggFilter}')`;
|
||||
return {
|
||||
operation: 'counter_rate',
|
||||
operationWithField: `counter_rate(max(${field}), kql='${aggFilter}')`,
|
||||
sourceField: field || '',
|
||||
};
|
||||
}
|
||||
|
||||
if (aggType === Aggregators.AVERAGE) operation = 'average';
|
||||
|
@ -23,14 +33,10 @@ export const getLensOperationFromRuleMetric = (metric: GenericMetric): string =>
|
|||
if (aggType === Aggregators.P95 || aggType === Aggregators.P99) operation = 'percentile';
|
||||
if (aggType === Aggregators.COUNT) operation = 'count';
|
||||
|
||||
let sourceField = field;
|
||||
|
||||
if (aggType === Aggregators.COUNT) {
|
||||
sourceField = '___records___';
|
||||
if (field) {
|
||||
operationArgs.push(field);
|
||||
}
|
||||
|
||||
operationArgs.push(sourceField || '');
|
||||
|
||||
if (aggType === Aggregators.P95) {
|
||||
operationArgs.push('percentile=95');
|
||||
}
|
||||
|
@ -41,7 +47,11 @@ export const getLensOperationFromRuleMetric = (metric: GenericMetric): string =>
|
|||
|
||||
if (aggFilter) operationArgs.push(`kql='${aggFilter}'`);
|
||||
|
||||
return operation + '(' + operationArgs.join(', ') + ')';
|
||||
return {
|
||||
operation,
|
||||
operationWithField: `${operation}(${operationArgs.join(', ')})`,
|
||||
sourceField: field || '',
|
||||
};
|
||||
};
|
||||
|
||||
export const getBufferThreshold = (threshold?: number): string =>
|
||||
|
|
|
@ -17,7 +17,11 @@ describe('PainlessTinyMathParser', () => {
|
|||
const parser = new PainlessTinyMathParser({
|
||||
equation,
|
||||
aggMap: {
|
||||
A: 'average(system.cpu.system.pct)',
|
||||
A: {
|
||||
operationWithField: 'average(system.cpu.system.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.system.pct',
|
||||
},
|
||||
},
|
||||
});
|
||||
// ✅ checked with Lens Formula editor
|
||||
|
@ -28,7 +32,11 @@ describe('PainlessTinyMathParser', () => {
|
|||
const parser = new PainlessTinyMathParser({
|
||||
equation,
|
||||
aggMap: {
|
||||
'ABC-abc': 'average(system.cpu.system.pct)',
|
||||
'ABC-abc': {
|
||||
operationWithField: 'average(system.cpu.system.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.system.pct',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(parser.parse()).toEqual('100*average(system.cpu.system.pct)');
|
||||
|
@ -38,8 +46,16 @@ describe('PainlessTinyMathParser', () => {
|
|||
const parser = new PainlessTinyMathParser({
|
||||
equation,
|
||||
aggMap: {
|
||||
A: 'average(system.cpu.system.pct)',
|
||||
B: 'average(system.cpu.user.pct)',
|
||||
A: {
|
||||
operationWithField: 'average(system.cpu.system.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.system.pct',
|
||||
},
|
||||
B: {
|
||||
operationWithField: 'average(system.cpu.user.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
},
|
||||
});
|
||||
// ✅ checked with Lens Formula editor
|
||||
|
@ -52,9 +68,21 @@ describe('PainlessTinyMathParser', () => {
|
|||
const parser = new PainlessTinyMathParser({
|
||||
equation,
|
||||
aggMap: {
|
||||
A: 'average(system.cpu.system.pct)',
|
||||
B: 'average(system.cpu.user.pct)',
|
||||
C: 'average(system.cpu.cores)',
|
||||
A: {
|
||||
operationWithField: 'average(system.cpu.system.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.system.pct',
|
||||
},
|
||||
B: {
|
||||
operationWithField: 'average(system.cpu.user.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
C: {
|
||||
operationWithField: 'average(system.cpu.cores)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.cores',
|
||||
},
|
||||
},
|
||||
});
|
||||
// ✅ checked with Lens Formula editor
|
||||
|
@ -67,7 +95,11 @@ describe('PainlessTinyMathParser', () => {
|
|||
const parser = new PainlessTinyMathParser({
|
||||
equation,
|
||||
aggMap: {
|
||||
A: 'average(system.cpu.system.pct)',
|
||||
A: {
|
||||
operationWithField: 'average(system.cpu.system.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.system.pct',
|
||||
},
|
||||
},
|
||||
});
|
||||
// ✅ checked with Lens Formula editor
|
||||
|
@ -79,8 +111,16 @@ describe('PainlessTinyMathParser', () => {
|
|||
const parser = new PainlessTinyMathParser({
|
||||
equation,
|
||||
aggMap: {
|
||||
A: 'average(system.cpu.system.pct)',
|
||||
B: 'average(system.cpu.user.pct)',
|
||||
A: {
|
||||
operationWithField: 'average(system.cpu.system.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.system.pct',
|
||||
},
|
||||
B: {
|
||||
operationWithField: 'average(system.cpu.user.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
},
|
||||
});
|
||||
// ✅ checked with Lens Formula editor
|
||||
|
@ -93,8 +133,16 @@ describe('PainlessTinyMathParser', () => {
|
|||
const parser = new PainlessTinyMathParser({
|
||||
equation,
|
||||
aggMap: {
|
||||
A: 'average(system.cpu.system.pct)',
|
||||
B: 'average(system.cpu.user.pct)',
|
||||
A: {
|
||||
operationWithField: 'average(system.cpu.system.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.system.pct',
|
||||
},
|
||||
B: {
|
||||
operationWithField: 'average(system.cpu.user.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
},
|
||||
});
|
||||
// ✅ checked with Lens Formula editor
|
||||
|
@ -107,8 +155,16 @@ describe('PainlessTinyMathParser', () => {
|
|||
const parser = new PainlessTinyMathParser({
|
||||
equation,
|
||||
aggMap: {
|
||||
A: 'average(system.cpu.system.pct)',
|
||||
B: 'average(system.cpu.user.pct)',
|
||||
A: {
|
||||
operationWithField: 'average(system.cpu.system.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.system.pct',
|
||||
},
|
||||
B: {
|
||||
operationWithField: 'average(system.cpu.user.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
},
|
||||
});
|
||||
// ✅ checked with Lens Formula editor
|
||||
|
@ -121,8 +177,16 @@ describe('PainlessTinyMathParser', () => {
|
|||
const parser = new PainlessTinyMathParser({
|
||||
equation,
|
||||
aggMap: {
|
||||
A: 'average(system.cpu.system.pct)',
|
||||
B: 'average(system.cpu.user.pct)',
|
||||
A: {
|
||||
operationWithField: 'average(system.cpu.system.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.system.pct',
|
||||
},
|
||||
B: {
|
||||
operationWithField: 'average(system.cpu.user.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
},
|
||||
});
|
||||
// ✅ checked with Lens Formula editor
|
||||
|
@ -135,8 +199,16 @@ describe('PainlessTinyMathParser', () => {
|
|||
const parser = new PainlessTinyMathParser({
|
||||
equation,
|
||||
aggMap: {
|
||||
A: 'average(system.cpu.system.pct)',
|
||||
B: 'average(system.cpu.user.pct)',
|
||||
A: {
|
||||
operationWithField: 'average(system.cpu.system.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.system.pct',
|
||||
},
|
||||
B: {
|
||||
operationWithField: 'average(system.cpu.user.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
},
|
||||
});
|
||||
// ✅ checked with Lens Formula editor
|
||||
|
@ -149,8 +221,16 @@ describe('PainlessTinyMathParser', () => {
|
|||
const parser = new PainlessTinyMathParser({
|
||||
equation,
|
||||
aggMap: {
|
||||
A: 'average(system.cpu.system.pct)',
|
||||
B: 'average(system.cpu.user.pct)',
|
||||
A: {
|
||||
operationWithField: 'average(system.cpu.system.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.system.pct',
|
||||
},
|
||||
B: {
|
||||
operationWithField: 'average(system.cpu.user.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
},
|
||||
});
|
||||
// ✅ checked with Lens Formula editor
|
||||
|
@ -163,8 +243,16 @@ describe('PainlessTinyMathParser', () => {
|
|||
const parser = new PainlessTinyMathParser({
|
||||
equation,
|
||||
aggMap: {
|
||||
A: 'average(system.cpu.system.pct)',
|
||||
B: 'average(system.cpu.user.pct)',
|
||||
A: {
|
||||
operationWithField: 'average(system.cpu.system.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.system.pct',
|
||||
},
|
||||
B: {
|
||||
operationWithField: 'average(system.cpu.user.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
},
|
||||
});
|
||||
// ✅ checked with Lens Formula editor
|
||||
|
@ -178,8 +266,16 @@ describe('PainlessTinyMathParser', () => {
|
|||
const parser = new PainlessTinyMathParser({
|
||||
equation,
|
||||
aggMap: {
|
||||
aa: 'average(system.cpu.system.pct)',
|
||||
baa: 'average(system.cpu.user.pct)',
|
||||
aa: {
|
||||
operationWithField: 'average(system.cpu.system.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.system.pct',
|
||||
},
|
||||
baa: {
|
||||
operationWithField: 'average(system.cpu.user.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(parser.parse()).toEqual(
|
||||
|
@ -193,12 +289,36 @@ describe('PainlessTinyMathParser', () => {
|
|||
const parser = new PainlessTinyMathParser({
|
||||
equation,
|
||||
aggMap: {
|
||||
A: 'average(system.cpu.system.pct)',
|
||||
B: 'average(system.cpu.user.pct)',
|
||||
C: 'average(system.cpu.total.pct)',
|
||||
D: 'average(system.cpu.cores)',
|
||||
E: 'count()',
|
||||
F: 'sum(system.cpu.total.pct)',
|
||||
A: {
|
||||
operationWithField: 'average(system.cpu.system.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.system.pct',
|
||||
},
|
||||
B: {
|
||||
operationWithField: 'average(system.cpu.user.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
C: {
|
||||
operationWithField: 'average(system.cpu.total.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.total.pct',
|
||||
},
|
||||
D: {
|
||||
operationWithField: 'average(system.cpu.cores)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.cores',
|
||||
},
|
||||
E: {
|
||||
operationWithField: 'count()',
|
||||
operation: 'count',
|
||||
sourceField: '',
|
||||
},
|
||||
F: {
|
||||
operationWithField: 'sum(system.cpu.total.pct)',
|
||||
operation: 'sum',
|
||||
sourceField: 'system.cpu.total.pct',
|
||||
},
|
||||
},
|
||||
});
|
||||
// ✅ checked with Lens Formula editor
|
||||
|
@ -213,12 +333,36 @@ describe('PainlessTinyMathParser', () => {
|
|||
const parser = new PainlessTinyMathParser({
|
||||
equation,
|
||||
aggMap: {
|
||||
A: 'average(system.cpu.system.pct)',
|
||||
B: 'average(system.cpu.user.pct)',
|
||||
C: 'average(system.cpu.total.pct)',
|
||||
D: 'average(system.cpu.cores)',
|
||||
E: 'count()',
|
||||
F: 'sum(system.cpu.total.pct)',
|
||||
A: {
|
||||
operationWithField: 'average(system.cpu.system.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.system.pct',
|
||||
},
|
||||
B: {
|
||||
operationWithField: 'average(system.cpu.user.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.user.pct',
|
||||
},
|
||||
C: {
|
||||
operationWithField: 'average(system.cpu.total.pct)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.total.pct',
|
||||
},
|
||||
D: {
|
||||
operationWithField: 'average(system.cpu.cores)',
|
||||
operation: 'average',
|
||||
sourceField: 'system.cpu.cores',
|
||||
},
|
||||
E: {
|
||||
operationWithField: 'count()',
|
||||
operation: 'count',
|
||||
sourceField: '',
|
||||
},
|
||||
F: {
|
||||
operationWithField: 'sum(system.cpu.total.pct)',
|
||||
operation: 'sum',
|
||||
sourceField: 'system.cpu.total.pct',
|
||||
},
|
||||
},
|
||||
});
|
||||
// ✅ checked with Lens Formula editor
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { LensOperation } from './helpers';
|
||||
|
||||
// This is a parser of a subset operations/expression/statement of Painless A-Z, +, -, /, *, (, ), ?, !, &, :, |, >, <, = to be used in Lens formula editor that uses TinyMath
|
||||
// The goal is to parse painless expressions to a format that can be used in Lens formula editor
|
||||
// The parser will also replace the characters A-Z with the values from aggMap
|
||||
|
@ -13,7 +15,7 @@
|
|||
// This parser is using a simple recursive function to parse the expression and replace the characters with the values from aggMap
|
||||
|
||||
export interface AggMap {
|
||||
[key: string]: string;
|
||||
[key: string]: LensOperation;
|
||||
}
|
||||
interface PainlessTinyMathParserProps {
|
||||
equation: string;
|
||||
|
@ -81,7 +83,10 @@ export class PainlessTinyMathParser {
|
|||
.sort()
|
||||
.reverse()
|
||||
.forEach((metricName) => {
|
||||
parsedInputString = parsedInputString.replaceAll(metricName, aggMap[metricName]);
|
||||
parsedInputString = parsedInputString.replaceAll(
|
||||
metricName,
|
||||
aggMap[metricName].operationWithField
|
||||
);
|
||||
});
|
||||
|
||||
return parsedInputString;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { EuiEmptyPrompt, useEuiTheme } from '@elastic/eui';
|
||||
import { Query, Filter } from '@kbn/es-query';
|
||||
import { FillStyle, SeriesType } from '@kbn/lens-plugin/public';
|
||||
import { FillStyle, SeriesType, TermsIndexPatternColumn } from '@kbn/lens-plugin/public';
|
||||
import { DataView } from '@kbn/data-views-plugin/common';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
|
@ -82,6 +82,10 @@ export interface RuleConditionChartProps {
|
|||
additionalFilters?: Filter[];
|
||||
}
|
||||
|
||||
export type TopValuesOrderParams =
|
||||
| Pick<TermsIndexPatternColumn['params'], 'orderDirection' | 'orderBy' | 'orderAgg'>
|
||||
| undefined;
|
||||
|
||||
const defaultQuery: Query = {
|
||||
language: 'kuery',
|
||||
query: '',
|
||||
|
@ -299,10 +303,10 @@ export function RuleConditionChart({
|
|||
return;
|
||||
}
|
||||
const aggMapFromMetrics = metrics.reduce((acc, metric) => {
|
||||
const operationField = getLensOperationFromRuleMetric(metric);
|
||||
const { operation, operationWithField, sourceField } = getLensOperationFromRuleMetric(metric);
|
||||
return {
|
||||
...acc,
|
||||
[metric.name]: operationField,
|
||||
[metric.name]: { operation, operationWithField, sourceField },
|
||||
};
|
||||
}, {} as AggMap);
|
||||
|
||||
|
@ -354,6 +358,26 @@ export function RuleConditionChart({
|
|||
seriesType: seriesType ? seriesType : 'bar',
|
||||
};
|
||||
|
||||
const firstMetricAggMap = aggMap && metrics.length > 0 ? aggMap[metrics[0].name] : undefined;
|
||||
const convertToMaxOperation = ['counter_rate', 'last_value', 'percentile'];
|
||||
|
||||
const orderParams: TopValuesOrderParams = firstMetricAggMap
|
||||
? {
|
||||
orderDirection: 'desc',
|
||||
orderBy: { type: 'custom' },
|
||||
orderAgg: {
|
||||
label: firstMetricAggMap.operationWithField,
|
||||
dataType: 'number',
|
||||
operationType: convertToMaxOperation.includes(firstMetricAggMap.operation)
|
||||
? 'max'
|
||||
: firstMetricAggMap.operation,
|
||||
sourceField: firstMetricAggMap.sourceField,
|
||||
isBucketed: false,
|
||||
scale: 'ratio',
|
||||
},
|
||||
}
|
||||
: undefined;
|
||||
|
||||
if (groupBy && groupBy?.length) {
|
||||
xYDataLayerOptions.breakdown = {
|
||||
type: 'top_values',
|
||||
|
@ -362,6 +386,7 @@ export function RuleConditionChart({
|
|||
size: 3,
|
||||
secondaryFields: (groupBy as string[]).slice(1),
|
||||
accuracyMode: false,
|
||||
...orderParams,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -425,6 +450,7 @@ export function RuleConditionChart({
|
|||
timeUnit,
|
||||
seriesType,
|
||||
warningThresholdReferenceLine,
|
||||
aggMap,
|
||||
]);
|
||||
|
||||
if (
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue