Skip to content

Commit

Permalink
Address @johann-crabnebula's review
Browse files Browse the repository at this point in the history
  • Loading branch information
TejasQ committed Nov 21, 2023
1 parent 6b47d1a commit 61d1f62
Show file tree
Hide file tree
Showing 10 changed files with 241 additions and 191 deletions.
32 changes: 32 additions & 0 deletions web-client/src/components/span/span-detail-args.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { For, Show } from "solid-js";

type Props = {
args: string[];
};

export function SpanDetailArgs(props: Props) {
return (
<For each={props.args}>
{(arg) => {
return (
<For each={Object.entries(JSON.parse(arg))}>
{([k, v]) => (
<Show
when={
!["cmd", "callback", "error", "__tauriModule"].includes(k)
}
>
<tr class="even:bg-nearly-invisible">
<td class="py-1 px-4 font-bold">{k}</td>
<td class="py-1 px-4">
{typeof v === "object" ? JSON.stringify(v) : String(v)}
</td>
</tr>
</Show>
)}
</For>
);
}}
</For>
);
}
26 changes: 26 additions & 0 deletions web-client/src/components/span/span-detail-trace.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { For } from "solid-js";
import { UiSpan } from "~/lib/span/format-spans-for-ui";

export function SpanDetailTrace(props: { span: UiSpan }) {
return (
<tr class="even:bg-nearly-invisible cursor-pointer hover:bg-[#ffffff05] even:hover:bg-[#ffffff10]">
<td class="py-1 px-4">{props.span.name}</td>
<td class="py-1 px-4 relative w-[60%]">
<div class="relative w-[90%]">
<div class="bg-gray-800 w-full absolute rounded-sm h-2" />
<div class="relative h-2" style={props.span.waterfall}>
{/* Slices is "time slices" as in multiple entry points to a given span */}
<For each={props.span.slices}>
{(slice) => (
<div
class="absolute bg-teal-500 top-0 left-0 h-full"
style={slice}
/>
)}
</For>
</div>
</div>
</td>
</tr>
);
}
67 changes: 10 additions & 57 deletions web-client/src/components/span/span-detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { createHighlighter, getHighlightedCode } from "~/lib/code-highlight";
import { useSearchParams } from "@solidjs/router";
import { processFieldValue } from "~/lib/span/process-field-value";
import { getChildrenList } from "~/lib/span/get-children-list";
import { SpanDetailTrace } from "./span-detail-trace";
import { SpanDetailArgs } from "./span-detail-args";

const ipcSpans = [
"ipc::request",
Expand All @@ -32,12 +34,13 @@ export function SpanDetail() {
),
};
}
return null;
throw new Error("No Span");
};

const formattedSpan = () =>
formatSpansForUi({
allSpans: monitorData.spans,
spans: [span()!],
spans: [span()],
metadata: monitorData.metadata,
})[0];
// filter child only used for metadata (response in this case)
Expand All @@ -47,16 +50,16 @@ export function SpanDetail() {
const responseCode = () => {
const field = getIpcRequestValues({
metadata: monitorData.metadata,
rootSpan: span()!,
rootSpan: span(),
})("ipc::request::response")?.fields[0]?.response;
return field ? processFieldValue(field) : null;
};

const args = () =>
getIpcRequestValues({
metadata: monitorData.metadata,
rootSpan: span()!,
})("ipc::request")!.fields.map((f) => processFieldValue(f.request));
rootSpan: span(),
})("ipc::request")?.fields.map((f) => processFieldValue(f.request)) ?? [];

