Skip to content

Commit

Permalink
feat(slo): add events chart (#170896)
Browse files Browse the repository at this point in the history
  • Loading branch information
kdelemme authored Nov 16, 2023
1 parent 1d704eb commit 7398fe9
Show file tree
Hide file tree
Showing 28 changed files with 531 additions and 88 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ x-pack/plugins/banners @elastic/appex-sharedux
packages/kbn-bazel-runner @elastic/kibana-operations
examples/bfetch_explorer @elastic/appex-sharedux
src/plugins/bfetch @elastic/appex-sharedux
packages/kbn-calculate-auto @elastic/obs-ux-management-team
x-pack/plugins/canvas @elastic/kibana-presentation
x-pack/test/cases_api_integration/common/plugins/cases @elastic/response-ops
packages/kbn-cases-components @elastic/response-ops
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@
"@kbn/banners-plugin": "link:x-pack/plugins/banners",
"@kbn/bfetch-explorer-plugin": "link:examples/bfetch_explorer",
"@kbn/bfetch-plugin": "link:src/plugins/bfetch",
"@kbn/calculate-auto": "link:packages/kbn-calculate-auto",
"@kbn/canvas-plugin": "link:x-pack/plugins/canvas",
"@kbn/cases-api-integration-test-plugin": "link:x-pack/test/cases_api_integration/common/plugins/cases",
"@kbn/cases-components": "link:packages/kbn-cases-components",
Expand Down
3 changes: 3 additions & 0 deletions packages/kbn-calculate-auto/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @kbn/calculate-auto

Empty package generated by @kbn/generate
9 changes: 9 additions & 0 deletions packages/kbn-calculate-auto/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

export { calculateAuto } from './src/calculate_auto';
13 changes: 13 additions & 0 deletions packages/kbn-calculate-auto/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

module.exports = {
preset: '@kbn/test/jest_node',
rootDir: '../..',
roots: ['<rootDir>/packages/kbn-calculate-auto'],
};
5 changes: 5 additions & 0 deletions packages/kbn-calculate-auto/kibana.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/calculate-auto",
"owner": "@elastic/obs-ux-management-team"
}
6 changes: 6 additions & 0 deletions packages/kbn-calculate-auto/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "@kbn/calculate-auto",
"private": true,
"version": "1.0.0",
"license": "SSPL-1.0 OR Elastic License 2.0"
}
31 changes: 31 additions & 0 deletions packages/kbn-calculate-auto/src/calculate_auto.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { calculateAuto } from './calculate_auto';
import moment, { isDuration } from 'moment';

describe('calculateAuto.near(bucket, duration)', () => {
it('should calculate the bucket size for 15 minutes', () => {
const bucketSizeDuration = calculateAuto.near(100, moment.duration(15, 'minutes'));
expect(bucketSizeDuration).not.toBeUndefined();
expect(isDuration(bucketSizeDuration)).toBeTruthy();
expect(bucketSizeDuration!.asSeconds()).toBe(10);
});
it('should calculate the bucket size for an hour', () => {
const bucketSizeDuration = calculateAuto.near(100, moment.duration(1, 'hour'));
expect(bucketSizeDuration).not.toBeUndefined();
expect(isDuration(bucketSizeDuration)).toBeTruthy();
expect(bucketSizeDuration!.asSeconds()).toBe(30);
});
it('should calculate the bucket size for a day', () => {
const bucketSizeDuration = calculateAuto.near(100, moment.duration(1, 'day'));
expect(bucketSizeDuration).not.toBeUndefined();
expect(isDuration(bucketSizeDuration)).toBeTruthy();
expect(bucketSizeDuration!.asMinutes()).toBe(10);
});
});
83 changes: 83 additions & 0 deletions packages/kbn-calculate-auto/src/calculate_auto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import moment, { isDuration, Duration } from 'moment';
const d = moment.duration;

const roundingRules = [
[d(500, 'ms'), d(100, 'ms')],
[d(5, 'second'), d(1, 'second')],
[d(7.5, 'second'), d(5, 'second')],
[d(15, 'second'), d(10, 'second')],
[d(45, 'second'), d(30, 'second')],
[d(3, 'minute'), d(1, 'minute')],
[d(9, 'minute'), d(5, 'minute')],
[d(20, 'minute'), d(10, 'minute')],
[d(45, 'minute'), d(30, 'minute')],
[d(2, 'hour'), d(1, 'hour')],
[d(6, 'hour'), d(3, 'hour')],
[d(24, 'hour'), d(12, 'hour')],
[d(1, 'week'), d(1, 'd')],
[d(3, 'week'), d(1, 'week')],
[d(1, 'year'), d(1, 'month')],
[d(Infinity, 'year'), d(1, 'year')],
];

const reverseRoundingRules = [...roundingRules].reverse();
type CheckFunction = (bound: Duration, interval: Duration, target: number) => Duration | undefined;

