Skip to content

Commit 0341739

Browse files
authored
feat: add telemetry page displaying telemetry logs grouped by tool calls (#1112)
This adds a telemetry page for viewing logs grouped by tool call. This is the initial MVP - there are a lot of design improvements we can make in the future, but I'd rather ship this and iterate over time. ## Screenshots <img width="1276" height="1269" alt="image" src="https://github.com/user-attachments/assets/a0857643-ef81-4315-8235-ec6b886ba352" /> <img width="1244" height="586" alt="image" src="https://github.com/user-attachments/assets/f3bf5609-3328-4a19-b9fa-ee037083cd7b" /> <img width="1230" height="347" alt="image" src="https://github.com/user-attachments/assets/23fbf1fe-548b-4cf6-9a1c-267d041d4fba" />
1 parent bc34fdb commit 0341739

File tree

9 files changed

+1128
-0
lines changed

9 files changed

+1128
-0
lines changed

.changeset/thirty-zebras-fly.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"dashboard": minor
3+
---
4+
5+
Add a new telemetry page to view logs grouped by tool calls

client/dashboard/src/components/app-sidebar.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
8787
active={routes.logs.active}
8888
/>
8989
</SidebarMenuItem>
90+
<SidebarMenuItem>
91+
<NavButton
92+
title="Telemetry"
93+
Icon={routes.telemetry.Icon}
94+
href={routes.telemetry.href()}
95+
active={routes.telemetry.active}
96+
/>
97+
</SidebarMenuItem>
9098
<SidebarMenuItem>
9199
<NavButton
92100
title="Metrics"
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import { parseGramUrn } from "./utils";
2+
3+
interface StatusBadgeProps {
4+
isSuccess: boolean;
5+
httpStatusCode?: number;
6+
severity?: string;
7+
}
8+
9+
export function StatusBadge({
10+
isSuccess,
11+
httpStatusCode,
12+
severity,
13+
}: StatusBadgeProps) {
14+
// For log entries with severity
15+
if (severity) {
16+
return <SeverityBadge severity={severity} />;
17+
}
18+
19+
// For trace entries with HTTP status
20+
if (httpStatusCode) {
21+
const is4xx = httpStatusCode >= 400 && httpStatusCode < 500;
22+
const is5xx = httpStatusCode >= 500;
23+
24+
if (is5xx) {
25+
return (
26+
<span className="px-1.5 py-0.5 text-[10px] font-medium rounded bg-destructive-softest text-destructive-default">
27+
{httpStatusCode}
28+
</span>
29+
);
30+
}
31+
if (is4xx) {
32+
return (
33+
<span className="px-1.5 py-0.5 text-[10px] font-medium rounded bg-warning-softest text-warning-default">
34+
{httpStatusCode}
35+
</span>
36+
);
37+
}
38+
return (
39+
<span className="px-1.5 py-0.5 text-[10px] font-medium rounded bg-success-softest text-success-default">
40+
{httpStatusCode}
41+
</span>
42+
);
43+
}
44+
45+
// Default OK/ERROR badge
46+
if (isSuccess) {
47+
return (
48+
<span className="px-1.5 py-0.5 text-[10px] font-medium rounded bg-success-softest text-success-default">
49+
OK
50+
</span>
51+
);
52+
}
53+
54+
return (
55+
<span className="px-1.5 py-0.5 text-[10px] font-medium rounded bg-destructive-softest text-destructive-default">
56+
ERROR
57+
</span>
58+
);
59+
}
60+
61+
function SeverityBadge({ severity }: { severity: string }) {
62+
const upper = severity.toUpperCase();
63+
64+
switch (upper) {
65+
case "ERROR":
66+
case "FATAL":
67+
return (
68+
<span className="px-1.5 py-0.5 text-[10px] font-medium rounded bg-destructive-softest text-destructive-default">
69+
{upper}
70+
</span>
71+
);
72+
case "WARN":
73+
case "WARNING":
74+
return (
75+
<span className="px-1.5 py-0.5 text-[10px] font-medium rounded bg-warning-softest text-warning-default">
76+
WARN
77+
</span>
78+
);
79+
case "DEBUG":
80+
return (
81+
<span className="px-1.5 py-0.5 text-[10px] font-medium rounded bg-surface-secondary-default text-muted-foreground">
82+
DEBUG
83+
</span>
84+
);
85+
case "INFO":
86+
default:
87+
return (
88+
<span className="px-1.5 py-0.5 text-[10px] font-medium rounded bg-primary-softest text-primary-default">
89+
INFO
90+
</span>
91+
);
92+
}
93+
}
94+
95+
interface SpanTypeBadgeProps {
96+
urn: string;
97+
}
98+
99+
export function SpanTypeBadge({ urn }: SpanTypeBadgeProps) {
100+
const { kind } = parseGramUrn(urn);
101+
102+
switch (kind) {
103+
case "http":
104+
return (
105+
<span className="px-1.5 py-0.5 text-[10px] font-medium rounded bg-cyan-500/20 text-cyan-400 uppercase">
106+
HTTP
107+
</span>
108+
);
109+
case "function":
110+
return (
111+
<span className="px-1.5 py-0.5 text-[10px] font-medium rounded bg-purple-500/20 text-purple-400 uppercase">
112+
FN
113+
</span>
114+
);
115+
case "prompt":
116+
return (
117+
<span className="px-1.5 py-0.5 text-[10px] font-medium rounded bg-amber-500/20 text-amber-400 uppercase">
118+
PROMPT
119+
</span>
120+
);
121+
default:
122+
return (
123+
<span className="px-1.5 py-0.5 text-[10px] font-medium rounded bg-surface-secondary-default text-muted-foreground uppercase">
124+
{kind || "SPAN"}
125+
</span>
126+
);
127+
}
128+
}

0 commit comments

Comments
 (0)