Skip to content

Stop patching Tracy core: tracy-2.12.x is now the Tracy 2.12.2 release (plus the OPcache patch) - #119

Merged
adrianbj merged 17 commits into
masterfrom
tracy-depatch
Oct 22, 2026
Merged

adrianbj merged 17 commits into
masterfrom
tracy-depatch

Conversation

@adrianbj

Copy link
Copy Markdown
Owner

Makes the bundled tracy-2.12.x (the copy used on PHP 8.2+) the unmodified Tracy v2.12.2 release plus one patch: the Info panel's OPcache row, until nette/tracy#623 is merged or declined. Every behaviour TracyDebugger used to get from patching Tracy core now comes from its own code, so the next Tracy update can be a straight copy. The older copies (2.7.x, 2.9.x, 2.10.x) are left as they are.

Core patches replaced

Former patch Now done by
$customCssStr/$customJsStr/$customBodyStr in Debugger.php and DeferredContent.php TD's bar JS goes through the official Debugger::$customJsFiles, as a content-hashed file in the cache dir (barJsFile()). Cookie/session-dependent bits are decided in the browser, so the bundle is the same for every request.
header_remove('Expires'/'Pragma') in DeferredContent.php TD removes them before Debugger::enable() on ?_tracy_bar= requests.
💙 removed from the BlueScreen footer Not needed: deferred content is stored with FileSession, and TD only switches to NativeSession when SessionHandlerDB is not installed.
Narrower hover rule in reset.css main.js narrows Tracy's hover-reset selector at runtime.
Dump location moved below the dump in Dumper/Renderer.php main.js moves it client-side when Tracy initialises dumps (Tracy's own dump()/bdump() never go through TD's PHP).
Debugger::$disableShutdownHandler (Console) A shutdown function registered before Debugger::enable(), as suggested in nette/tracy#279.

Other changes

  • Tracy 2.12.1 → 2.12.2.
  • Shorter bundle cache: browsers now keep the bar bundle for 1 hour instead of 10 days, so TD updates and settings changes show up within the hour.
  • Same bundle for every panel selection: dumps-polling.js and exception-loader.js are always included. Before, a browser that had cached the bundle without them kept it after those panels were switched on.
  • No more polling loops: TD's bar setup runs from Tracy's init hooks instead of polling every animation frame. That was 2 endless loops on every page and 7 in popped-out panel windows; now there are none.
  • Bar JS file: old bar-*.js files are cleaned up without deleting a variant still in use, a failed write is handled and logged, and the file is only built on ?_tracy_bar= requests.
  • Console: @-suppressed errors are no longer logged on PHP 8; Force Scream now shows them; fatal errors under @ are reported.
  • !empty() for the PW Info panel links setting, which could throw on PHP 8 if a cleared setting was saved as ''.
  • Version bumped to 5.0.73.

Possibly breaking

Debugger::$customCssStr, $customJsStr, $customBodyStr and $disableShutdownHandler no longer exist on the 2.12.x copy. Site code or other modules that set them would hit a fatal "undeclared static property" error on PHP 8.2+.

Testing

  • Each change, before and after: tested on pwtest. Each test was first shown to fail without the change where it could, then compared with the patched core.

  • Full scan on PHP 8.5 with Tracy 2.12.x, 2.10.x and 2.9.x forced:

    • all 41 panels opened and floated, plus popup window, redirect bar, full-page and AJAX BlueScreens, and hide/show;
    • dump locations, Dumps Recorder polling, and Console fatal/clean runs under both use_php_session settings;
    • bundle headers and stability, production error page, hover check, and log scan.

    No JS errors. The only new log lines were the old copies' own PHP 8.5 deprecations and the test script.

  • Tracy 2.7.x: doesn't run on PHP 8.4+, so it was checked by reading the code. No other PHP versions were available.

  • GriefCoach dev: CSP tests with a nonce-only style-src after each step. No Tracy violations.

Before merging: click through the bar in a real browser. After installing, do a hard reload, because browsers may still hold a bundle cached under the old 10-day header.

🤖 Generated with Claude Code

…er instead of patching core

