Compare commits

..

2 Commits

Author SHA1 Message Date
srikanthccv
2c721113bf chore: some more updates 2026-02-19 02:21:26 +05:30
srikanthccv
8c4a0ad512 chore: add list metrics 2026-02-19 01:56:38 +05:30
10 changed files with 962 additions and 531 deletions

View File

@@ -455,6 +455,38 @@ components:
nullable: true
type: array
type: object
MetricsexplorertypesListMetric:
properties:
description:
type: string
isMonotonic:
type: boolean
metricName:
type: string
temporality:
$ref: '#/components/schemas/MetrictypesTemporality'
type:
$ref: '#/components/schemas/MetrictypesType'
unit:
type: string
required:
- metricName
- description
- type
- unit
- temporality
- isMonotonic
type: object
MetricsexplorertypesListMetricsResponse:
properties:
metrics:
items:
$ref: '#/components/schemas/MetricsexplorertypesListMetric'
nullable: true
type: array
required:
- metrics
type: object
MetricsexplorertypesMetricAlert:
properties:
alertId:
@@ -492,19 +524,6 @@ components:
- values
- valueCount
type: object
MetricsexplorertypesMetricAttributesRequest:
properties:
end:
nullable: true
type: integer
metricName:
type: string
start:
nullable: true
type: integer
required:
- metricName
type: object
MetricsexplorertypesMetricAttributesResponse:
properties:
attributes:
@@ -4749,14 +4768,83 @@ paths:
summary: Search ingestion keys for workspace
tags:
- gateway
/api/v2/metric/alerts:
/api/v2/metrics:
get:
deprecated: false
description: This endpoint returns a list of distinct metric names within the
specified time range
operationId: ListMetrics
parameters:
- in: query
name: start
schema:
nullable: true
type: integer
- in: query
name: end
schema:
nullable: true
type: integer
- in: query
name: limit
schema:
type: integer
- in: query
name: searchText
schema:
type: string
responses:
"200":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/MetricsexplorertypesListMetricsResponse'
status:
type: string
type: object
description: OK
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- VIEWER
- tokenizer:
- VIEWER
summary: List metric names
tags:
- metrics
/api/v2/metrics/{metric_name}/alerts:
get:
deprecated: false
description: This endpoint returns associated alerts for a specified metric
operationId: GetMetricAlerts
parameters:
- in: query
name: metricName
- in: path
name: metric_name
required: true
schema:
type: string
@@ -4804,14 +4892,80 @@ paths:
summary: Get metric alerts
tags:
- metrics
/api/v2/metric/dashboards:
/api/v2/metrics/{metric_name}/attributes:
get:
deprecated: false
description: This endpoint returns attribute keys and their unique values for
a specified metric
operationId: GetMetricAttributes
parameters:
- in: query
name: start
schema:
nullable: true
type: integer
- in: query
name: end
schema:
nullable: true
type: integer
- in: path
name: metric_name
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/MetricsexplorertypesMetricAttributesResponse'
status:
type: string
type: object
description: OK
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- VIEWER
- tokenizer:
- VIEWER
summary: Get metric attributes
tags:
- metrics
/api/v2/metrics/{metric_name}/dashboards:
get:
deprecated: false
description: This endpoint returns associated dashboards for a specified metric
operationId: GetMetricDashboards
parameters:
- in: query
name: metricName
- in: path
name: metric_name
required: true
schema:
type: string
@@ -4859,15 +5013,15 @@ paths:
summary: Get metric dashboards
tags:
- metrics
/api/v2/metric/highlights:
/api/v2/metrics/{metric_name}/highlights:
get:
deprecated: false
description: This endpoint returns highlights like number of datapoints, totaltimeseries,
active time series, last received time for a specified metric
operationId: GetMetricHighlights
parameters:
- in: query
name: metricName
- in: path
name: metric_name
required: true
schema:
type: string
@@ -4916,6 +5070,67 @@ paths:
tags:
- metrics
/api/v2/metrics/{metric_name}/metadata:
get:
deprecated: false
description: This endpoint returns metadata information like metric description,
unit, type, temporality, monotonicity for a specified metric
operationId: GetMetricMetadata
parameters:
- in: path
name: metric_name
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/MetricsexplorertypesMetricMetadata'
status:
type: string
type: object
description: OK
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- VIEWER
- tokenizer:
- VIEWER
summary: Get metric metadata
tags:
- metrics
post:
deprecated: false
description: This endpoint helps to update metadata information like metric
@@ -4971,123 +5186,6 @@ paths:
summary: Update metric metadata
tags:
- metrics
/api/v2/metrics/attributes:
post:
deprecated: false
description: This endpoint returns attribute keys and their unique values for
a specified metric
operationId: GetMetricAttributes
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/MetricsexplorertypesMetricAttributesRequest'
responses:
"200":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/MetricsexplorertypesMetricAttributesResponse'
status:
type: string
type: object
description: OK
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- VIEWER
- tokenizer:
- VIEWER
summary: Get metric attributes
tags:
- metrics
/api/v2/metrics/metadata:
get:
deprecated: false
description: This endpoint returns metadata information like metric description,
unit, type, temporality, monotonicity for a specified metric
operationId: GetMetricMetadata
parameters:
- in: query
name: metricName
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/MetricsexplorertypesMetricMetadata'
status:
type: string
type: object
description: OK
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- VIEWER
- tokenizer:
- VIEWER
summary: Get metric metadata
tags:
- metrics
/api/v2/metrics/stats:
post:
deprecated: false

View File

