feat: Add debug output to MaxRecursionDepthError when debug header is set#3070
feat: Add debug output to MaxRecursionDepthError when debug header is set#3070tstirrat15 merged 13 commits intomainfrom
Conversation
f710fda to
301e035
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #3070 +/- ##
===========================================
+ Coverage 50.15% 75.49% +25.34%
===========================================
Files 460 488 +28
Lines 57073 59629 +2556
===========================================
+ Hits 28618 45008 +16390
+ Misses 25305 11329 -13976
- Partials 3150 3292 +142 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
27a7069 to
3af61b7
Compare
3af61b7 to
157d239
Compare
There was a problem hiding this comment.
Please include in the testing section of the PR description:
- the schema + relationships that would produce a cycle.
- the CURL requests we can use to test out the thing e2e for LR and LS.
With this command and this data (plus another rel group:secondgroup#member@user:maria), I get an error as expected (400), but I don't get any debug info. Can you look into why it doesn't work with http?
curl --location --request POST 'http://localhost:8443/v1/permissions/resources' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'io.spicedb.requestdebuginfo: true' \
--header 'Authorization: Bearer super-secret-key' \
--data '{
"resourceObjectType": "resource",
"permission": "view",
"subject": {
"object": {
"objectType": "user",
"objectId": "maria"
}
}
}'
f0d3fd9 to
109bd9e
Compare
c0b79ee to
8f50a91
Compare
| debugInfo := &dispatch.LookupDebugInfo{} | ||
| req.NoError(prototext.Unmarshal([]byte(traceStr), debugInfo), "trace must parse as LookupDebugTrace") | ||
| req.Len(debugInfo.CycleMembers, 1, "there should be one cycle member found at the final depth") | ||
| // NOTE: this value will change if the max recursion depth changes, since that determines |
| // We'll only attach debug info if cyclemembers is non-empty. Otherwise we're | ||
| // in a normal recursion-too-deep scenario and the debuginfo doesn't help. | ||
| if len(debugInfo.CycleMembers) > 0 { | ||
| logging.Warn().Strs("cycle-members", debugInfo.CycleMembers).Msg("The following resource/relation pairs were found in a cycle in LookupResources:") |
There was a problem hiding this comment.
I don't think our logging is currently set up for that - we'd need to pass the event through the tree in a way that we don't currently do. It's why I opted to make it a warn instead of an info.
There was a problem hiding this comment.
OK, in that case, i think i'd also add a span attribute or a span event to the ongoing span indicating that a cycle was found. But can be done in a followup.
miparnisari
left a comment
There was a problem hiding this comment.
LGTM but you gotta fix conflicts
…ubjects Fixes #2056 - Add LookupDebugTrace proto message to all 3 Lookup dispatch responses - Add enable_debug_trace bool to all 3 Lookup dispatch requests - Add internal/graph/debug.go with zero-cost traversalTracker - Wire trackVisit in lookupresources2.go, lookupresources3.go, lookupsubjects.go - Wire debug trace enable via requestmeta header in permissions.go - Add unit tests in internal/graph/cycle_detection_test.go - Add integration tests in internal/dispatch/graph/cycle_detection_test.go
- remove all trailer-based debug tracing (responsemeta, SerializeLookupDebugTrace) - fix streaming logic (buffer lastResp, no double send) - attach DebugInformationV2 only on final streamed response - update tests to validate DebugInformationV2 instead of trailers - clean up unused imports and legacy code Note: build errors expected until authzed/api and authzed-go updates land
- add root node to DebugTree for clearer traversal structure - ensure stable node identifiers for debug annotations - minor test validation improvement - no behavioral changes
- replace traversal map with stack-based trace - capture per-edge traversal frames (resource, relation, permission) - emit trace on MaxRecursionDepthExceeded when debug is enabled - ensure concurrency safety via CloneTraversalStack - remove batch-based sampling and fix incorrect traversal representation - update tests for stack-based validation Note: current implementation prioritizes trace correctness over batching by splitting dispatches per ID. This may introduce additional overhead and can be optimized in a follow-up by preserving batching while maintaining per-edge trace accuracy.
Co-authored-by: Maria Ines Parnisari <maria.ines.parnisari@authzed.com>
78f6883 to
b3baf82
Compare

Description
Opening as an alternative/continuation to #3036. This takes a slightly different approach, which is to wait until a max depth error is encountered and then build the trace as the dispatch stack is unwound. It tracks across dispatch boundaries as well.
Notes
This code is a no-op if the request flag isn't present or if a max recursion depth error isn't encountered.
Changes
Will annotate.
Testing
Review. See that tests pass. See authzed/zed#682 and its testing section for an example of code that drives this.