const [responseHtml] = createResource(
() => [responseCode(), createHighlighter()] as const,
Expand All @@ -81,65 +84,15 @@ export function SpanDetail() {
<table>
<tbody>
<For each={children()}>
{(span) => {
return (
<tr class="even:bg-[#ffffff09] cursor-pointer hover:bg-[#ffffff05] even:hover:bg-[#ffffff10]">
<td class="py-1 px-4">{span.name}</td>
<td class="py-1 px-4 relative w-[60%]">
<div class="relative w-[90%]">
<div class="bg-gray-800 w-full absolute rounded-sm h-2" />
<div class="relative h-2" style={span.waterfall}>
{/* Slices is "time slices" as in multiple entry points to a given span */}
<For each={span.slices}>
{(slice) => (
<div
class="absolute bg-teal-500 top-0 left-0 h-full"
style={slice}
/>
)}
</For>
</div>
</div>
</td>
</tr>
);
}}
{(span) => <SpanDetailTrace span={span} />}
</For>
</tbody>
</table>
<div class="grid gap-2">
<h2 class="text-xl p-4">Inputs</h2>
<table>
<tbody>
<For each={args()}>
{(arg) => {
return (
<For each={Object.entries(JSON.parse(arg))}>
{([k, v]) => (
<Show
when={
![
"cmd",
"callback",
"error",
"__tauriModule",
].includes(k)
}
>
<tr class="even:bg-[#ffffff09]">
<td class="py-1 px-4 font-bold">{k}</td>
<td class="py-1 px-4">
{typeof v === "object"
? JSON.stringify(v)
: String(v)}
</td>
</tr>
</Show>
)}
</For>
);
}}
</For>
<SpanDetailArgs args={args()} />
</tbody>
</table>
</div>
Expand Down
108 changes: 108 additions & 0 deletions web-client/src/components/span/span-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { useSearchParams } from "@solidjs/router";
import { For } from "solid-js";
import type { UiSpan, formatSpansForUi } from "~/lib/span/format-spans-for-ui";
import { getColumnDirection } from "~/lib/span/get-column-direction";
import { resolveColumnAlias } from "~/lib/span/resolve-column-alias";
import { SortCaret } from "./sort-caret";
import { getTime } from "~/lib/formatters";
import clsx from "clsx";

export type SortDirection = "asc" | "desc";
export type SortableColumn = keyof ReturnType<typeof formatSpansForUi>[-1];
export type ColumnSort = {
name: SortableColumn;
direction: SortDirection;
};

type Props = {
spans: UiSpan[];
columnSort: ColumnSort;
setColumnSort: (columnSort: ColumnSort) => void;
};

export function SpanList(props: Props) {
const columns = () =>
[...Object.keys(props.spans?.[0] ?? {})].filter((k) =>
["name", "initiated", "time", "waterfall"].includes(k)
);
const [, setSearchParams] = useSearchParams();

const sortColumn = (name: SortableColumn) => {
props.setColumnSort({
name,
direction: getColumnDirection(props.columnSort, name),
});
};

return (
<table class="w-full table-fixed">
<thead>
<tr class="text-left">
<For each={columns()}>
{(column) => {
const resolvedColumn = resolveColumnAlias(
column as SortableColumn
);
return (
<th
tabIndex={0}
onKeyDown={(e) => {
if ([" ", "Enter"].includes(e.key)) {
sortColumn(resolvedColumn);
}
}}
onClick={() => sortColumn(resolvedColumn)}
class="p-1 cursor-pointer hover:bg-[#ffffff09]"
>
<div class="flex uppercase select-none items-center gap-2">
{column}
{props.columnSort.name === resolvedColumn && (
<SortCaret direction={props.columnSort.direction} />
)}
</div>
</th>
);
}}
</For>
</tr>
</thead>
<tbody>
<For each={props.spans}>
{(span) => {
return (
<tr
onClick={() => setSearchParams({ span: span.id })}
class="even:bg-nearly-invisible cursor-pointer hover:bg-[#ffffff05] even:hover:bg-[#ffffff10]"
>
<td class="p-1">{span.name}</td>
<td class="p-1">{getTime(new Date(span.initiated))}</td>
<td class="p-1">{span.time.toFixed(2)}ms</td>
<td class="p-1 relative">
<div class="relative w-[90%]">
<div class="bg-gray-800 w-full absolute rounded-sm h-2" />
<div
class={clsx(
"relative rounded-sm h-2",
span.colorClassName
)}
style={span.waterfall}
>
<For each={span.slices}>
{(slice) => (
<div
class="absolute top-0 left-0 bg-black bg-opacity-10 h-full"
style={slice}
/>
)}
</For>
</div>
</div>
</td>
</tr>
);
}}
</For>
</tbody>
</table>
);
}
37 changes: 37 additions & 0 deletions web-client/src/components/span/span-scale-slider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Tooltip } from "@kobalte/core";
import { Show } from "solid-js";

type Props = {
granularity: number;
setGranularity: (granularity: number) => void;
totalDuration: number;
};

export function SpanScaleSlider(props: Props) {
return (
<div class="flex items-center gap-2">
<Tooltip.Root>
<Tooltip.Trigger>
<span class="flex items-center gap-1">
Scale Spans
<Show when={props.granularity > 1}>
<span></span>
</Show>
</span>
</Tooltip.Trigger>
<Tooltip.Content>
<div class="rounded p-2 bg-black shadow">
Concurrency may appear skewed when spans are scaled.
</div>
</Tooltip.Content>
</Tooltip.Root>
<input
type="range"
min={1}
max={props.totalDuration}
value={props.granularity}
onInput={(e) => props.setGranularity(Number(e.currentTarget.value))}
/>
</div>
);
}
2 changes: 1 addition & 1 deletion web-client/src/lib/span/find-spans-by-name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function findSpansByName(
}

return (
span.children.filter((c) => metadata.get(c.metadataId)!.name === name) ??
span.children.filter((c) => metadata.get(c.metadataId)?.name === name) ??
null
);
}
2 changes: 1 addition & 1 deletion web-client/src/lib/span/format-spans-for-ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type Options = {
granularity?: number;
};

