Skip to content

Commit cc6dc02

Browse files
committed
Changed pagination to use span_id, not trace_id, more granular
Improved cursor Removed debug from logs
1 parent a614149 commit cc6dc02

File tree

4 files changed

+10
-62
lines changed

4 files changed

+10
-62
lines changed

apps/webapp/app/presenters/v3/LogsListPresenter.server.ts

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ export type LogsListOptions = {
5050
retentionLimitDays?: number;
5151
// search
5252
search?: string;
53-
includeDebugLogs?: boolean;
5453
// pagination
5554
direction?: Direction;
5655
cursor?: string;
@@ -69,7 +68,6 @@ export const LogsListOptionsSchema = z.object({
6968
defaultPeriod: z.string().optional(),
7069
retentionLimitDays: z.number().int().positive().optional(),
7170
search: z.string().max(1000).optional(),
72-
includeDebugLogs: z.boolean().optional(),
7371
direction: z.enum(["forward", "backward"]).optional(),
7472
cursor: z.string().optional(),
7573
pageSize: z.number().int().positive().max(1000).optional(),
@@ -83,12 +81,14 @@ export type LogsListAppliedFilters = LogsList["filters"];
8381

8482
// Cursor is a base64 encoded JSON of the pagination keys
8583
type LogCursor = {
84+
organizationId: string;
8685
environmentId: string;
8786
triggeredTimestamp: string; // DateTime64(9) string
8887
spanId: string;
8988
};
9089

9190
const LogCursorSchema = z.object({
91+
organizationId: z.string(),
9292
environmentId: z.string(),
9393
triggeredTimestamp: z.string(),
9494
spanId: z.string(),
@@ -166,7 +166,6 @@ export class LogsListPresenter extends BasePresenter {
166166
to,
167167
cursor,
168168
pageSize = DEFAULT_PAGE_SIZE,
169-
includeDebugLogs = true,
170169
defaultPeriod,
171170
retentionLimitDays,
172171
}: LogsListOptions
@@ -349,32 +348,22 @@ export class LogsListPresenter extends BasePresenter {
349348
}
350349
}
351350

352-
// Debug logs are available only to admins
353-
// if (includeDebugLogs === false) {
354-
// queryBuilder.where("kind NOT IN {debugKinds: Array(String)}", {
355-
// debugKinds: ["DEBUG_EVENT"],
356-
// });
357-
//
358-
// queryBuilder.where("NOT ((kind = 'LOG_INFO') AND (attributes_text = '{}'))");
359-
// }
360-
361-
// SPAN, ANCESTOR_OVERRIDE, SPAN_EVENT kinds are already filtered out by the materialized view
362-
363351
// Cursor pagination using explicit lexicographic comparison
364-
// Must mirror the ORDER BY columns: (environment_id DESC, triggered_timestamp DESC, span_id DESC)
352+
// Must mirror the ORDER BY columns: (organization_id DESC, environment_id DESC, triggered_timestamp DESC, span_id DESC)
365353
const decodedCursor = cursor ? decodeCursor(cursor) : null;
366354
if (decodedCursor) {
367355
queryBuilder.where(
368-
`((environment_id = {cursorEnvId: String} AND triggered_timestamp < {cursorTriggeredTimestamp: String}) OR (environment_id = {cursorEnvId: String} AND triggered_timestamp = {cursorTriggeredTimestamp: String} AND span_id < {cursorSpanId: String}) OR (environment_id < {cursorEnvId: String}))`,
356+
`((organization_id = {cursorOrgId: String} AND environment_id = {cursorEnvId: String} AND triggered_timestamp = {cursorTriggeredTimestamp: String} AND span_id < {cursorSpanId: String}) OR (organization_id = {cursorOrgId: String} AND environment_id = {cursorEnvId: String} AND triggered_timestamp < {cursorTriggeredTimestamp: String}) OR (organization_id = {cursorOrgId: String} AND environment_id < {cursorEnvId: String}) OR (organization_id < {cursorOrgId: String}))`,
369357
{
358+
cursorOrgId: decodedCursor.organizationId,
370359
cursorEnvId: decodedCursor.environmentId,
371360
cursorTriggeredTimestamp: decodedCursor.triggeredTimestamp,
372361
cursorSpanId: decodedCursor.spanId,
373362
}
374363
);
375364
}
376365

377-
queryBuilder.orderBy("environment_id DESC, triggered_timestamp DESC, span_id DESC");
366+
queryBuilder.orderBy("organization_id DESC, environment_id DESC, triggered_timestamp DESC, span_id DESC");
378367
// Limit + 1 to check if there are more results
379368
queryBuilder.limit(pageSize + 1);
380369

@@ -393,6 +382,7 @@ export class LogsListPresenter extends BasePresenter {
393382
if (hasMore && logs.length > 0) {
394383
const lastLog = logs[logs.length - 1];
395384
nextCursor = encodeCursor({
385+
organizationId,
396386
environmentId,
397387
triggeredTimestamp: lastLog.triggered_timestamp,
398388
spanId: lastLog.span_id,

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.logs/route.tsx

Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import {
3636
ResizablePanel,
3737
ResizablePanelGroup,
3838
} from "~/components/primitives/Resizable";
39-
import { Switch } from "~/components/primitives/Switch";
4039
import { Button } from "~/components/primitives/Buttons";
4140
import { FEATURE_FLAG, validateFeatureFlagValue } from "~/v3/featureFlags.server";
4241

@@ -95,7 +94,6 @@ async function hasLogsPageAccess(
9594
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
9695
const user = await requireUser(request);
9796
const userId = user.id;
98-
const isAdmin = user.admin || user.isImpersonating;
9997

10098
const { projectParam, organizationSlug, envParam } = EnvironmentParamSchema.parse(params);
10199

@@ -126,7 +124,6 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
126124
const runId = url.searchParams.get("runId") ?? undefined;
127125
const search = url.searchParams.get("search") ?? undefined;
128126
const levels = parseLevelsFromUrl(url);
129-
const showDebug = url.searchParams.get("showDebug") === "true";
130127
const period = url.searchParams.get("period") ?? undefined;
131128
const fromStr = url.searchParams.get("from");
132129
const toStr = url.searchParams.get("to");
@@ -150,7 +147,6 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
150147
period,
151148
from,
152149
to,
153-
includeDebugLogs: isAdmin && showDebug,
154150
defaultPeriod: "1h",
155151
retentionLimitDays
156152
})
@@ -163,15 +159,13 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
163159

164160
return typeddefer({
165161
data: listPromise,
166-
isAdmin,
167-
showDebug,
168162
defaultPeriod: "1h",
169163
retentionLimitDays,
170164
});
171165
};
172166

173167
export default function Page() {
174-
const { data, isAdmin, showDebug, defaultPeriod, retentionLimitDays } =
168+
const { data, defaultPeriod, retentionLimitDays } =
175169
useTypedLoaderData<typeof loader>();
176170

177171
return (
@@ -199,8 +193,6 @@ export default function Page() {
199193
errorElement={
200194
<div className="grid h-full max-h-full grid-rows-[2.5rem_auto_1fr] overflow-hidden">
201195
<FiltersBar
202-
isAdmin={isAdmin}
203-
showDebug={showDebug}
204196
defaultPeriod={defaultPeriod}
205197
retentionLimitDays={retentionLimitDays}
206198
/>
@@ -218,8 +210,6 @@ export default function Page() {
218210
return (
219211
<div className="grid h-full max-h-full grid-rows-[2.5rem_auto_1fr] overflow-hidden">
220212
<FiltersBar
221-
isAdmin={isAdmin}
222-
showDebug={showDebug}
223213
defaultPeriod={defaultPeriod}
224214
retentionLimitDays={retentionLimitDays}
225215
/>
@@ -235,15 +225,11 @@ export default function Page() {
235225
<div className="grid h-full max-h-full grid-rows-[2.5rem_1fr] overflow-hidden">
236226
<FiltersBar
237227
list={result}
238-
isAdmin={isAdmin}
239-
showDebug={showDebug}
240228
defaultPeriod={defaultPeriod}
241229
retentionLimitDays={retentionLimitDays}
242230
/>
243231
<LogsList
244232
list={result}
245-
isAdmin={isAdmin}
246-
showDebug={showDebug}
247233
defaultPeriod={defaultPeriod}
248234
/>
249235
</div>
@@ -258,14 +244,10 @@ export default function Page() {
258244

259245
function FiltersBar({
260246
list,
261-
isAdmin,
262-
showDebug,
263247
defaultPeriod,
264248
retentionLimitDays,
265249
}: {
266250
list?: Exclude<Awaited<UseDataFunctionReturn<typeof loader>["data"]>, { error: string }>;
267-
isAdmin: boolean;
268-
showDebug: boolean;
269251
defaultPeriod?: string;
270252
retentionLimitDays: number;
271253
}) {
@@ -280,16 +262,6 @@ function FiltersBar({
280262
searchParams.has("from") ||
281263
searchParams.has("to");
282264

283-
const handleDebugToggle = useCallback((checked: boolean) => {
284-
const url = new URL(window.location.href);
285-
if (checked) {
286-
url.searchParams.set("showDebug", "true");
287-
} else {
288-
url.searchParams.delete("showDebug");
289-
}
290-
window.location.href = url.toString();
291-
}, []);
292-
293265
return (
294266
<div className="flex items-start justify-between gap-x-2 border-b border-grid-bright p-2">
295267
<div className="flex flex-row flex-wrap items-center gap-1">
@@ -329,16 +301,6 @@ function FiltersBar({
329301
</>
330302
)}
331303
</div>
332-
<div className="flex items-center gap-2">
333-
{isAdmin && (
334-
<Switch
335-
variant="small"
336-
label="Debug"
337-
checked={showDebug}
338-
onCheckedChange={handleDebugToggle}
339-
/>
340-
)}
341-
</div>
342304
</div>
343305
);
344306
}
@@ -347,8 +309,6 @@ function LogsList({
347309
list,
348310
}: {
349311
list: Exclude<Awaited<UseDataFunctionReturn<typeof loader>["data"]>, { error: string }>; //exclude error, it is handled
350-
isAdmin: boolean;
351-
showDebug: boolean;
352312
defaultPeriod?: string;
353313
}) {
354314
const navigation = useNavigation();

apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.logs.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ function parseLevelsFromUrl(url: URL): LogLevel[] | undefined {
2121
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
2222
const user = await requireUser(request);
2323
const userId = user.id;
24-
const isAdmin = user?.admin || user?.isImpersonating;
2524

2625
const { projectParam, organizationSlug, envParam } = EnvironmentParamSchema.parse(params);
2726

@@ -46,7 +45,6 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
4645
const search = url.searchParams.get("search") ?? undefined;
4746
const cursor = url.searchParams.get("cursor") ?? undefined;
4847
const levels = parseLevelsFromUrl(url);
49-
const showDebug = url.searchParams.get("showDebug") === "true";
5048
const period = url.searchParams.get("period") ?? undefined;
5149
const fromStr = url.searchParams.get("from");
5250
const toStr = url.searchParams.get("to");
@@ -67,7 +65,6 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
6765
from,
6866
to,
6967
levels,
70-
includeDebugLogs: isAdmin && showDebug,
7168
defaultPeriod: "1h",
7269
retentionLimitDays,
7370
}) as any; // Validated by LogsListOptionsSchema at runtime

internal-packages/clickhouse/schema/016_add_task_events_search_v1.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ CREATE TABLE IF NOT EXISTS trigger_dev.task_events_search_v1
2424
)
2525
ENGINE = MergeTree
2626
PARTITION BY toDate(triggered_timestamp)
27-
ORDER BY (organization_id, environment_id, triggered_timestamp)
27+
ORDER BY (organization_id, environment_id, triggered_timestamp, span_id)
2828
--Right now we have maximum retention of up to 30 days based on plan.
2929
--We put a logical limit for now, the 90 DAY TTL is just a backup
3030
--This might need to be updated for longer retention periods
@@ -55,6 +55,7 @@ WHERE
5555
kind != 'DEBUG_EVENT'
5656
AND status != 'PARTIAL'
5757
AND NOT (kind = 'SPAN_EVENT' AND attributes_text = '{}')
58+
AND kind != 'ANCESTOR_OVERRIDE'
5859
AND message != 'trigger.dev/start';
5960

6061
-- +goose Down

0 commit comments

Comments
 (0)