PHP's session cache limiter queues "Expires: Thu, 19 Nov 1981" and
"Pragma: no-cache" before Tracy serves ?_tracy_bar= assets, which
contradicted the Cache-Control Tracy sends with them. TracyDebugger now
removes both headers itself just before Debugger::enable() on those
requests, so the local patch in tracy-2.12.x DeferredContent.php is
dropped (the bundle injection patch there remains for now).
The emoji was removed because a 4-byte character broke deferred content
stored in a utf8 (mb3) DB session. Tracy 2.10+ stores deferred content
with FileSession, and TracyDebugger only switches to NativeSession when
use_php_session is on and SessionHandlerDB is not installed, so the
content never reaches a DB session. Tested with SessionHandlerDB on a
utf8mb3 sessions table and use_php_session on: the AJAX BlueScreen
arrives intact.
…f patched core properties

Tracy caches the bar bundle by URL for 10 days, but TracyDebugger's
$customJsStr/$customCssStr/$customBodyStr content depended on the request
(tracyHidden/tracyShow cookies, $showPanels, the session), so a browser
kept whichever variant it fetched first. The same URL gave a different
bundle with and without the tracyHidden cookie.

- the JS is built in $barJs and added as a content-hashed file in the
  TracyDebugger cache dir (barJsFile()), via the official customJsFiles,
  for every bundled Tracy version
- the tracyHidden/tracyShow checks read document.cookie in the browser
- the Dumps Recorder localStorage key is cleared when that panel isn't
  in the bar, instead of checking the session and $showPanels
- font-awesome is loaded for users who could open the File Editor (or
  when PW Info panel custom links are set), not based on $showPanels
- the font-awesome <link> and the show button are created as elements,
  not via innerHTML

tracy-2.12.x drops the $customCssStr/$customJsStr/$customBodyStr
properties from Debugger.php, and DeferredContent.php is now upstream's.
Each change to what feeds TracyDebugger's bar JS (config, module
version, a new front end/admin or privilege variant) left another
bar-<md5>.js in the cache dir, and nothing removed them. Writing a new
file now also deletes other bar-*.js files more than a day old; a
variant still in use is simply written again by its next request.
…tching reset.css

Upstream's "tracy-div:not(a b) *:hover { color: inherit; background:
transparent }" beats any lower-specificity color/background rule on
hover, so with it the Console and File Editor's Ace editor lost its
theme background and colors while hovered, as did keyboard-shortcut
boxes, filter-box counters, Viewports headings and Validator
highlights (62 elements with every front-end panel open). The colors
come from the user's Ace theme, so overriding them in styles.css
doesn't work.

main.js now finds that rule in each <style class="tracy-debug"> sheet
and sets its selector to "tracy-div:not(a b) > *:hover", the selector
the core patch used, on load and after Tracy.BlueScreen.loadAjax.
tracy-2.12.x's reset.css is upstream's again.
tracy-2.12.x is now the v2.12.2 release as exported by git archive
(which also adds phpstan-stubs.php, previously left out) plus the three
remaining TracyDebugger patches, re-applied unchanged:
- Debugger::$disableShutdownHandler (Console)
- the Info panel's OPcache row (nette/tracy#623)
- the dump location below the dump, with its full path

2.12.2 adds PHP 8.6 support and hides /*sensitive{*/ regions in the
BlueScreen's markdown output; no API TracyDebugger uses changed. The bar
bundle URL now carries v=2.12.2, so browsers fetch a fresh bundle.
…ad of patching Dumper/Renderer.php

Tracy's global dump() and bdump() render without going through
TracyDebugger's PHP (Tracy's functions.php is loaded first), so the
layout is now changed client-side. main.js wraps Tracy.Dumper.init, which
runs for the page, panels, popups, AJAX BlueScreens, the Console and the
Dumps Recorder: each <a class="tracy-dump-location"> moves out of its
<pre> into a div.tracy-dump-location-container after it, without the pin
emoji, followed by the file's path in the markup Helpers::editorLink()
gives. The path shown has Debugger::$editorMapping applied, read from the
link's editor URL by matching it against the URL templates TracyDebugger
sets Debugger::$editor to (window.TracyDebuggerEditorTemplates, in the
bar JS).

Tested on pwtest with dump(), bdump() and bd(), for an external editor
and the online editor: the markup is identical to the patched core's.
tracy-2.12.x's Renderer.php is upstream's again.
…ead of patching Debugger.php

