mirror of
https://github.com/hyperdxio/hyperdx
synced 2026-04-21 13:37:15 +00:00
fix: convert fixed minute unit granularity to Granularity enum (chart alert link) (#278)
This commit is contained in:
parent
6a7c2d0675
commit
e92bf4fff2
8 changed files with 124 additions and 52 deletions
6
.changeset/short-cars-taste.md
Normal file
6
.changeset/short-cars-taste.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
'@hyperdx/api': patch
|
||||
'@hyperdx/app': patch
|
||||
---
|
||||
|
||||
fix: convert fixed minute unit granularity to Granularity enum
|
||||
|
|
@ -26,7 +26,6 @@ import type {
|
|||
} from '@/utils/logParser';
|
||||
import { chartSeriesSchema } from '@/utils/zod';
|
||||
|
||||
import { redisClient } from '../utils/redis';
|
||||
import {
|
||||
LogsPropertyTypeMappingsModel,
|
||||
MetricsPropertyTypeMappingsModel,
|
||||
|
|
@ -82,6 +81,7 @@ export enum AggFn {
|
|||
SumRate = 'sum_rate',
|
||||
}
|
||||
|
||||
// TODO: move this somewhere shareable across the project
|
||||
export enum Granularity {
|
||||
ThirtySecond = '30 second',
|
||||
OneMinute = '1 minute',
|
||||
|
|
@ -488,7 +488,7 @@ export const fetchLogsPropertyTypeMappings =
|
|||
};
|
||||
|
||||
// ******************************************************
|
||||
// ****************** Helpers ***************************
|
||||
// ******************** Utils ***************************
|
||||
// ******************************************************
|
||||
export const msRangeToHistogramInterval = (msRange: number, total: number) => {
|
||||
const diffSeconds = Math.floor(msRange / 1000);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import Dashboard, { IDashboard } from '@/models/dashboard';
|
|||
import LogView from '@/models/logView';
|
||||
import { ITeam } from '@/models/team';
|
||||
import Webhook from '@/models/webhook';
|
||||
import { truncateString } from '@/utils/common';
|
||||
import { convertMsToGranularityString, truncateString } from '@/utils/common';
|
||||
import logger from '@/utils/logger';
|
||||
import * as slack from '@/utils/slack';
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ export const buildChartLink = ({
|
|||
const to = (endTime.getTime() + ms(granularity) * 7).toString();
|
||||
const queryParams = new URLSearchParams({
|
||||
from,
|
||||
granularity,
|
||||
granularity: convertMsToGranularityString(ms(granularity)),
|
||||
to,
|
||||
});
|
||||
url.search = queryParams.toString();
|
||||
|
|
|
|||
26
packages/api/src/utils/__tests__/common.test.ts
Normal file
26
packages/api/src/utils/__tests__/common.test.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import ms from 'ms';
|
||||
|
||||
import { convertMsToGranularityString } from '@/utils/common';
|
||||
|
||||
describe('utils/common', () => {
|
||||
it('convertMsToGranularityString', () => {
|
||||
// 30 second is the min granularity
|
||||
expect(convertMsToGranularityString(ms('1s'))).toEqual('30 second');
|
||||
expect(convertMsToGranularityString(ms('30'))).toEqual('30 second');
|
||||
expect(convertMsToGranularityString(ms('1m'))).toEqual('1 minute');
|
||||
expect(convertMsToGranularityString(ms('5m'))).toEqual('5 minute');
|
||||
expect(convertMsToGranularityString(ms('10m'))).toEqual('10 minute');
|
||||
expect(convertMsToGranularityString(ms('15m'))).toEqual('15 minute');
|
||||
expect(convertMsToGranularityString(ms('30m'))).toEqual('30 minute');
|
||||
expect(convertMsToGranularityString(ms('60 minute'))).toEqual('1 hour');
|
||||
expect(convertMsToGranularityString(ms('2h'))).toEqual('2 hour');
|
||||
expect(convertMsToGranularityString(ms('6h'))).toEqual('6 hour');
|
||||
expect(convertMsToGranularityString(ms('12h'))).toEqual('12 hour');
|
||||
expect(convertMsToGranularityString(ms('1d'))).toEqual('1 day');
|
||||
expect(convertMsToGranularityString(ms('2d'))).toEqual('2 day');
|
||||
expect(convertMsToGranularityString(ms('7d'))).toEqual('7 day');
|
||||
expect(convertMsToGranularityString(ms('30d'))).toEqual('30 day');
|
||||
// 30 day is the max granularity
|
||||
expect(convertMsToGranularityString(ms('1y'))).toEqual('30 day');
|
||||
});
|
||||
});
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
import { Granularity } from '@/clickhouse';
|
||||
|
||||
export type JSONBlob = Record<string, Json>;
|
||||
|
||||
export type Json =
|
||||
|
|
@ -34,3 +36,39 @@ export const truncateString = (str: string, length: number) => {
|
|||
|
||||
export const sleep = (ms: number) =>
|
||||
new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
export const convertMsToGranularityString = (ms: number): Granularity => {
|
||||
const granularitySizeSeconds = Math.ceil(ms / 1000);
|
||||
|
||||
if (granularitySizeSeconds <= 30) {
|
||||
return Granularity.ThirtySecond;
|
||||
} else if (granularitySizeSeconds <= 60) {
|
||||
return Granularity.OneMinute;
|
||||
} else if (granularitySizeSeconds <= 5 * 60) {
|
||||
return Granularity.FiveMinute;
|
||||
} else if (granularitySizeSeconds <= 10 * 60) {
|
||||
return Granularity.TenMinute;
|
||||
} else if (granularitySizeSeconds <= 15 * 60) {
|
||||
return Granularity.FifteenMinute;
|
||||
} else if (granularitySizeSeconds <= 30 * 60) {
|
||||
return Granularity.ThirtyMinute;
|
||||
} else if (granularitySizeSeconds <= 3600) {
|
||||
return Granularity.OneHour;
|
||||
} else if (granularitySizeSeconds <= 2 * 3600) {
|
||||
return Granularity.TwoHour;
|
||||
} else if (granularitySizeSeconds <= 6 * 3600) {
|
||||
return Granularity.SixHour;
|
||||
} else if (granularitySizeSeconds <= 12 * 3600) {
|
||||
return Granularity.TwelveHour;
|
||||
} else if (granularitySizeSeconds <= 24 * 3600) {
|
||||
return Granularity.OneDay;
|
||||
} else if (granularitySizeSeconds <= 2 * 24 * 3600) {
|
||||
return Granularity.TwoDay;
|
||||
} else if (granularitySizeSeconds <= 7 * 24 * 3600) {
|
||||
return Granularity.SevenDay;
|
||||
} else if (granularitySizeSeconds <= 30 * 24 * 3600) {
|
||||
return Granularity.ThirtyDay;
|
||||
}
|
||||
|
||||
return Granularity.ThirtyDay;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,18 +2,19 @@ import { sub } from 'date-fns';
|
|||
import { Form, FormSelectProps } from 'react-bootstrap';
|
||||
|
||||
import api from './api';
|
||||
import { Granularity } from './ChartUtils';
|
||||
import type { AlertChannelType, AlertInterval } from './types';
|
||||
|
||||
export function intervalToGranularity(interval: AlertInterval) {
|
||||
if (interval === '1m') return '1 minute' as const;
|
||||
if (interval === '5m') return '5 minute' as const;
|
||||
if (interval === '15m') return '15 minute' as const;
|
||||
if (interval === '30m') return '30 minute' as const;
|
||||
if (interval === '1h') return '1 hour' as const;
|
||||
if (interval === '6h') return '6 hour' as const;
|
||||
if (interval === '12h') return '12 hour' as const;
|
||||
if (interval === '1d') return '1 day' as const;
|
||||
return '1 day';
|
||||
if (interval === '1m') return Granularity.OneMinute;
|
||||
if (interval === '5m') return Granularity.FiveMinute;
|
||||
if (interval === '15m') return Granularity.FifteenMinute;
|
||||
if (interval === '30m') return Granularity.ThirtyMinute;
|
||||
if (interval === '1h') return Granularity.OneHour;
|
||||
if (interval === '6h') return Granularity.SixHour;
|
||||
if (interval === '12h') return Granularity.TwelveHour;
|
||||
if (interval === '1d') return Granularity.OneDay;
|
||||
return Granularity.OneDay;
|
||||
}
|
||||
|
||||
export function intervalToDateRange(interval: AlertInterval): [Date, Date] {
|
||||
|
|
|
|||
|
|
@ -48,21 +48,22 @@ export const METRIC_AGG_FNS = [
|
|||
{ value: 'min' as const, label: 'Minimum' },
|
||||
];
|
||||
|
||||
export type Granularity =
|
||||
| '30 second'
|
||||
| '1 minute'
|
||||
| '5 minute'
|
||||
| '10 minute'
|
||||
| '15 minute'
|
||||
| '30 minute'
|
||||
| '1 hour'
|
||||
| '2 hour'
|
||||
| '6 hour'
|
||||
| '12 hour'
|
||||
| '1 day'
|
||||
| '2 day'
|
||||
| '7 day'
|
||||
| '30 day';
|
||||
export enum Granularity {
|
||||
ThirtySecond = '30 second',
|
||||
OneMinute = '1 minute',
|
||||
FiveMinute = '5 minute',
|
||||
TenMinute = '10 minute',
|
||||
FifteenMinute = '15 minute',
|
||||
ThirtyMinute = '30 minute',
|
||||
OneHour = '1 hour',
|
||||
TwoHour = '2 hour',
|
||||
SixHour = '6 hour',
|
||||
TwelveHour = '12 hour',
|
||||
OneDay = '1 day',
|
||||
TwoDay = '2 day',
|
||||
SevenDay = '7 day',
|
||||
ThirtyDay = '30 day',
|
||||
}
|
||||
|
||||
const seriesDisplayName = (
|
||||
s: ChartSeries,
|
||||
|
|
@ -1107,36 +1108,36 @@ export function convertDateRangeToGranularityString(
|
|||
const granularitySizeSeconds = Math.ceil(diffSeconds / maxNumBuckets);
|
||||
|
||||
if (granularitySizeSeconds <= 30) {
|
||||
return '30 second';
|
||||
return Granularity.ThirtySecond;
|
||||
} else if (granularitySizeSeconds <= 60) {
|
||||
return '1 minute';
|
||||
return Granularity.OneMinute;
|
||||
} else if (granularitySizeSeconds <= 5 * 60) {
|
||||
return '5 minute';
|
||||
return Granularity.FiveMinute;
|
||||
} else if (granularitySizeSeconds <= 10 * 60) {
|
||||
return '10 minute';
|
||||
return Granularity.TenMinute;
|
||||
} else if (granularitySizeSeconds <= 15 * 60) {
|
||||
return '15 minute';
|
||||
return Granularity.FifteenMinute;
|
||||
} else if (granularitySizeSeconds <= 30 * 60) {
|
||||
return '30 minute';
|
||||
return Granularity.ThirtyMinute;
|
||||
} else if (granularitySizeSeconds <= 3600) {
|
||||
return '1 hour';
|
||||
return Granularity.OneHour;
|
||||
} else if (granularitySizeSeconds <= 2 * 3600) {
|
||||
return '2 hour';
|
||||
return Granularity.TwoHour;
|
||||
} else if (granularitySizeSeconds <= 6 * 3600) {
|
||||
return '6 hour';
|
||||
return Granularity.SixHour;
|
||||
} else if (granularitySizeSeconds <= 12 * 3600) {
|
||||
return '12 hour';
|
||||
return Granularity.TwelveHour;
|
||||
} else if (granularitySizeSeconds <= 24 * 3600) {
|
||||
return '1 day';
|
||||
return Granularity.OneDay;
|
||||
} else if (granularitySizeSeconds <= 2 * 24 * 3600) {
|
||||
return '2 day';
|
||||
return Granularity.TwoDay;
|
||||
} else if (granularitySizeSeconds <= 7 * 24 * 3600) {
|
||||
return '7 day';
|
||||
return Granularity.SevenDay;
|
||||
} else if (granularitySizeSeconds <= 30 * 24 * 3600) {
|
||||
return '30 day';
|
||||
return Granularity.ThirtyDay;
|
||||
}
|
||||
|
||||
return '30 day';
|
||||
return Granularity.ThirtyDay;
|
||||
}
|
||||
|
||||
export function convertGranularityToSeconds(granularity: Granularity): number {
|
||||
|
|
|
|||
|
|
@ -16,39 +16,39 @@ export default function GranularityPicker({
|
|||
label: 'Auto Granularity',
|
||||
},
|
||||
{
|
||||
value: '30 second' as const,
|
||||
value: Granularity.ThirtySecond,
|
||||
label: '30 Seconds Granularity',
|
||||
},
|
||||
{
|
||||
value: '1 minute' as const,
|
||||
value: Granularity.OneMinute,
|
||||
label: '1 Minute Granularity',
|
||||
},
|
||||
{
|
||||
value: '5 minute' as const,
|
||||
value: Granularity.FiveMinute,
|
||||
label: '5 Minutes Granularity',
|
||||
},
|
||||
{
|
||||
value: '10 minute' as const,
|
||||
value: Granularity.TenMinute,
|
||||
label: '10 Minutes Granularity',
|
||||
},
|
||||
{
|
||||
value: '30 minute' as const,
|
||||
value: Granularity.ThirtyMinute,
|
||||
label: '30 Minutes Granularity',
|
||||
},
|
||||
{
|
||||
value: '1 hour' as const,
|
||||
value: Granularity.OneHour,
|
||||
label: '1 Hour Granularity',
|
||||
},
|
||||
{
|
||||
value: '12 hour' as const,
|
||||
value: Granularity.TwelveHour,
|
||||
label: '12 Hours Granularity',
|
||||
},
|
||||
{
|
||||
value: '1 day' as const,
|
||||
value: Granularity.OneDay,
|
||||
label: '1 Day Granularity',
|
||||
},
|
||||
{
|
||||
value: '7 day' as const,
|
||||
value: Granularity.SevenDay,
|
||||
label: '7 Day Granularity',
|
||||
},
|
||||
]}
|
||||
|
|
|
|||
Loading…
Reference in a new issue