From 42688468ddbb768cc672d9a81e002133b5e17343 Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg <118265418+CrabNejonas@users.noreply.github.com> Date: Mon, 18 Dec 2023 11:40:40 +0100 Subject: [PATCH 1/6] feat: add span details numbers --- .../src/components/span/span-detail-trace.tsx | 77 ++++++++++++------- web-client/src/lib/connection/monitor.ts | 4 +- web-client/src/lib/formatters.ts | 10 +++ web-client/src/lib/span/normalize-spans.ts | 27 ++++--- web-client/src/lib/span/update-spans.ts | 4 +- 5 files changed, 79 insertions(+), 43 deletions(-) diff --git a/web-client/src/components/span/span-detail-trace.tsx b/web-client/src/components/span/span-detail-trace.tsx index 6a313b69..d09c5f70 100644 --- a/web-client/src/components/span/span-detail-trace.tsx +++ b/web-client/src/components/span/span-detail-trace.tsx @@ -4,6 +4,8 @@ import { computeWaterfallStyle, computeSlices, } from "~/lib/span/normalize-spans"; +import { Popover } from "@kobalte/core"; +import {getDetailedTime} from "~/lib/formatters.ts"; export function SpanDetailTrace(props: { span: UiSpan; @@ -15,33 +17,54 @@ export function SpanDetailTrace(props: { }; }) { return ( - - {props.span.name} - -
-
-
- {/* Slices is "time slices" as in multiple entry points to a given span */} - - {(slice) => ( -
- )} - + + {props.span.name} + +
+
+
+ {/* Slices is "time slices" as in multiple entry points to a given span */} + + {(slice) => ( + + + + + + +

+ time: {((slice.exited - slice.entered) / 1e6).toFixed(3)}ms ({slice.busy.toFixed(3)}% of + total) +

+

+ on thread: {slice.threadID} +

+

+ entered: {getDetailedTime(new Date(slice.entered / 1e6))} +

+

+ exited: {getDetailedTime(new Date(slice.exited / 1e6))} +

+
+
+
+ )} +
+
-
- - + + {props.span.time.toFixed(2)}ms + ); } diff --git a/web-client/src/lib/connection/monitor.ts b/web-client/src/lib/connection/monitor.ts index 8ff15954..aae83402 100644 --- a/web-client/src/lib/connection/monitor.ts +++ b/web-client/src/lib/connection/monitor.ts @@ -15,8 +15,8 @@ export type Span = { metadataId: bigint; fields: Field[]; createdAt: number; - enters: number[]; - exits: number[]; + enters: { timestamp: number, threadID: number }[]; + exits: { timestamp: number, threadID: number }[]; closedAt: number; duration: number; }; diff --git a/web-client/src/lib/formatters.ts b/web-client/src/lib/formatters.ts index 9a32d53f..618934cf 100644 --- a/web-client/src/lib/formatters.ts +++ b/web-client/src/lib/formatters.ts @@ -36,3 +36,13 @@ export function getTime(date: Date) { second: "2-digit", }).format(date); } + +export function getDetailedTime(date: Date) { + return Intl.DateTimeFormat('en', { + hour: "2-digit", + minute: "2-digit", + hour12: false, + second: "2-digit", + fractionalSecondDigits: 3 + }).format(date); +} diff --git a/web-client/src/lib/span/normalize-spans.ts b/web-client/src/lib/span/normalize-spans.ts index 3ae7ff52..e3138ffe 100644 --- a/web-client/src/lib/span/normalize-spans.ts +++ b/web-client/src/lib/span/normalize-spans.ts @@ -54,20 +54,23 @@ export function computeWaterfallStyle( } export function computeSlices(span: Span) { - const allExits = span.exits.reduce((acc, e) => acc + e, 0); - const allEnters = span.enters.reduce((acc, e) => acc + e, 0); + const allExits = span.exits.reduce((acc, e) => acc + e.timestamp, 0); + const allEnters = span.enters.reduce((acc, e) => acc + e.timestamp, 0); - const slices = span.enters.map((enter, i) => { - const width = scaleToMax([span.exits[i] - enter], allExits - allEnters)[0]; - const offset = scaleNumbers([enter], span.createdAt, span.closedAt)[0]; + return span.enters.map((entered, i) => { + const exited = span.exits[i].timestamp; + + const width = scaleToMax([exited - entered.timestamp], allExits - allEnters)[0]; + const offset = scaleNumbers([entered.timestamp], span.createdAt, span.closedAt)[0]; const marginLeft = offset - (offset * width) / 100; + return { + entered: entered.timestamp, + exited, + busy: width, + threadID: entered.threadID, width, - marginLeft, - }; - }); - - return slices.map( - (slice) => `width:${slice.width}%;margin-left:${slice.marginLeft}%;` - ); + marginLeft + } + }) } diff --git a/web-client/src/lib/span/update-spans.ts b/web-client/src/lib/span/update-spans.ts index 97d5fbe5..74355771 100644 --- a/web-client/src/lib/span/update-spans.ts +++ b/web-client/src/lib/span/update-spans.ts @@ -31,7 +31,7 @@ export function updatedSpans(currentSpans: Span[], spanEvents: SpanEvent[]) { ? convertTimestampToNanoseconds(event.event.enterSpan.at) : -1; if (span) { - span.enters.push(enteredAt); + span.enters.push({ timestamp: enteredAt, threadID: Number(event.event.enterSpan.threadId) }); } break; @@ -43,7 +43,7 @@ export function updatedSpans(currentSpans: Span[], spanEvents: SpanEvent[]) { ? convertTimestampToNanoseconds(event.event.exitSpan.at) : -1; if (span) { - span.exits.push(exitedAt); + span.exits.push({ timestamp: exitedAt, threadID: Number(event.event.exitSpan.threadId) }); } break; } From 5bc273dce8c5752f2c06589a27c9115632fa024c Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg <118265418+CrabNejonas@users.noreply.github.com> Date: Mon, 18 Dec 2023 12:04:37 +0100 Subject: [PATCH 2/6] format --- .../src/components/span/span-detail-trace.tsx | 103 +++++++++--------- web-client/src/lib/connection/monitor.ts | 4 +- web-client/src/lib/formatters.ts | 4 +- web-client/src/lib/span/normalize-spans.ts | 18 ++- web-client/src/lib/span/update-spans.ts | 10 +- 5 files changed, 78 insertions(+), 61 deletions(-) diff --git a/web-client/src/components/span/span-detail-trace.tsx b/web-client/src/components/span/span-detail-trace.tsx index d09c5f70..5b546681 100644 --- a/web-client/src/components/span/span-detail-trace.tsx +++ b/web-client/src/components/span/span-detail-trace.tsx @@ -5,7 +5,7 @@ import { computeSlices, } from "~/lib/span/normalize-spans"; import { Popover } from "@kobalte/core"; -import {getDetailedTime} from "~/lib/formatters.ts"; +import { getDetailedTime } from "~/lib/formatters.ts"; export function SpanDetailTrace(props: { span: UiSpan; @@ -17,54 +17,59 @@ export function SpanDetailTrace(props: { }; }) { return ( - - {props.span.name} - -
-
-
- {/* Slices is "time slices" as in multiple entry points to a given span */} - - {(slice) => ( - - - - - - -

- time: {((slice.exited - slice.entered) / 1e6).toFixed(3)}ms ({slice.busy.toFixed(3)}% of - total) -

-

- on thread: {slice.threadID} -

-

- entered: {getDetailedTime(new Date(slice.entered / 1e6))} -

-

- exited: {getDetailedTime(new Date(slice.exited / 1e6))} -

-
-
-
- )} -
-
+ + {props.span.name} + +
+
+
+ {/* Slices is "time slices" as in multiple entry points to a given span */} + + {(slice) => ( + + + + + +

+ time:{" "} + {((slice.exited - slice.entered) / 1e6).toFixed(3)}ms +

+

on thread: {slice.threadID}

+

+ entered:{" "} + {getDetailedTime(new Date(slice.entered / 1e6))} +

+

+ exited: {getDetailedTime(new Date(slice.exited / 1e6))} +

+
+
+
+ )} +
- - {props.span.time.toFixed(2)}ms - +
+ + {props.span.time.toFixed(2)}ms + ); } diff --git a/web-client/src/lib/connection/monitor.ts b/web-client/src/lib/connection/monitor.ts index aae83402..dde12723 100644 --- a/web-client/src/lib/connection/monitor.ts +++ b/web-client/src/lib/connection/monitor.ts @@ -15,8 +15,8 @@ export type Span = { metadataId: bigint; fields: Field[]; createdAt: number; - enters: { timestamp: number, threadID: number }[]; - exits: { timestamp: number, threadID: number }[]; + enters: { timestamp: number; threadID: number }[]; + exits: { timestamp: number; threadID: number }[]; closedAt: number; duration: number; }; diff --git a/web-client/src/lib/formatters.ts b/web-client/src/lib/formatters.ts index 618934cf..bd3dac5f 100644 --- a/web-client/src/lib/formatters.ts +++ b/web-client/src/lib/formatters.ts @@ -38,11 +38,11 @@ export function getTime(date: Date) { } export function getDetailedTime(date: Date) { - return Intl.DateTimeFormat('en', { + return Intl.DateTimeFormat("en", { hour: "2-digit", minute: "2-digit", hour12: false, second: "2-digit", - fractionalSecondDigits: 3 + fractionalSecondDigits: 3, }).format(date); } diff --git a/web-client/src/lib/span/normalize-spans.ts b/web-client/src/lib/span/normalize-spans.ts index e3138ffe..52c6c413 100644 --- a/web-client/src/lib/span/normalize-spans.ts +++ b/web-client/src/lib/span/normalize-spans.ts @@ -60,17 +60,23 @@ export function computeSlices(span: Span) { return span.enters.map((entered, i) => { const exited = span.exits[i].timestamp; - const width = scaleToMax([exited - entered.timestamp], allExits - allEnters)[0]; - const offset = scaleNumbers([entered.timestamp], span.createdAt, span.closedAt)[0]; + const width = scaleToMax( + [exited - entered.timestamp], + allExits - allEnters + )[0]; + const offset = scaleNumbers( + [entered.timestamp], + span.createdAt, + span.closedAt + )[0]; const marginLeft = offset - (offset * width) / 100; return { entered: entered.timestamp, exited, - busy: width, threadID: entered.threadID, width, - marginLeft - } - }) + marginLeft, + }; + }); } diff --git a/web-client/src/lib/span/update-spans.ts b/web-client/src/lib/span/update-spans.ts index 74355771..368e66c2 100644 --- a/web-client/src/lib/span/update-spans.ts +++ b/web-client/src/lib/span/update-spans.ts @@ -31,7 +31,10 @@ export function updatedSpans(currentSpans: Span[], spanEvents: SpanEvent[]) { ? convertTimestampToNanoseconds(event.event.enterSpan.at) : -1; if (span) { - span.enters.push({ timestamp: enteredAt, threadID: Number(event.event.enterSpan.threadId) }); + span.enters.push({ + timestamp: enteredAt, + threadID: Number(event.event.enterSpan.threadId), + }); } break; @@ -43,7 +46,10 @@ export function updatedSpans(currentSpans: Span[], spanEvents: SpanEvent[]) { ? convertTimestampToNanoseconds(event.event.exitSpan.at) : -1; if (span) { - span.exits.push({ timestamp: exitedAt, threadID: Number(event.event.exitSpan.threadId) }); + span.exits.push({ + timestamp: exitedAt, + threadID: Number(event.event.exitSpan.threadId), + }); } break; } From cb1ddf12969919ae22dc4303018b395e6fcb01b5 Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg <118265418+CrabNejonas@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:01:38 +0100 Subject: [PATCH 3/6] Update span-detail-trace.tsx --- .../src/components/span/span-detail-trace.tsx | 52 ++++++++++++------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/web-client/src/components/span/span-detail-trace.tsx b/web-client/src/components/span/span-detail-trace.tsx index 5b546681..afdcf16a 100644 --- a/web-client/src/components/span/span-detail-trace.tsx +++ b/web-client/src/components/span/span-detail-trace.tsx @@ -16,8 +16,15 @@ export function SpanDetailTrace(props: { longest: number; }; }) { + const busy = () => props.span.original.enters.reduce((acc, enter, i) => { + const exit = props.span.original.exits[i]; + + return acc + (exit.timestamp - enter.timestamp) + }, 0) + return ( - + + {props.span.name}
@@ -37,7 +44,7 @@ export function SpanDetailTrace(props: { {(slice) => ( - -

- time:{" "} - {((slice.exited - slice.entered) / 1e6).toFixed(3)}ms -

-

on thread: {slice.threadID}

-

- entered:{" "} - {getDetailedTime(new Date(slice.entered / 1e6))} -

-

- exited: {getDetailedTime(new Date(slice.exited / 1e6))} -

+ + Time + {((slice.exited - slice.entered) / 1e6).toFixed(3)}ms + Thread + {slice.threadID} + Start + {getDetailedTime(new Date(slice.entered / 1e6))} + End + {getDetailedTime(new Date(slice.exited / 1e6))}
@@ -70,6 +73,19 @@ export function SpanDetailTrace(props: {
{props.span.time.toFixed(2)}ms - +
+ + + + {props.span.name} + Busy + {(busy() / 1e6).toFixed(3)}ms + Idle + {(props.span.time - busy() / 1e6).toFixed(3)}ms + + +
); } From 814ed55a10e278d315b55aa7087f16e2bfc39723 Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg <118265418+CrabNejonas@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:03:38 +0100 Subject: [PATCH 4/6] format --- .../src/components/span/span-detail-trace.tsx | 146 ++++++++++-------- 1 file changed, 80 insertions(+), 66 deletions(-) diff --git a/web-client/src/components/span/span-detail-trace.tsx b/web-client/src/components/span/span-detail-trace.tsx index afdcf16a..923c0184 100644 --- a/web-client/src/components/span/span-detail-trace.tsx +++ b/web-client/src/components/span/span-detail-trace.tsx @@ -16,76 +16,90 @@ export function SpanDetailTrace(props: { longest: number; }; }) { - const busy = () => props.span.original.enters.reduce((acc, enter, i) => { - const exit = props.span.original.exits[i]; + const busy = () => + props.span.original.enters.reduce((acc, enter, i) => { + const exit = props.span.original.exits[i]; - return acc + (exit.timestamp - enter.timestamp) - }, 0) + return acc + (exit.timestamp - enter.timestamp); + }, 0); return ( - - - {props.span.name} - -
-
-
- {/* Slices is "time slices" as in multiple entry points to a given span */} - - {(slice) => ( - - - - - - Time - {((slice.exited - slice.entered) / 1e6).toFixed(3)}ms - Thread - {slice.threadID} - Start - {getDetailedTime(new Date(slice.entered / 1e6))} - End - {getDetailedTime(new Date(slice.exited / 1e6))} - - - + + + {props.span.name} + +
+
+
+ > + {/* Slices is "time slices" as in multiple entry points to a given span */} + + {(slice) => ( + + + + + + Time + + {((slice.exited - slice.entered) / 1e6).toFixed(3)}ms + + Thread + {slice.threadID} + Start + + {getDetailedTime(new Date(slice.entered / 1e6))} + + End + + {getDetailedTime(new Date(slice.exited / 1e6))} + + + + + )} + +
-
- - {props.span.time.toFixed(2)}ms -
- - - - {props.span.name} - Busy - {(busy() / 1e6).toFixed(3)}ms - Idle - {(props.span.time - busy() / 1e6).toFixed(3)}ms - - -
+ + {props.span.time.toFixed(2)}ms + + + + + {props.span.name} + + Busy + {(busy() / 1e6).toFixed(3)}ms + Idle + {(props.span.time - busy() / 1e6).toFixed(3)}ms + + + ); } From 3e53722c6cb47643e31aa48a8b5e9df9cd2b4b58 Mon Sep 17 00:00:00 2001 From: Johann Derdak Date: Tue, 19 Dec 2023 16:56:00 +0100 Subject: [PATCH 5/6] fix: lint warnings and improve readability --- .../src/components/span/span-detail-trace.tsx | 115 ++++++++++-------- 1 file changed, 66 insertions(+), 49 deletions(-) diff --git a/web-client/src/components/span/span-detail-trace.tsx b/web-client/src/components/span/span-detail-trace.tsx index 923c0184..c7ab83da 100644 --- a/web-client/src/components/span/span-detail-trace.tsx +++ b/web-client/src/components/span/span-detail-trace.tsx @@ -1,5 +1,6 @@ import { For } from "solid-js"; import { UiSpan } from "~/lib/span/format-spans-for-ui"; +import { Span } from "~/lib/connection/monitor"; import { computeWaterfallStyle, computeSlices, @@ -16,13 +17,6 @@ export function SpanDetailTrace(props: { longest: number; }; }) { - const busy = () => - props.span.original.enters.reduce((acc, enter, i) => { - const exit = props.span.original.exits[i]; - - return acc + (exit.timestamp - enter.timestamp); - }, 0); - return ( {/* Slices is "time slices" as in multiple entry points to a given span */} - {(slice) => ( - - - - - - Time - - {((slice.exited - slice.entered) / 1e6).toFixed(3)}ms - - Thread - {slice.threadID} - Start - - {getDetailedTime(new Date(slice.entered / 1e6))} - - End - - {getDetailedTime(new Date(slice.exited / 1e6))} - - - - - )} + {(slice) => }
{props.span.time.toFixed(2)}ms + + + + + ); +} + +function SpanDetailPopOverContent(props: { span: UiSpan }) { + const busy = (span: Span) => + span.enters.reduce((acc, enter, i) => { + const exit = span.exits[i]; + + return acc + (exit.timestamp - enter.timestamp); + }, 0); + + return ( + + + {props.span.name} + + Busy + {(busy(props.span.original) / 1e6).toFixed(3)}ms + Idle + + {(props.span.time - busy(props.span.original) / 1e6).toFixed(3)}ms + + + ); +} + +function SpanDetailSlice(props: { + slice: { + entered: number; + exited: number; + threadID: number; + width: number; + marginLeft: number; + }; +}) { + return ( + + - {props.span.name} - - Busy - {(busy() / 1e6).toFixed(3)}ms - Idle - {(props.span.time - busy() / 1e6).toFixed(3)}ms + Time + + {((props.slice.exited - props.slice.entered) / 1e6).toFixed(3)}ms + + Thread + {props.slice.threadID} + Start + {getDetailedTime(new Date(props.slice.entered / 1e6))} + End + {getDetailedTime(new Date(props.slice.exited / 1e6))} From 62a90ec62bb9c4eff8d59e4a5d514f52e9a09ee0 Mon Sep 17 00:00:00 2001 From: Johann Derdak Date: Tue, 19 Dec 2023 20:46:31 +0100 Subject: [PATCH 6/6] fix: use table to represent tabular span data --- .../src/components/span/span-detail-trace.tsx | 68 ++++++++++++------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/web-client/src/components/span/span-detail-trace.tsx b/web-client/src/components/span/span-detail-trace.tsx index c7ab83da..e83b4fa6 100644 --- a/web-client/src/components/span/span-detail-trace.tsx +++ b/web-client/src/components/span/span-detail-trace.tsx @@ -1,4 +1,4 @@ -import { For } from "solid-js"; +import { For, JSXElement, Show } from "solid-js"; import { UiSpan } from "~/lib/span/format-spans-for-ui"; import { Span } from "~/lib/connection/monitor"; import { @@ -63,18 +63,18 @@ function SpanDetailPopOverContent(props: { span: UiSpan }) { return ( - - {props.span.name} - - Busy - {(busy(props.span.original) / 1e6).toFixed(3)}ms - Idle - - {(props.span.time - busy(props.span.original) / 1e6).toFixed(3)}ms - + + + + {(busy(props.span.original) / 1e6).toFixed(3)}ms + + + {(props.span.time - busy(props.span.original) / 1e6).toFixed(3)}ms + + ); } @@ -99,24 +99,46 @@ function SpanDetailSlice(props: { /> - - Time - - {((props.slice.exited - props.slice.entered) / 1e6).toFixed(3)}ms - - Thread - {props.slice.threadID} - Start - {getDetailedTime(new Date(props.slice.entered / 1e6))} - End - {getDetailedTime(new Date(props.slice.exited / 1e6))} + + + {((props.slice.exited - props.slice.entered) / 1e6).toFixed(3)} + ms + + {props.slice.threadID} + + {getDetailedTime(new Date(props.slice.entered / 1e6))} + + + {getDetailedTime(new Date(props.slice.exited / 1e6))} + + ); } + +function ToolTipContent(props: { children: JSXElement }) { + return ( + <> + + {props.children}
+ + ); +} + +function ToolTipRow(props: { title: string; children?: JSXElement }) { + return ( + + {props.title} + + {props.children} + + + ); +}