Trim shared frames from error cause backtraces - #1559
Conversation
|
Hi @unflxw, We've found some issues with your Pull Request.
|
d18f046 to
6019d2a
Compare
There was a problem hiding this comment.
Pull request overview
This PR reduces the size of appsignal.error_causes payloads in collector mode by trimming each cause鈥檚 backtrace to remove the suffix shared with the reported error鈥檚 backtrace, preventing the collector鈥檚 20,000-character attribute limit from truncating the JSON and dropping the entire cause chain.
Changes:
- Trim shared trailing frames from each cause backtrace before serializing
appsignal.error_causes. - Add spec coverage for shared-tail trimming behavior, including edge cases (full overlap, no overlap, missing backtraces).
- Add a patch changeset describing the restored visibility of error causes in collector mode.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| lib/appsignal/transaction/opentelemetry_backend.rb | Introduces lines_without_shared_tail and applies it when serializing error causes to avoid duplicating shared backtrace tails. |
| spec/lib/appsignal/transaction/opentelemetry_backend_spec.rb | Adds test cases validating the trimming logic across overlap and nil/empty backtrace scenarios. |
| .changesets/show-error-causes-in-collector-mode.md | Documents the fix as a patch release item for collector-mode error causes display. |
馃挕 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
2fac3f6 to
7f89e5a
Compare
7f89e5a to
fb1c1a0
Compare
|
Rebased onto The two commits applied without conflicts, and the full test suite passes on the new base. I also dropped the changeset here. The collector mode work is staying under the single changeset on This still needs a human review, which is why it was not included in the batch that just landed. |
|
Hi @unflxw, We've found new issues for this Pull Request. Please see the main comment on this issue for a list of all current warnings. This comment will not be updated to reflect resolved warnings.
|
This comment has been minimized.
This comment has been minimized.
5 similar comments
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This is a message from the daily scheduled checks. |
In collector mode, an error's causes are sent as one JSON span-event attribute, `appsignal.error_causes`, and each cause carried its full backtrace. A cause is raised inside the frames that led to the reported error, so its backtrace ends with the same lines as the reported error's own backtrace. For a web request that shared tail is the whole framework and web server stack, and it was repeated for every cause. In a measured three-deep cause chain from a Rails controller action, 88 of each cause's 92 lines were a verbatim repeat, and the attribute came to 21,080 characters. The AppSignal Collector caps a span-event attribute value at 20,000 characters. When it truncates, the JSON is no longer valid, so the collector could not read the causes and dropped the whole chain. Nothing was shown under the error's causes in the trace. Drop from each cause's backtrace the trailing lines it shares with the reported error's backtrace. Those lines are already sent once, in `exception.stacktrace`. What is left is where the cause was raised, which is the part worth showing. On the measured payload this brings the attribute down to about 904 characters. If a cause shares every line, its first line is kept, because a cause with no lines leaves nothing to show.
Each error cause in `appsignal.error_causes` no longer carries the trailing backtrace lines it shares with the reported error's own backtrace. A consumer of the attribute could not tell that lines were left out, or how many of them there were. Add a `lines_omitted` key to each cause, holding the number of trailing lines that were dropped for that cause. The AppSignal Processor uses the count to add a line reading "[88 repeated lines omitted]" to the end of the cause's backtrace, so the trace shows how much is missing. The count is the number of lines actually removed. When a cause shares every line with the reported error, its first line is kept, so that kept line does not count as removed. The key is left out entirely when nothing was dropped, because a consumer reads a missing key as zero.
fb1c1a0 to
e13e18c
Compare
See also https://github.com/appsignal/appsignal-processor-rs/pull/2236 for the change to the processor that does something with the omitted lines attribute.
Trim shared frames from error cause backtraces
In collector mode, an error's causes are sent as one JSON span-event
attribute,
appsignal.error_causes, and each cause carried its fullbacktrace.
A cause is raised inside the frames that led to the reported error, so
its backtrace ends with the same lines as the reported error's own
backtrace. For a web request that shared tail is the whole framework
and web server stack, and it was repeated for every cause. In a
measured three-deep cause chain from a Rails controller action, 88 of
each cause's 92 lines were a verbatim repeat, and the attribute came
to 21,080 characters.
The AppSignal Collector caps a span-event attribute value at 20,000
characters. When it truncates, the JSON is no longer valid, so the
collector could not read the causes and dropped the whole chain.
Nothing was shown under the error's causes in the trace.
Drop from each cause's backtrace the trailing lines it shares with the
reported error's backtrace. Those lines are already sent once, in
exception.stacktrace. What is left is where the cause was raised,which is the part worth showing. On the measured payload this brings
the attribute down to about 904 characters. If a cause shares every
line, its first line is kept, because a cause with no lines leaves
nothing to show.
Report how many cause lines were omitted
Each error cause in
appsignal.error_causesno longer carries thetrailing backtrace lines it shares with the reported error's own
backtrace. A consumer of the attribute could not tell that lines were
left out, or how many of them there were.
Add a
lines_omittedkey to each cause, holding the number of trailinglines that were dropped for that cause. The AppSignal Processor uses
the count to add a line reading "[88 repeated lines omitted]" to the
end of the cause's backtrace, so the trace shows how much is missing.
The count is the number of lines actually removed. When a cause shares
every line with the reported error, its first line is kept, so that
kept line does not count as removed. The key is left out entirely when
nothing was dropped, because a consumer reads a missing key as zero.