Skip to content

Commit 53274b7

Browse files
committed
merge kind ans status from clickhouse to log level
1 parent 16ee2db commit 53274b7

9 files changed

Lines changed: 120 additions & 78 deletions

File tree

apps/webapp/app/components/logs/LogDetailView.tsx

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ function getLevelColor(level: string): string {
6868
return "text-blue-400 bg-blue-500/10 border-blue-500/20";
6969
case "TRACE":
7070
return "text-charcoal-500 bg-charcoal-800 border-charcoal-700";
71-
case "LOG":
71+
case "CANCELLED":
72+
return "text-charcoal-400 bg-charcoal-700 border-charcoal-600";
7273
default:
7374
return "text-text-dimmed bg-charcoal-750 border-charcoal-700";
7475
}
@@ -114,22 +115,6 @@ function getKindLabel(kind: string): string {
114115
}
115116
}
116117

117-
// Status badge color styles
118-
function getStatusColor(status: string): string {
119-
switch (status) {
120-
case "OK":
121-
return "text-success bg-success/10 border-success/20";
122-
case "ERROR":
123-
return "text-error bg-error/10 border-error/20";
124-
case "CANCELLED":
125-
return "text-charcoal-400 bg-charcoal-700 border-charcoal-600";
126-
case "PARTIAL":
127-
return "text-pending bg-pending/10 border-pending/20";
128-
default:
129-
return "text-text-dimmed bg-charcoal-750 border-charcoal-700";
130-
}
131-
}
132-
133118
export function LogDetailView({ logId, initialLog, onClose }: LogDetailViewProps) {
134119
const organization = useOrganization();
135120
const project = useProject();
@@ -359,7 +344,6 @@ function DetailsTab({ log, runPath }: { log: LogEntry; runPath: string }) {
359344
<div className="grid grid-cols-2 gap-4 rounded-md border border-grid-dimmed bg-charcoal-850 p-3">
360345
<DetailItem label="Task" value={log.taskIdentifier} mono />
361346
<DetailItem label="Kind" value={log.kind} />
362-
<DetailItem label="Status" value={log.status} />
363347
<DetailItem
364348
label="Duration"
365349
value={

apps/webapp/app/components/logs/LogsLevelFilter.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const allLogLevels: { level: LogLevel; label: string; color: string }[] = [
2020
{ level: "ERROR", label: "Error", color: "text-error" },
2121
{ level: "WARN", label: "Warning", color: "text-warning" },
2222
{ level: "INFO", label: "Info", color: "text-blue-400" },
23-
{ level: "LOG", label: "Log", color: "text-text-dimmed" },
23+
{ level: "CANCELLED", label: "Cancelled", color: "text-charcoal-400" },
2424
{ level: "DEBUG", label: "Debug", color: "text-charcoal-400" },
2525
{ level: "TRACE", label: "Trace", color: "text-charcoal-500" },
2626
];
@@ -44,7 +44,8 @@ function getLevelBadgeColor(level: LogLevel): string {
4444
return "text-blue-400 bg-blue-500/10 border-blue-500/20";
4545
case "TRACE":
4646
return "text-charcoal-500 bg-charcoal-800 border-charcoal-700";
47-
case "LOG":
47+
case "CANCELLED":
48+
return "text-charcoal-400 bg-charcoal-700 border-charcoal-600";
4849
default:
4950
return "text-text-dimmed bg-charcoal-750 border-charcoal-700";
5051
}

apps/webapp/app/components/logs/LogsTable.tsx

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -51,23 +51,8 @@ function getLevelColor(level: LogEntry["level"]): string {
5151
return "text-blue-400 bg-blue-500/10 border-blue-500/20";
5252
case "TRACE":
5353
return "text-charcoal-500 bg-charcoal-800 border-charcoal-700";
54-
case "LOG":
55-
default:
56-
return "text-text-dimmed bg-charcoal-750 border-charcoal-700";
57-
}
58-
}
59-
60-
// Status badge color styles
61-
function getStatusColor(status: string): string {
62-
switch (status) {
63-
case "OK":
64-
return "text-success bg-success/10 border-success/20";
65-
case "ERROR":
66-
return "text-error bg-error/10 border-error/20";
6754
case "CANCELLED":
6855
return "text-charcoal-400 bg-charcoal-700 border-charcoal-600";
69-
case "PARTIAL":
70-
return "text-pending bg-pending/10 border-pending/20";
7156
default:
7257
return "text-text-dimmed bg-charcoal-750 border-charcoal-700";
7358
}
@@ -82,9 +67,10 @@ function getLevelBorderColor(level: LogEntry["level"]): string {
8267
return "border-l-warning";
8368
case "INFO":
8469
return "border-l-blue-500";
70+
case "CANCELLED":
71+
return "border-l-charcoal-600";
8572
case "DEBUG":
8673
case "TRACE":
87-
case "LOG":
8874
default:
8975
return "border-l-transparent hover:border-l-charcoal-800";
9076
}
@@ -182,14 +168,13 @@ export function LogsTable({
182168
<TableHeaderCell className="w-24 whitespace-nowrap">Run</TableHeaderCell>
183169
<TableHeaderCell className="w-32 whitespace-nowrap">Task</TableHeaderCell>
184170
<TableHeaderCell className="whitespace-nowrap">Level</TableHeaderCell>
185-
<TableHeaderCell className="whitespace-nowrap">Status</TableHeaderCell>
186171
<TableHeaderCell className="whitespace-nowrap">Duration</TableHeaderCell>
187172
<TableHeaderCell className="w-full min-w-0">Message</TableHeaderCell>
188173
</TableRow>
189174
</TableHeader>
190175
<TableBody>
191176
{logs.length === 0 && !hasFilters ? (
192-
<TableBlankRow colSpan={7}>
177+
<TableBlankRow colSpan={6}>
193178
{!isLoading && <NoLogs title="No logs found" />}
194179
</TableBlankRow>
195180
) : logs.length === 0 ? (
@@ -240,16 +225,6 @@ export function LogsTable({
240225
{log.level}
241226
</span>
242227
</TableCell>
243-
<TableCell onClick={handleRowClick} hasAction>
244-
<span
245-
className={cn(
246-
"inline-flex items-center rounded border px-1 py-0.5 text-xxs font-medium uppercase tracking-wider",
247-
getStatusColor(log.status)
248-
)}
249-
>
250-
{log.status}
251-
</span>
252-
</TableCell>
253228
<TableCell
254229
className="whitespace-nowrap tabular-nums text-text-dimmed"
255230
onClick={handleRowClick}

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

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,19 @@ export type LogDetailOptions = {
1515
export type LogDetail = Awaited<ReturnType<LogDetailPresenter["call"]>>;
1616

1717
// Convert ClickHouse kind to display level
18-
function kindToLevel(
19-
kind: string
20-
): "TRACE" | "DEBUG" | "INFO" | "WARN" | "ERROR" | "LOG" {
18+
type LogLevel = "TRACE" | "DEBUG" | "INFO" | "WARN" | "ERROR" | "CANCELLED";
19+
20+
function kindToLevel(kind: string, status: string): LogLevel {
21+
// CANCELLED status takes precedence
22+
if (status === "CANCELLED") {
23+
return "CANCELLED";
24+
}
25+
26+
// ERROR can come from either kind or status
27+
if (kind === "LOG_ERROR" || status === "ERROR") {
28+
return "ERROR";
29+
}
30+
2131
switch (kind) {
2232
case "DEBUG_EVENT":
2333
case "LOG_DEBUG":
@@ -26,10 +36,8 @@ function kindToLevel(
2636
return "INFO";
2737
case "LOG_WARN":
2838
return "WARN";
29-
case "LOG_ERROR":
30-
return "ERROR";
3139
case "LOG_LOG":
32-
return "LOG";
40+
return "INFO"; // Changed from "LOG"
3341
case "SPAN":
3442
case "ANCESTOR_OVERRIDE":
3543
case "SPAN_EVENT":
@@ -111,7 +119,7 @@ export class LogDetailPresenter {
111119
kind: log.kind,
112120
status: log.status,
113121
duration: typeof log.duration === "number" ? log.duration : Number(log.duration),
114-
level: kindToLevel(log.kind),
122+
level: kindToLevel(log.kind, log.status),
115123
metadata: parsedMetadata,
116124
attributes: parsedAttributes,
117125
// Raw strings for display

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

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
convertClickhouseDateTime64ToJsDate,
1919
} from "~/v3/eventRepository/clickhouseEventRepository.server";
2020

21-
export type LogLevel = "TRACE" | "DEBUG" | "INFO" | "WARN" | "ERROR" | "LOG";
21+
export type LogLevel = "TRACE" | "DEBUG" | "INFO" | "WARN" | "ERROR" | "CANCELLED";
2222

2323
export type LogsListOptions = {
2424
userId?: string;
@@ -78,9 +78,17 @@ function decodeCursor(cursor: string): LogCursor | null {
7878
}
7979

8080
// Convert ClickHouse kind to display level
81-
function kindToLevel(
82-
kind: string
83-
): "TRACE" | "DEBUG" | "INFO" | "WARN" | "ERROR" | "LOG" {
81+
function kindToLevel(kind: string, status: string): LogLevel {
82+
// CANCELLED status takes precedence
83+
if (status === "CANCELLED") {
84+
return "CANCELLED";
85+
}
86+
87+
// ERROR can come from either kind or status
88+
if (kind === "LOG_ERROR" || status === "ERROR") {
89+
return "ERROR";
90+
}
91+
8492
switch (kind) {
8593
case "DEBUG_EVENT":
8694
case "LOG_DEBUG":
@@ -89,10 +97,8 @@ function kindToLevel(
8997
return "INFO";
9098
case "LOG_WARN":
9199
return "WARN";
92-
case "LOG_ERROR":
93-
return "ERROR";
94100
case "LOG_LOG":
95-
return "LOG";
101+
return "INFO"; // Changed from "LOG"
96102
case "SPAN":
97103
case "ANCESTOR_OVERRIDE":
98104
case "SPAN_EVENT":
@@ -101,21 +107,23 @@ function kindToLevel(
101107
}
102108
}
103109

104-
// Convert display level to ClickHouse kinds
105-
function levelToKinds(level: LogLevel): string[] {
110+
// Convert display level to ClickHouse kinds and statuses
111+
function levelToKindsAndStatuses(
112+
level: LogLevel
113+
): { kinds?: string[]; statuses?: string[] } {
106114
switch (level) {
107115
case "DEBUG":
108-
return ["DEBUG_EVENT", "LOG_DEBUG"];
116+
return { kinds: ["DEBUG_EVENT", "LOG_DEBUG"] };
109117
case "INFO":
110-
return ["LOG_INFO"];
118+
return { kinds: ["LOG_INFO", "LOG_LOG"] };
111119
case "WARN":
112-
return ["LOG_WARN"];
120+
return { kinds: ["LOG_WARN"] };
113121
case "ERROR":
114-
return ["LOG_ERROR"];
115-
case "LOG":
116-
return ["LOG_LOG"];
122+
return { kinds: ["LOG_ERROR"], statuses: ["ERROR"] };
123+
case "CANCELLED":
124+
return { statuses: ["CANCELLED"] };
117125
case "TRACE":
118-
return ["SPAN", "ANCESTOR_OVERRIDE", "SPAN_EVENT"];
126+
return { kinds: ["SPAN", "ANCESTOR_OVERRIDE", "SPAN_EVENT"] };
119127
}
120128
}
121129

@@ -395,10 +403,45 @@ export class LogsListPresenter {
395403
);
396404
}
397405

398-
// Level filter (map display levels to ClickHouse kinds)
406+
// Level filter (map display levels to ClickHouse kinds/statuses)
399407
if (levels && levels.length > 0) {
400-
const kinds = levels.flatMap(levelToKinds);
401-
queryBuilder.where("kind IN {kinds: Array(String)}", { kinds });
408+
const conditions: string[] = [];
409+
const params: Record<string, unknown> = {};
410+
const hasTraceLevel = levels.includes("TRACE");
411+
const hasErrorOrCancelledLevel = levels.includes("ERROR") || levels.includes("CANCELLED");
412+
413+
for (const level of levels) {
414+
const filter = levelToKindsAndStatuses(level);
415+
const levelConditions: string[] = [];
416+
417+
if (filter.kinds && filter.kinds.length > 0) {
418+
const kindsKey = `kinds_${level}`;
419+
let kindCondition = `kind IN {${kindsKey}: Array(String)}`;
420+
421+
// For TRACE: exclude error/cancelled traces if ERROR/CANCELLED not explicitly selected
422+
if (level === "TRACE" && !hasErrorOrCancelledLevel) {
423+
kindCondition += ` AND status NOT IN {excluded_statuses: Array(String)}`;
424+
params["excluded_statuses"] = ["ERROR", "CANCELLED"];
425+
}
426+
427+
levelConditions.push(kindCondition);
428+
params[kindsKey] = filter.kinds;
429+
}
430+
431+
if (filter.statuses && filter.statuses.length > 0) {
432+
const statusesKey = `statuses_${level}`;
433+
levelConditions.push(`status IN {${statusesKey}: Array(String)}`);
434+
params[statusesKey] = filter.statuses;
435+
}
436+
437+
if (levelConditions.length > 0) {
438+
conditions.push(`(${levelConditions.join(" OR ")})`);
439+
}
440+
}
441+
442+
if (conditions.length > 0) {
443+
queryBuilder.where(`(${conditions.join(" OR ")})`);
444+
}
402445
}
403446

404447
// Exclude DEBUG logs if not included
@@ -474,7 +517,7 @@ export class LogsListPresenter {
474517
kind: log.kind,
475518
status: log.status,
476519
duration: typeof log.duration === "number" ? log.duration : Number(log.duration),
477-
level: kindToLevel(log.kind),
520+
level: kindToLevel(log.kind, log.status),
478521
}));
479522

480523
return {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import { Switch } from "~/components/primitives/Switch";
4343
import { getUserById } from "~/models/user.server";
4444

4545
// Valid log levels for filtering
46-
const validLevels: LogLevel[] = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "LOG"];
46+
const validLevels: LogLevel[] = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "CANCELLED"];
4747

4848
function parseLevelsFromUrl(url: URL): LogLevel[] | undefined {
4949
const levelParams = url.searchParams.getAll("levels").filter((v) => v.length > 0);

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import { getRunFiltersFromRequest } from "~/presenters/RunFilters.server";
88
import { LogsListPresenter, type LogLevel } from "~/presenters/v3/LogsListPresenter.server";
99
import { $replica } from "~/db.server";
1010
import { clickhouseClient } from "~/services/clickhouseInstance.server";
11+
import { getUserById } from "~/models/user.server";
1112

1213
// Valid log levels for filtering
13-
const validLevels: LogLevel[] = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "LOG"];
14+
const validLevels: LogLevel[] = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "CANCELLED"];
1415

1516
function parseLevelsFromUrl(url: URL): LogLevel[] | undefined {
1617
const levelParams = url.searchParams.getAll("levels").filter((v) => v.length > 0);
@@ -32,13 +33,18 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
3233
throw new Response("Environment not found", { status: 404 });
3334
}
3435

36+
const user = await requireUserId(request);
37+
const userRecord = await getUserById(user);
38+
const isAdmin = userRecord?.admin || userRecord?.isImpersonating;
39+
3540
const filters = await getRunFiltersFromRequest(request);
3641

37-
// Get search term, cursor, and levels from query params
42+
// Get search term, cursor, levels, and showDebug from query params
3843
const url = new URL(request.url);
3944
const search = url.searchParams.get("search") ?? undefined;
4045
const cursor = url.searchParams.get("cursor") ?? undefined;
4146
const levels = parseLevelsFromUrl(url);
47+
const showDebug = url.searchParams.get("showDebug") === "true";
4248

4349
const presenter = new LogsListPresenter($replica, clickhouseClient);
4450
const result = await presenter.call(project.organizationId, environment.id, {
@@ -48,6 +54,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
4854
search,
4955
cursor,
5056
levels,
57+
includeDebugLogs: isAdmin && showDebug,
5158
});
5259

5360
return json({

references/seed/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.trigger

references/seed/package.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "references-seed",
3+
"private": true,
4+
"type": "module",
5+
"devDependencies": {
6+
"trigger.dev": "workspace:*"
7+
},
8+
"dependencies": {
9+
"@trigger.dev/build": "workspace:*",
10+
"@trigger.dev/sdk": "workspace:*",
11+
"arktype": "^2.0.0",
12+
"openai": "^4.97.0",
13+
"puppeteer-core": "^24.15.0",
14+
"replicate": "^1.0.1",
15+
"yup": "^1.6.1",
16+
"zod": "3.25.76",
17+
"@sinclair/typebox": "^0.34.3"
18+
},
19+
"scripts": {
20+
"dev": "trigger dev",
21+
"deploy": "trigger deploy"
22+
}
23+
}

0 commit comments

Comments
 (0)