diff --git a/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/table/hooks/use-logs-query.ts b/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/table/hooks/use-logs-query.ts index ea5550adf7..8dff4f9534 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/table/hooks/use-logs-query.ts +++ b/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/table/hooks/use-logs-query.ts @@ -119,7 +119,6 @@ export function useKeysOverviewLogsQuery({ apiId, limit = 50 }: UseLogsQueryPara isLoading: isLoadingInitial, } = trpc.api.keys.query.useInfiniteQuery(queryParams, { getNextPageParam: (lastPage) => lastPage.nextCursor, - initialCursor: { requestId: null, time: null }, staleTime: Number.POSITIVE_INFINITY, refetchOnMount: false, refetchOnWindowFocus: false, diff --git a/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/table/query-logs.schema.ts b/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/table/query-logs.schema.ts index a456c74567..fb725602f3 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/table/query-logs.schema.ts +++ b/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/table/query-logs.schema.ts @@ -11,13 +11,7 @@ export const keysQueryOverviewLogsPayload = z.object({ endTime: z.number().int(), apiId: z.string(), since: z.string(), - cursor: z - .object({ - requestId: z.string().nullable(), - time: z.number().nullable(), - }) - .optional() - .nullable(), + cursor: z.number().nullable().optional().nullable(), outcomes: z .array( z.object({ diff --git a/apps/dashboard/app/(app)/logs/components/table/hooks/use-logs-query.ts b/apps/dashboard/app/(app)/logs/components/table/hooks/use-logs-query.ts index 8886a52ebd..ac5382f727 100644 --- a/apps/dashboard/app/(app)/logs/components/table/hooks/use-logs-query.ts +++ b/apps/dashboard/app/(app)/logs/components/table/hooks/use-logs-query.ts @@ -138,7 +138,6 @@ export function useLogsQuery({ isLoading: isLoadingInitial, } = trpc.logs.queryLogs.useInfiniteQuery(queryParams, { getNextPageParam: (lastPage) => lastPage.nextCursor, - initialCursor: { requestId: null, time: null }, staleTime: Number.POSITIVE_INFINITY, refetchOnMount: false, refetchOnWindowFocus: false, diff --git a/apps/dashboard/app/(app)/logs/components/table/query-logs.schema.ts b/apps/dashboard/app/(app)/logs/components/table/query-logs.schema.ts index 198fa3ccf7..feadf1eed1 100644 --- a/apps/dashboard/app/(app)/logs/components/table/query-logs.schema.ts +++ b/apps/dashboard/app/(app)/logs/components/table/query-logs.schema.ts @@ -56,11 +56,5 @@ export const queryLogsPayload = z.object({ ), }) .nullable(), - cursor: z - .object({ - requestId: z.string().nullable(), - time: z.number().nullable(), - }) - .optional() - .nullable(), + cursor: z.number().nullable().optional().nullable(), }); diff --git a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/table/hooks/use-logs-query.ts b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/table/hooks/use-logs-query.ts index e0a907dfbd..256ee3ec1c 100644 --- a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/table/hooks/use-logs-query.ts +++ b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/table/hooks/use-logs-query.ts @@ -95,7 +95,6 @@ export function useRatelimitOverviewLogsQuery({ namespaceId, limit = 50 }: UseLo isLoading: isLoadingInitial, } = trpc.ratelimit.overview.logs.query.useInfiniteQuery(queryParams, { getNextPageParam: (lastPage) => lastPage.nextCursor, - initialCursor: { requestId: null, time: null }, staleTime: Number.POSITIVE_INFINITY, refetchOnMount: false, refetchOnWindowFocus: false, diff --git a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/table/query-logs.schema.ts b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/table/query-logs.schema.ts index 21f05d4a0b..5e23cdda26 100644 --- a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/table/query-logs.schema.ts +++ b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/_overview/components/table/query-logs.schema.ts @@ -30,13 +30,7 @@ export const ratelimitQueryOverviewLogsPayload = z.object({ ), }) .nullable(), - cursor: z - .object({ - requestId: z.string().nullable(), - time: z.number().nullable(), - }) - .optional() - .nullable(), + cursor: z.number().nullable().optional().nullable(), sorts: z .array( z.object({ diff --git a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/table/hooks/use-logs-query.ts b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/table/hooks/use-logs-query.ts index 1d50c9e6c4..73ead945b5 100644 --- a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/table/hooks/use-logs-query.ts +++ b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/table/hooks/use-logs-query.ts @@ -116,7 +116,6 @@ export function useRatelimitLogsQuery({ isLoading: isLoadingInitial, } = trpc.ratelimit.logs.query.useInfiniteQuery(queryParams, { getNextPageParam: (lastPage) => lastPage.nextCursor, - initialCursor: { requestId: null, time: null }, staleTime: Number.POSITIVE_INFINITY, refetchOnMount: false, refetchOnWindowFocus: false, diff --git a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/table/query-logs.schema.ts b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/table/query-logs.schema.ts index dbeef0ae95..568d1efbc2 100644 --- a/apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/table/query-logs.schema.ts +++ b/apps/dashboard/app/(app)/ratelimits/[namespaceId]/logs/components/table/query-logs.schema.ts @@ -37,13 +37,7 @@ export const ratelimitQueryLogsPayload = z.object({ ), }) .nullable(), - cursor: z - .object({ - requestId: z.string().nullable(), - time: z.number().nullable(), - }) - .optional() - .nullable(), + cursor: z.number().nullable().optional().nullable(), }); export type RatelimitQueryLogsPayload = z.infer; diff --git a/apps/dashboard/lib/trpc/routers/api/keys/query-overview-logs/index.ts b/apps/dashboard/lib/trpc/routers/api/keys/query-overview-logs/index.ts index e0338ea08d..44269abfe7 100644 --- a/apps/dashboard/lib/trpc/routers/api/keys/query-overview-logs/index.ts +++ b/apps/dashboard/lib/trpc/routers/api/keys/query-overview-logs/index.ts @@ -10,12 +10,7 @@ import { transformKeysFilters } from "./utils"; const KeysOverviewLogsResponse = z.object({ keysOverviewLogs: z.array(keysLogs), hasMore: z.boolean(), - nextCursor: z - .object({ - time: z.number().int(), - requestId: z.string(), - }) - .optional(), + nextCursor: z.number().int().optional(), }); type KeysOverviewLogsResponse = z.infer; @@ -46,8 +41,7 @@ export const queryKeysOverviewLogs = t.procedure const clickhouseResult = await clickhouse.api.keys.logs({ ...transformedInputs, - cursorRequestId: input.cursor?.requestId ?? null, - cursorTime: input.cursor?.time ?? null, + cursorTime: input.cursor ?? null, workspaceId: ctx.workspace.id, keyspaceId: keyspaceId, // Only include keyIds filters if explicitly provided in the input @@ -99,13 +93,7 @@ export const queryKeysOverviewLogs = t.procedure const response: KeysOverviewLogsResponse = { keysOverviewLogs, hasMore: logs.length === input.limit && keysOverviewLogs.length > 0, - nextCursor: - logs.length === input.limit - ? { - time: logs[logs.length - 1].time, - requestId: logs[logs.length - 1].request_id, - } - : undefined, + nextCursor: logs.length === input.limit ? logs[logs.length - 1].time : undefined, }; return response; diff --git a/apps/dashboard/lib/trpc/routers/api/keys/query-overview-logs/utils.ts b/apps/dashboard/lib/trpc/routers/api/keys/query-overview-logs/utils.ts index 8ea0179493..c0122f951d 100644 --- a/apps/dashboard/lib/trpc/routers/api/keys/query-overview-logs/utils.ts +++ b/apps/dashboard/lib/trpc/routers/api/keys/query-overview-logs/utils.ts @@ -51,8 +51,7 @@ export function transformKeysFilters( names, identities, outcomes, - cursorTime: params.cursor?.time ?? null, - cursorRequestId: params.cursor?.requestId ?? null, + cursorTime: params.cursor ?? null, sorts, }; } diff --git a/apps/dashboard/lib/trpc/routers/logs/query-logs/index.ts b/apps/dashboard/lib/trpc/routers/logs/query-logs/index.ts index c2bf141dce..aacac64412 100644 --- a/apps/dashboard/lib/trpc/routers/logs/query-logs/index.ts +++ b/apps/dashboard/lib/trpc/routers/logs/query-logs/index.ts @@ -11,12 +11,7 @@ const LogsResponse = z.object({ logs: z.array(log), hasMore: z.boolean(), total: z.number(), - nextCursor: z - .object({ - time: z.number().int(), - requestId: z.string(), - }) - .optional(), + nextCursor: z.number().int().optional(), }); type LogsResponse = z.infer; @@ -52,8 +47,7 @@ export const queryLogs = t.procedure const transformedInputs = transformFilters(input); const { logsQuery, totalQuery } = await clickhouse.api.logs({ ...transformedInputs, - cursorRequestId: input.cursor?.requestId ?? null, - cursorTime: input.cursor?.time ?? null, + cursorTime: input.cursor ?? null, workspaceId: workspace.id, }); @@ -73,13 +67,7 @@ export const queryLogs = t.procedure logs, hasMore: logs.length === input.limit, total: countResult.val[0].total_count, - nextCursor: - logs.length > 0 - ? { - time: logs[logs.length - 1].time, - requestId: logs[logs.length - 1].request_id, - } - : undefined, + nextCursor: logs.length > 0 ? logs[logs.length - 1].time : undefined, }; return response; diff --git a/apps/dashboard/lib/trpc/routers/logs/query-logs/utils.test.ts b/apps/dashboard/lib/trpc/routers/logs/query-logs/utils.test.ts index 74b6a6bd7d..8af2119451 100644 --- a/apps/dashboard/lib/trpc/routers/logs/query-logs/utils.test.ts +++ b/apps/dashboard/lib/trpc/routers/logs/query-logs/utils.test.ts @@ -28,7 +28,6 @@ describe("transformFilters", () => { statusCodes: [], requestIds: [], cursorTime: null, - cursorRequestId: null, }); }); @@ -96,6 +95,5 @@ describe("transformFilters", () => { const result = transformFilters(payload); expect(result.cursorTime).toBe(1706024400000); - expect(result.cursorRequestId).toBe("req123"); }); }); diff --git a/apps/dashboard/lib/trpc/routers/logs/query-logs/utils.ts b/apps/dashboard/lib/trpc/routers/logs/query-logs/utils.ts index d60b8d4a8e..1ca631ccb1 100644 --- a/apps/dashboard/lib/trpc/routers/logs/query-logs/utils.ts +++ b/apps/dashboard/lib/trpc/routers/logs/query-logs/utils.ts @@ -38,7 +38,6 @@ export function transformFilters( methods, paths, statusCodes, - cursorTime: params.cursor?.time ?? null, - cursorRequestId: params.cursor?.requestId ?? null, + cursorTime: params.cursor ?? null, }; } diff --git a/apps/dashboard/lib/trpc/routers/ratelimit/query-logs/index.ts b/apps/dashboard/lib/trpc/routers/ratelimit/query-logs/index.ts index c5e2f2f229..85af5ce30d 100644 --- a/apps/dashboard/lib/trpc/routers/ratelimit/query-logs/index.ts +++ b/apps/dashboard/lib/trpc/routers/ratelimit/query-logs/index.ts @@ -11,12 +11,7 @@ const RatelimitLogsResponse = z.object({ ratelimitLogs: z.array(ratelimitLogs), hasMore: z.boolean(), total: z.number(), - nextCursor: z - .object({ - time: z.number().int(), - requestId: z.string(), - }) - .optional(), + nextCursor: z.number().int().optional(), }); type RatelimitLogsResponse = z.infer; @@ -61,8 +56,7 @@ export const queryRatelimitLogs = t.procedure const transformedInputs = transformFilters(input); const { countQuery, logsQuery } = await clickhouse.ratelimits.logs({ ...transformedInputs, - cursorRequestId: input.cursor?.requestId ?? null, - cursorTime: input.cursor?.time ?? null, + cursorTime: input.cursor ?? null, workspaceId: ctx.workspace.id, namespaceId: ratelimitNamespaces[0].id, }); @@ -81,13 +75,7 @@ export const queryRatelimitLogs = t.procedure ratelimitLogs: logs, total: countResult.val[0].total_count, hasMore: logs.length === input.limit, - nextCursor: - logs.length > 0 - ? { - time: logs[logs.length - 1].time, - requestId: logs[logs.length - 1].request_id, - } - : undefined, + nextCursor: logs.length > 0 ? logs[logs.length - 1].time : undefined, }; return response; diff --git a/apps/dashboard/lib/trpc/routers/ratelimit/query-logs/utils.ts b/apps/dashboard/lib/trpc/routers/ratelimit/query-logs/utils.ts index 9c709b2d9d..8ff10d3c1c 100644 --- a/apps/dashboard/lib/trpc/routers/ratelimit/query-logs/utils.ts +++ b/apps/dashboard/lib/trpc/routers/ratelimit/query-logs/utils.ts @@ -34,7 +34,6 @@ export function transformFilters( identifiers, requestIds: params.requestIds?.filters.map((f) => f.value) || [], status, - cursorTime: params.cursor?.time ?? null, - cursorRequestId: params.cursor?.requestId ?? null, + cursorTime: params.cursor ?? null, }; } diff --git a/apps/dashboard/lib/trpc/routers/ratelimit/query-overview-logs/index.ts b/apps/dashboard/lib/trpc/routers/ratelimit/query-overview-logs/index.ts index ebacd801d4..1b62586be7 100644 --- a/apps/dashboard/lib/trpc/routers/ratelimit/query-overview-logs/index.ts +++ b/apps/dashboard/lib/trpc/routers/ratelimit/query-overview-logs/index.ts @@ -11,12 +11,7 @@ const RatelimitOverviewLogsResponse = z.object({ ratelimitOverviewLogs: z.array(ratelimitOverviewLogs), hasMore: z.boolean(), total: z.number(), - nextCursor: z - .object({ - time: z.number().int(), - requestId: z.string(), - }) - .optional(), + nextCursor: z.number().int().optional(), }); type RatelimitOverviewLogsResponse = z.infer; @@ -61,8 +56,7 @@ export const queryRatelimitOverviewLogs = t.procedure const transformedInputs = transformFilters(input); const { countQuery, logsQuery } = await clickhouse.ratelimits.overview.logs({ ...transformedInputs, - cursorRequestId: input.cursor?.requestId ?? null, - cursorTime: input.cursor?.time ?? null, + cursorTime: input.cursor ?? null, workspaceId: ctx.workspace.id, namespaceId: ratelimitNamespaces[0].id, }); @@ -84,10 +78,7 @@ export const queryRatelimitOverviewLogs = t.procedure hasMore: logsWithOverrides.length === input.limit, nextCursor: logsWithOverrides.length === input.limit - ? { - time: logsWithOverrides[logsWithOverrides.length - 1].time, - requestId: logsWithOverrides[logsWithOverrides.length - 1].request_id, - } + ? logsWithOverrides[logsWithOverrides.length - 1].time : undefined, }; diff --git a/apps/dashboard/lib/trpc/routers/ratelimit/query-overview-logs/utils.ts b/apps/dashboard/lib/trpc/routers/ratelimit/query-overview-logs/utils.ts index e63f9dd101..11f2ee6b9d 100644 --- a/apps/dashboard/lib/trpc/routers/ratelimit/query-overview-logs/utils.ts +++ b/apps/dashboard/lib/trpc/routers/ratelimit/query-overview-logs/utils.ts @@ -36,9 +36,8 @@ export function transformFilters( startTime, endTime, identifiers, - cursorTime: params.cursor?.time ?? null, + cursorTime: params.cursor ?? null, status, - cursorRequestId: params.cursor?.requestId ?? null, sorts, // Add sorts to the returned params }; } diff --git a/internal/clickhouse/src/keys/keys.ts b/internal/clickhouse/src/keys/keys.ts index d0ae02cc14..85fe571050 100644 --- a/internal/clickhouse/src/keys/keys.ts +++ b/internal/clickhouse/src/keys/keys.ts @@ -50,7 +50,6 @@ export const keysOverviewLogsParams = z.object({ ) .nullable(), cursorTime: z.number().int().nullable(), - cursorRequestId: z.string().nullable(), sorts: z .array( z.object({ @@ -207,34 +206,27 @@ export function getKeysOverviewLogs(ch: Querier) { // Remove any existing time sort from the orderBy array const orderByWithoutTime = orderBy.filter((clause) => !clause.startsWith("time")); - // Construct final ORDER BY clause with time and request_id always at the end + // Construct final ORDER BY clause with only time at the end const orderByClause = - [...orderByWithoutTime, `time ${timeDirection}`, `request_id ${timeDirection}`].join(", ") || - "time DESC, request_id DESC"; // Fallback if empty + [...orderByWithoutTime, `time ${timeDirection}`].join(", ") || "time DESC"; // Fallback if empty // Create cursor condition based on time direction let cursorCondition: string; // For first page or no cursor provided - if (!args.cursorTime || !args.cursorRequestId) { + if (!args.cursorTime) { cursorCondition = ` - AND ({cursorTime: Nullable(UInt64)} IS NULL AND {cursorRequestId: Nullable(String)} IS NULL) + AND ({cursorTime: Nullable(UInt64)} IS NULL) `; } else { // For subsequent pages, use cursor based on time direction if (timeDirection === "ASC") { cursorCondition = ` - AND ( - (time = {cursorTime: Nullable(UInt64)} AND request_id > {cursorRequestId: Nullable(String)}) - OR time > {cursorTime: Nullable(UInt64)} - ) + AND (time > {cursorTime: Nullable(UInt64)}) `; } else { cursorCondition = ` - AND ( - (time = {cursorTime: Nullable(UInt64)} AND request_id < {cursorRequestId: Nullable(String)}) - OR time < {cursorTime: Nullable(UInt64)} - ) + AND (time < {cursorTime: Nullable(UInt64)}) `; } } @@ -258,7 +250,7 @@ WITH AND (${keyIdConditions}) -- Apply dynamic outcome filtering AND (${outcomeCondition}) - -- Handle pagination using time and request_id as cursor + -- Handle pagination using only time as cursor ${cursorCondition} ), -- Second CTE: Calculate per-key aggregated metrics diff --git a/internal/clickhouse/src/logs.ts b/internal/clickhouse/src/logs.ts index 826031dc3a..ab81c11b10 100644 --- a/internal/clickhouse/src/logs.ts +++ b/internal/clickhouse/src/logs.ts @@ -19,7 +19,6 @@ export const getLogsClickhousePayload = z.object({ requestIds: z.array(z.string()).nullable(), statusCodes: z.array(z.number().int()).nullable(), cursorTime: z.number().int().nullable(), - cursorRequestId: z.string().nullable(), }); export const log = z.object({ @@ -143,36 +142,24 @@ export function getLogs(ch: Querier) { const logsQuery = ch.query({ query: ` - SELECT - request_id, - time, - workspace_id, - host, - method, - path, - request_headers, - request_body, - response_status, - response_headers, - response_body, - error, - service_latency - FROM metrics.raw_api_requests_v1 - WHERE ${filterConditions} - -- Apply cursor pagination last - AND ( - CASE - WHEN {cursorTime: Nullable(UInt64)} IS NOT NULL - AND {cursorRequestId: Nullable(String)} IS NOT NULL - THEN (time, request_id) < ( - {cursorTime: Nullable(UInt64)}, - {cursorRequestId: Nullable(String)} - ) - ELSE TRUE - END - ) - ORDER BY time DESC, request_id DESC - LIMIT {limit: Int}`, + SELECT + request_id, + time, + workspace_id, + host, + method, + path, + request_headers, + request_body, + response_status, + response_headers, + response_body, + error, + service_latency + FROM metrics.raw_api_requests_v1 + WHERE ${filterConditions} AND ({cursorTime: Nullable(UInt64)} IS NULL OR time < {cursorTime: Nullable(UInt64)}) + ORDER BY time DESC + LIMIT {limit: Int}`, params: extendedParamsSchema, schema: log, }); diff --git a/internal/clickhouse/src/ratelimits.ts b/internal/clickhouse/src/ratelimits.ts index e30ee52d9b..d5df31f145 100644 --- a/internal/clickhouse/src/ratelimits.ts +++ b/internal/clickhouse/src/ratelimits.ts @@ -263,7 +263,6 @@ export const ratelimitLogsParams = z.object({ ) .nullable(), cursorTime: z.number().int().nullable(), - cursorRequestId: z.string().nullable(), }); export const ratelimitLogs = z.object({ @@ -355,8 +354,9 @@ WITH filtered_ratelimits AS ( ${hasRequestIds ? "AND request_id IN {requestIds: Array(String)}" : ""} AND (${identifierConditions}) AND (${statusCondition}) - AND (({cursorTime: Nullable(UInt64)} IS NULL AND {cursorRequestId: Nullable(String)} IS NULL) - OR (time, request_id) < ({cursorTime: Nullable(UInt64)}, {cursorRequestId: Nullable(String)})) + AND ( + {cursorTime: Nullable(UInt64)} IS NULL OR time < {cursorTime: Nullable(UInt64)} + ) ) SELECT fr.request_id, @@ -395,7 +395,7 @@ LEFT JOIN ( WHERE workspace_id = {workspaceId: String} AND time BETWEEN {startTime: UInt64} AND {endTime: UInt64} ) m ON fr.request_id = m.request_id -ORDER BY fr.time DESC, fr.request_id DESC +ORDER BY fr.time DESC LIMIT {limit: Int}`, params: extendedParamsSchema, schema: ratelimitLogs, @@ -448,7 +448,6 @@ export const ratelimitOverviewLogsParams = z.object({ ) .nullable(), cursorTime: z.number().int().nullable(), - cursorRequestId: z.string().nullable(), sorts: z .array( @@ -580,32 +579,26 @@ export function getRatelimitOverviewLogs(ch: Querier) { ...orderByWithoutTime, `last_request_time ${timeDirection}`, `request_id ${timeDirection}`, - ].join(", ") || "last_request_time DESC, request_id DESC"; // Fallback if empty + ].join(", ") || "last_request_time DESC"; // Fallback if empty // Create cursor condition based on time direction let cursorCondition: string; // For first page or no cursor provided - if (!args.cursorTime || !args.cursorRequestId) { + if (!args.cursorTime) { cursorCondition = ` - AND ({cursorTime: Nullable(UInt64)} IS NULL AND {cursorRequestId: Nullable(String)} IS NULL) - `; + AND ({cursorTime: Nullable(UInt64)} IS NULL) + `; } else { // For subsequent pages, use cursor based on time direction if (timeDirection === "ASC") { cursorCondition = ` - AND ( - (time = {cursorTime: Nullable(UInt64)} AND request_id > {cursorRequestId: Nullable(String)}) - OR time > {cursorTime: Nullable(UInt64)} - ) - `; + AND (time > {cursorTime: Nullable(UInt64)}) + `; } else { cursorCondition = ` - AND ( - (time = {cursorTime: Nullable(UInt64)} AND request_id < {cursorRequestId: Nullable(String)}) - OR time < {cursorTime: Nullable(UInt64)} - ) - `; + AND (time < {cursorTime: Nullable(UInt64)}) + `; } }