Skip to content

feat(stacktrace): conditional stack capture (WrapIf/HereIf) (#40) - #52

Merged
denisvmedia merged 2 commits into
masterfrom
feat/stacktrace-conditional-capture-40
Jul 13, 2026
Merged

denisvmedia merged 2 commits into
masterfrom
feat/stacktrace-conditional-capture-40

Conversation

@denisvmedia

@denisvmedia denisvmedia commented Jul 13, 2026

Copy link
Copy Markdown
Member

Description

Adds conditional stack capture APIs to the stacktrace package. When an error chain already contains a trace, these helpers skip redundant capture while still wrapping or classifying the error.

Type of Change

  • New feature (non-breaking change that adds functionality)

Related Issues

Fixes #40

Changes Made

  • Add HasTrace(err) bool for efficient trace presence checks
  • Add HereIf / HereIfDepth — no-op Classified when a trace already exists
  • Add WrapIf / WrapIfDepth — wrap without redundant stack capture
  • Add ClassifyIf / ClassifyIfDepth — classify without redundant stack capture
  • Fix collectFrom so empty Tracer frames do not count as having a trace
  • Add 19 tests and 2 examples (ExampleWrapIf, ExampleHereIf)
  • Update CHANGELOG

Testing

Test Coverage

  • All new code is covered by tests
  • All existing tests pass (go test ./...)
  • Tests pass with race detector (go test -race ./...)

Manual Testing

  • Verified examples compile and run (go test -run Example)
  • golangci-lint run ./... — 0 issues

Documentation

  • Code is documented with godoc comments
  • CHANGELOG updated
  • Examples added/updated (if applicable)

Code Quality

  • Code follows the project's style guidelines
  • golangci-lint passes (golangci-lint run)
  • go vet passes
  • go fmt has been run
  • No new warnings introduced

Breaking Changes

Does this PR introduce breaking changes?

  • No

Performance Impact

  • Performance improvement (include benchmarks)

HasTrace uses early-exit traversal (presenceOnly) to avoid collecting full traces when only checking presence. *If variants skip runtime.Callers when a trace is already present.

Additional Notes

Closes #40

Summary by CodeRabbit

  • New Features

    • Added conditional stack-trace helpers that capture traces only when an error does not already contain one.
    • Added conditional variants for attaching, wrapping, and classifying errors, including depth-limited options.
    • Added a trace-presence check that works across wrapped and joined errors.
    • Prevented duplicate traces during layered error handling while preserving existing classifications.
  • Documentation

    • Added usage examples and documented the new conditional stack-capture APIs.

Add HereIf/HereIfDepth, WrapIf/WrapIfDepth, ClassifyIf/ClassifyIfDepth,
and HasTrace so layered wrapping skips duplicate stack traces when the
cause chain already carries one. Includes early-exit trace presence
detection, examples, tests, and CHANGELOG entry.

Closes #40
Copilot AI review requested due to automatic review settings July 13, 2026 19:02

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@denisvmedia, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 16 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 610f2f8e-c839-496d-a131-cbf21e54729e

📥 Commits

Reviewing files that changed from the base of the PR and between d2a773c and 29a1336.

📒 Files selected for processing (2)
  • stacktrace/stacktrace.go
  • stacktrace/stacktrace_test.go
📝 Walkthrough

Walkthrough

The stacktrace package adds conditional trace detection and capture APIs, depth-aware variants, examples, changelog entries, and tests covering wrapped, external, and joined error chains.

Changes

Conditional stack capture

Layer / File(s) Summary
Trace detection and conditional capture internals
stacktrace/stacktrace.go
Trace walking detects non-empty traces across wrapped and joined errors, enabling conditional capture and the no-trace classification marker.
Conditional stacktrace APIs and examples
stacktrace/stacktrace.go, stacktrace/example_test.go, CHANGELOG.md
HereIf, WrapIf, and ClassifyIf variants conditionally attach traces, support depth limits, preserve classifications, and are documented with examples.
Conditional behavior test coverage
stacktrace/stacktrace_test.go
Tests cover capture and skip behavior, depth limits, nil causes, classification preservation, external tracers, and multi-error joins.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant WrapIf
  participant HasTrace
  participant ErrorChain
  Caller->>WrapIf: provide cause and message
  WrapIf->>HasTrace: inspect cause
  HasTrace->>ErrorChain: walk wrapped or joined errors
  ErrorChain-->>HasTrace: trace frames or no trace
  alt no trace present
    WrapIf-->>Caller: wrapped error with captured trace
  else trace present
    WrapIf-->>Caller: wrapped error without duplicate trace
  end
Loading

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main feature: conditional stack capture in stacktrace with WrapIf and HereIf.
Description check ✅ Passed The description matches the template well, covering change summary, issue link, testing, documentation, quality, and impact.
Linked Issues check ✅ Passed The PR implements the requested opt-in conditional stack capture behavior for HereIf and WrapIf, plus depth-aware variants.
Out of Scope Changes check ✅ Passed The changes are focused on the stacktrace feature, tests, examples, and changelog, with no obvious unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/stacktrace-conditional-capture-40

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
stacktrace/stacktrace_test.go (1)

195-206: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a top-frame identity check to catch the suspected skip-depth issue.

This test only bounds frame count; it wouldn't detect if WrapIfDepth's captured trace starts inside wrapIfDepth/captureTraceUnlessPresent rather than at the real caller (see the skip-depth concern raised on stacktrace.go lines 201-206/477-520). Consider asserting frames[0].Function matches the test function, mirroring ExampleHere's Top frame: ...ExampleHere check in stacktrace/example_test.go.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@stacktrace/stacktrace_test.go` around lines 195 - 206, Strengthen
TestWrapIfDepthCapturesWhenAbsent by asserting the first extracted frame
identifies TestWrapIfDepthCapturesWhenAbsent. Add the check after confirming
frames are non-nil, preserving the existing maximum-frame-count assertion and
failing with the observed function name when the captured trace starts inside
WrapIfDepth or captureTraceUnlessPresent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@stacktrace/stacktrace_test.go`:
- Around line 195-206: Strengthen TestWrapIfDepthCapturesWhenAbsent by asserting
the first extracted frame identifies TestWrapIfDepthCapturesWhenAbsent. Add the
check after confirming frames are non-nil, preserving the existing
maximum-frame-count assertion and failing with the observed function name when
the captured trace starts inside WrapIfDepth or captureTraceUnlessPresent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bd2fd452-d5d5-4797-9ded-8d10aa465f28

📥 Commits

Reviewing files that changed from the base of the PR and between 731872e and d2a773c.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • stacktrace/example_test.go
  • stacktrace/stacktrace.go
  • stacktrace/stacktrace_test.go

WrapIf/ClassifyIf captured traces starting inside internal helpers
instead of the real caller. Use skip=4 to match Wrap()'s effective
caller depth.

Add top-frame identity checks to *If depth tests so a wrong skip
depth is caught immediately.
Copilot AI review requested due to automatic review settings July 13, 2026 19:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@denisvmedia
denisvmedia added this pull request to the merge queue Jul 13, 2026
Merged via the queue into master with commit 9e56167 Jul 13, 2026
4 checks passed
@denisvmedia
denisvmedia deleted the feat/stacktrace-conditional-capture-40 branch July 13, 2026 19:47
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.

Proposal: conditional stack capture (capture a trace only if absent)

2 participants