Skip to content

Commit

Permalink
ref: Unify and simplify duration calculations and representations (#688)
Browse files Browse the repository at this point in the history
  • Loading branch information
BYK authored Feb 4, 2025
1 parent 9c498dd commit 0fcb37d
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 77 deletions.
8 changes: 8 additions & 0 deletions .changeset/wild-lobsters-doubt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@spotlightjs/spotlight': patch
'@spotlightjs/electron': patch
'@spotlightjs/overlay': patch
'@spotlightjs/astro': patch
---

Unify and simplify duration calculations and representations
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useState } from 'react';
import { useParams } from 'react-router-dom';
import sentryDataCache from '../../../../../data/sentryDataCache';
import { getDuration } from '../../../../../utils/duration';
import DateTime from '../../../../DateTime';
import SpanDetails from '../../spans/SpanDetails';
import SpanTree from '../../spans/SpanTree';
import { getFormattedSpanDuration } from '../../../../../utils/duration';

type TraceTreeViewProps = { traceId: string };

Expand All @@ -29,10 +29,7 @@ export default function TraceTreeview({ traceId }: TraceTreeViewProps) {
</div>
<span>&mdash;</span>
<span>
<strong className="text-primary-200 font-bold">
{getDuration(trace.start_timestamp, trace.timestamp).toLocaleString()} ms
</strong>{' '}
recorded in{' '}
<strong className="text-primary-200 font-bold">{getFormattedSpanDuration(trace)}</strong> recorded in{' '}
<strong className="text-primary-200 font-bold">{trace.spans.length.toLocaleString()} spans</strong>
</span>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import classNames from '../../../../../lib/classNames';
import { useSpotlightContext } from '../../../../../lib/useSpotlightContext';
import { useSentryHelpers } from '../../../data/useSentryHelpers';
import { useSentryTraces } from '../../../data/useSentryTraces';
import { getDuration } from '../../../utils/duration';
import { getFormattedSpanDuration } from '../../../utils/duration';
import { truncateId } from '../../../utils/text';
import HiddenItemsButton from '../../HiddenItemsButton';
import { TraceRootTxnName } from './TraceDetails/components/TraceRootTxnName';
Expand Down Expand Up @@ -35,7 +35,6 @@ export default function TraceList() {
/>
)}
{filteredTraces.map(trace => {
const duration = getDuration(trace.start_timestamp, trace.timestamp);
return (
<Link
className="hover:bg-primary-900 flex cursor-pointer items-center gap-x-4 px-6 py-2"
Expand Down Expand Up @@ -63,7 +62,7 @@ export default function TraceList() {
{trace.status || ''}
</div>
<div>&mdash;</div>
<div>{duration} ms</div>
<div>{getFormattedSpanDuration(trace)}</div>
<div>&mdash;</div>
<div>
{trace.spans.length.toLocaleString()} spans, {trace.transactions.length.toLocaleString()} txns
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { DB_SPAN_REGEX } from '../../../../constants';
import dataCache from '../../../../data/sentryDataCache';
import type { SentryErrorEvent, Span, TraceContext } from '../../../../types';
import { formatBytes } from '../../../../utils/bytes';
import { getDuration } from '../../../../utils/duration';
import { getFormattedDuration } from '../../../../utils/duration';
import DateTime from '../../../DateTime';
import { ErrorTitle } from '../../../events/error/Error';
import SpanTree from './SpanTree';
Expand Down Expand Up @@ -87,7 +87,7 @@ export default function SpanDetails({
}) {
const [spanNodeWidth, setSpanNodeWidth] = useState<number>(50);

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

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

Expand Down Expand Up @@ -115,19 +115,19 @@ export default function SpanDetails({
<DateTime date={span.start_timestamp} />
<span>&mdash;</span>
<span>
<strong>{getDuration(startTimestamp, span.start_timestamp)} ms</strong> into trace
<strong>{getFormattedDuration(spanDuration)}</strong> into trace
</span>
</div>
<div className="flex-1">
<div className="border-primary-800 relative h-8 border py-1">
<div
className="bg-primary-800 absolute bottom-0 top-0 -m-0.5 flex w-full items-center p-0.5"
style={{
left: `min(${((span.start_timestamp - startTimestamp) / totalDuration) * 100}%, 100% - 1px)`,
left: `min(${(spanDuration / totalDuration) * 100}%, 100% - 1px)`,
width: `max(1px, ${(spanDuration / totalDuration) * 100}%)`,
}}
>
<span className="whitespace-nowrap">{spanDuration} ms</span>
<span className="whitespace-nowrap">{getFormattedDuration(spanDuration)}</span>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Link, useParams } from 'react-router-dom';
import { ReactComponent as ChevronIcon } from '~/assets/chevronDown.svg';
import classNames from '../../../../../../lib/classNames';
import type { Span, TraceContext } from '../../../../types';
import { getDuration, getSpanDurationClassName } from '../../../../utils/duration';
import { getSpanDurationClassName, getFormattedDuration } from '../../../../utils/duration';
import PlatformIcon from '../../../PlatformIcon';
import SpanResizer from '../../../SpanResizer';
import SpanTree from './SpanTree';
Expand Down Expand Up @@ -37,7 +37,7 @@ const SpanItem = ({
);
const [isResizing, setIsResizing] = useState(false);

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

const handleResize = (e: MouseEvent) => {
if (containerRef.current) {
Expand Down Expand Up @@ -117,7 +117,7 @@ const SpanItem = ({
}}
>
<span className={classNames('whitespace-nowrap', getSpanDurationClassName(spanDuration))}>
{spanDuration.toLocaleString()} ms
{getFormattedDuration(spanDuration)}
</span>
</div>
</div>
Expand Down
81 changes: 20 additions & 61 deletions packages/overlay/src/integrations/sentry/utils/duration.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,16 @@
export const SECOND = 1000;
export const MINUTE = 60000;
export const HOUR = 3600000;
export const DAY = 86400000;
export const WEEK = 604800000;
export const MONTH = 2629800000;
export const YEAR = 31557600000;

export const DURATION_LABELS = {
yr: 'yr',
mo: 'mo',
wk: 'wk',
d: 'd',
hr: 'hr',
min: 'min',
s: 's',
ms: 'ms',
31557600000: 'yr',
2629800000: 'mo',
604800000: 'wk',
86400000: 'd',
3600000: 'hr',
60000: 'min',
1000: 's',
};

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

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

export function getFormattedNumber(num: number, decimalPlaces: number = 2): string {
if (num % 1 !== 0 || (num % 1 === 0 && num.toString().includes('.'))) {
return num.toFixed(decimalPlaces);
} else {
return num.toFixed(0);
}
return num.toFixed(decimalPlaces).replace(/\.00$/, '');
}

export function getFormattedDuration(duration: number): string {
if (duration >= YEAR) {
const num = getFormattedNumber(duration / YEAR);
return `${num}${DURATION_LABELS.yr}`;
}

if (duration >= MONTH) {
const num = getFormattedNumber(duration / MONTH);
return `${num}${DURATION_LABELS.mo}`;
}

if (duration >= WEEK) {
const num = getFormattedNumber(duration / WEEK);
return `${num}${DURATION_LABELS.wk}`;
}

if (duration >= DAY) {
const num = getFormattedNumber(duration / DAY);
return `${num}${DURATION_LABELS.d}`;
}

if (duration >= HOUR) {
const num = getFormattedNumber(duration / HOUR);
return `${num}${DURATION_LABELS.hr}`;
}

if (duration >= MINUTE) {
const num = getFormattedNumber(duration / MINUTE);
return `${num}${DURATION_LABELS.min}`;
}

if (duration >= SECOND) {
const num = getFormattedNumber(duration / SECOND);
return `${num}${DURATION_LABELS.s}`;
for (const limit of DURATIONS) {
if (duration >= limit) {
const num = getFormattedNumber(duration / limit);
return `${num}${DURATION_LABELS[limit as keyof typeof DURATION_LABELS]}`;
}
}
return `${getFormattedNumber(duration)}ms`;
}

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

0 comments on commit 0fcb37d

Please sign in to comment.