As suggested in nette/tracy#279: TracyDebugger registers a shutdown
function just before Debugger::enable(), so it runs before Tracy's.
When CodeProcessor sets TracyDebugger::$skipTracyShutdownHandler (as
before, when use_php_session is 1 or on Tracy 2.7), it keeps
error_get_last() in TracyDebugger::$consoleLastError for
tracyConsoleShutdownHandler, clears it, and turns the bar off, so
Tracy's handler has nothing to log or render. This works the same for
every bundled Tracy version.

Tested on pwtest by running a fatal (time limit) and a clean Console run
over curl, with and without X-Tracy-Ajax, with use_php_session 1 and the
default: the response, status files, deferred AJAX content and log files
match the patched core. Without the patch or this, Tracy logged each
fatal as an exception file.

tracy-2.12.x's Debugger.php is upstream's again; the copy now differs
from the v2.12.2 release only in the Info panel's OPcache row.
Tracy serves ?_tracy_bar=js with Cache-Control: max-age=864000 under a
URL that only changes with Tracy's version, so a TracyDebugger update
(main.js, styles.css, ...) or a settings change that feeds the bundle
(bar position, server type colors, ...) reached browsers up to 10 days
late unless they hard-reloaded. On those requests a
header_register_callback() now replaces it with max-age=3600 just before
the headers go out. The bundle body, the content(-ajax) responses and
normal pages are unchanged.
Both were added only when their panel (Dumps Recorder, Tracy Exceptions)
was in $showPanels, which varies with the sticky/once panel cookies, so
the bundle a browser cached decided whether they were there: with the
Dumps Recorder switched on after a page had cached a bundle without it,
the panel never polled. They are now always in the bundle, which is the
same for every panel selection, and dumps-polling.js only polls when the
Dumps Recorder panel is in the bar.
Since the font-awesome check no longer depends on $showPanels, the
count($this->data['customPWInfoPanelLinks']) in it runs for every user
without File Editor access, and count() throws a TypeError on PHP 8 if a
cleared setting was saved as ''.
tracyConsoleErrorHandler skipped suppressed errors with
error_reporting() === 0, but since PHP 8 the @ operator lowers
error_reporting() to the fatal levels instead of 0, so every suppressed
warning in Console code (and inside libraries it calls, e.g. Tracy's
@http_response_code()) was shown as a red error block and logged. It now
tests the error's own level against error_reporting(), as TD's dump
error handler already does.
…ing every animation frame

Several scripts waited for an element by calling requestAnimationFrame
until it appeared, and some never appear: on every page with the bar,
bsZIndex (waiting for a BlueScreen) and the File Editor's
initializeEditor (waiting for its panel to be opened) ran 60 times a
second for as long as the page was open, and a panel popped out into
its own window ran seven such loops, since it has no bar.

main.js adds tracyDebuggerOnBar() and tracyDebuggerOnPanelInit(), which
run callbacks after Tracy.Debug.init and DebugPanel.prototype.init (also
if they throw partway). The hide link, the logo changes, the Dumps
Recorder state clean-up, dumps polling and the File Editor's recently
opened list use them; the show button gets its click handler when it is
created; and the BlueScreen's z-index is a CSS rule, so it applies to
every BlueScreen rather than the first one. Measured on pwtest: 0 loops
on a page (was 2) and in a popup (was 7).
…write

The clean-up deleted any bar-*.js older than a day, including a variant
still in use whose file was written long ago, so a concurrent bundle
request could build without TracyDebugger's bar JS and browsers would
cache that. A file in use is now written again at most hourly, which
keeps its mtime recent, so only variants nothing has asked for in a day
are removed. A failed write (unwritable cache dir, full disk) removes its
.tmp file, logs an error and returns null, and the caller then adds no
file rather than one Tracy can't read.
Tracy reads Debugger::$customJsFiles only when it serves the bar bundle,
but every page view with the bar hashed TracyDebugger's bar JS and
checked (sometimes wrote) its cache file.
…rors in scream mode

tracyConsoleShutdownHandler still returned early on the pre-PHP-8
error_reporting() === 0 check, which on PHP 7 hid a fatal error raised
inside an @ expression; a fatal error is now always reported. And the
error handler's @ check now gives way to Tracy's scream mode
(forceScream), whose purpose is to show those errors.
@adrianbj
adrianbj merged commit 9ce65a1 into master Oct 22, 2026
@adrianbj
adrianbj deleted the tracy-depatch branch October 22, 2026 22:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant