diff --git a/frontend/snapshots.yml b/frontend/snapshots.yml index de63cf19d27d..40b9ddfd540e 100644 --- a/frontend/snapshots.yml +++ b/frontend/snapshots.yml @@ -5453,9 +5453,9 @@ snapshots: products-tracing-operationstable--loading--light: hash: v1.k794b7964.04bcc55cb9522d72f548084a92d35c0aba20ff4995949bd8b2ee8686f96cb6ac.P_KhZ-T4DKSiE8XyxMJSgUEUR9bDfDvgYnGqSOiR860 products-tracing-virtualizedspanlist--default--dark: - hash: v1.k794b7964.2d26cb574fb8b9011fcf44c766f491adb06c254b9bc1bb70fa1a14bf757eb72d.HK_kiCD_GlyKPWUd6GcCvJJ5tVWaz6t45kZwDWUYg_4 + hash: v1.k794b7964.d6cf5ccbc379f67404b237b878878ce7e60512d45869c05c24dfab7784335406.zEh7cw_wZ10BGEuJkOUdjqS8SiWt7386-Cuz4Qc0Les products-tracing-virtualizedspanlist--default--light: - hash: v1.k794b7964.21b6c26c19954d60a3447075f70b9c9dcfb5f6032f94c85fa223f728ee02bf1c.dAAs5oIhp4WcsPd9uA5wTgaPWyEeuf7PV46c6WFv-9g + hash: v1.k794b7964.7ec7e24fc514e8eac101ce26ef491c0becbbe2cc6aeb8759c1c451b5977e6aa7.cP3_uVsCx_-JFlTOLhjShsAIyaSC9JRkJ4Rnlgog0Kk products-tracing-virtualizedspanlist--empty--dark: hash: v1.k794b7964.5590e8e6497de2fefefa74cf07edd5f814a798deb8f7e5f0102a383f5e8ac6c8.ZvuooUS3qT6kDX8yW2_oQ1iDgO1DwVFMAWM517bhCHw products-tracing-virtualizedspanlist--empty--light: diff --git a/products/tracing/frontend/TracingLatencyHeatmap.tsx b/products/tracing/frontend/TracingLatencyHeatmap.tsx index e038cd8a9207..72683f77b71f 100644 --- a/products/tracing/frontend/TracingLatencyHeatmap.tsx +++ b/products/tracing/frontend/TracingLatencyHeatmap.tsx @@ -6,6 +6,7 @@ import { Heatmap, type HeatmapBrushData, useChartTheme } from '@posthog/quill-ch import { dayjs } from 'lib/dayjs' import { shortTimeZone } from 'lib/utils/timezones' +import { TRACING_DATE_TIME_FORMAT } from './dateFormats' import type { TracingLatencyHeatmapData } from './durationBuckets' const MAX_X_TICKS = 6 @@ -38,7 +39,7 @@ export function TracingLatencyHeatmap({ } else if (hoursDiff <= 48) { return 'HH:mm' } - return 'D MMM HH:mm' + return 'MM-DD HH:mm' }, [data.timeBuckets]) const tickStep = Math.max(1, Math.ceil(data.timeBuckets.length / MAX_X_TICKS)) @@ -57,7 +58,7 @@ export function TracingLatencyHeatmap({ (label: string): string => { const d = displayTimezone ? dayjs(label).tz(displayTimezone) : dayjs(label) const tz = displayTimezone === 'UTC' ? 'UTC' : (shortTimeZone(displayTimezone, d.toDate()) ?? 'Local') - return `${d.format('D MMM YYYY HH:mm:ss')} ${tz}` + return `${d.format(TRACING_DATE_TIME_FORMAT)} ${tz}` }, [displayTimezone] ) diff --git a/products/tracing/frontend/TracingOperationScene.tsx b/products/tracing/frontend/TracingOperationScene.tsx index b65091639645..bf1c0ab9c9e0 100644 --- a/products/tracing/frontend/TracingOperationScene.tsx +++ b/products/tracing/frontend/TracingOperationScene.tsx @@ -4,7 +4,7 @@ import { IconChevronLeft, IconChevronRight } from '@posthog/icons' import { LemonButton, LemonSegmentedButton, LemonTag, Link, SpinnerOverlay } from '@posthog/lemon-ui' import { DateFilter } from 'lib/components/DateFilter/DateFilter' -import { humanFriendlyDetailedTime } from 'lib/utils/datetime' +import { TZLabel } from 'lib/components/TZLabel' import { humanFriendlyNumber } from 'lib/utils/numbers' import { SceneExport } from 'scenes/sceneTypes' import { urls } from 'scenes/urls' @@ -14,6 +14,7 @@ import { SceneDivider } from '~/layout/scenes/components/SceneDivider' import { SceneTitleSection } from '~/layout/scenes/components/SceneTitleSection' import { ProductKey } from '~/queries/schema/schema-general' +import { TRACING_DATE_FORMAT, TRACING_DISPLAY_TIMEZONE, TRACING_TIME_FORMAT } from './dateFormats' import { formatBucketLabel } from './durationBuckets' import { OperationHistogram } from './OperationHistogram' import { errorRate, formatErrorRate } from './OperationsTable' @@ -162,7 +163,7 @@ export function TracingOperationScene(): JSX.Element { @@ -216,7 +217,13 @@ export function TracingOperationScene(): JSX.Element { /> {currentSample && (
- {humanFriendlyDetailedTime(currentSample.timestamp)} + {formatDuration(currentSample.duration_nano)} {currentSample.status_code === 2 && Error}
diff --git a/products/tracing/frontend/TracingScene.tsx b/products/tracing/frontend/TracingScene.tsx index cb520e66e964..c94aaa780af0 100644 --- a/products/tracing/frontend/TracingScene.tsx +++ b/products/tracing/frontend/TracingScene.tsx @@ -21,6 +21,7 @@ import { ComparisonBar } from './components/Comparison/ComparisonBar' import { FacetRail } from './components/FacetRail/FacetRail' import { TraceDrawer } from './components/TraceDrawer/TraceDrawer' import { VirtualizedSpanList } from './components/VirtualizedSpanList/VirtualizedSpanList' +import { TRACING_DISPLAY_TIMEZONE } from './dateFormats' import { tracingEmptyState } from './emptyState/tracingEmptyState' import { OperationsTable } from './OperationsTable' import { TraceCompareFlame } from './TraceCompareFlame' @@ -203,7 +204,7 @@ function TracingSceneContents(): JSX.Element { sparklineData={sparklineData} sparklineLoading={sparklineLoading || (isDurationMode && !showHeatmap && durationHistogramLoading)} onDateRangeChange={setDateRange} - displayTimezone="UTC" + displayTimezone={TRACING_DISPLAY_TIMEZONE} compare={compareConfig} visibleRowDateRange={visibleRowDateRange} durationHistogram={isDurationMode && !showHeatmap ? durationHistogramData : null} diff --git a/products/tracing/frontend/TracingSparkline.tsx b/products/tracing/frontend/TracingSparkline.tsx index 21dcc2ad9364..2daac3be6c1a 100644 --- a/products/tracing/frontend/TracingSparkline.tsx +++ b/products/tracing/frontend/TracingSparkline.tsx @@ -25,6 +25,7 @@ import { shortTimeZone } from 'lib/utils/timezones' import { DateRange } from '~/queries/schema/schema-general' +import { TRACING_DATE_TIME_FORMAT } from './dateFormats' import { type TracingDurationHistogramData, type TracingLatencyHeatmapData, @@ -116,7 +117,7 @@ export function TracingSparkline({ (label: string): string => { const d = displayTimezone ? dayjs(label).tz(displayTimezone) : dayjs(label) const tz = displayTimezone === 'UTC' ? 'UTC' : (shortTimeZone(displayTimezone, d.toDate()) ?? 'Local') - return `${d.format('D MMM YYYY HH:mm:ss')} ${tz}` + return `${d.format(TRACING_DATE_TIME_FORMAT)} ${tz}` }, [displayTimezone] ) diff --git a/products/tracing/frontend/components/Comparison/ComparisonBar.tsx b/products/tracing/frontend/components/Comparison/ComparisonBar.tsx index 3ee1e9de6dcc..493605af6825 100644 --- a/products/tracing/frontend/components/Comparison/ComparisonBar.tsx +++ b/products/tracing/frontend/components/Comparison/ComparisonBar.tsx @@ -5,6 +5,7 @@ import { LemonButton, LemonTag } from '@posthog/lemon-ui' import { dayjs } from 'lib/dayjs' +import { TRACING_DATE_FORMAT } from '../../dateFormats' import { COMPARE_CURRENT_BORDER, COMPARE_PREVIOUS_BORDER } from '../../SparklineCompareOverlay' import { type OverlayWindow, TIME_COMPARE_PRESET_DEFS, tracingFiltersLogic } from '../../tracingFiltersLogic' @@ -13,8 +14,8 @@ import { type OverlayWindow, TIME_COMPARE_PRESET_DEFS, tracingFiltersLogic } fro function formatComparisonWindow(window: OverlayWindow): string { const start = dayjs(window.startMs).utc() const end = dayjs(window.endMs).utc() - const endFormat = start.isSame(end, 'day') ? 'HH:mm' : 'MMM D, HH:mm' - return `${start.format('MMM D, HH:mm')} – ${end.format(endFormat)} UTC` + const endFormat = start.isSame(end, 'day') ? 'HH:mm' : `${TRACING_DATE_FORMAT} HH:mm` + return `${start.format(`${TRACING_DATE_FORMAT} HH:mm`)} – ${end.format(endFormat)} UTC` } function ComparisonPill({ color, label, detail }: { color: string; label: string; detail: string }): JSX.Element { diff --git a/products/tracing/frontend/components/TraceDrawer/SpanSummaryHeader.tsx b/products/tracing/frontend/components/TraceDrawer/SpanSummaryHeader.tsx index 2b260a3caf76..b1825fd52b90 100644 --- a/products/tracing/frontend/components/TraceDrawer/SpanSummaryHeader.tsx +++ b/products/tracing/frontend/components/TraceDrawer/SpanSummaryHeader.tsx @@ -4,8 +4,10 @@ import { LemonTag } from '@posthog/lemon-ui' import { getSeriesColor } from 'lib/colors' import { CopyToClipboardInline } from 'lib/components/CopyToClipboard' +import { TZLabel } from 'lib/components/TZLabel' import { dayjs } from 'lib/dayjs' +import { TRACING_DATE_FORMAT, TRACING_DISPLAY_TIMEZONE, TRACING_TIME_FORMAT } from '../../dateFormats' import { deriveSpanSummary } from '../../spanSummary' import { formatDuration } from '../../TraceWaterfallView' import type { Span } from '../../types' @@ -80,12 +82,18 @@ export function SpanSummaryHeader({ )} {formatDuration(summary.durationNano)} - {/* UTC to match the waterfall/sparkline (displayTimezone="UTC"). end shows time-only — - same day as start in all but pathological spans, so the date would just be noise. */} + {/* UTC to match the waterfall/sparkline. end shows time-only — same day as start in + all but pathological spans, so the date would just be noise. */} - {dayjs(summary.timestamp).tz('UTC').format('MMM D HH:mm:ss.SSS')} + {' → '} - {dayjs(summary.endTimestamp).tz('UTC').format('HH:mm:ss.SSS')} + {dayjs(summary.endTimestamp).tz(TRACING_DISPLAY_TIMEZONE).format(TRACING_TIME_FORMAT)} diff --git a/products/tracing/frontend/components/VirtualizedSpanList/VirtualizedSpanList.tsx b/products/tracing/frontend/components/VirtualizedSpanList/VirtualizedSpanList.tsx index a40ce23bad54..fc33da1f0dab 100644 --- a/products/tracing/frontend/components/VirtualizedSpanList/VirtualizedSpanList.tsx +++ b/products/tracing/frontend/components/VirtualizedSpanList/VirtualizedSpanList.tsx @@ -5,9 +5,11 @@ import { LemonTag } from '@posthog/lemon-ui' import { AutoSizer } from 'lib/components/AutoSizer' import { SizeProps } from 'lib/components/AutoSizer/AutoSizer' +import { TZLabel } from 'lib/components/TZLabel' import { SortingIndicator } from 'lib/lemon-ui/LemonTable/sorting' import { cn } from 'lib/utils/css-classes' +import { TRACING_DATE_FORMAT, TRACING_DISPLAY_TIMEZONE, TRACING_TIME_FORMAT } from '../../dateFormats' import { formatDuration } from '../../TraceWaterfallView' import type { TracingOrderBy, TracingOrderDirection } from '../../tracingFiltersLogic' import { SPAN_KIND_LABELS, STATUS_CODE_LABELS } from '../../types' @@ -25,7 +27,7 @@ const LOAD_MORE_THRESHOLD = 10 // Default column widths (px), in render order. Anyone can drag a column wider or narrower from here. const SPAN_COLUMNS: ResizableColumnSpec[] = [ - { key: 'timestamp', width: 190 }, + { key: 'timestamp', width: 215 }, { key: 'name', width: 320, grow: true }, { key: 'service', width: 200 }, { key: 'kind', width: 90 }, @@ -164,7 +166,17 @@ function SpanRow({ role="button" tabIndex={0} > - {new Date(span.timestamp).toLocaleString()} + + + + + {span.name} diff --git a/products/tracing/frontend/dateFormats.ts b/products/tracing/frontend/dateFormats.ts new file mode 100644 index 000000000000..d46b20e4c277 --- /dev/null +++ b/products/tracing/frontend/dateFormats.ts @@ -0,0 +1,11 @@ +// Tracing shows timestamps the way Logs does: an ISO-ordered date and a 24-hour clock. A +// month-first date is ambiguous outside the US. +export const TRACING_DATE_FORMAT = 'YYYY-MM-DD' +export const TRACING_TIME_FORMAT = 'HH:mm:ss.SSS' + +// Charts and range pills drop the milliseconds. A bucket edge is never sub-second. +export const TRACING_DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss' + +// Every chart, axis, and timestamp in the product reads in UTC, so a span lines up with the +// sparkline above it. TZLabel converts to the reader's own timezone on hover. +export const TRACING_DISPLAY_TIMEZONE = 'UTC' diff --git a/products/tracing/frontend/tracingDataLogic.ts b/products/tracing/frontend/tracingDataLogic.ts index 1debf7c055d2..52175f0f5590 100644 --- a/products/tracing/frontend/tracingDataLogic.ts +++ b/products/tracing/frontend/tracingDataLogic.ts @@ -29,6 +29,7 @@ import { PropertyGroupFilter } from '~/types' import type { DateRange } from '../../../frontend/src/queries/schema/schema-general' import type { UniversalFiltersGroup } from '../../../frontend/src/types' +import { TRACING_DATE_FORMAT } from './dateFormats' import { type DurationHistogramRow, type LatencyHeatmapRow, @@ -1264,7 +1265,7 @@ export const tracingDataLogic = kea([ (accumulator, currentItem) => { if (currentItem.time !== lastTime) { labels.push( - humanFriendlyDetailedTime(currentItem.time, 'YYYY-MM-DD', 'HH:mm:ss', { + humanFriendlyDetailedTime(currentItem.time, TRACING_DATE_FORMAT, 'HH:mm:ss', { timestampStyle: 'absolute', }) )