function findRule(rules: Duration[][], check: CheckFunction, last?: boolean) {
function pickInterval(buckets: number, duration: Duration) {
const target = duration.asMilliseconds() / buckets;
let lastResult = null;

for (const [end, start] of rules) {
const result = check(end, start, target);

if (result == null) {
if (!last) continue;
if (lastResult) return lastResult;
break;
}

if (!last) return result;
lastResult = result;
}

// fallback to just a number of milliseconds, ensure ms is >= 1
const ms = Math.max(Math.floor(target), 1);
return moment.duration(ms, 'ms');
}

return (buckets: number, duration: Duration) => {
const interval = pickInterval(buckets, duration);
if (isDuration(interval)) return interval;
};
}

export const calculateAuto = {
near: findRule(
reverseRoundingRules,
function near(bound, interval, target) {
if (isDuration(bound) && bound.asMilliseconds() > target) return interval;
},
true
),
lessThan: findRule(
reverseRoundingRules,
function lessThan(_bound: Duration, interval: Duration, target: number) {
if (interval.asMilliseconds() < target) return interval;
}
),
atLeast: findRule(
reverseRoundingRules,
function atLeast(_bound: Duration, interval: Duration, target: number) {
if (interval.asMilliseconds() <= target) return interval;
}
),
};
17 changes: 17 additions & 0 deletions packages/kbn-calculate-auto/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node"
]
},
"include": [
"**/*.ts",
],
"exclude": [
"target/**/*"
],
"kbn_references": []
}
2 changes: 2 additions & 0 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@
"@kbn/bfetch-explorer-plugin/*": ["examples/bfetch_explorer/*"],
"@kbn/bfetch-plugin": ["src/plugins/bfetch"],
"@kbn/bfetch-plugin/*": ["src/plugins/bfetch/*"],
"@kbn/calculate-auto": ["packages/kbn-calculate-auto"],
"@kbn/calculate-auto/*": ["packages/kbn-calculate-auto/*"],
"@kbn/canvas-plugin": ["x-pack/plugins/canvas"],
"@kbn/canvas-plugin/*": ["x-pack/plugins/canvas/*"],
"@kbn/cases-api-integration-test-plugin": ["x-pack/test/cases_api_integration/common/plugins/cases"],
Expand Down
4 changes: 4 additions & 0 deletions x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ const createSLOResponseSchema = t.type({
const getPreviewDataParamsSchema = t.type({
body: t.type({
indicator: indicatorSchema,
range: t.type({
start: t.number,
end: t.number,
}),
}),
});

Expand Down
17 changes: 13 additions & 4 deletions x-pack/packages/kbn-slo-schema/src/schema/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,19 @@ const historicalSummarySchema = t.intersection([
summarySchema,
]);

const previewDataSchema = t.type({
date: dateType,
sliValue: t.number,
});
const previewDataSchema = t.intersection([
t.type({
date: dateType,
sliValue: t.number,
}),
t.partial({
events: t.type({
good: t.number,
bad: t.number,
total: t.number,
}),
}),
]);

const dateRangeSchema = t.type({ from: dateType, to: dateType });

Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/observability/public/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@

export const DEFAULT_INTERVAL = '60s';
export const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH:mm';
export const SLO_LONG_REFETCH_INTERVAL = 60 * 1000; // 1 minute
export const SLO_SHORT_REFETCH_INTERVAL = 5 * 1000; // 5 seconds
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ export const sloKeys = {
globalDiagnosis: () => [...sloKeys.all, 'globalDiagnosis'] as const,
burnRates: (sloId: string, instanceId: string | undefined) =>
[...sloKeys.all, 'burnRates', sloId, instanceId] as const,
preview: (indicator?: Indicator) => [...sloKeys.all, 'preview', indicator] as const,
preview: (indicator: Indicator, range: { start: number; end: number }) =>
[...sloKeys.all, 'preview', indicator, range] as const,
};

export type SloKeys = typeof sloKeys;
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { ALL_VALUE, SLOResponse } from '@kbn/slo-schema';
import { AlertConsumers } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names';
import { useKibana } from '../../utils/kibana_react';
import { sloKeys } from './query_key_factory';
import { SLO_LONG_REFETCH_INTERVAL } from '../../constants';

type SLO = Pick<SLOResponse, 'id' | 'instanceId'>;

Expand Down Expand Up @@ -71,7 +72,6 @@ interface FindApiResponse {
};
}

const LONG_REFETCH_INTERVAL = 1000 * 60; // 1 minute
const EMPTY_ACTIVE_ALERTS_MAP = new ActiveAlerts();

export function useFetchActiveAlerts({
Expand Down Expand Up @@ -141,7 +141,7 @@ export function useFetchActiveAlerts({
}
},
refetchOnWindowFocus: false,
refetchInterval: shouldRefetch ? LONG_REFETCH_INTERVAL : undefined,
refetchInterval: shouldRefetch ? SLO_LONG_REFETCH_INTERVAL : undefined,
enabled: Boolean(sloIdsAndInstanceIds.length),
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { FetchHistoricalSummaryResponse } from '@kbn/slo-schema';

import { useKibana } from '../../utils/kibana_react';
import { sloKeys } from './query_key_factory';
import { SLO_LONG_REFETCH_INTERVAL } from '../../constants';

export interface UseFetchHistoricalSummaryResponse {
data: FetchHistoricalSummaryResponse | undefined;
Expand All @@ -25,8 +26,6 @@ export interface Params {
shouldRefetch?: boolean;
}

const LONG_REFETCH_INTERVAL = 1000 * 60; // 1 minute

export function useFetchHistoricalSummary({
list = [],
shouldRefetch,
Expand All @@ -50,7 +49,7 @@ export function useFetchHistoricalSummary({
// ignore error
}
},
refetchInterval: shouldRefetch ? LONG_REFETCH_INTERVAL : undefined,
refetchInterval: shouldRefetch ? SLO_LONG_REFETCH_INTERVAL : undefined,
refetchOnWindowFocus: false,
keepPreviousData: true,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { ALL_VALUE, GetSLOBurnRatesResponse, SLOWithSummaryResponse } from '@kbn/slo-schema';
import { useKibana } from '../../utils/kibana_react';
import { sloKeys } from './query_key_factory';
import { SLO_LONG_REFETCH_INTERVAL } from '../../constants';

export interface UseFetchSloBurnRatesResponse {
isInitialLoading: boolean;
Expand All @@ -26,8 +27,6 @@ export interface UseFetchSloBurnRatesResponse {
) => Promise<QueryObserverResult<GetSLOBurnRatesResponse | undefined, unknown>>;
}

const LONG_REFETCH_INTERVAL = 1000 * 60; // 1 minute

interface UseFetchSloBurnRatesParams {
slo: SLOWithSummaryResponse;
windows: Array<{ name: string; duration: string }>;
Expand Down Expand Up @@ -58,7 +57,7 @@ export function useFetchSloBurnRates({
// ignore error
}
},
refetchInterval: shouldRefetch ? LONG_REFETCH_INTERVAL : undefined,
refetchInterval: shouldRefetch ? SLO_LONG_REFETCH_INTERVAL : undefined,
refetchOnWindowFocus: false,
keepPreviousData: true,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
RefetchQueryFilters,
useQuery,
} from '@tanstack/react-query';
import { SLO_LONG_REFETCH_INTERVAL } from '../../constants';
import { useKibana } from '../../utils/kibana_react';
import { sloKeys } from './query_key_factory';

Expand All @@ -27,8 +28,6 @@ export interface UseFetchSloDetailsResponse {
) => Promise<QueryObserverResult<GetSLOResponse | undefined, unknown>>;
}

const LONG_REFETCH_INTERVAL = 1000 * 60; // 1 minute

export function useFetchSloDetails({
sloId,
instanceId,
Expand Down Expand Up @@ -59,7 +58,7 @@ export function useFetchSloDetails({
},
keepPreviousData: true,
enabled: Boolean(sloId),
refetchInterval: shouldRefetch ? LONG_REFETCH_INTERVAL : undefined,
refetchInterval: shouldRefetch ? SLO_LONG_REFETCH_INTERVAL : undefined,
refetchOnWindowFocus: false,
}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n';
import { FindSLOResponse } from '@kbn/slo-schema';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useState } from 'react';
import { SLO_LONG_REFETCH_INTERVAL, SLO_SHORT_REFETCH_INTERVAL } from '../../constants';

import { useKibana } from '../../utils/kibana_react';
import { sloKeys } from './query_key_factory';
Expand All @@ -30,9 +31,6 @@ export interface UseFetchSloListResponse {
data: FindSLOResponse | undefined;
}

const SHORT_REFETCH_INTERVAL = 1000 * 5; // 5 seconds
const LONG_REFETCH_INTERVAL = 1000 * 60; // 1 minute

export function useFetchSloList({
kqlQuery = '',
page = 1,
Expand All @@ -45,7 +43,9 @@ export function useFetchSloList({
notifications: { toasts },
} = useKibana().services;
const queryClient = useQueryClient();
const [stateRefetchInterval, setStateRefetchInterval] = useState<number>(SHORT_REFETCH_INTERVAL);
const [stateRefetchInterval, setStateRefetchInterval] = useState<number>(
SLO_SHORT_REFETCH_INTERVAL
);

const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({
queryKey: sloKeys.list({ kqlQuery, page, sortBy, sortDirection }),
Expand Down Expand Up @@ -81,9 +81,9 @@ export function useFetchSloList({
}

if (results.find((slo) => slo.summary.status === 'NO_DATA' || !slo.summary)) {
setStateRefetchInterval(SHORT_REFETCH_INTERVAL);
setStateRefetchInterval(SLO_SHORT_REFETCH_INTERVAL);
} else {
setStateRefetchInterval(LONG_REFETCH_INTERVAL);
setStateRefetchInterval(SLO_LONG_REFETCH_INTERVAL);
}
},
onError: (error: Error) => {
Expand Down
Loading

0 comments on commit 7398fe9

Please sign in to comment.