Skip to content

Commit 09cf311

Browse files
committed
ref: Unify and simplify duration calculations and representations
1 parent 9c498dd commit 09cf311

File tree

6 files changed

+40
-77
lines changed

6 files changed

+40
-77
lines changed

.changeset/wild-lobsters-doubt.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@spotlightjs/spotlight': patch
3+
'@spotlightjs/electron': patch
4+
'@spotlightjs/overlay': patch
5+
'@spotlightjs/astro': patch
6+
---
7+
8+
Unify and simplify duration calculations and representations

packages/overlay/src/integrations/sentry/components/explore/traces/TraceDetails/components/TraceTreeview.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { useState } from 'react';
22
import { useParams } from 'react-router-dom';
33
import sentryDataCache from '../../../../../data/sentryDataCache';
4-
import { getDuration } from '../../../../../utils/duration';
54
import DateTime from '../../../../DateTime';
65
import SpanDetails from '../../spans/SpanDetails';
76
import SpanTree from '../../spans/SpanTree';
7+
import { getFormattedSpanDuration } from '../../../../../utils/duration';
88

99
type TraceTreeViewProps = { traceId: string };
1010

@@ -29,10 +29,7 @@ export default function TraceTreeview({ traceId }: TraceTreeViewProps) {
2929
</div>
3030
<span>&mdash;</span>
3131
<span>
32-
<strong className="text-primary-200 font-bold">
33-
{getDuration(trace.start_timestamp, trace.timestamp).toLocaleString()} ms
34-
</strong>{' '}
35-
recorded in{' '}
32+
<strong className="text-primary-200 font-bold">{getFormattedSpanDuration(trace)}</strong> recorded in{' '}
3633
<strong className="text-primary-200 font-bold">{trace.spans.length.toLocaleString()} spans</strong>
3734
</span>
3835
</div>

packages/overlay/src/integrations/sentry/components/explore/traces/TraceList.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import classNames from '../../../../../lib/classNames';
77
import { useSpotlightContext } from '../../../../../lib/useSpotlightContext';
88
import { useSentryHelpers } from '../../../data/useSentryHelpers';
99
import { useSentryTraces } from '../../../data/useSentryTraces';
10-
import { getDuration } from '../../../utils/duration';
10+
import { getFormattedSpanDuration } from '../../../utils/duration';
1111
import { truncateId } from '../../../utils/text';
1212
import HiddenItemsButton from '../../HiddenItemsButton';
1313
import { TraceRootTxnName } from './TraceDetails/components/TraceRootTxnName';
@@ -35,7 +35,6 @@ export default function TraceList() {
3535
/>
3636
)}
3737
{filteredTraces.map(trace => {
38-
const duration = getDuration(trace.start_timestamp, trace.timestamp);
3938
return (
4039
<Link
4140
className="hover:bg-primary-900 flex cursor-pointer items-center gap-x-4 px-6 py-2"
@@ -63,7 +62,7 @@ export default function TraceList() {
6362
{trace.status || ''}
6463
</div>
6564
<div>&mdash;</div>
66-
<div>{duration} ms</div>
65+
<div>{getFormattedSpanDuration(trace)}</div>
6766
<div>&mdash;</div>
6867
<div>
6968
{trace.spans.length.toLocaleString()} spans, {trace.transactions.length.toLocaleString()} txns

packages/overlay/src/integrations/sentry/components/explore/traces/spans/SpanDetails.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { DB_SPAN_REGEX } from '../../../../constants';
77
import dataCache from '../../../../data/sentryDataCache';
88
import type { SentryErrorEvent, Span, TraceContext } from '../../../../types';
99
import { formatBytes } from '../../../../utils/bytes';
10-
import { getDuration } from '../../../../utils/duration';
10+
import { getFormattedDuration } from '../../../../utils/duration';
1111
import DateTime from '../../../DateTime';
1212
import { ErrorTitle } from '../../../events/error/Error';
1313
import SpanTree from './SpanTree';
@@ -87,7 +87,7 @@ export default function SpanDetails({
8787
}) {
8888
const [spanNodeWidth, setSpanNodeWidth] = useState<number>(50);
8989

90-
const spanDuration = getDuration(span.start_timestamp, span.timestamp);
90+
const spanDuration = span.timestamp - span.start_timestamp;
9191

9292
const errors = dataCache.getEventsByTrace(span.trace_id).filter(e => e.type !== 'transaction' && 'exception' in e);
9393

@@ -115,19 +115,19 @@ export default function SpanDetails({
115115
<DateTime date={span.start_timestamp} />
116116
<span>&mdash;</span>
117117
<span>
118-
<strong>{getDuration(startTimestamp, span.start_timestamp)} ms</strong> into trace
118+
<strong>{getFormattedDuration(spanDuration)}</strong> into trace
119119
</span>
120120
</div>
121121
<div className="flex-1">
122122
<div className="border-primary-800 relative h-8 border py-1">
123123
<div
124124
className="bg-primary-800 absolute bottom-0 top-0 -m-0.5 flex w-full items-center p-0.5"
125125
style={{
126-
left: `min(${((span.start_timestamp - startTimestamp) / totalDuration) * 100}%, 100% - 1px)`,
126+
left: `min(${(spanDuration / totalDuration) * 100}%, 100% - 1px)`,
127127
width: `max(1px, ${(spanDuration / totalDuration) * 100}%)`,
128128
}}
129129
>
130-
<span className="whitespace-nowrap">{spanDuration} ms</span>
130+
<span className="whitespace-nowrap">{getFormattedDuration(spanDuration)}</span>
131131
</div>
132132
</div>
133133
</div>

packages/overlay/src/integrations/sentry/components/explore/traces/spans/SpanItem.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Link, useParams } from 'react-router-dom';
33
import { ReactComponent as ChevronIcon } from '~/assets/chevronDown.svg';
44
import classNames from '../../../../../../lib/classNames';
55
import type { Span, TraceContext } from '../../../../types';
6-
import { getDuration, getSpanDurationClassName } from '../../../../utils/duration';
6+
import { getSpanDurationClassName, getFormattedDuration } from '../../../../utils/duration';
77
import PlatformIcon from '../../../PlatformIcon';
88
import SpanResizer from '../../../SpanResizer';
99
import SpanTree from './SpanTree';
@@ -37,7 +37,7 @@ const SpanItem = ({
3737
);
3838
const [isResizing, setIsResizing] = useState(false);
3939

40-
const spanDuration = getDuration(span.start_timestamp, span.timestamp);
40+
const spanDuration = span.timestamp - span.start_timestamp;
4141

4242
const handleResize = (e: MouseEvent) => {
4343
if (containerRef.current) {
@@ -117,7 +117,7 @@ const SpanItem = ({
117117
}}
118118
>
119119
<span className={classNames('whitespace-nowrap', getSpanDurationClassName(spanDuration))}>
120-
{spanDuration.toLocaleString()} ms
120+
{getFormattedDuration(spanDuration)}
121121
</span>
122122
</div>
123123
</div>
Lines changed: 20 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,16 @@
1-
export const SECOND = 1000;
2-
export const MINUTE = 60000;
3-
export const HOUR = 3600000;
4-
export const DAY = 86400000;
5-
export const WEEK = 604800000;
6-
export const MONTH = 2629800000;
7-
export const YEAR = 31557600000;
8-
91
export const DURATION_LABELS = {
10-
yr: 'yr',
11-
mo: 'mo',
12-
wk: 'wk',
13-
d: 'd',
14-
hr: 'hr',
15-
min: 'min',
16-
s: 's',
17-
ms: 'ms',
2+
31557600000: 'yr',
3+
2629800000: 'mo',
4+
604800000: 'wk',
5+
86400000: 'd',
6+
3600000: 'hr',
7+
60000: 'min',
8+
1000: 's',
189
};
1910

20-
export function getDuration(start: string | number, end: string | number) {
21-
const startTs = typeof start === 'string' ? new Date(start).getTime() : start;
22-
const endTs = typeof end === 'string' ? new Date(end).getTime() : end;
23-
return Math.floor(endTs - startTs);
24-
}
11+
const DURATIONS = Object.keys(DURATION_LABELS)
12+
.map(Number)
13+
.sort((a, b) => b - a);
2514

2615
export function getSpanDurationClassName(duration: number) {
2716
if (duration > 1000) return 'text-red-400';
@@ -30,49 +19,19 @@ export function getSpanDurationClassName(duration: number) {
3019
}
3120

3221
export function getFormattedNumber(num: number, decimalPlaces: number = 2): string {
33-
if (num % 1 !== 0 || (num % 1 === 0 && num.toString().includes('.'))) {
34-
return num.toFixed(decimalPlaces);
35-
} else {
36-
return num.toFixed(0);
37-
}
22+
return num.toFixed(decimalPlaces).replace(/\.00$/, '');
3823
}
3924

4025
export function getFormattedDuration(duration: number): string {
41-
if (duration >= YEAR) {
42-
const num = getFormattedNumber(duration / YEAR);
43-
return `${num}${DURATION_LABELS.yr}`;
44-
}
45-
46-
if (duration >= MONTH) {
47-
const num = getFormattedNumber(duration / MONTH);
48-
return `${num}${DURATION_LABELS.mo}`;
49-
}
50-
51-
if (duration >= WEEK) {
52-
const num = getFormattedNumber(duration / WEEK);
53-
return `${num}${DURATION_LABELS.wk}`;
54-
}
55-
56-
if (duration >= DAY) {
57-
const num = getFormattedNumber(duration / DAY);
58-
return `${num}${DURATION_LABELS.d}`;
59-
}
60-
61-
if (duration >= HOUR) {
62-
const num = getFormattedNumber(duration / HOUR);
63-
return `${num}${DURATION_LABELS.hr}`;
64-
}
65-
66-
if (duration >= MINUTE) {
67-
const num = getFormattedNumber(duration / MINUTE);
68-
return `${num}${DURATION_LABELS.min}`;
69-
}
70-
71-
if (duration >= SECOND) {
72-
const num = getFormattedNumber(duration / SECOND);
73-
return `${num}${DURATION_LABELS.s}`;
26+
for (const limit of DURATIONS) {
27+
if (duration >= limit) {
28+
const num = getFormattedNumber(duration / limit);
29+
return `${num}${DURATION_LABELS[limit as keyof typeof DURATION_LABELS]}`;
30+
}
7431
}
32+
return `${getFormattedNumber(duration)}ms`;
33+
}
7534

76-
const num = getFormattedNumber(duration);
77-
return `${num}${DURATION_LABELS.ms}`;
35+
export function getFormattedSpanDuration(span: { timestamp: number; start_timestamp: number }): string {
36+
return getFormattedDuration(span.timestamp - span.start_timestamp);
7837
}

0 commit comments

Comments
 (0)