mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
This features adds a configuration option when creating an alert rule query. This option already exists as part of the alert query model but is not currently configurable through the UI.
123 lines
3.3 KiB
TypeScript
123 lines
3.3 KiB
TypeScript
import { describeInterval } from '@grafana/data/src/datetime/rangeutil';
|
|
|
|
import { TimeOptions } from '../types/time';
|
|
|
|
/**
|
|
* ⚠️
|
|
* Some of these functions might be confusing, but there is a significant difference between "Golang duration",
|
|
* supported by the time.ParseDuration() function and "prometheus duration" which is similar but does not support anything
|
|
* smaller than seconds and adds the following supported units: "d, w, y"
|
|
*/
|
|
|
|
export function parseInterval(value: string): [number, string] {
|
|
const match = value.match(/(\d+)(\w+)/);
|
|
if (match) {
|
|
return [Number(match[1]), match[2]];
|
|
}
|
|
throw new Error(`Invalid interval description: ${value}`);
|
|
}
|
|
|
|
export function intervalToSeconds(interval: string): number {
|
|
const { sec, count } = describeInterval(interval);
|
|
return sec * count;
|
|
}
|
|
|
|
export const timeOptions = Object.entries(TimeOptions).map(([key, value]) => ({
|
|
label: key[0].toUpperCase() + key.slice(1),
|
|
value: value,
|
|
}));
|
|
|
|
export function isValidPrometheusDuration(duration: string): boolean {
|
|
try {
|
|
parsePrometheusDuration(duration);
|
|
return true;
|
|
} catch (err) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
const PROMETHEUS_SUFFIX_MULTIPLIER: Record<string, number> = {
|
|
ms: 1,
|
|
s: 1000,
|
|
m: 60 * 1000,
|
|
h: 60 * 60 * 1000,
|
|
d: 24 * 60 * 60 * 1000,
|
|
w: 7 * 24 * 60 * 60 * 1000,
|
|
y: 365 * 24 * 60 * 60 * 1000,
|
|
};
|
|
|
|
const DURATION_REGEXP = new RegExp(/^(?:(?<value>\d+)(?<type>ms|s|m|h|d|w|y))|0$/);
|
|
const INVALID_FORMAT = new Error(
|
|
`Must be of format "(number)(unit)", for example "1m", or just "0". Available units: ${Object.values(
|
|
TimeOptions
|
|
).join(', ')}`
|
|
);
|
|
|
|
/**
|
|
* According to https://prometheus.io/docs/alerting/latest/configuration/#configuration-file
|
|
* see <duration>
|
|
*
|
|
* @returns Duration in milliseconds
|
|
*/
|
|
export function parsePrometheusDuration(duration: string): number {
|
|
let input = duration;
|
|
let parts: Array<[number, string]> = [];
|
|
|
|
function matchDuration(part: string) {
|
|
const match = DURATION_REGEXP.exec(part);
|
|
const hasValueAndType = match?.groups?.value && match?.groups?.type;
|
|
|
|
if (!match || !hasValueAndType) {
|
|
throw INVALID_FORMAT;
|
|
}
|
|
|
|
if (match && match.groups?.value && match.groups?.type) {
|
|
input = input.replace(match[0], '');
|
|
parts.push([Number(match.groups.value), match.groups.type]);
|
|
}
|
|
|
|
if (input) {
|
|
matchDuration(input);
|
|
}
|
|
}
|
|
|
|
matchDuration(duration);
|
|
|
|
if (!parts.length) {
|
|
throw INVALID_FORMAT;
|
|
}
|
|
|
|
const totalDuration = parts.reduce((acc, [value, type]) => {
|
|
const duration = value * PROMETHEUS_SUFFIX_MULTIPLIER[type];
|
|
return acc + duration;
|
|
}, 0);
|
|
|
|
return totalDuration;
|
|
}
|
|
|
|
export const safeParseDurationstr = (duration: string): number => {
|
|
try {
|
|
return parsePrometheusDuration(duration);
|
|
} catch (e) {
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
export const isNullDate = (date: string) => {
|
|
return date.includes('0001-01-01T00');
|
|
};
|
|
|
|
// Format given time span in MS to the largest single unit duration string up to hours.
|
|
export function msToSingleUnitDuration(rangeMs: number): string {
|
|
if (rangeMs % (1000 * 60 * 60) === 0) {
|
|
return rangeMs / (1000 * 60 * 60) + 'h';
|
|
}
|
|
if (rangeMs % (1000 * 60) === 0) {
|
|
return rangeMs / (1000 * 60) + 'm';
|
|
}
|
|
if (rangeMs % 1000 === 0) {
|
|
return rangeMs / 1000 + 's';
|
|
}
|
|
return rangeMs.toFixed() + 'ms';
|
|
}
|