@@ -20,17 +20,20 @@ import { useMutation, useQuery } from 'react-query';
import { GeneratedAPIInstance } from '../../../index';
import type {
GetMetricAlerts200,
GetMetricAlertsParams,
GetMetricAlertsPathParameters,
GetMetricAttributes200,
GetMetricAttributesParams,
GetMetricAttributesPathParameters,
GetMetricDashboards200,
GetMetricDashboardsParams,
GetMetricDashboardsPathParameters,
GetMetricHighlights200,
GetMetricHighlightsParams,
GetMetricHighlightsPathParameters,
GetMetricMetadata200,
GetMetricMetadataParams,
GetMetricMetadataPathParameters,
GetMetricsStats200,
GetMetricsTreemap200,
MetricsexplorertypesMetricAttributesRequestDTO,
ListMetrics200,
ListMetricsParams,
MetricsexplorertypesStatsRequestDTO,
MetricsexplorertypesTreemapRequestDTO,
MetricsexplorertypesUpdateMetricMetadataRequestDTO,
@@ -43,30 +46,128 @@ type AwaitedInput<T> = PromiseLike<T> | T;
type Awaited<O> = O extends AwaitedInput<infer T> ? T : never;
/**
* This endpoint returns associated alerts for a specified metric
* @summary Get metric alerts
* This endpoint returns a list of distinct metric names within the specified time range
* @summary List metric names
*/
export const getMetricAlerts = (
params: GetMetricAlertsParams,
export const listMetrics = (
params?: ListMetricsParams,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetMetricAlerts200>({
url: `/api/v2/metric/alerts`,
return GeneratedAPIInstance<ListMetrics200>({
url: `/api/v2/metrics`,
method: 'GET',
params,
signal,
});
};
export const getGetMetricAlertsQueryKey = (params?: GetMetricAlertsParams) => {
return ['getMetricAlerts', ...(params ? [params] : [])] as const;
export const getListMetricsQueryKey = (params?: ListMetricsParams) => {
return ['listMetrics', ...(params ? [params] : [])] as const;
};
export const getListMetricsQueryOptions = <
TData = Awaited<ReturnType<typeof listMetrics>>,
TError = RenderErrorResponseDTO
>(
params?: ListMetricsParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listMetrics>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey = queryOptions?.queryKey ?? getListMetricsQueryKey(params);
const queryFn: QueryFunction<Awaited<ReturnType<typeof listMetrics>>> = ({
signal,
}) => listMetrics(params, signal);
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof listMetrics>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type ListMetricsQueryResult = NonNullable<
Awaited<ReturnType<typeof listMetrics>>
>;
export type ListMetricsQueryError = RenderErrorResponseDTO;
/**
* @summary List metric names
*/
export function useListMetrics<
TData = Awaited<ReturnType<typeof listMetrics>>,
TError = RenderErrorResponseDTO
>(
params?: ListMetricsParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listMetrics>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getListMetricsQueryOptions(params, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary List metric names
*/
export const invalidateListMetrics = async (
queryClient: QueryClient,
params?: ListMetricsParams,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getListMetricsQueryKey(params) },
options,
);
return queryClient;
};
/**
* This endpoint returns associated alerts for a specified metric
* @summary Get metric alerts
*/
export const getMetricAlerts = (
{ metricName }: GetMetricAlertsPathParameters,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetMetricAlerts200>({
url: `/api/v2/metrics/${metricName}/alerts`,
method: 'GET',
signal,
});
};
export const getGetMetricAlertsQueryKey = ({
metricName,
}: GetMetricAlertsPathParameters) => {
return ['getMetricAlerts'] as const;
};
export const getGetMetricAlertsQueryOptions = <
TData = Awaited<ReturnType<typeof getMetricAlerts>>,
TError = RenderErrorResponseDTO
>(
params: GetMetricAlertsParams,
{ metricName }: GetMetricAlertsPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getMetricAlerts>>,
@@ -77,13 +178,19 @@ export const getGetMetricAlertsQueryOptions = <
) => {
const { query: queryOptions } = options ?? {};
const queryKey = queryOptions?.queryKey ?? getGetMetricAlertsQueryKey(params);
const queryKey =
queryOptions?.queryKey ?? getGetMetricAlertsQueryKey({ metricName });
const queryFn: QueryFunction<Awaited<ReturnType<typeof getMetricAlerts>>> = ({
signal,
}) => getMetricAlerts(params, signal);
}) => getMetricAlerts({ metricName }, signal);
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
return {
queryKey,
queryFn,
enabled: !!metricName,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof getMetricAlerts>>,
TError,
TData
@@ -103,7 +210,7 @@ export function useGetMetricAlerts<
TData = Awaited<ReturnType<typeof getMetricAlerts>>,
TError = RenderErrorResponseDTO
>(
params: GetMetricAlertsParams,
{ metricName }: GetMetricAlertsPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getMetricAlerts>>,
@@ -112,7 +219,7 @@ export function useGetMetricAlerts<
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetMetricAlertsQueryOptions(params, options);
const queryOptions = getGetMetricAlertsQueryOptions({ metricName }, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
@@ -128,11 +235,126 @@ export function useGetMetricAlerts<
*/
export const invalidateGetMetricAlerts = async (
queryClient: QueryClient,
params: GetMetricAlertsParams,
{ metricName }: GetMetricAlertsPathParameters,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetMetricAlertsQueryKey(params) },
{ queryKey: getGetMetricAlertsQueryKey({ metricName }) },
options,
);
return queryClient;
};
/**
* This endpoint returns attribute keys and their unique values for a specified metric
* @summary Get metric attributes
*/
export const getMetricAttributes = (
{ metricName }: GetMetricAttributesPathParameters,
params?: GetMetricAttributesParams,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetMetricAttributes200>({
url: `/api/v2/metrics/${metricName}/attributes`,
method: 'GET',
params,
signal,
});
};
export const getGetMetricAttributesQueryKey = (
{ metricName }: GetMetricAttributesPathParameters,
params?: GetMetricAttributesParams,
) => {
return ['getMetricAttributes', ...(params ? [params] : [])] as const;
};
export const getGetMetricAttributesQueryOptions = <
TData = Awaited<ReturnType<typeof getMetricAttributes>>,
TError = RenderErrorResponseDTO
>(
{ metricName }: GetMetricAttributesPathParameters,
params?: GetMetricAttributesParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getMetricAttributes>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ??
getGetMetricAttributesQueryKey({ metricName }, params);
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getMetricAttributes>>
> = ({ signal }) => getMetricAttributes({ metricName }, params, signal);
return {
queryKey,
queryFn,
enabled: !!metricName,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof getMetricAttributes>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type GetMetricAttributesQueryResult = NonNullable<
Awaited<ReturnType<typeof getMetricAttributes>>
>;
export type GetMetricAttributesQueryError = RenderErrorResponseDTO;
/**
* @summary Get metric attributes
*/
export function useGetMetricAttributes<
TData = Awaited<ReturnType<typeof getMetricAttributes>>,
TError = RenderErrorResponseDTO
>(
{ metricName }: GetMetricAttributesPathParameters,
params?: GetMetricAttributesParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getMetricAttributes>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetMetricAttributesQueryOptions(
{ metricName },
params,
options,
);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary Get metric attributes
*/
export const invalidateGetMetricAttributes = async (
queryClient: QueryClient,
{ metricName }: GetMetricAttributesPathParameters,
params?: GetMetricAttributesParams,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetMetricAttributesQueryKey({ metricName }, params) },
options,
);
@@ -144,28 +366,27 @@ export const invalidateGetMetricAlerts = async (
* @summary Get metric dashboards
*/
export const getMetricDashboards = (
params: GetMetricDashboardsParams,
{ metricName }: GetMetricDashboardsPathParameters,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetMetricDashboards200>({
url: `/api/v2/metric/dashboards`,
url: `/api/v2/metrics/${metricName}/dashboards`,
method: 'GET',
params,
signal,
});
};
export const getGetMetricDashboardsQueryKey = (
params?: GetMetricDashboardsParams,
) => {
return ['getMetricDashboards', ...(params ? [params] : [])] as const;
export const getGetMetricDashboardsQueryKey = ({
metricName,
}: GetMetricDashboardsPathParameters) => {
return ['getMetricDashboards'] as const;
};
export const getGetMetricDashboardsQueryOptions = <
TData = Awaited<ReturnType<typeof getMetricDashboards>>,
TError = RenderErrorResponseDTO
>(
params: GetMetricDashboardsParams,
{ metricName }: GetMetricDashboardsPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getMetricDashboards>>,
@@ -177,13 +398,18 @@ export const getGetMetricDashboardsQueryOptions = <
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getGetMetricDashboardsQueryKey(params);
queryOptions?.queryKey ?? getGetMetricDashboardsQueryKey({ metricName });
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getMetricDashboards>>
> = ({ signal }) => getMetricDashboards(params, signal);
> = ({ signal }) => getMetricDashboards({ metricName }, signal);
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
return {
queryKey,
queryFn,
enabled: !!metricName,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof getMetricDashboards>>,
TError,
TData
@@ -203,7 +429,7 @@ export function useGetMetricDashboards<
TData = Awaited<ReturnType<typeof getMetricDashboards>>,
TError = RenderErrorResponseDTO
>(
params: GetMetricDashboardsParams,
{ metricName }: GetMetricDashboardsPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getMetricDashboards>>,
@@ -212,7 +438,10 @@ export function useGetMetricDashboards<
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetMetricDashboardsQueryOptions(params, options);
const queryOptions = getGetMetricDashboardsQueryOptions(
{ metricName },
options,
);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
@@ -228,11 +457,11 @@ export function useGetMetricDashboards<
*/
export const invalidateGetMetricDashboards = async (
queryClient: QueryClient,
params: GetMetricDashboardsParams,
{ metricName }: GetMetricDashboardsPathParameters,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetMetricDashboardsQueryKey(params) },
{ queryKey: getGetMetricDashboardsQueryKey({ metricName }) },
options,
);
@@ -244,28 +473,27 @@ export const invalidateGetMetricDashboards = async (
* @summary Get metric highlights
*/
export const getMetricHighlights = (
params: GetMetricHighlightsParams,
{ metricName }: GetMetricHighlightsPathParameters,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetMetricHighlights200>({
url: `/api/v2/metric/highlights`,
url: `/api/v2/metrics/${metricName}/highlights`,
method: 'GET',
params,
signal,
});
};
export const getGetMetricHighlightsQueryKey = (
params?: GetMetricHighlightsParams,
) => {
return ['getMetricHighlights', ...(params ? [params] : [])] as const;
export const getGetMetricHighlightsQueryKey = ({
metricName,
}: GetMetricHighlightsPathParameters) => {
return ['getMetricHighlights'] as const;
};
export const getGetMetricHighlightsQueryOptions = <
TData = Awaited<ReturnType<typeof getMetricHighlights>>,
TError = RenderErrorResponseDTO
>(
params: GetMetricHighlightsParams,
{ metricName }: GetMetricHighlightsPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getMetricHighlights>>,
@@ -277,13 +505,18 @@ export const getGetMetricHighlightsQueryOptions = <
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getGetMetricHighlightsQueryKey(params);
queryOptions?.queryKey ?? getGetMetricHighlightsQueryKey({ metricName });
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getMetricHighlights>>
> = ({ signal }) => getMetricHighlights(params, signal);
> = ({ signal }) => getMetricHighlights({ metricName }, signal);
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
return {
queryKey,
queryFn,
enabled: !!metricName,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof getMetricHighlights>>,
TError,
TData
@@ -303,7 +536,7 @@ export function useGetMetricHighlights<
TData = Awaited<ReturnType<typeof getMetricHighlights>>,
TError = RenderErrorResponseDTO
>(
params: GetMetricHighlightsParams,
{ metricName }: GetMetricHighlightsPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getMetricHighlights>>,
@@ -312,7 +545,10 @@ export function useGetMetricHighlights<
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetMetricHighlightsQueryOptions(params, options);
const queryOptions = getGetMetricHighlightsQueryOptions(
{ metricName },
options,
);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
@@ -328,11 +564,115 @@ export function useGetMetricHighlights<
*/
export const invalidateGetMetricHighlights = async (
queryClient: QueryClient,
params: GetMetricHighlightsParams,
{ metricName }: GetMetricHighlightsPathParameters,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetMetricHighlightsQueryKey(params) },
{ queryKey: getGetMetricHighlightsQueryKey({ metricName }) },
options,
);
return queryClient;
};
/**
* This endpoint returns metadata information like metric description, unit, type, temporality, monotonicity for a specified metric
* @summary Get metric metadata
*/
export const getMetricMetadata = (
{ metricName }: GetMetricMetadataPathParameters,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetMetricMetadata200>({
url: `/api/v2/metrics/${metricName}/metadata`,
method: 'GET',
signal,
});
};
export const getGetMetricMetadataQueryKey = ({
metricName,
}: GetMetricMetadataPathParameters) => {
return ['getMetricMetadata'] as const;
};
export const getGetMetricMetadataQueryOptions = <
TData = Awaited<ReturnType<typeof getMetricMetadata>>,
TError = RenderErrorResponseDTO
>(
{ metricName }: GetMetricMetadataPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getMetricMetadata>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getGetMetricMetadataQueryKey({ metricName });
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getMetricMetadata>>
> = ({ signal }) => getMetricMetadata({ metricName }, signal);
return {
queryKey,
queryFn,
enabled: !!metricName,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof getMetricMetadata>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type GetMetricMetadataQueryResult = NonNullable<
Awaited<ReturnType<typeof getMetricMetadata>>
>;
export type GetMetricMetadataQueryError = RenderErrorResponseDTO;
/**
* @summary Get metric metadata
*/
export function useGetMetricMetadata<
TData = Awaited<ReturnType<typeof getMetricMetadata>>,
TError = RenderErrorResponseDTO
>(
{ metricName }: GetMetricMetadataPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getMetricMetadata>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetMetricMetadataQueryOptions({ metricName }, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary Get metric metadata
*/
export const invalidateGetMetricMetadata = async (
queryClient: QueryClient,
{ metricName }: GetMetricMetadataPathParameters,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetMetricMetadataQueryKey({ metricName }) },
options,
);
@@ -438,189 +778,6 @@ export const useUpdateMetricMetadata = <
return useMutation(mutationOptions);
};
/**
* This endpoint returns attribute keys and their unique values for a specified metric
* @summary Get metric attributes
*/
export const getMetricAttributes = (
metricsexplorertypesMetricAttributesRequestDTO: MetricsexplorertypesMetricAttributesRequestDTO,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetMetricAttributes200>({
url: `/api/v2/metrics/attributes`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: metricsexplorertypesMetricAttributesRequestDTO,
signal,
});
};
export const getGetMetricAttributesMutationOptions = <
TError = RenderErrorResponseDTO,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof getMetricAttributes>>,
TError,
{ data: MetricsexplorertypesMetricAttributesRequestDTO },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof getMetricAttributes>>,
TError,
{ data: MetricsexplorertypesMetricAttributesRequestDTO },
TContext
> => {
const mutationKey = ['getMetricAttributes'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof getMetricAttributes>>,
{ data: MetricsexplorertypesMetricAttributesRequestDTO }
> = (props) => {
const { data } = props ?? {};
return getMetricAttributes(data);
};
return { mutationFn, ...mutationOptions };
};
export type GetMetricAttributesMutationResult = NonNullable<
Awaited<ReturnType<typeof getMetricAttributes>>
>;
export type GetMetricAttributesMutationBody = MetricsexplorertypesMetricAttributesRequestDTO;
export type GetMetricAttributesMutationError = RenderErrorResponseDTO;
/**
* @summary Get metric attributes
*/
export const useGetMetricAttributes = <
TError = RenderErrorResponseDTO,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof getMetricAttributes>>,
TError,
{ data: MetricsexplorertypesMetricAttributesRequestDTO },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof getMetricAttributes>>,
TError,
{ data: MetricsexplorertypesMetricAttributesRequestDTO },
TContext
> => {
const mutationOptions = getGetMetricAttributesMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* This endpoint returns metadata information like metric description, unit, type, temporality, monotonicity for a specified metric
* @summary Get metric metadata
*/
export const getMetricMetadata = (
params: GetMetricMetadataParams,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetMetricMetadata200>({
url: `/api/v2/metrics/metadata`,
method: 'GET',
params,
signal,
});
};
export const getGetMetricMetadataQueryKey = (
params?: GetMetricMetadataParams,
) => {
return ['getMetricMetadata', ...(params ? [params] : [])] as const;
};
export const getGetMetricMetadataQueryOptions = <
TData = Awaited<ReturnType<typeof getMetricMetadata>>,
TError = RenderErrorResponseDTO
>(
params: GetMetricMetadataParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getMetricMetadata>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getGetMetricMetadataQueryKey(params);
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getMetricMetadata>>
> = ({ signal }) => getMetricMetadata(params, signal);
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof getMetricMetadata>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type GetMetricMetadataQueryResult = NonNullable<
Awaited<ReturnType<typeof getMetricMetadata>>
>;
export type GetMetricMetadataQueryError = RenderErrorResponseDTO;
/**
* @summary Get metric metadata
*/
export function useGetMetricMetadata<
TData = Awaited<ReturnType<typeof getMetricMetadata>>,
TError = RenderErrorResponseDTO
>(
params: GetMetricMetadataParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getMetricMetadata>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetMetricMetadataQueryOptions(params, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary Get metric metadata
*/
export const invalidateGetMetricMetadata = async (
queryClient: QueryClient,
params: GetMetricMetadataParams,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetMetricMetadataQueryKey(params) },
options,
);
return queryClient;
};
/**
* This endpoint provides list of metrics with their number of samples and timeseries for the given time range
* @summary Get metrics statistics

View File

@@ -646,6 +646,35 @@ export interface GatewaytypesUpdatableIngestionKeyLimitDTO {
tags?: string[] | null;
}
export interface MetricsexplorertypesListMetricDTO {
/**
* @type string
*/
description: string;
/**
* @type boolean
*/
isMonotonic: boolean;
/**
* @type string
*/
metricName: string;
temporality: MetrictypesTemporalityDTO;
type: MetrictypesTypeDTO;
/**
* @type string
*/
unit: string;
}
export interface MetricsexplorertypesListMetricsResponseDTO {
/**
* @type array
* @nullable true
*/
metrics: MetricsexplorertypesListMetricDTO[] | null;
}
export interface MetricsexplorertypesMetricAlertDTO {
/**
* @type string
@@ -682,23 +711,6 @@ export interface MetricsexplorertypesMetricAttributeDTO {
values: string[] | null;
}
export interface MetricsexplorertypesMetricAttributesRequestDTO {
/**
* @type integer
* @nullable true
*/
end?: number | null;
/**
* @type string
*/
metricName: string;
/**
* @type integer
* @nullable true
*/
start?: number | null;
}
export interface MetricsexplorertypesMetricAttributesResponseDTO {
/**
* @type array
@@ -2963,14 +2975,42 @@ export type SearchIngestionKeys200 = {
status?: string;
};
export type GetMetricAlertsParams = {
export type ListMetricsParams = {
/**
* @type integer
* @nullable true
* @description undefined
*/
start?: number | null;
/**
* @type integer
* @nullable true
* @description undefined
*/
end?: number | null;
/**
* @type integer
* @description undefined
*/
limit?: number;
/**
* @type string
* @description undefined
*/
metricName: string;
searchText?: string;
};
export type ListMetrics200 = {
data?: MetricsexplorertypesListMetricsResponseDTO;
/**
* @type string
*/
status?: string;
};
export type GetMetricAlertsPathParameters = {
metricName: string;
};
export type GetMetricAlerts200 = {
data?: MetricsexplorertypesMetricAlertsResponseDTO;
/**
@@ -2979,14 +3019,35 @@ export type GetMetricAlerts200 = {
status?: string;
};
export type GetMetricDashboardsParams = {
/**
* @type string
* @description undefined
*/
export type GetMetricAttributesPathParameters = {
metricName: string;
};
export type GetMetricAttributesParams = {
/**
* @type integer
* @nullable true
* @description undefined
*/
start?: number | null;
/**
* @type integer
* @nullable true
* @description undefined
*/
end?: number | null;
};
export type GetMetricAttributes200 = {
data?: MetricsexplorertypesMetricAttributesResponseDTO;
/**
* @type string
*/
status?: string;
};
export type GetMetricDashboardsPathParameters = {
metricName: string;
};
export type GetMetricDashboards200 = {
data?: MetricsexplorertypesMetricDashboardsResponseDTO;
/**
@@ -2995,14 +3056,9 @@ export type GetMetricDashboards200 = {
status?: string;
};
export type GetMetricHighlightsParams = {
/**
* @type string
* @description undefined
*/
export type GetMetricHighlightsPathParameters = {
metricName: string;
};
export type GetMetricHighlights200 = {
data?: MetricsexplorertypesMetricHighlightsResponseDTO;
/**
@@ -3011,33 +3067,20 @@ export type GetMetricHighlights200 = {
status?: string;
};
export type GetMetricMetadataPathParameters = {
metricName: string;
};
export type GetMetricMetadata200 = {
data?: MetricsexplorertypesMetricMetadataDTO;
/**
* @type string
*/
status?: string;
};
export type UpdateMetricMetadataPathParameters = {
metricName: string;
};
export type GetMetricAttributes200 = {
data?: MetricsexplorertypesMetricAttributesResponseDTO;
/**
* @type string
*/
status?: string;
};
export type GetMetricMetadataParams = {
/**
* @type string
* @description undefined
*/
metricName: string;
};
export type GetMetricMetadata200 = {
data?: MetricsexplorertypesMetricMetadataDTO;
/**
* @type string
*/
status?: string;
};
export type GetMetricsStats200 = {
data?: MetricsexplorertypesStatsResponseDTO;
/**

View File

@@ -11,13 +11,10 @@ export const getMetricMetadata = async (
): Promise<SuccessResponseV2<MetricMetadataResponse> | ErrorResponseV2> => {
try {
const encodedMetricName = encodeURIComponent(metricName);
const response = await axios.get(
`/metrics/metadata?metricName=${encodedMetricName}`,
{
signal,
headers,
},
);
const response = await axios.get(`/metrics/${encodedMetricName}/metadata`, {
signal,
headers,
});
return {
httpStatusCode: response.status,

View File

@@ -14,11 +14,9 @@ import {
VisibilityMode,
} from 'lib/uPlotV2/config/types';
import { UPlotConfigBuilder } from 'lib/uPlotV2/config/UPlotConfigBuilder';
import { isInvalidPlotValue } from 'lib/uPlotV2/utils/dataUtils';
import { Widgets } from 'types/api/dashboard/getAll';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { QueryData } from 'types/api/widgets/getQuery';
import { PanelMode } from '../types';
import { buildBaseConfig } from '../utils/baseConfigBuilder';
@@ -33,22 +31,6 @@ export const prepareChartData = (
return [timestampArr, ...yAxisValuesArr];
};
function hasSingleVisiblePointForSeries(series: QueryData): boolean {
const rawValues = series.values ?? [];
let validPointCount = 0;
for (const [, rawValue] of rawValues) {
if (!isInvalidPlotValue(rawValue)) {
validPointCount += 1;
if (validPointCount > 1) {
return false;
}
}
}
return true;
}
export const prepareUPlotConfig = ({
widget,
isDarkMode,
@@ -86,7 +68,6 @@ export const prepareUPlotConfig = ({
});
apiResponse.data?.result?.forEach((series) => {
const hasSingleVisiblePoint = hasSingleVisiblePointForSeries(series);
const baseLabelName = getLabelName(
series.metric,
series.queryName || '', // query
@@ -99,15 +80,13 @@ export const prepareUPlotConfig = ({
builder.addSeries({
scaleKey: 'y',
drawStyle: hasSingleVisiblePoint ? DrawStyle.Points : DrawStyle.Line,
drawStyle: DrawStyle.Line,
label: label,
colorMapping: widget.customLegendColors ?? {},
spanGaps: true,
lineStyle: LineStyle.Solid,
lineInterpolation: LineInterpolation.Spline,
showPoints: hasSingleVisiblePoint
? VisibilityMode.Always
: VisibilityMode.Never,
showPoints: VisibilityMode.Never,
pointSize: 5,
isDarkMode,
panelType: PANEL_TYPES.TIME_SERIES,

View File

@@ -10,6 +10,26 @@ import (
)
func (provider *provider) addMetricsExplorerRoutes(router *mux.Router) error {
if err := router.Handle("/api/v2/metrics", handler.New(
provider.authZ.ViewAccess(provider.metricsExplorerHandler.ListMetrics),
handler.OpenAPIDef{
ID: "ListMetrics",
Tags: []string{"metrics"},
Summary: "List metric names",
Description: "This endpoint returns a list of distinct metric names within the specified time range",
Request: nil,
RequestQuery: new(metricsexplorertypes.ListMetricsParams),
RequestContentType: "",
Response: new(metricsexplorertypes.ListMetricsResponse),
ResponseContentType: "application/json",
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized, http.StatusInternalServerError},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
})).Methods(http.MethodGet).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v2/metrics/stats", handler.New(
provider.authZ.ViewAccess(provider.metricsExplorerHandler.GetStats),
handler.OpenAPIDef{
@@ -48,26 +68,27 @@ func (provider *provider) addMetricsExplorerRoutes(router *mux.Router) error {
return err
}
if err := router.Handle("/api/v2/metrics/attributes", handler.New(
if err := router.Handle("/api/v2/metrics/{metric_name}/attributes", handler.New(
provider.authZ.ViewAccess(provider.metricsExplorerHandler.GetMetricAttributes),
handler.OpenAPIDef{
ID: "GetMetricAttributes",
Tags: []string{"metrics"},
Summary: "Get metric attributes",
Description: "This endpoint returns attribute keys and their unique values for a specified metric",
Request: new(metricsexplorertypes.MetricAttributesRequest),
RequestContentType: "application/json",
Request: nil,
RequestQuery: new(metricsexplorertypes.MetricAttributesRequest),
RequestContentType: "",
Response: new(metricsexplorertypes.MetricAttributesResponse),
ResponseContentType: "application/json",
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized, http.StatusInternalServerError},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
})).Methods(http.MethodPost).GetError(); err != nil {
})).Methods(http.MethodGet).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v2/metrics/metadata", handler.New(
if err := router.Handle("/api/v2/metrics/{metric_name}/metadata", handler.New(
provider.authZ.ViewAccess(provider.metricsExplorerHandler.GetMetricMetadata),
handler.OpenAPIDef{
ID: "GetMetricMetadata",
@@ -75,7 +96,6 @@ func (provider *provider) addMetricsExplorerRoutes(router *mux.Router) error {
Summary: "Get metric metadata",
Description: "This endpoint returns metadata information like metric description, unit, type, temporality, monotonicity for a specified metric",
Request: nil,
RequestQuery: new(metricsexplorertypes.MetricNameParams),
RequestContentType: "",
Response: new(metricsexplorertypes.MetricMetadata),
ResponseContentType: "application/json",
@@ -106,7 +126,7 @@ func (provider *provider) addMetricsExplorerRoutes(router *mux.Router) error {
return err
}
if err := router.Handle("/api/v2/metric/highlights", handler.New(
if err := router.Handle("/api/v2/metrics/{metric_name}/highlights", handler.New(
provider.authZ.ViewAccess(provider.metricsExplorerHandler.GetMetricHighlights),
handler.OpenAPIDef{
ID: "GetMetricHighlights",
@@ -114,7 +134,6 @@ func (provider *provider) addMetricsExplorerRoutes(router *mux.Router) error {
Summary: "Get metric highlights",
Description: "This endpoint returns highlights like number of datapoints, totaltimeseries, active time series, last received time for a specified metric",
Request: nil,
RequestQuery: new(metricsexplorertypes.MetricNameParams),
RequestContentType: "",
Response: new(metricsexplorertypes.MetricHighlightsResponse),
ResponseContentType: "application/json",
@@ -126,7 +145,7 @@ func (provider *provider) addMetricsExplorerRoutes(router *mux.Router) error {
return err
}
if err := router.Handle("/api/v2/metric/alerts", handler.New(
if err := router.Handle("/api/v2/metrics/{metric_name}/alerts", handler.New(
provider.authZ.ViewAccess(provider.metricsExplorerHandler.GetMetricAlerts),
handler.OpenAPIDef{
ID: "GetMetricAlerts",
@@ -134,7 +153,6 @@ func (provider *provider) addMetricsExplorerRoutes(router *mux.Router) error {
Summary: "Get metric alerts",
Description: "This endpoint returns associated alerts for a specified metric",
Request: nil,
RequestQuery: new(metricsexplorertypes.MetricNameParams),
RequestContentType: "",
Response: new(metricsexplorertypes.MetricAlertsResponse),
ResponseContentType: "application/json",
@@ -146,7 +164,7 @@ func (provider *provider) addMetricsExplorerRoutes(router *mux.Router) error {
return err
}
if err := router.Handle("/api/v2/metric/dashboards", handler.New(
if err := router.Handle("/api/v2/metrics/{metric_name}/dashboards", handler.New(
provider.authZ.ViewAccess(provider.metricsExplorerHandler.GetMetricDashboards),
handler.OpenAPIDef{
ID: "GetMetricDashboards",
@@ -154,7 +172,6 @@ func (provider *provider) addMetricsExplorerRoutes(router *mux.Router) error {
Summary: "Get metric dashboards",
Description: "This endpoint returns associated dashboards for a specified metric",
Request: nil,
RequestQuery: new(metricsexplorertypes.MetricNameParams),
RequestContentType: "",
Response: new(metricsexplorertypes.MetricDashboardsResponse),
ResponseContentType: "application/json",

View File

@@ -13,6 +13,14 @@ import (
"github.com/gorilla/mux"
)
func extractMetricName(req *http.Request) (string, error) {
metricName := mux.Vars(req)["metric_name"]
if metricName == "" {
return "", errors.NewInvalidInputf(errors.CodeInvalidInput, "metric_name is required in URL path")
}
return metricName, nil
}
type handler struct {
module metricsexplorer.Module
}
@@ -24,6 +32,34 @@ func NewHandler(m metricsexplorer.Module) metricsexplorer.Handler {
}
}
func (h *handler) ListMetrics(rw http.ResponseWriter, req *http.Request) {
claims, err := authtypes.ClaimsFromContext(req.Context())
if err != nil {
render.Error(rw, err)
return
}
var params metricsexplorertypes.ListMetricsParams
if err := binding.Query.BindQuery(req.URL.Query(), &params); err != nil {
render.Error(rw, err)
return
}
if err := params.Validate(); err != nil {
render.Error(rw, err)
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
out, err := h.module.ListMetrics(req.Context(), orgID, &params)
if err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusOK, out)
}
func (h *handler) GetStats(rw http.ResponseWriter, req *http.Request) {
claims, err := authtypes.ClaimsFromContext(req.Context())
if err != nil {
@@ -114,28 +150,23 @@ func (h *handler) GetMetricMetadata(rw http.ResponseWriter, req *http.Request) {
return
}
var params metricsexplorertypes.MetricNameParams
if err := binding.Query.BindQuery(req.URL.Query(), &params); err != nil {
render.Error(rw, err)
return
}
if params.MetricName == "" {
render.Error(rw, errors.NewInvalidInputf(errors.CodeInvalidInput, "metricName query parameter is required"))
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
metadataMap, err := h.module.GetMetricMetadataMulti(req.Context(), orgID, []string{params.MetricName})
metricName, err := extractMetricName(req)
if err != nil {
render.Error(rw, err)
return
}
metadata, ok := metadataMap[params.MetricName]
orgID := valuer.MustNewUUID(claims.OrgID)
metadataMap, err := h.module.GetMetricMetadataMulti(req.Context(), orgID, []string{metricName})
if err != nil {
render.Error(rw, err)
return
}
metadata, ok := metadataMap[metricName]
if !ok || metadata == nil {
render.Error(rw, errors.NewNotFoundf(errors.CodeNotFound, "metadata not found for metric %q", params.MetricName))
render.Error(rw, errors.NewNotFoundf(errors.CodeNotFound, "metadata not found for metric %q", metricName))
return
}
@@ -149,19 +180,14 @@ func (h *handler) GetMetricAlerts(rw http.ResponseWriter, req *http.Request) {
return
}
var params metricsexplorertypes.MetricNameParams
if err := binding.Query.BindQuery(req.URL.Query(), &params); err != nil {
metricName, err := extractMetricName(req)
if err != nil {
render.Error(rw, err)
return
}
if params.MetricName == "" {
render.Error(rw, errors.NewInvalidInputf(errors.CodeInvalidInput, "metricName query parameter is required"))
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
out, err := h.module.GetMetricAlerts(req.Context(), orgID, params.MetricName)
out, err := h.module.GetMetricAlerts(req.Context(), orgID, metricName)
if err != nil {
render.Error(rw, err)
return
@@ -176,19 +202,14 @@ func (h *handler) GetMetricDashboards(rw http.ResponseWriter, req *http.Request)
return
}
var params metricsexplorertypes.MetricNameParams
if err := binding.Query.BindQuery(req.URL.Query(), &params); err != nil {
metricName, err := extractMetricName(req)
if err != nil {
render.Error(rw, err)
return
}
if params.MetricName == "" {
render.Error(rw, errors.NewInvalidInputf(errors.CodeInvalidInput, "metricName query parameter is required"))
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
out, err := h.module.GetMetricDashboards(req.Context(), orgID, params.MetricName)
out, err := h.module.GetMetricDashboards(req.Context(), orgID, metricName)
if err != nil {
render.Error(rw, err)
return
@@ -203,19 +224,14 @@ func (h *handler) GetMetricHighlights(rw http.ResponseWriter, req *http.Request)
return
}
var params metricsexplorertypes.MetricNameParams
if err := binding.Query.BindQuery(req.URL.Query(), &params); err != nil {
metricName, err := extractMetricName(req)
if err != nil {
render.Error(rw, err)
return
}
if params.MetricName == "" {
render.Error(rw, errors.NewInvalidInputf(errors.CodeInvalidInput, "metricName query parameter is required"))
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
highlights, err := h.module.GetMetricHighlights(req.Context(), orgID, params.MetricName)
highlights, err := h.module.GetMetricHighlights(req.Context(), orgID, metricName)
if err != nil {
render.Error(rw, err)
return
@@ -230,8 +246,21 @@ func (h *handler) GetMetricAttributes(rw http.ResponseWriter, req *http.Request)
return
}
metricName, err := extractMetricName(req)
if err != nil {
render.Error(rw, err)
return
}
var in metricsexplorertypes.MetricAttributesRequest
if err := binding.JSON.BindBody(req.Body, &in); err != nil {
if err := binding.Query.BindQuery(req.URL.Query(), &in); err != nil {
render.Error(rw, err)
return
}
in.MetricName = metricName
if err := in.Validate(); err != nil {
render.Error(rw, err)
return
}

View File

@@ -56,6 +56,88 @@ func NewModule(ts telemetrystore.TelemetryStore, telemetryMetadataStore telemetr
}
}
func (m *module) ListMetrics(ctx context.Context, orgID valuer.UUID, params *metricsexplorertypes.ListMetricsParams) (*metricsexplorertypes.ListMetricsResponse, error) {
if err := params.Validate(); err != nil {
return nil, err
}
sb := sqlbuilder.NewSelectBuilder()
sb.Select("DISTINCT metric_name")
if params.Start != nil && params.End != nil {
start, end, distributedTsTable, _ := telemetrymetrics.WhichTSTableToUse(uint64(*params.Start), uint64(*params.End), nil)
sb.From(fmt.Sprintf("%s.%s", telemetrymetrics.DBName, distributedTsTable))
sb.Where(sb.Between("unix_milli", start, end))
} else {
sb.From(fmt.Sprintf("%s.%s", telemetrymetrics.DBName, telemetrymetrics.TimeseriesV41weekTableName))
}
sb.Where(sb.E("__normalized", false))
if params.Search != "" {
searchLower := strings.ToLower(params.Search)
searchLower = strings.ReplaceAll(searchLower, "%", "\\%")
searchLower = strings.ReplaceAll(searchLower, "_", "\\_")
sb.Where(sb.Like("lower(metric_name)", fmt.Sprintf("%%%s%%", searchLower)))
}
sb.OrderBy("metric_name ASC")
sb.Limit(params.Limit)
query, args := sb.BuildWithFlavor(sqlbuilder.ClickHouse)
valueCtx := ctxtypes.SetClickhouseMaxThreads(ctx, m.config.TelemetryStore.Threads)
db := m.telemetryStore.ClickhouseDB()
rows, err := db.Query(valueCtx, query, args...)
if err != nil {
return nil, errors.WrapInternalf(err, errors.CodeInternal, "failed to list metrics")
}
defer rows.Close()
metricNames := make([]string, 0)
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
return nil, errors.WrapInternalf(err, errors.CodeInternal, "failed to scan metric name")
}
metricNames = append(metricNames, name)
}
if err := rows.Err(); err != nil {
return nil, errors.WrapInternalf(err, errors.CodeInternal, "error iterating metric names")
}
if len(metricNames) == 0 {
return &metricsexplorertypes.ListMetricsResponse{
Metrics: []metricsexplorertypes.ListMetric{},
}, nil
}
metadata, err := m.GetMetricMetadataMulti(ctx, orgID, metricNames)
if err != nil {
return nil, err
}
metrics := make([]metricsexplorertypes.ListMetric, 0, len(metricNames))
for _, name := range metricNames {
metric := metricsexplorertypes.ListMetric{
MetricName: name,
}
if meta, ok := metadata[name]; ok && meta != nil {
metric.Description = meta.Description
metric.MetricType = meta.MetricType
metric.MetricUnit = meta.MetricUnit
metric.Temporality = meta.Temporality
metric.IsMonotonic = meta.IsMonotonic
}
metrics = append(metrics, metric)
}
return &metricsexplorertypes.ListMetricsResponse{
Metrics: metrics,
}, nil
}
func (m *module) GetStats(ctx context.Context, orgID valuer.UUID, req *metricsexplorertypes.StatsRequest) (*metricsexplorertypes.StatsResponse, error) {
if err := req.Validate(); err != nil {
return nil, err

View File

@@ -10,6 +10,7 @@ import (
// Handler exposes HTTP handlers for the metrics module.
type Handler interface {
ListMetrics(http.ResponseWriter, *http.Request)
GetStats(http.ResponseWriter, *http.Request)
GetTreemap(http.ResponseWriter, *http.Request)
GetMetricMetadata(http.ResponseWriter, *http.Request)
@@ -22,6 +23,7 @@ type Handler interface {
// Module represents the metrics module interface.
type Module interface {
ListMetrics(ctx context.Context, orgID valuer.UUID, params *metricsexplorertypes.ListMetricsParams) (*metricsexplorertypes.ListMetricsResponse, error)
GetStats(ctx context.Context, orgID valuer.UUID, req *metricsexplorertypes.StatsRequest) (*metricsexplorertypes.StatsResponse, error)
GetTreemap(ctx context.Context, orgID valuer.UUID, req *metricsexplorertypes.TreemapRequest) (*metricsexplorertypes.TreemapResponse, error)
GetMetricMetadataMulti(ctx context.Context, orgID valuer.UUID, metricNames []string) (map[string]*metricsexplorertypes.MetricMetadata, error)

View File

@@ -260,11 +260,11 @@ type MetricHighlightsResponse struct {
ActiveTimeSeries uint64 `json:"activeTimeSeries" required:"true"`
}
// MetricAttributesRequest represents the payload for the metric attributes endpoint.
// MetricAttributesRequest represents the query parameters for the metric attributes endpoint.
type MetricAttributesRequest struct {
MetricName string `json:"metricName" required:"true"`
Start *int64 `json:"start,omitempty"`
End *int64 `json:"end,omitempty"`
MetricName string `json:"-"`
Start *int64 `query:"start"`
End *int64 `query:"end"`
}
// Validate ensures MetricAttributesRequest contains acceptable values.
@@ -273,10 +273,6 @@ func (req *MetricAttributesRequest) Validate() error {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "request is nil")
}
if req.MetricName == "" {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "metric_name is required")
}
if req.Start != nil && req.End != nil {
if *req.Start >= *req.End {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "start (%d) must be less than end (%d)", *req.Start, *req.End)
@@ -286,17 +282,6 @@ func (req *MetricAttributesRequest) Validate() error {
return nil
}
// UnmarshalJSON validates input immediately after decoding.
func (req *MetricAttributesRequest) UnmarshalJSON(data []byte) error {
type raw MetricAttributesRequest
var decoded raw
if err := json.Unmarshal(data, &decoded); err != nil {
return err
}
*req = MetricAttributesRequest(decoded)
return req.Validate()
}
// MetricAttribute represents a single attribute with its values and count.
type MetricAttribute struct {
Key string `json:"key" required:"true"`
@@ -310,6 +295,48 @@ type MetricAttributesResponse struct {
TotalKeys int64 `json:"totalKeys" required:"true"`
}
type MetricNameParams struct {
MetricName string `query:"metricName" required:"true"`
// ListMetricsParams represents the query parameters for the list metrics endpoint.
type ListMetricsParams struct {
Start *int64 `query:"start"`
End *int64 `query:"end"`
Limit int `query:"limit"`
Search string `query:"searchText"`
}
// Validate ensures ListMetricsParams contains acceptable values.
func (p *ListMetricsParams) Validate() error {
if p.Start != nil && *p.Start <= 0 {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "start must be greater than 0")
}
if p.End != nil && *p.End <= 0 {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "end must be greater than 0")
}
if p.Start != nil && p.End != nil && *p.Start >= *p.End {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "start (%d) must be less than end (%d)", *p.Start, *p.End)
}
if p.Limit < 0 {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "limit cannot be negative")
}
if p.Limit == 0 {
p.Limit = 100
}
if p.Limit > 5000 {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "limit must not exceed 5000")
}
return nil
}
// ListMetric represents a single metric with its metadata in the list metrics response.
type ListMetric struct {
MetricName string `json:"metricName" required:"true"`
Description string `json:"description" required:"true"`
MetricType metrictypes.Type `json:"type" required:"true"`
MetricUnit string `json:"unit" required:"true"`
Temporality metrictypes.Temporality `json:"temporality" required:"true"`
IsMonotonic bool `json:"isMonotonic" required:"true"`
}
// ListMetricsResponse represents the response for the list metrics endpoint.
type ListMetricsResponse struct {
Metrics []ListMetric `json:"metrics" required:"true" nullable:"true"`
}