type UiSpan = {
export type UiSpan = {
id: string;
isProcessing: boolean;
name: string;
Expand Down
20 changes: 10 additions & 10 deletions web-client/src/lib/span/update-spans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export function updatedSpans(currentSpans: Span[], spanEvents: SpanEvent[]) {
parentId: event.event.newSpan.parent,
metadataId: event.event.newSpan.metadataId,
fields: event.event.newSpan.fields,
createdAt: convertTimestampToNanoseconds(event.event.newSpan.at!),
createdAt: event.event.newSpan.at ? convertTimestampToNanoseconds(event.event.newSpan.at) : -1,
enters: [],
exits: [],
closedAt: -1,
Expand All @@ -25,9 +25,9 @@ export function updatedSpans(currentSpans: Span[], spanEvents: SpanEvent[]) {
case "enterSpan": {
const spanId = event.event.enterSpan.spanId;
const span = currentSpans.find((s) => s.id === spanId);
const enteredAt = convertTimestampToNanoseconds(
event.event.enterSpan.at!
);
const enteredAt = event.event.enterSpan.at ? convertTimestampToNanoseconds(
event.event.enterSpan.at
) : -1;
if (span) {
span.enters.push(enteredAt);
}
Expand All @@ -37,9 +37,9 @@ export function updatedSpans(currentSpans: Span[], spanEvents: SpanEvent[]) {
case "exitSpan": {
const spanId = event.event.exitSpan.spanId;
const span = currentSpans.find((s) => s.id === spanId);
const exitedAt = convertTimestampToNanoseconds(
event.event.exitSpan.at!
);
const exitedAt = event.event.exitSpan.at ? convertTimestampToNanoseconds(
event.event.exitSpan.at
) : -1;
if (span) {
span.exits.push(exitedAt);
}
Expand All @@ -50,9 +50,9 @@ export function updatedSpans(currentSpans: Span[], spanEvents: SpanEvent[]) {
const spanId = event.event.closeSpan.spanId;
const span = currentSpans.find((s) => s.id === spanId);
if (span) {
span.closedAt = convertTimestampToNanoseconds(
event.event.closeSpan.at!
);
span.closedAt = event.event.closeSpan.at ? convertTimestampToNanoseconds(
event.event.closeSpan.at
) : -1;
span.duration = span.closedAt - span.createdAt;
}
break;
Expand Down
Loading

0 comments on commit 61d1f62

Please sign in to comment.