fix(tracing): use the logs timestamp format - #92400
Conversation
Span timestamps rendered through toLocaleString, so a US reader saw 3/8/2026, 2:07:09 PM and a reader elsewhere saw a different order. Logs shows 2026-03-08 14:07:09.123 and converts the timestamp on hover. Render the tracing timestamps with TZLabel in UTC, on the logs format, and collect the format and timezone constants in dateFormats.ts. Generated-By: PostHog Desktop Task-Id: dbdbefb4-52bf-47b3-a940-6d76bd6251b9
|
😎 Merged successfully - details. |
🤖 CI report✅ Trunk lane — non-backend laneThis PR is assigned to the non-backend lane. It does not run backend Python tests and may merge in parallel with PRs in other lanes.
|
| Function | Location | Complexity |
|---|---|---|
TracingSceneContents |
products/tracing/frontend/TracingScene.tsx:70 |
24 |
TracingOperationScene |
products/tracing/frontend/TracingOperationScene.tsx:68 |
21 |
TracingSparkline |
products/tracing/frontend/TracingSparkline.tsx:72 |
21 |
⚠️ Bundle size — 🔺 +205 B (+0.0%)
Uncompressed size of every built .js bundle, compared against the base branch.
Total: 68.09 MiB · 🔺 +205 B (+0.0%)
No file changed by more than 1000 B.
Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report
✅ Eager graph — within budget
How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.
| Root | Eager (shipped) | Δ vs base | Budget |
|---|---|---|---|
entry (logged-out pages, app bootstrap)src/index.tsx |
1.42 MiB · 22 files | no change | ███░░░░░░░ 31.5% of 4.51 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
8.84 MiB · 3,246 files | no change | █████████░ 91.0% of 9.71 MiB |
🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
Largest files eagerly shipped from src/index.tsx
| Size | File |
|---|---|
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 24.6 KiB | ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js |
| 6.3 KiB | ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js |
| 4.5 KiB | ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js |
| 3.9 KiB | ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js |
| 1.4 KiB | ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js |
| 1.3 KiB | src/RootErrorBoundary.tsx |
| 912 B | ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js |
| 789 B | src/scenes/ChunkLoadErrorBoundary.tsx |
| 762 B | src/index.tsx |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
| Size | File |
|---|---|
| 307.0 KiB | ../node_modules/.pnpm/posthog-js@1.422.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js |
| 267.7 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 263.5 KiB | ../node_modules/.pnpm/posthog-js@1.422.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.js |
| 253.8 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 154.2 KiB | ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 104.7 KiB | src/lib/api.ts |
| 95.2 KiB | ../packages/quill/packages/quill/dist/index.js |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 90.6 KiB | ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js |
Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479
✅ Toolbar bundle — eager 2.26 MiB within budget
What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.
| Metric | Size | Δ vs base | Budget |
|---|---|---|---|
| Eager (shipped) entry + static imports |
2.26 MiB · 18 files | no change | ████░░░░░░ 39.5% of 5.72 MiB |
| Deferred (lazy) | 2.11 MiB · 45 files | no change | n/a — loads on demand |
Loader dist/toolbar.js |
1.1 KiB | no change | █░░░░░░░░░ 5.8% of 19.5 KiB |
Largest eagerly-shipped chunks
| Size | File |
|---|---|
| 751.0 KiB | dist/toolbar/toolbar-app-2F4EKOCO.css |
| 588.3 KiB | dist/toolbar/chunk-chunk-CFLMJQWS.js |
| 484.7 KiB | dist/toolbar/chunk-chunk-NRMPD72D.js |
| 134.1 KiB | dist/toolbar/chunk-chunk-MUTOPEMM.js |
| 131.8 KiB | dist/toolbar/chunk-chunk-FDH2IBXT.js |
| 71.3 KiB | dist/toolbar/toolbar-app-IHGHOZGL.js |
| 69.0 KiB | dist/toolbar/chunk-chunk-TSAL54PB.js |
| 35.6 KiB | dist/toolbar/chunk-chunk-4F2F4EYQ.js |
| 21.0 KiB | dist/toolbar/chunk-chunk-NXB4O7BJ.js |
| 6.8 KiB | dist/toolbar/chunk-chunk-DV7IWQNF.js |
Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile
✅ Dist folder size — 🔺 +3.1 KiB (+0.0%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 1447.90 MiB · 🔺 +3.1 KiB (+0.0%)
🦔 Hogbox preview · ❌ build failedThe preview didn't come up for commit Previews are optional and never block merging. A failure here is often a hogland or tailnet hiccup rather than anything in your PR, so the check stays green and this comment is the status. |
Prompt To Fix All With AI### Issue 1
products/tracing/frontend/components/VirtualizedSpanList/VirtualizedSpanList.tsx:171-176
**Popover drops timestamp seconds**
The row displays seconds and milliseconds, but omitting `showSeconds` makes its timezone-conversion popover stop at the minute, unlike the sample picker and drawer header.
```suggestion
<TZLabel
time={span.timestamp}
formatDate={TRACING_DATE_FORMAT}
formatTime={TRACING_TIME_FORMAT}
displayTimezone={TRACING_DISPLAY_TIMEZONE}
showSeconds
/>
```
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "fix(tracing): use the logs timestamp for..." | Re-trigger Greptile |
The span row renders seconds and milliseconds, so its hover popover has to match. Without showSeconds the conversion stopped at the minute, unlike the sample picker and the drawer header. Generated-By: PostHog Desktop Task-Id: f91f83fa-3425-44d7-b290-3df28097e4d6
Generated-By: PostHog Desktop Task-Id: f91f83fa-3425-44d7-b290-3df28097e4d6
|
✅ Visual changes approved by @jonmcwest — baseline updated in 2 changed. |
2 updated Run: 68f06fd3-9a1e-45c2-8d58-292cf762bac6 Co-authored-by: jonmcwest <66999846+jonmcwest@users.noreply.github.com>
Generated-By: PostHog Desktop Task-Id: f7fa93bf-ade5-4c54-8ec8-6ee5b47aa353
|
Reviews (2): Last reviewed commit: "Merge branch 'master' into posthog/traci..." | Re-trigger Greptile |
There was a problem hiding this comment.
Approved.
Contained frontend formatting change within the tracing product by an owning-team author; the one reviewer-flagged issue (missing showSeconds) is already present in the current diff, and no other unresolved concerns or holds exist.
- Author wrote 67% of the modified lines and has 180 merged PRs in these paths (familiarity MODERATE).
- 👍 on the PR from greptile-apps[bot].
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✓ | no deny categories matched |
| size | ✓ | 79L, 10F substantive — within ceiling |
| tier | ✓ | T1-agent / T1c-medium (79L, 10F, two-areas, fix) |
| stamphog 2.0.0b4 | .stamphog/policy.yml @ faab042 · reviewed head faab042 |
CI status: green except a master-wide Jest breakageEverything owned by this PR is green on
The three remaining red checks (
Fixes are already open upstream in #92543 and #92557, so I am not duplicating one here. This PR should go green on its own once either lands and master is merged in. 🦉 via talyn.dev |
Generated-By: PostHog Desktop Task-Id: f7fa93bf-ade5-4c54-8ec8-6ee5b47aa353
|
#92557 landed, master is merged in (
🦉 via talyn.dev |
Co-authored-by: posthog[bot] <206114724+posthog[bot]@users.noreply.github.com>
Co-authored-by: posthog[bot] <206114724+posthog[bot]@users.noreply.github.com>
Co-authored-by: posthog[bot] <206114724+posthog[bot]@users.noreply.github.com>
Problem
Someone reading a span list in Tracing sees a date whose order depends on their browser locale:
3/8/2026, 2:07:09 PMin the US,08/03/2026, 14:07:09elsewhere. Nothing on the page says which one it is, and there is no way to convert it.Logs, the product next door, shows
2026-03-08 14:07:09.123and converts the timestamp to the reader's timezone on hover.Raised through the Tracing feedback survey.
Changes
2026-08-28 10:24:27.000, and hovering it opens the timezone conversion popover that Logs already has.YYYY-MM-DDfromD MMM YYYYandMMM D.products/tracing/frontend/dateFormats.tsholds the format and timezone constants. Eight call sites carried their own literals before, which is how the product drifted apart.The span list, rendered from the committed
Products/Tracing/VirtualizedSpanListstory with the browser timezone set toAmerica/New_York:Before — month-first, and the clock reads in whatever timezone the browser is in:
After — ISO-ordered, monospaced, milliseconds kept, and a dotted underline marking the hover target:
The two read
6:24 AMand10:24 AMfor the same span, which is the timezone change below, not a formatting artifact. Hovering explains it in place, down to the same second-and-millisecond precision the row shows:Note
Span list timestamps move from the browser's local timezone to UTC. Every chart in Tracing already renders in UTC, so a span row and the sparkline above it disagreed by the reader's offset. The popover shows displayed, device, project and UTC time together.
The span drawer header takes the same format. Its end time stays time-only, because start and end share a day in all but pathological spans:
The timestamp column default width grows from 190px to 215px, because the new string is longer. A reader who already dragged that column keeps their stored width.
Mechanical: the two
displayTimezone="UTC"literals in the scenes now read the shared constant.How did you test this code?
The screenshots are real renders, not mockups: the committed
VirtualizedSpanListstory driven in headless Chromium at this branch's head. "Before" is the same story withVirtualizedSpanList.tsxswapped to its state at the merge base with master, so the pair differs only by this PR. The script asserted the expected format on each render, which caught a stale Vite module that had otherwise produced a wrongly-labelled "after".Storybook needs the nested
@posthog/quillworkspace built before it boots, becausefrontend/src/styles/global.scssimports@posthog/quill/dist/tokens.scoped.css. That is local setup only, and no repo change came out of it.The drawer-header shot came from a throwaway story; both it and an earlier throwaway jsdom render test were deleted rather than committed. That test confirmed
TZLabelwith the new props renders exactly2026-03-08 14:07:09.123.The 22 existing tracing frontend suites pass unchanged, and frontend typecheck reports no error in
products/tracing. Theproducts-tracing-virtualizedspanlist--defaultvisual baselines move with this change; the regenerated hashes are already on the branch.No new test. The five surfaces are a render away from a shared constant now, and a single render assertion on one of them would only look like coverage.
Automatic notifications
Docs update
None.
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Written by the PostHog Slack app from a Slack thread on a Tracing feedback survey response. Left unassigned: the requester's GitHub handle was not verified this session, and guessing one tags a stranger.
Skills invoked:
/writing-testsand/writing-pr-descriptions.The first pass targeted
products/ai_observability(LLM analytics), which also renders month-first dates. That was the wrong product and was reverted. Its ambiguous dates are a separate, still-open problem:AIObservabilityClusterSceneand the evaluation report components calltoLocaleDateString()andtoLocaleString()with no arguments.Two earlier claims in this description were wrong and have been replaced. It said screenshots were impossible in the sandbox; Storybook boots there once quill is built. It then said no tracing story carried a visual baseline, having looked for PNGs while the hashes live in
frontend/snapshots.yml. A first set of screenshots was also taken from a stale checkout, before theshowSecondspopover fix and the master merges on this branch, and was re-shot at the branch head. Images went to the publicPostHog/pr-assetsrepo the wayhogli pr:upload-imagedoes it, by hand, because hogli's Python environment is not synced here. They show only invented fixture data.Created with PostHog from a Slack thread