Repository navigation
feat(xdebug-trace): HTTP upload, trace files on disk, tree/search/summary API - #410
Merged
Merged
Conversation
…to feat/xdebug-trace-storage
…mary API
New module xdebug-trace. POST with X-Buggregator-Event: xdebug-trace
(or xdebug-trace@host) streams the body to <uuid>.xt[.gz] in the trace
dir and summarizes it in the same pass; the trace is never held whole
in memory. Format other than trace_format=1 -> 400 with the hint.
Limits xdebug_trace.max_upload (100MB), max_size (256MB unpacked, cut
there), keep (20, oldest unpinned deleted first); env XDEBUG_TRACE_*.
Files live under storage.path/xdebug-traces in filesystem mode, in a
temp dir removed at exit otherwise. SQLite keeps the event with the
summary; the call index goes to <uuid>.idx.json. Deleting or clearing
events removes the files (EventDeleteListener); startup removes files
no event refers to.
API (behind auth): /api/xdebug-traces/{uuid}/summary, /tree
(parent=, from=, limit=: one level of calls with incl/self/memory,
args and return values clipped), /search (q=, from=, limit=).
…h results carry caller path Xdebug writes the R line after the call's exit. Search dropped a match on its exit and Children stopped at the parent's exit, so their return values were lost; both now take the next record's R. Search nodes get path (callers from the top level down) so the UI can open the tree to a hit; the scan starts at the beginning also for from. Startup sweep also drops trace events whose file is gone.
Such a trace starts at the caller's real depth (e.g. level 3) and later goes up to level 2. The top level is now the calls that start while no listed call is open, not level 1, and search paths are a stack popped by call number. from= keeps the list it pages: pass the same parent.
This was referenced Nov 8, 2026
…UI menu The frontend has the trace page (frontend #337), so settings now name the module and the UI shows it.
…rted as cut in tree and search Recorded live traces: xdebug_stop_trace() and its caller never get an exit line. With TRACE END present those open calls are not a cut; Summarize already treated it so.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #407 (base
feat/xdebug-trace-parser; retarget tomasteronce #407 lands). Part of #288.What
New module
xdebug-trace: upload an Xdebug function trace (xdebug.trace_format=1, plain or.gz) over HTTP and browse it without loading it whole.<uuid>.xt[.gz](kept as sent) and summarizes it in the same pass (io.TeeReader→Summarize). Another format → 400 with thetrace_format=1hint; nothing left on disk.xdebug_trace.max_upload(100MB),max_size(256MB unpacked; a longer trace is cut there and markedtruncated),keep(20; storing one more deletes the oldest unpinned). EnvXDEBUG_TRACE_MAX_UPLOAD,XDEBUG_TRACE_MAX_SIZE,XDEBUG_TRACE_KEEP. Module flagmodules.xdebug-trace(on by default).storage.path/xdebug-tracesin filesystem mode, a temp dir removed at exit otherwise. SQLite keeps the event and its summary; the call index goes to<uuid>.idx.json, so event payloads stay small. Delete / clear-all remove the files viaEventDeleteListener(fix: remove attachment files when events are deleted or cleared #408); startup removes files no event refers to.GET /api/xdebug-traces/{uuid}/summary— summary + index.GET /api/xdebug-traces/{uuid}/tree?parent=&from=&limit=— one level of calls: top level, callees of the entry at byte offsetparent, or the next page (from= previousnext). Each node: incl/self time, memory delta, args and return value (clipped to 512 B, 20 args), direct callee count,offset.GET /api/xdebug-traces/{uuid}/search?q=&from=&limit=— calls whose function or file containsq.buggregator.yaml.exampledocuments the section.Frontend (card + page) and MCP tools come in follow-ups.
EnabledTypes()does not listxdebug-traceyet, so the UI menu does not change until the frontend has a page for it.Tests
modules/xdebugtrace:TestChildren,TestChildren_BadOffset,TestChildren_CutTrace,TestSearch,TestClip,TestModule_UploadAndAPI,TestModule_IndexAndPaging(2500 callees paged through the API),TestModule_RejectsAndLeavesNoFiles,TestModule_MaxSizeCutsTheSummary,TestModule_KeepsTheNewest(pinned stays),TestModule_SweepRemovesOrphans.internal/app:TestParseSize,TestModulesConfig_XdebugTrace.go test -race -count=1onmodules/xdebugtrace,internal/app,internal/storage,internal/module,internal/server/http,modules/smtp,modules/httpdumps: ok.go vetclean.DELETE /api/event/{uuid}→ files gone; memory mode — temp dir removed on SIGTERM.Checked on the traces recorded by a live Xdebug (#407):
TestRecorded_MainTree(13 callees of {main}, closure, search paging 25 fib calls by 10, each match's path) andTestRecorded_MidTree. The live trace found one bug, fixed in cf42363:xdebug_stop_trace()and its caller never get an exit line, so tree and search reported every stopped trace as cut; with TRACE END present they no longer do (Summarize already did so). Live: both files uploaded to the built binary over HTTP; tree/search answers match the tests.Made with harnsy