feat: add symbolication support for 7 platforms#11
Conversation
Add stack trace symbolication support for 7 platforms: - Android: ProGuard/R8 mapping.txt parsing - JavaScript/Electron: source map support - Flutter/Dart: flutter symbolize integration - Rust: backtrace parsing - Go: goroutine stack parsing - Python: traceback parsing - React Native: Hermes bytecode + JS source maps Includes MappingStore for organizing mapping files by platform/app_id/version directory structure. Closes #10 Signed-off-by: alltheseas Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add `bugstr symbolicate` command for symbolicating stack traces: - Reads from file or stdin - Supports all 7 platforms (android, electron, flutter, rust, go, python, react-native) - Pretty and JSON output formats - Uses mapping files from configurable directory Usage: bugstr symbolicate -P python -i stack.txt echo "traceback..." | bugstr symbolicate -P go --format json Signed-off-by: alltheseas Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add POST /api/symbolicate endpoint for dashboard integration: - Accepts stack trace with platform, app_id, version, build_id - Returns symbolicated frames with function, file, line info - Returns 503 if symbolication not configured Add --mappings option to `bugstr serve`: - Configures mapping files directory for symbolication - Creates Symbolicator and passes to AppState - Displays mappings path in startup banner Signed-off-by: alltheseas Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document symbolication feature and initial release notes. Signed-off-by: alltheseas Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughAdds a multi-platform symbolication subsystem: platform-specific symbolicators, an on-disk MappingStore with fallback logic, CLI Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant CLI as "bugstr CLI"
participant Store as "MappingStore"
participant Sym as "Symbolicator"
participant Formatter as "Output Formatter"
User->>CLI: bugstr symbolicate --platform ... --mappings ...
CLI->>Store: scan(mappings_dir)
Store-->>CLI: mappings_loaded
CLI->>Sym: Symbolicator::new(Store)
CLI->>Sym: symbolicate(stack, context)
Sym->>Store: get(platform, app_id, version)
Store-->>Sym: MappingInfo?
Sym->>Sym: dispatch to platform-specific symbolicator
Sym-->>CLI: SymbolicatedStack
CLI->>Formatter: format(result, Pretty|Json)
Formatter-->>User: output
sequenceDiagram
participant Client
participant Web as "Web Server"
participant AppState
participant Sym as "Symbolicator"
participant Store as "MappingStore"
Client->>Web: POST /api/symbolicate {platform, stack, app_id, version}
Web->>AppState: check symbolicator
alt symbolicator configured
AppState-->>Web: Some(Symbolicator)
Web->>Sym: symbolicate(stack, context)
Sym->>Store: get_with_fallback(platform, app_id, version)
Store-->>Sym: MappingInfo?
Sym->>Sym: platform dispatch & parse/deobfuscate
Sym-->>Web: SymbolicatedStack
Web-->>Client: 200 {frames, counts}
else not configured
AppState-->>Web: None
Web-->>Client: 503 Service Unavailable
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~70 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧹 Recent nitpick comments
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (7)
✅ Files skipped from review due to trivial changes (1)
🧰 Additional context used📓 Path-based instructions (4)**/CHANGELOG.md📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{kt,dart,ts,tsx,rs,go,py}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{kt,ts,tsx,dart,rs,go,py}📄 CodeRabbit inference engine (AGENTS.md)
Files:
rust/**/*.rs📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (3)📚 Learning: 2026-01-16T15:49:11.199ZApplied to files:
📚 Learning: 2026-01-16T15:49:11.199ZApplied to files:
📚 Learning: 2026-01-16T15:49:11.199ZApplied to files:
🧬 Code graph analysis (3)rust/src/bin/main.rs (5)
rust/src/symbolication/android.rs (6)
rust/src/symbolication/store.rs (1)
🔇 Additional comments (23)
✏️ Tip: You can disable this entire section by setting 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 20
🤖 Fix all issues with AI agents
In `@rust/CHANGELOG.md`:
- Around line 8-34: Update the changelog sections under the headings "##
[Unreleased]" and "## [0.1.0] - 2025-01-15" to include "Changed" and "Fixed"
subsections in addition to the existing "Added" lists; for each section add "###
Changed" and "### Fixed" headings and list any relevant entries or the word
"None" if there are no changes/fixes to report so the file follows the required
Added/Changed/Fixed format.
In `@rust/src/bin/main.rs`:
- Around line 308-312: The MappingStore created in the serve path (mappings_dir
-> MappingStore::new) never calls scan(), so Symbolicator::new(store) is
constructed with no mappings; update the block that builds the symbolicator to
call store.scan() (and await/handle the Result if async) before passing the
store into Symbolicator::new, and propagate or log any error appropriately so
mappings are actually loaded for the web server.
- Around line 223-225: The MappingStore is instantiated with
MappingStore::new(mappings_dir) but scan() is never invoked, so mappings are not
loaded; after creating store (the MappingStore::new call) call store.scan() and
handle its Result (e.g., propagate the error with ? or log and exit) before
constructing Symbolicator::new(store) so the symbolicator receives a populated
store; ensure you call store.scan() in the same scope where store is created and
handle any errors appropriately.
In `@rust/src/symbolication/android.rs`:
- Around line 92-116: The current code in the method_re capture block
incorrectly stores (start_line, end_line, start_line, end_line) into
MethodMapping.line_mapping; replace that with a representation that marks
obfuscated line ranges as unknown and stores only the original source range
(e.g. push (0, 0, start_line, end_line) or otherwise change the tuple order to
(obf_start, obf_end, orig_start, orig_end)); then update the deobfuscate_frame
logic to recognize an obfuscated range of 0 as "unknown" and fall back to
matching the incoming line against the stored original range (or otherwise
handle lack of obfuscated ranges). Modify usages of MethodMapping.line_mapping,
method_re parsing block, and deobfuscate_frame to consistently treat the first
two tuple fields as obfuscated ranges (possibly 0 when unavailable) and the last
two as original ranges.
In `@rust/src/symbolication/flutter.rs`:
- Around line 15-34: Update the public rustdoc for the FlutterSymbolicator
struct and its public methods (FlutterSymbolicator, new, symbolicate) to include
explicit descriptions of parameters (e.g., store: &MappingStore, stack_trace:
&str, context: &SymbolicationContext), the return type
(Result<SymbolicatedStack, SymbolicationError>), and the possible error cases
(what triggers SymbolicationError and when fallbacks occur). Add brief examples
showing how to construct a FlutterSymbolicator via FlutterSymbolicator::new and
call symbolicate, and document the behavior (uses `flutter symbolize` if
available, otherwise falls back to mapping parsing) and any panics/side-effects.
Ensure each public item has a short one-line summary followed by sections for
Arguments, Returns, Errors, and an optional Example.
- Around line 59-73: The current symbolicate() implementation in
rust/src/symbolication/flutter.rs writes to a fixed temp filename and unwraps
path UTF-8, causing race/symlink risks and panics; replace the fixed temp file
with tempfile::NamedTempFile (move tempfile from dev-dependencies to
[dependencies]) to create a unique temp file and let it be cleaned up, write the
stack_trace into that file, and pass the file path to Command by using .arg(...)
with the OsStr/Path (avoid to_str().unwrap()) so invalid UTF-8 won’t panic; also
add documentation comments to the public symbolicate() signature describing
parameters, return value, and possible errors.
In `@rust/src/symbolication/go.rs`:
- Around line 12-31: The public GoSymbolicator API lacks comprehensive rustdoc;
update the doc comments for the struct GoSymbolicator<'a> and its associated
methods (new and symbolicate) to include parameter descriptions (e.g., store:
&MappingStore, stack_trace: &str, context: &SymbolicationContext), the return
type details (SymbolicatedStack) and all error cases returned as
SymbolicationError, plus usage examples demonstrating typical invocation and
expected output; ensure you document lifetime semantics for 'a, explain what
MappingStore provides, describe side effects/constraints, and include code
examples and links to related types like SymbolicationContext and
SymbolicatedStack per project doc guidelines.
- Around line 54-88: The func_re regex doesn't match Go pointer-receiver names
like main.(*Type).Method; update the func_re used in the parsing loop (the Regex
assigned to func_re and its captures usage) to allow any characters (including
parentheses, asterisks and dots) in the function name portion (e.g., use a
pattern that captures "any chars" for the name and then the argument list), trim
surrounding whitespace from the captured name and args before assigning to
current_function/current_args, and keep the existing logic that saves a previous
frame into frames (SymbolicatedFrame creation) when current_function is taken.
In `@rust/src/symbolication/javascript.rs`:
- Around line 15-31: Add comprehensive rustdoc for the public
JavaScriptSymbolicator API: document the struct JavaScriptSymbolicator and its
methods (especially fn new and fn symbolicate) including descriptions of
parameters (store: &MappingStore, stack_trace: &str, context:
&SymbolicationContext), the return type (Result<SymbolicatedStack,
SymbolicationError>), all possible error cases from SymbolicationError, and
provide a short usage example showing construction via
JavaScriptSymbolicator::new and calling symbolicate; ensure docs follow project
guidelines and appear above the JavaScriptSymbolicator type and the symbolicate
method.
- Around line 54-63: The JavaScript stack frame regexes chrome_re and firefox_re
are incorrectly using ([^:]+) which stops at the first colon and breaks URLs and
Windows paths; update the Regex::new patterns for chrome_re and firefox_re to
use a non-greedy file capture like (.+?) and anchor the pattern so it matches
the file path up to the final :line:col (e.g., ensure the pattern expects
:(\d+):(\d+)$), then unwrap as before; modify the two Regex::new(...) calls
accordingly so file paths with embedded colons are captured correctly.
In `@rust/src/symbolication/python.rs`:
- Around line 13-33: Add comprehensive rustdoc comments for the public API
around PythonSymbolicator, including the struct, its constructor new(), and the
symbolicate() method: describe the purpose and behavior of PythonSymbolicator,
document parameters (store: &MappingStore for new; stack_trace: &str and
context: &SymbolicationContext for symbolicate), the return type
(Result<SymbolicatedStack, SymbolicationError>), list possible error cases
(SymbolicationError variants) and any side-effects, and include a short usage
example showing creating a PythonSymbolicator via new() and calling
symbolicate(); ensure docs follow project style (purpose, behavior, params,
returns, errors, example) and are placed above the struct and each public
method.
- Around line 24-41: The code fetches mapping info into _mapping_info in
symbolicate but never applies it, so bundled-app paths aren't resolved; either
use the mapping or remove the doc claim. Fix by retrieving the mapping result
from store.get_with_fallback (store in a named variable like mapping_info), then
thread it into the Python traceback processing: update parse_python_traceback to
accept an Option<MappingType> (or a reference) and apply path transformations to
each frame file path, or if you don't want to implement mapping, update the
symbolicate docstring to remove the "attempts to resolve bundled app paths"
claim; key symbols: symbolicate, parse_python_traceback, get_with_fallback, and
mapping_info.
- Around line 57-60: The exception_re currently matches any capitalized word and
so incorrectly captures the "Traceback ..." header; update the Regex used for
exception_re to only match a valid Python exception identifier (starts with a
letter or underscore, followed by letters, digits, underscores or dots) and
require a literal colon separator before the message (i.e., exception name
followed by ':' then optional whitespace and the message) so that only real
exception lines are parsed into frames.
In `@rust/src/symbolication/react_native.rs`:
- Around line 15-36: Add comprehensive rustdoc to the public
ReactNativeSymbolicator API: document the struct and its methods
(ReactNativeSymbolicator::new and ReactNativeSymbolicator::symbolicate)
including parameter descriptions (store: &MappingStore, stack_trace: &str,
context: &SymbolicationContext), return type (Result<SymbolicatedStack,
SymbolicationError>), all possible error cases produced by symbolicate, and
expected behavior for different frame types (JS, native, Hermes). Include a
short usage example showing construction via ReactNativeSymbolicator::new and
calling symbolicate, and note thread-safety or lifetime considerations tied to
the 'a lifetime if relevant. Ensure docs follow rustdoc conventions (///) and
mention when callers should handle or propagate SymbolicationError.
- Around line 85-133: The JS/Hermes parsing branch currently discards the parsed
file path (stored as _file) when no source-map token is found; update the
unsymbolicated fallback in the js_frame_re handling to preserve that parsed path
by mapping the parsed file (the variable _file produced alongside function,
line_num and col_num) into the SymbolicatedFrame's file field (e.g., file:
_file.map(|s| s.to_string())) instead of None, leaving the rest of the fields
and behavior (function, line, column, symbolicated: false) unchanged so it
matches how native Android frames retain file info.
- Around line 66-68: The regex in react_native.rs (js_frame_re) incorrectly uses
([^:]+) which stops at the first colon and breaks on URLs and Windows paths;
update the pattern to use (.+?) for the source capture and add an end-of-line
anchor ($) so it non-greedily captures up to the final :line:column sequence
(i.e., change the group for the file to (.+?) and append $ to the regex), then
update/add tests that exercise React Native frames with URLs (e.g.,
http://example.com:1:2345) and Windows/file:///C:/... paths to verify correct
parsing.
In `@rust/src/symbolication/rust_sym.rs`:
- Around line 12-32: Update the rustdoc for the public RustSymbolicator API:
expand the doc comment on the RustSymbolicator struct and its public methods
new() and symbolicate() to include parameter descriptions (e.g., explain the
store field and the parameters stack_trace: &str and context:
&SymbolicationContext), the return value (Result<SymbolicatedStack,
SymbolicationError>), the error conditions that may produce SymbolicationError,
and at least one short usage example showing constructing
RustSymbolicator::new(&store) and calling symbolicate(stack_trace, &context);
keep docs concise, follow project style (sections: Arguments, Returns, Errors,
Examples), and mention any relevant lifetime or thread-safety considerations for
the store reference.
- Around line 23-50: The docstring for symbolicate claims addr2line lookup for
stripped binaries but parse_rust_backtrace currently ignores the _symbols_path
and never uses mapping_info; either implement addr2line-based resolution or
change the docs. To fix: either (A) implement symbol resolution in
parse_rust_backtrace using the provided _symbols_path/mapping_info (call
addr2line or use gimli/addr2line crates to open the debug file and resolve
addresses found in stack_trace) and wire mapping_info.path from symbolicate into
parse_rust_backtrace, or (B) update the symbolicate docstring to remove the
claim about addr2line and state that only backtraces containing source info are
parsed; reference functions/vars: symbolicate, parse_rust_backtrace,
mapping_info, _symbols_path, store.get_with_fallback, and SymbolicationContext
to locate the code to change.
In `@rust/src/symbolication/store.rs`:
- Around line 205-209: The version fallback currently uses lexicographic
comparison via max_by with a.version.cmp(&b.version), which misorders semantic
versions; update the comparison to use semantic versioning (add semver = "1" to
Cargo.toml), parse versions with semver::Version::parse inside the max_by
comparator (treat parse failures as lesser than valid semver or fall back to
lexicographic), and replace the a.version.cmp(&b.version) comparator with the
semver-aware ordering so self.mappings selection returns the correct latest
semantic version.
In `@rust/src/web.rs`:
- Around line 26-29: AppState currently holds symbolicator directly
(Option<Symbolicator>) which can cause blocking in async handlers; change it to
Option<Arc<Symbolicator>> (or wrap the existing Symbolicator in Arc when
constructing AppState), then in the async handler call the blocking
symbolication via tokio::task::spawn_blocking by cloning the Arc and moving it
into spawn_blocking to call symbolicator.symbolicate(...) so all filesystem IO
and external process invocations happen off the Tokio worker threads; ensure you
clone any args needed (e.g., request data) into the closure and await the
spawn_blocking JoinHandle, converting its Result into the handler's response;
finally add unit tests for the handler (using #[tokio::test]) that exercise
success and error paths by injecting a test/mocked Symbolicator (Arc-wrapped) to
verify proper spawn_blocking behavior and error propagation.
🧹 Nitpick comments (9)
rust/src/symbolication/python.rs (1)
174-188: Add edge-case tests for headers and exception-only lines.
The test only checks a happy path. Please add cases to ensure the header line isn’t treated as an exception frame and that exceptions without messages (e.g.,KeyboardInterrupt) are parsed correctly. As per coding guidelines, edge/error cases should be covered.rust/src/symbolication/react_native.rs (1)
44-49: Surface sourcemap parse errors instead of silently ignoring.
.ok()hides invalid mappings and makes failures indistinguishable from “no map”. Consider returningParseError(consistent with JavaScriptSymbolicator) so clients can troubleshoot.♻️ Proposed refactor
- let sourcemap = if let Some(info) = mapping_info { - let content = fs::read_to_string(&info.path)?; - SourceMap::from_reader(content.as_bytes()).ok() - } else { - None - }; + let sourcemap = if let Some(info) = mapping_info { + let content = fs::read_to_string(&info.path)?; + Some( + SourceMap::from_reader(content.as_bytes()) + .map_err(|e| SymbolicationError::ParseError(e.to_string()))?, + ) + } else { + None + };rust/src/symbolication/android.rs (4)
55-63: Consider caching compiled regex patterns.These regex patterns are compiled on every call to
parse(). For better performance, consider usinglazy_static!orstd::sync::LazyLock(stable in Rust 1.80+) to compile these patterns once.♻️ Suggested optimization using LazyLock
use std::sync::LazyLock; static CLASS_RE: LazyLock<Regex> = LazyLock::new(|| { Regex::new(r"^(\S+)\s+->\s+(\S+):$").unwrap() }); static METHOD_RE: LazyLock<Regex> = LazyLock::new(|| { Regex::new(r"^\s+(\d+):(\d+):(\S+)\s+(\S+)\((.*)\)\s+->\s+(\S+)$").unwrap() }); // ... etc for other patterns
201-210: Public struct and method lack detailed documentation.Per coding guidelines, public structs and methods should have documentation explaining purpose, parameters, and behavior. Consider adding parameter documentation for
new().📝 Suggested documentation improvement
/// Android stack trace symbolicator. +/// +/// Uses ProGuard/R8 mapping files to deobfuscate Android stack traces +/// by translating obfuscated class and method names back to their originals. pub struct AndroidSymbolicator<'a> { store: &'a MappingStore, } impl<'a> AndroidSymbolicator<'a> { /// Create a new Android symbolicator. + /// + /// # Arguments + /// + /// * `store` - Reference to the mapping store containing ProGuard mapping files pub fn new(store: &'a MappingStore) -> Self { Self { store } }
244-246: Regex compiled insidesymbolicate()on each call.The
frame_repattern is compiled every timesymbolicate()is invoked. This should be moved to a static lazy initialization for better performance, especially when symbolicating multiple stack traces.
299-325: Test coverage is minimal.The test validates basic parsing but doesn't test:
- The
symbolicate()method end-to-end- Line number deobfuscation
- Edge cases (malformed input, missing mappings)
Consider adding more comprehensive tests.
rust/src/bin/main.rs (1)
213-221: Consider making unknown platform a hard error for CLI.Currently, an unknown platform prints a warning but continues. Since symbolication will likely fail or produce incorrect results for unknown platforms, consider returning an error instead to provide clearer feedback.
rust/src/symbolication/store.rs (1)
158-169: Fallback file search may return unrelated files.The fallback logic that searches for any
.map,.txt, or.symbolsfile could return an incorrect file if multiple files with these extensions exist in the directory. Consider logging a warning when using this fallback path to aid debugging.rust/src/symbolication/mod.rs (1)
91-104: Consider implementingstd::str::FromStrtrait instead of inherent method.The
from_strmethod name shadows the standardFromStrtrait convention. Implementing the trait would enable more idiomatic usage like"android".parse::<Platform>()and integration with other parsing utilities.♻️ Suggested trait implementation
+use std::str::FromStr; + +impl FromStr for Platform { + type Err = std::convert::Infallible; // Never fails, returns Unknown for unrecognized + + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(match s.to_lowercase().as_str() { + "android" => Platform::Android, + "electron" | "javascript" | "js" => Platform::Electron, + "flutter" | "dart" => Platform::Flutter, + "rust" => Platform::Rust, + "go" | "golang" => Platform::Go, + "python" => Platform::Python, + "react-native" | "reactnative" | "rn" => Platform::ReactNative, + other => Platform::Unknown(other.to_string()), + }) + } +} -impl Platform { - /// Parse platform from string. - pub fn from_str(s: &str) -> Self { - ... - }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
rust/CHANGELOG.mdrust/Cargo.tomlrust/src/bin/main.rsrust/src/lib.rsrust/src/symbolication/android.rsrust/src/symbolication/flutter.rsrust/src/symbolication/go.rsrust/src/symbolication/javascript.rsrust/src/symbolication/mod.rsrust/src/symbolication/python.rsrust/src/symbolication/react_native.rsrust/src/symbolication/rust_sym.rsrust/src/symbolication/store.rsrust/src/web.rs
🧰 Additional context used
📓 Path-based instructions (4)
rust/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
Use rustdoc format (
/// ...or//!) for docstrings in Rust code
Files:
rust/src/lib.rsrust/src/symbolication/android.rsrust/src/symbolication/javascript.rsrust/src/symbolication/flutter.rsrust/src/symbolication/python.rsrust/src/symbolication/go.rsrust/src/web.rsrust/src/symbolication/rust_sym.rsrust/src/symbolication/react_native.rsrust/src/bin/main.rsrust/src/symbolication/mod.rsrust/src/symbolication/store.rs
**/*.{kt,dart,ts,tsx,rs,go,py}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{kt,dart,ts,tsx,rs,go,py}: All public classes, methods, and non-trivial functions must have documentation explaining purpose, behavior, parameters, return values, exceptions, and usage examples for complex APIs
All code must be reviewable by human developers with clear, descriptive variable and function names, appropriate comments for non-obvious logic, and consistent formatting per language conventions
Files:
rust/src/lib.rsrust/src/symbolication/android.rsrust/src/symbolication/javascript.rsrust/src/symbolication/flutter.rsrust/src/symbolication/python.rsrust/src/symbolication/go.rsrust/src/web.rsrust/src/symbolication/rust_sym.rsrust/src/symbolication/react_native.rsrust/src/bin/main.rsrust/src/symbolication/mod.rsrust/src/symbolication/store.rs
**/*.{kt,ts,tsx,dart,rs,go,py}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{kt,ts,tsx,dart,rs,go,py}: Rumor events must includesig: ""(empty string, not omitted) for NIP-17/59 implementation
Rumor events must include computedidfield with SHA256 of serialized event in lowercase hex format (64 characters) for NIP-17/59 implementation
Event serialization order must be:[0, pubkey, created_at, kind, tags, content]for NIP-17/59 compliance
Seal events must be signed by the sender's key for NIP-17/59 implementation
Gift wrap events must be signed by an ephemeral key for NIP-17/59 implementation
All new code should have corresponding unit tests and test edge cases and error conditions
Files:
rust/src/lib.rsrust/src/symbolication/android.rsrust/src/symbolication/javascript.rsrust/src/symbolication/flutter.rsrust/src/symbolication/python.rsrust/src/symbolication/go.rsrust/src/web.rsrust/src/symbolication/rust_sym.rsrust/src/symbolication/react_native.rsrust/src/bin/main.rsrust/src/symbolication/mod.rsrust/src/symbolication/store.rs
**/CHANGELOG.md
📄 CodeRabbit inference engine (AGENTS.md)
All user-facing changes require a CHANGELOG.md entry following the specified format (Added, Changed, Fixed sections)
Files:
rust/CHANGELOG.md
🧠 Learnings (2)
📚 Learning: 2026-01-16T15:49:11.199Z
Learnt from: CR
Repo: alltheseas/bugstr PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-16T15:49:11.199Z
Learning: Applies to **/CHANGELOG.md : All user-facing changes require a CHANGELOG.md entry following the specified format (Added, Changed, Fixed sections)
Applied to files:
rust/CHANGELOG.md
📚 Learning: 2026-01-16T15:49:11.199Z
Learnt from: CR
Repo: alltheseas/bugstr PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-16T15:49:11.199Z
Learning: Applies to rust/**/*.rs : Use rustdoc format (`/// ...` or `//!`) for docstrings in Rust code
Applied to files:
rust/Cargo.toml
🧬 Code graph analysis (8)
rust/src/symbolication/flutter.rs (1)
rust/src/symbolication/mod.rs (4)
new(241-243)symbolicate(246-282)symbolicated(165-180)raw(153-162)
rust/src/symbolication/python.rs (2)
rust/src/symbolication/mod.rs (2)
new(241-243)symbolicate(246-282)rust/src/symbolication/rust_sym.rs (2)
new(19-21)symbolicate(28-43)
rust/src/symbolication/go.rs (2)
rust/src/symbolication/mod.rs (4)
new(241-243)symbolicate(246-282)frames(217-220)raw(153-162)rust/src/symbolication/store.rs (1)
new(61-66)
rust/src/web.rs (3)
rust/src/symbolication/store.rs (1)
get(175-182)rust/src/bin/main.rs (2)
symbolicate_stack(195-291)serde_json(697-697)rust/src/symbolication/mod.rs (1)
from_str(93-104)
rust/src/symbolication/rust_sym.rs (3)
rust/src/lib.rs (2)
new(96-100)path(103-105)rust/src/symbolication/mod.rs (3)
new(241-243)symbolicate(246-282)raw(153-162)rust/src/symbolication/store.rs (1)
new(61-66)
rust/src/symbolication/react_native.rs (3)
rust/src/symbolication/android.rs (2)
new(208-210)symbolicate(213-291)rust/src/symbolication/javascript.rs (2)
new(22-24)symbolicate(27-121)rust/src/symbolication/mod.rs (6)
new(241-243)symbolicate(246-282)frames(217-220)symbolicated(165-180)raw(153-162)as_str(107-118)
rust/src/bin/main.rs (6)
rust/src/compression.rs (2)
decompress_payload(83-103)map(195-197)rust/src/storage.rs (2)
parse_crash_content(231-279)serde_json(233-233)rust/src/web.rs (2)
create_router(32-50)symbolicate_stack(93-134)rust/src/lib.rs (1)
new(96-100)rust/src/event.rs (1)
new(40-56)rust/src/symbolication/mod.rs (5)
from_str(93-104)percentage(225-231)raw(153-162)frames(217-220)symbolicated(165-180)
rust/src/symbolication/store.rs (9)
rust/src/lib.rs (2)
path(103-105)new(96-100)rust/src/symbolication/android.rs (1)
new(208-210)rust/src/symbolication/flutter.rs (1)
new(22-24)rust/src/symbolication/go.rs (1)
new(19-21)rust/src/symbolication/javascript.rs (1)
new(22-24)rust/src/symbolication/mod.rs (2)
new(241-243)from_str(93-104)rust/src/symbolication/python.rs (1)
new(20-22)rust/src/symbolication/react_native.rs (1)
new(22-24)rust/src/symbolication/rust_sym.rs (1)
new(19-21)
🔇 Additional comments (13)
rust/src/lib.rs (1)
29-38: Clean public exposure of the symbolication API.Nice, consistent re-export surface at the crate root.
rust/Cargo.toml (1)
44-46: No actionable changes needed. Verification confirms regex 1.10 (MSRV 1.65.0), sourcemap 9.0, and tempfile 3.14 (MSRV 1.63.0) have no known RustSec advisories and are compatible with Rust edition 2021 (MSRV 1.56.0).rust/src/symbolication/android.rs (1)
1-5: Good module-level documentation.The rustdoc format is properly used with
//!for module documentation, explaining the purpose and functionality clearly.rust/src/bin/main.rs (2)
81-107: Good CLI design for the Symbolicate command.The command structure is well-designed with appropriate flags, default values, and clear help text. The
-Pshort option for platform and-default for stdin input follow common CLI conventions.
239-288: Good output formatting implementation.The pretty and JSON output formats are well-implemented with appropriate use of colored output for the terminal and structured JSON for machine consumption.
rust/src/symbolication/store.rs (4)
1-4: Good module documentation.Clear rustdoc format with appropriate description of the module's purpose.
40-66: Excellent documentation with directory structure example.The code block showing the expected directory layout is very helpful for users understanding how to organize their mapping files.
73-136: Solid implementation of directory scanning.The scan logic properly handles the platform/app/version hierarchy, gracefully creates the root directory if missing, and tracks discovered mappings. Error handling using
?propagation is appropriate.
292-307: Good test structure.The test properly uses
tempfile::tempdir()for isolated test environments and validates the basic scan and lookup functionality.rust/src/symbolication/mod.rs (4)
1-33: Excellent module-level documentation with usage example.The documentation clearly explains supported platforms, includes a practical code example, and follows rustdoc conventions properly.
55-76: Well-designed error enum using thiserror.The error variants cover the expected failure modes with informative messages. The
#[from]attribute onIoErrorenables seamless conversion fromstd::io::Error.
134-199: Clean data structure design for symbolicated frames.The
SymbolicatedFramestruct with its constructors (rawandsymbolicated) anddisplaymethod provides a clear API. The booleansymbolicatedfield makes it easy to distinguish processed vs unprocessed frames.
234-282: Clean dispatcher pattern for platform-specific symbolication.The
Symbolicator::symbolicatemethod cleanly dispatches to platform-specific implementations. The match is exhaustive and properly handles theUnknownvariant with an error.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| ## [Unreleased] | ||
|
|
||
| ### Added | ||
| - Symbolication module with support for 7 platforms: | ||
| - Android (ProGuard/R8 mapping.txt parsing) | ||
| - JavaScript/Electron (source map support) | ||
| - Flutter/Dart (flutter symbolize integration) | ||
| - Rust (backtrace parsing) | ||
| - Go (goroutine stack parsing) | ||
| - Python (traceback parsing) | ||
| - React Native (Hermes bytecode + JS source maps) | ||
| - `bugstr symbolicate` CLI command for symbolicating stack traces | ||
| - `POST /api/symbolicate` web API endpoint for dashboard integration | ||
| - `--mappings` option for `bugstr serve` to enable symbolication | ||
| - `MappingStore` for organizing mapping files by platform/app/version | ||
|
|
||
| ## [0.1.0] - 2025-01-15 | ||
|
|
||
| ### Added | ||
| - Initial release | ||
| - Crash report receiver with NIP-17 gift wrap decryption | ||
| - Web dashboard for viewing and grouping crash reports | ||
| - SQLite storage with deduplication | ||
| - Gzip compression support for large payloads | ||
| - `bugstr listen` command for terminal-only crash monitoring | ||
| - `bugstr serve` command for web dashboard with crash collection | ||
| - `bugstr pubkey` command to display receiver public key |
There was a problem hiding this comment.
Add Changed/Fixed sections to match required changelog format.
The guideline calls for Added/Changed/Fixed sections; currently only Added is present in both sections. As per coding guidelines, please include Changed and Fixed headings (even if “None”).
📄 Suggested changelog structure
## [Unreleased]
### Added
- Symbolication module with support for 7 platforms:
- Android (ProGuard/R8 mapping.txt parsing)
- JavaScript/Electron (source map support)
- Flutter/Dart (flutter symbolize integration)
- Rust (backtrace parsing)
- Go (goroutine stack parsing)
- Python (traceback parsing)
- React Native (Hermes bytecode + JS source maps)
- `bugstr symbolicate` CLI command for symbolicating stack traces
- `POST /api/symbolicate` web API endpoint for dashboard integration
- `--mappings` option for `bugstr serve` to enable symbolication
- `MappingStore` for organizing mapping files by platform/app/version
+
+### Changed
+- None
+
+### Fixed
+- None
## [0.1.0] - 2025-01-15
### Added
- Initial release
- Crash report receiver with NIP-17 gift wrap decryption
- Web dashboard for viewing and grouping crash reports
- SQLite storage with deduplication
- Gzip compression support for large payloads
- `bugstr listen` command for terminal-only crash monitoring
- `bugstr serve` command for web dashboard with crash collection
- `bugstr pubkey` command to display receiver public key
+
+### Changed
+- None
+
+### Fixed
+- None📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ## [Unreleased] | |
| ### Added | |
| - Symbolication module with support for 7 platforms: | |
| - Android (ProGuard/R8 mapping.txt parsing) | |
| - JavaScript/Electron (source map support) | |
| - Flutter/Dart (flutter symbolize integration) | |
| - Rust (backtrace parsing) | |
| - Go (goroutine stack parsing) | |
| - Python (traceback parsing) | |
| - React Native (Hermes bytecode + JS source maps) | |
| - `bugstr symbolicate` CLI command for symbolicating stack traces | |
| - `POST /api/symbolicate` web API endpoint for dashboard integration | |
| - `--mappings` option for `bugstr serve` to enable symbolication | |
| - `MappingStore` for organizing mapping files by platform/app/version | |
| ## [0.1.0] - 2025-01-15 | |
| ### Added | |
| - Initial release | |
| - Crash report receiver with NIP-17 gift wrap decryption | |
| - Web dashboard for viewing and grouping crash reports | |
| - SQLite storage with deduplication | |
| - Gzip compression support for large payloads | |
| - `bugstr listen` command for terminal-only crash monitoring | |
| - `bugstr serve` command for web dashboard with crash collection | |
| - `bugstr pubkey` command to display receiver public key | |
| ## [Unreleased] | |
| ### Added | |
| - Symbolication module with support for 7 platforms: | |
| - Android (ProGuard/R8 mapping.txt parsing) | |
| - JavaScript/Electron (source map support) | |
| - Flutter/Dart (flutter symbolize integration) | |
| - Rust (backtrace parsing) | |
| - Go (goroutine stack parsing) | |
| - Python (traceback parsing) | |
| - React Native (Hermes bytecode + JS source maps) | |
| - `bugstr symbolicate` CLI command for symbolicating stack traces | |
| - `POST /api/symbolicate` web API endpoint for dashboard integration | |
| - `--mappings` option for `bugstr serve` to enable symbolication | |
| - `MappingStore` for organizing mapping files by platform/app/version | |
| ### Changed | |
| - None | |
| ### Fixed | |
| - None | |
| ## [0.1.0] - 2025-01-15 | |
| ### Added | |
| - Initial release | |
| - Crash report receiver with NIP-17 gift wrap decryption | |
| - Web dashboard for viewing and grouping crash reports | |
| - SQLite storage with deduplication | |
| - Gzip compression support for large payloads | |
| - `bugstr listen` command for terminal-only crash monitoring | |
| - `bugstr serve` command for web dashboard with crash collection | |
| - `bugstr pubkey` command to display receiver public key | |
| ### Changed | |
| - None | |
| ### Fixed | |
| - None |
🤖 Prompt for AI Agents
In `@rust/CHANGELOG.md` around lines 8 - 34, Update the changelog sections under
the headings "## [Unreleased]" and "## [0.1.0] - 2025-01-15" to include
"Changed" and "Fixed" subsections in addition to the existing "Added" lists; for
each section add "### Changed" and "### Fixed" headings and list any relevant
entries or the word "None" if there are no changes/fixes to report so the file
follows the required Added/Changed/Fixed format.
| /// Flutter stack trace symbolicator. | ||
| pub struct FlutterSymbolicator<'a> { | ||
| store: &'a MappingStore, | ||
| } | ||
|
|
||
| impl<'a> FlutterSymbolicator<'a> { | ||
| /// Create a new Flutter symbolicator. | ||
| pub fn new(store: &'a MappingStore) -> Self { | ||
| Self { store } | ||
| } | ||
|
|
||
| /// Symbolicate a Flutter stack trace. | ||
| /// | ||
| /// Attempts to use the `flutter symbolize` command if available, | ||
| /// otherwise falls back to basic symbol file parsing. | ||
| pub fn symbolicate( | ||
| &self, | ||
| stack_trace: &str, | ||
| context: &SymbolicationContext, | ||
| ) -> Result<SymbolicatedStack, SymbolicationError> { |
There was a problem hiding this comment.
Expand rustdoc for public FlutterSymbolicator APIs (params/returns/errors).
The current docs are brief but don’t describe parameters, return values, or error cases. As per coding guidelines, please expand rustdoc on the public struct/methods to include those details (and a short usage example if appropriate).
🤖 Prompt for AI Agents
In `@rust/src/symbolication/flutter.rs` around lines 15 - 34, Update the public
rustdoc for the FlutterSymbolicator struct and its public methods
(FlutterSymbolicator, new, symbolicate) to include explicit descriptions of
parameters (e.g., store: &MappingStore, stack_trace: &str, context:
&SymbolicationContext), the return type (Result<SymbolicatedStack,
SymbolicationError>), and the possible error cases (what triggers
SymbolicationError and when fallbacks occur). Add brief examples showing how to
construct a FlutterSymbolicator via FlutterSymbolicator::new and call
symbolicate, and document the behavior (uses `flutter symbolize` if available,
otherwise falls back to mapping parsing) and any panics/side-effects. Ensure
each public item has a short one-line summary followed by sections for
Arguments, Returns, Errors, and an optional Example.
| /// Rust stack trace symbolicator. | ||
| pub struct RustSymbolicator<'a> { | ||
| store: &'a MappingStore, | ||
| } | ||
|
|
||
| impl<'a> RustSymbolicator<'a> { | ||
| /// Create a new Rust symbolicator. | ||
| pub fn new(store: &'a MappingStore) -> Self { | ||
| Self { store } | ||
| } | ||
|
|
||
| /// Symbolicate a Rust stack trace. | ||
| /// | ||
| /// Rust stack traces from panics typically include source locations | ||
| /// in debug builds. For release builds with symbols stripped, this | ||
| /// attempts to use addr2line with debug symbols if available. | ||
| pub fn symbolicate( | ||
| &self, | ||
| stack_trace: &str, | ||
| context: &SymbolicationContext, | ||
| ) -> Result<SymbolicatedStack, SymbolicationError> { |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Expand rustdoc for the public RustSymbolicator API.
The current docs don’t describe parameters, return values, error conditions, or usage examples. Please expand the rustdoc on the public struct and methods to meet the project’s documentation requirements. As per coding guidelines.
🤖 Prompt for AI Agents
In `@rust/src/symbolication/rust_sym.rs` around lines 12 - 32, Update the rustdoc
for the public RustSymbolicator API: expand the doc comment on the
RustSymbolicator struct and its public methods new() and symbolicate() to
include parameter descriptions (e.g., explain the store field and the parameters
stack_trace: &str and context: &SymbolicationContext), the return value
(Result<SymbolicatedStack, SymbolicationError>), the error conditions that may
produce SymbolicationError, and at least one short usage example showing
constructing RustSymbolicator::new(&store) and calling symbolicate(stack_trace,
&context); keep docs concise, follow project style (sections: Arguments,
Returns, Errors, Examples), and mention any relevant lifetime or thread-safety
considerations for the store reference.
| /// Symbolicate a Rust stack trace. | ||
| /// | ||
| /// Rust stack traces from panics typically include source locations | ||
| /// in debug builds. For release builds with symbols stripped, this | ||
| /// attempts to use addr2line with debug symbols if available. | ||
| pub fn symbolicate( | ||
| &self, | ||
| stack_trace: &str, | ||
| context: &SymbolicationContext, | ||
| ) -> Result<SymbolicatedStack, SymbolicationError> { | ||
| // Try to find debug symbols | ||
| let mapping_info = self.store.get_with_fallback( | ||
| &context.platform, | ||
| context.app_id.as_deref().unwrap_or("unknown"), | ||
| context.version.as_deref().unwrap_or("unknown"), | ||
| ); | ||
|
|
||
| // Rust backtraces already include source info in debug builds | ||
| // We just need to parse and format them nicely | ||
| self.parse_rust_backtrace(stack_trace, mapping_info.map(|i| i.path.as_path())) | ||
| } | ||
|
|
||
| /// Parse a Rust backtrace. | ||
| fn parse_rust_backtrace( | ||
| &self, | ||
| stack_trace: &str, | ||
| _symbols_path: Option<&std::path::Path>, | ||
| ) -> Result<SymbolicatedStack, SymbolicationError> { |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n rust/src/symbolication/rust_sym.rs | head -80Repository: alltheseas/bugstr
Length of output: 3623
🏁 Script executed:
cat -n rust/src/symbolication/rust_sym.rs | tail -n +80 | head -60Repository: alltheseas/bugstr
Length of output: 2399
Docs overpromise addr2line support that isn't implemented.
Lines 25–27 claim the method "attempts to use addr2line with debug symbols if available" for stripped binaries, but parse_rust_backtrace ignores the _symbols_path parameter and only parses location info already present in the backtrace text. No addr2line lookup occurs. Either implement the symbol resolution using the passed mapping, or update the docstring to accurately reflect that only pre-symbolicated backtraces are supported.
🤖 Prompt for AI Agents
In `@rust/src/symbolication/rust_sym.rs` around lines 23 - 50, The docstring for
symbolicate claims addr2line lookup for stripped binaries but
parse_rust_backtrace currently ignores the _symbols_path and never uses
mapping_info; either implement addr2line-based resolution or change the docs. To
fix: either (A) implement symbol resolution in parse_rust_backtrace using the
provided _symbols_path/mapping_info (call addr2line or use gimli/addr2line
crates to open the debug file and resolve addresses found in stack_trace) and
wire mapping_info.path from symbolicate into parse_rust_backtrace, or (B) update
the symbolicate docstring to remove the claim about addr2line and state that
only backtraces containing source info are parsed; reference functions/vars:
symbolicate, parse_rust_backtrace, mapping_info, _symbols_path,
store.get_with_fallback, and SymbolicationContext to locate the code to change.
| pub struct AppState { | ||
| pub storage: Mutex<CrashStorage>, | ||
| pub symbolicator: Option<Symbolicator>, | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's find and read the web.rs file around the lines mentioned
fd web.rs --type fRepository: alltheseas/bugstr
Length of output: 76
🏁 Script executed:
# Get the structure of the rust directory
git ls-files rust/ | head -20Repository: alltheseas/bugstr
Length of output: 566
🏁 Script executed:
# Read rust/src/web.rs to see the AppState and handler code
wc -l rust/src/web.rsRepository: alltheseas/bugstr
Length of output: 80
🏁 Script executed:
# Read the relevant sections of rust/src/web.rs
sed -n '20,40p' rust/src/web.rs
echo "---"
sed -n '85,150p' rust/src/web.rsRepository: alltheseas/bugstr
Length of output: 3094
🏁 Script executed:
# Also examine the Symbolicator struct definition
cat -n rust/src/symbolication/mod.rs | head -100Repository: alltheseas/bugstr
Length of output: 3597
🏁 Script executed:
# Continue reading the Symbolicator struct and symbolicate method
sed -n '100,250p' rust/src/symbolication/mod.rsRepository: alltheseas/bugstr
Length of output: 4162
🏁 Script executed:
# Look for the actual symbolicate method implementation
rg "fn symbolicate" rust/src/symbolication/ -A 20Repository: alltheseas/bugstr
Length of output: 16041
🏁 Script executed:
# Check if there are any tests for the web handler
rg "test\|#\[test\]" rust/src/web.rs -A 5Repository: alltheseas/bugstr
Length of output: 43
🏁 Script executed:
# Check for tests in symbolication module
find rust -name "*test*" -o -name "*_test.rs"Repository: alltheseas/bugstr
Length of output: 43
🏁 Script executed:
# Look at the flutter.rs implementation more closely
sed -n '1,150p' rust/src/symbolication/flutter.rsRepository: alltheseas/bugstr
Length of output: 5319
🏁 Script executed:
# Check for any existing tests for the symbolicate handler
grep -r "symbolicate_stack\|POST.*symbolicate" rust/src --include="*.rs" | head -20Repository: alltheseas/bugstr
Length of output: 401
🏁 Script executed:
# Look for any tokio::task usages in the codebase to see patterns
rg "spawn_blocking\|spawn\|tokio::task" rust/src --type rs -B 2 -A 2Repository: alltheseas/bugstr
Length of output: 87
🏁 Script executed:
# Check the full symbolicate_stack handler to see the complete implementation
sed -n '92,150p' rust/src/web.rsRepository: alltheseas/bugstr
Length of output: 2195
🏁 Script executed:
# Look at the complete Symbolicator::symbolicate method in mod.rs
sed -n '230,320p' rust/src/symbolication/mod.rsRepository: alltheseas/bugstr
Length of output: 1882
🏁 Script executed:
# Check if there are any async operations in symbolication
rg "async\|await\|spawn" rust/src/symbolication/ -A 2Repository: alltheseas/bugstr
Length of output: 43
🏁 Script executed:
# Check Android symbolication for blocking operations
sed -n '1,100p' rust/src/symbolication/android.rsRepository: alltheseas/bugstr
Length of output: 3614
🏁 Script executed:
# Check if there are any other blocking operations we should know about
sed -n '1,80p' rust/src/symbolication/javascript.rsRepository: alltheseas/bugstr
Length of output: 2882
🏁 Script executed:
# Verify the full context - check if store operations are also blocking
cat -n rust/src/symbolication/store.rs | head -60Repository: alltheseas/bugstr
Length of output: 1960
🏁 Script executed:
# Check MappingStore::get_with_fallback which is called by all symbolication methods
sed -n '1,200p' rust/src/symbolication/store.rsRepository: alltheseas/bugstr
Length of output: 6636
🏁 Script executed:
# Check if there are any existing tests that exercise the symbolicator
rg "#\[test\]|#\[tokio::test\]" rust/src -A 5Repository: alltheseas/bugstr
Length of output: 8905
🏁 Script executed:
# Check Cargo.toml for test dependencies
cat rust/Cargo.toml | grep -A 10 "\[dev-dependencies\]"Repository: alltheseas/bugstr
Length of output: 97
🏁 Script executed:
# Final check - are there any async tests or integration tests for web handlers?
find rust -name "*test*" -type fRepository: alltheseas/bugstr
Length of output: 43
🏁 Script executed:
# Double-check the web.rs handler one more time to see if there's any context we missed
sed -n '1,30p' rust/src/web.rsRepository: alltheseas/bugstr
Length of output: 813
Use tokio::task::spawn_blocking to offload filesystem IO and external process calls.
The symbolicator.symbolicate method performs blocking filesystem operations (reading mapping files, writing temp files) and spawns external tools like flutter symbolize. Calling this directly in an async handler risks blocking Tokio's worker threads under load. Wrap the symbolicator with Arc, move it into a blocking task via spawn_blocking, and add unit tests for the handler to cover success and error cases.
💡 Suggested approach
pub struct AppState {
pub storage: Mutex<CrashStorage>,
- pub symbolicator: Option<Symbolicator>,
+ pub symbolicator: Option<Arc<Symbolicator>>,
}
async fn symbolicate_stack(
State(state): State<Arc<AppState>>,
Json(request): Json<SymbolicateRequest>,
) -> impl IntoResponse {
- let Some(ref symbolicator) = state.symbolicator else {
+ let Some(symbolicator) = state.symbolicator.as_ref() else {
return (
StatusCode::SERVICE_UNAVAILABLE,
Json(serde_json::json!({
"error": "Symbolication not configured. Start server with --mappings option."
}))
).into_response();
};
let platform = Platform::from_str(&request.platform);
let context = SymbolicationContext {
platform,
app_id: request.app_id,
version: request.version,
build_id: request.build_id,
};
- match symbolicator.symbolicate(&request.stack_trace, &context) {
+ let stack_trace = request.stack_trace.clone();
+ let result = match tokio::task::spawn_blocking({
+ let symbolicator = Arc::clone(symbolicator);
+ move || symbolicator.symbolicate(&stack_trace, &context)
+ }).await {
+ Ok(res) => res,
+ Err(_) => {
+ return (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ Json(serde_json::json!({ "error": "Symbolication task failed" }))
+ ).into_response();
+ }
+ };
+
+ match result {
Ok(result) => Json(SymbolicateResponse {
symbolicated_count: result.symbolicated_count,
total_count: result.total_count,
percentage: result.percentage(),
display: result.display(),
frames: result.frames.iter().map(|f| FrameJson {
raw: f.raw.clone(),
function: f.function.clone(),
file: f.file.clone(),
line: f.line,
column: f.column,
symbolicated: f.symbolicated,
}).collect(),
}).into_response(),
Err(e) => (
StatusCode::BAD_REQUEST,
Json(serde_json::json!({ "error": e.to_string() }))
).into_response(),
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| pub struct AppState { | |
| pub storage: Mutex<CrashStorage>, | |
| pub symbolicator: Option<Symbolicator>, | |
| } | |
| pub struct AppState { | |
| pub storage: Mutex<CrashStorage>, | |
| pub symbolicator: Option<Arc<Symbolicator>>, | |
| } |
🤖 Prompt for AI Agents
In `@rust/src/web.rs` around lines 26 - 29, AppState currently holds symbolicator
directly (Option<Symbolicator>) which can cause blocking in async handlers;
change it to Option<Arc<Symbolicator>> (or wrap the existing Symbolicator in Arc
when constructing AppState), then in the async handler call the blocking
symbolication via tokio::task::spawn_blocking by cloning the Arc and moving it
into spawn_blocking to call symbolicator.symbolicate(...) so all filesystem IO
and external process invocations happen off the Tokio worker threads; ensure you
clone any args needed (e.g., request data) into the closure and await the
spawn_blocking JoinHandle, converting its Result into the handler's response;
finally add unit tests for the handler (using #[tokio::test]) that exercise
success and error paths by injecting a test/mocked Symbolicator (Arc-wrapped) to
verify proper spawn_blocking behavior and error propagation.
The MappingStore.scan() method was never being called, which meant mapping files were never actually loaded. This fix ensures mappings are scanned in both the CLI symbolicate command and the serve command. Also adds helpful warnings when no mapping files are found in the specified directory. Signed-off-by: alltheseas Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Go: Match pointer receivers like main.(*Type).Method - JavaScript: Handle colons in URLs and Windows paths - Python: Require Error/Exception/Warning suffix to avoid matching "Traceback" - React Native: Handle URLs in file paths, preserve file path in fallback Adds tests for URL handling in JavaScript and React Native. Signed-off-by: alltheseas Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change symbolicator to Arc<Symbolicator> for safe sharing across threads. Use spawn_blocking to run CPU-intensive symbolication work without blocking the async runtime's executor threads. This prevents symbolication requests from blocking other API endpoints. Signed-off-by: alltheseas Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- flutter.rs: Use NamedTempFile for secure temp file handling instead of predictable fixed path that could be exploited - store.rs: Use semver for proper version comparison instead of lexicographic ordering (so 1.10.0 > 1.9.0) Signed-off-by: alltheseas Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Changed/Fixed subsections to CHANGELOG (Keep a Changelog format) - Fix incorrect claim about addr2line in Rust symbolication docs (we parse backtraces, not DWARF debug info) Signed-off-by: alltheseas Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@rust/src/bin/main.rs`:
- Around line 194-202: The symbolicate_stack function lacks a comprehensive
rustdoc; add a full doc comment above fn symbolicate_stack describing the
function's purpose, each parameter (platform_str, input, mappings_dir, app_id,
version, format) including expected formats and ownership/borrowing semantics,
the return type (Result<(), Box<dyn std::error::Error>>) and all possible error
cases, the behavior and structure of the produced output (how SymbolicateFormat
affects output), any side effects (file/IO, logging), and examples of typical
usage and expected input/output snippets; also document panics/edge-cases and
reference the SymbolicateFormat enum and mapping lookup behavior so callers know
how to handle errors and parse results.
In `@rust/src/symbolication/mod.rs`:
- Around line 121-251: Add expanded rustdoc comments for the public API:
document SymbolicationContext (fields: platform, app_id, version, build_id) with
parameter semantics and when fields can be None; document SymbolicatedFrame
(raw, function, file, line, column, symbolicated) and include how display()
formats frames; document SymbolicatedStack (raw, frames, symbolicated_count,
total_count) with explanation of display() and percentage(); and add a detailed
doc for Symbolicator::symbolicate describing arguments, the Result return (Ok
with SymbolicatedStack and Err with SymbolicationError) and possible error
cases; include short usage examples for creating a SymbolicationContext, calling
Symbolicator::symbolicate, and handling SymbolicationError in the docs.
In `@rust/src/symbolication/store.rs`:
- Around line 31-77: The public MappingStore API lacks comprehensive rustdoc;
update the docs for the MappingStore type and its public methods
(MappingStore::new, MappingStore::root, MappingStore::scan,
MappingStore::get_with_fallback, MappingStore::save_mapping and any other public
helpers) to include parameter descriptions, return value semantics, possible
SymbolicationError variants/errors, side effects (e.g., clearing/refreshing
mappings), and a short usage example showing typical creation, scan, lookup
(with fallback) and save flows; ensure examples compile (use doc-tests),
document thread-safety or mutability expectations, and mention directory layout
expectations already shown in the type doc.
- Around line 246-285: Validate and sanitize all path components used by
mapping_path/save_mapping: ensure Platform (handle Platform::Unknown) yields
only allowed token strings, and reject or canonicalize app_id, version, and
filename if they are absolute, contain "..", or contain path separators (e.g.,
'/' or '\\'); perform these checks in save_mapping before calling mapping_path
(or add a helper like validate_component) and return an error on invalid input
so files cannot be written outside self.root; keep add_mapping and mapping_path
unchanged except only call them after validation.
♻️ Duplicate comments (5)
rust/CHANGELOG.md (1)
30-40: Add Changed/Fixed sections to the 0.1.0 release entry.The [Unreleased] section now correctly includes all three sections, but the [0.1.0] release entry is still missing the Changed and Fixed headings. As per coding guidelines, all changelog entries should follow the same format.
📄 Suggested addition
## [0.1.0] - 2025-01-15 ### Added - Initial release - Crash report receiver with NIP-17 gift wrap decryption - Web dashboard for viewing and grouping crash reports - SQLite storage with deduplication - Gzip compression support for large payloads - `bugstr listen` command for terminal-only crash monitoring - `bugstr serve` command for web dashboard with crash collection - `bugstr pubkey` command to display receiver public key + +### Changed +- None + +### Fixed +- Nonerust/src/symbolication/react_native.rs (1)
15-36: Expand rustdoc for the public API.The current documentation is minimal. Per coding guidelines, public methods should document parameters, return values, error cases, and usage examples. The
symbolicatemethod would benefit from documenting:
- Parameter descriptions (
stack_trace,context)- Possible
SymbolicationErrorvariants returned- Example usage
rust/src/symbolication/python.rs (1)
34-41: Mapping lookup isn't applied, so bundled-app paths never resolve.The
symbolicatemethod fetches mapping info (lines 35-39) but stores it as_mapping_infowithout using it. The docstring on line 28 claims the method "attempts to resolve bundled app paths to original sources if a mapping is available", but no such resolution occurs.Either apply the mapping to transform file paths or remove the misleading docstring claim.
rust/src/symbolication/go.rs (2)
12-31: Expand rustdoc forGoSymbolicatorpublic API.
Current docs don’t describe parameters, return values, error cases, lifetime semantics, or usage examples. This is required for public APIs. As per coding guidelines, please expand the rustdoc accordingly.
54-88: Go function regex is still too restrictive for real-world stack traces.
Module paths often include-and generic receivers can introduce[...], which the current character class won’t match, so frames get skipped. A more permissive pattern (plus trimming) avoids false negatives; please also add test cases for module paths with hyphens and generic receivers.🐛 Suggested fix
- let func_re = Regex::new(r"^([a-zA-Z0-9_./]+(?:\(\*[^)]+\))?[a-zA-Z0-9_.]*)\(([^)]*)\)$").unwrap(); + let func_re = Regex::new(r"^(.+)\(([^)]*)\)$").unwrap(); @@ - current_function = Some(caps[1].to_string()); - current_args = Some(caps[2].to_string()); + current_function = Some(caps[1].trim().to_string()); + current_args = Some(caps[2].trim().to_string());
🧹 Nitpick comments (6)
rust/src/symbolication/python.rs (2)
74-83: Consider whethersymbolicated: trueis semantically correct here.All parsed Python frames are marked
symbolicated: true, but no actual symbolication (path resolution from bundled apps) occurs. The frames simply preserve the existing source information from the traceback.If the mapping was actually applied to resolve bundled paths, then marking as symbolicated would be appropriate. As-is, this inflates the "symbolicated percentage" metric to near 100% for Python traces without doing meaningful work.
Consider setting
symbolicated: falsefor frames where no mapping transformation was applied, or document that Python frames are considered "symbolicated" because they inherently contain source information.
175-189: Consider adding more test coverage for edge cases.The current test only verifies that frames are counted. Consider adding tests for:
- Empty or malformed tracebacks
- Tracebacks without an exception line
- Multi-line exception messages (e.g.,
AssertionErrorwith a diff)- Chained exceptions (
During handling of... another exception occurred)rust/src/symbolication/javascript.rs (1)
60-65: Chrome regex may over-match without end anchor.The Firefox regex correctly uses
$anchor but the Chrome regex doesn't. Without the anchor, the Chrome pattern may match partial lines or include trailing content. Consider adding$for consistency:- let chrome_re = Regex::new( - r"^\s*at\s+(?:(.+?)\s+)?\(?(.+):(\d+):(\d+)\)?" - ).unwrap(); + let chrome_re = Regex::new( + r"^\s*at\s+(?:(.+?)\s+)?\(?(.+):(\d+):(\d+)\)?$" + ).unwrap();The file capture is now
(.+)which correctly handles URLs and Windows paths - this addresses the previous feedback about colons in paths.rust/src/symbolication/react_native.rs (3)
66-69: Consider adding end anchor to JS frame regex for consistency.The regex now correctly uses
(.+)for the file capture (handling URLs), but lacks a$end anchor. This matches the JavaScript symbolicator's Chrome regex. For robustness, consider adding$:- let js_frame_re = Regex::new( - r"^\s*at\s+(?:(.+?)\s+)?\(?(?:address at\s+)?(.+):(\d+):(\d+)\)?" - ).unwrap(); + let js_frame_re = Regex::new( + r"^\s*at\s+(?:(.+?)\s+)?\(?(?:address at\s+)?(.+):(\d+):(\d+)\)?$" + ).unwrap();
145-155: Note: Native Android frames may still be obfuscated.The comment says "Native frames are usually not obfuscated", but ProGuard/R8 can obfuscate Java class and method names. These frames are marked
symbolicated: truebut no ProGuard deobfuscation is applied. Consider either:
- Marking as
symbolicated: falseand adding a separate ProGuard lookup- Updating the comment to clarify this limitation
191-219: Good URL test coverage; consider adding more frame type tests.The URL test case (
http://localhost:8081/index.bundle) verifies correct parsing. Consider adding tests for:
- Hermes format:
"at myFunction (address at index.android.bundle:1:2345)"- Native Android:
"at com.example.MyClass.method(MyClass.java:42)"- Native iOS:
"0 MyApp 0x00000001 myFunction + 123"
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
rust/CHANGELOG.mdrust/Cargo.tomlrust/src/bin/main.rsrust/src/symbolication/flutter.rsrust/src/symbolication/go.rsrust/src/symbolication/javascript.rsrust/src/symbolication/mod.rsrust/src/symbolication/python.rsrust/src/symbolication/react_native.rsrust/src/symbolication/store.rsrust/src/web.rs
🚧 Files skipped from review as they are similar to previous changes (2)
- rust/Cargo.toml
- rust/src/symbolication/flutter.rs
🧰 Additional context used
📓 Path-based instructions (4)
**/CHANGELOG.md
📄 CodeRabbit inference engine (AGENTS.md)
All user-facing changes require a CHANGELOG.md entry following the specified format (Added, Changed, Fixed sections)
Files:
rust/CHANGELOG.md
rust/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
Use rustdoc format (
/// ...or//!) for docstrings in Rust code
Files:
rust/src/web.rsrust/src/symbolication/react_native.rsrust/src/symbolication/javascript.rsrust/src/symbolication/python.rsrust/src/bin/main.rsrust/src/symbolication/mod.rsrust/src/symbolication/store.rsrust/src/symbolication/go.rs
**/*.{kt,dart,ts,tsx,rs,go,py}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{kt,dart,ts,tsx,rs,go,py}: All public classes, methods, and non-trivial functions must have documentation explaining purpose, behavior, parameters, return values, exceptions, and usage examples for complex APIs
All code must be reviewable by human developers with clear, descriptive variable and function names, appropriate comments for non-obvious logic, and consistent formatting per language conventions
Files:
rust/src/web.rsrust/src/symbolication/react_native.rsrust/src/symbolication/javascript.rsrust/src/symbolication/python.rsrust/src/bin/main.rsrust/src/symbolication/mod.rsrust/src/symbolication/store.rsrust/src/symbolication/go.rs
**/*.{kt,ts,tsx,dart,rs,go,py}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{kt,ts,tsx,dart,rs,go,py}: Rumor events must includesig: ""(empty string, not omitted) for NIP-17/59 implementation
Rumor events must include computedidfield with SHA256 of serialized event in lowercase hex format (64 characters) for NIP-17/59 implementation
Event serialization order must be:[0, pubkey, created_at, kind, tags, content]for NIP-17/59 compliance
Seal events must be signed by the sender's key for NIP-17/59 implementation
Gift wrap events must be signed by an ephemeral key for NIP-17/59 implementation
All new code should have corresponding unit tests and test edge cases and error conditions
Files:
rust/src/web.rsrust/src/symbolication/react_native.rsrust/src/symbolication/javascript.rsrust/src/symbolication/python.rsrust/src/bin/main.rsrust/src/symbolication/mod.rsrust/src/symbolication/store.rsrust/src/symbolication/go.rs
🧠 Learnings (3)
📚 Learning: 2026-01-16T15:49:11.199Z
Learnt from: CR
Repo: alltheseas/bugstr PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-16T15:49:11.199Z
Learning: Applies to **/CHANGELOG.md : All user-facing changes require a CHANGELOG.md entry following the specified format (Added, Changed, Fixed sections)
Applied to files:
rust/CHANGELOG.md
📚 Learning: 2026-01-16T15:49:11.199Z
Learnt from: CR
Repo: alltheseas/bugstr PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-16T15:49:11.199Z
Learning: Applies to rust/**/*.rs : Use rustdoc format (`/// ...` or `//!`) for docstrings in Rust code
Applied to files:
rust/src/symbolication/react_native.rsrust/src/symbolication/javascript.rsrust/src/symbolication/python.rsrust/src/symbolication/go.rs
📚 Learning: 2026-01-16T15:49:11.199Z
Learnt from: CR
Repo: alltheseas/bugstr PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-16T15:49:11.199Z
Learning: Applies to **/*.{kt,dart,ts,tsx,rs,go,py} : All public classes, methods, and non-trivial functions must have documentation explaining purpose, behavior, parameters, return values, exceptions, and usage examples for complex APIs
Applied to files:
rust/src/symbolication/react_native.rsrust/src/symbolication/javascript.rsrust/src/symbolication/python.rsrust/src/symbolication/go.rs
🧬 Code graph analysis (5)
rust/src/web.rs (2)
rust/src/bin/main.rs (2)
symbolicate_stack(195-299)serde_json(724-724)rust/src/symbolication/mod.rs (1)
from_str(93-104)
rust/src/symbolication/react_native.rs (3)
rust/src/symbolication/mod.rs (6)
new(241-243)symbolicate(246-282)frames(217-220)symbolicated(165-180)raw(153-162)as_str(107-118)rust/src/symbolication/javascript.rs (2)
new(22-24)symbolicate(27-123)rust/src/symbolication/android.rs (2)
new(208-210)symbolicate(213-291)
rust/src/symbolication/javascript.rs (2)
rust/src/symbolication/mod.rs (4)
new(241-243)symbolicate(246-282)symbolicated(165-180)raw(153-162)rust/src/symbolication/rust_sym.rs (2)
new(19-21)symbolicate(28-43)
rust/src/bin/main.rs (3)
rust/src/storage.rs (3)
count(184-187)serde_json(233-233)open(44-49)rust/src/web.rs (1)
symbolicate_stack(93-147)rust/src/symbolication/mod.rs (5)
from_str(93-104)percentage(225-231)raw(153-162)frames(217-220)symbolicated(165-180)
rust/src/symbolication/store.rs (10)
rust/src/lib.rs (2)
path(103-105)new(96-100)rust/src/symbolication/mod.rs (2)
new(241-243)from_str(93-104)rust/src/symbolication/flutter.rs (1)
new(23-25)rust/src/symbolication/go.rs (1)
new(19-21)rust/src/symbolication/javascript.rs (1)
new(22-24)rust/src/symbolication/python.rs (1)
new(20-22)rust/src/symbolication/react_native.rs (1)
new(22-24)rust/src/symbolication/rust_sym.rs (1)
new(19-21)rust/src/symbolication/android.rs (1)
new(208-210)rust/src/storage.rs (1)
count(184-187)
🔇 Additional comments (9)
rust/CHANGELOG.md (1)
8-29: LGTM!The [Unreleased] section properly documents the new symbolication module, CLI command, API endpoint, and MappingStore additions with the correct Added/Changed/Fixed structure.
rust/src/web.rs (3)
92-147: LGTM! Good use ofspawn_blockingfor CPU-bound work.The handler correctly:
- Returns 503 when symbolication is not configured
- Uses
Arc::cloneandspawn_blockingto offload filesystem I/O and CPU-bound parsing- Handles both symbolication errors (400) and task panics (500)
This addresses the previous review feedback about blocking the async runtime.
244-275: LGTM!Request and response types are well-structured with appropriate field documentation and serde derives.
25-29: LGTM!
AppStatenow correctly wrapsSymbolicatorinArcto enable safe sharing across async tasks viaspawn_blocking.rust/src/symbolication/python.rs (1)
60-61: LGTM!The exception regex now requires names to end with
Error,Exception, orWarning, which correctly excludes the "Traceback" header line.rust/src/symbolication/javascript.rs (2)
26-123: LGTM!The symbolication flow correctly:
- Requires a mapping file (returns
MappingNotFounderror if absent)- Converts 1-based stack frame coordinates to 0-based for sourcemap lookup
- Converts results back to 1-based for output
- Falls back to raw frames when no token is found
145-158: Good addition of URL test case.The
test_parse_chrome_stack_frame_with_urlcorrectly verifies that URLs with ports (likehttp://localhost:8080/bundle.js) are parsed properly. Consider also adding a test for Windows paths (C:/Users/app.js:10:5orfile:///C:/path/bundle.js:10:5) to complete coverage.rust/src/symbolication/react_native.rs (1)
126-136: LGTM!Good fix - unsymbolicated JS/Hermes frames now correctly preserve the parsed file path, line, and column information instead of discarding them. This addresses the previous review feedback.
rust/src/bin/main.rs (1)
223-233: Nice improvement: mappings are scanned and empties are surfaced.
This prevents silent “mapping not found” behavior and gives clear operator feedback.Also applies to: 316-331
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
Add detailed rustdoc documentation for the symbolication module: - symbolicate_stack function with parameters, errors, output formats - SymbolicationContext, SymbolicatedFrame, SymbolicatedStack structs - Symbolicator::symbolicate with error cases and examples - MappingStore and all public methods with usage examples Add path validation to MappingStore.save_mapping to prevent directory traversal attacks: - New InvalidPath error variant in SymbolicationError - validate_path_component() rejects empty, "..", "/", "\" in paths - 6 new tests for path validation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix three issues in Android symbolication: 1. HIGH: Support R8/ProGuard :origStart:origEnd format - Parse method lines like "1:5:void m()💯104 -> a" - Correctly map obfuscated line numbers to original source lines 2. MEDIUM: Handle overloaded/inlined methods correctly - Store each line range with its associated method name - Different line ranges can map to different original methods 3. MEDIUM: Preserve original line number when mapping absent - Return original line number instead of None when no range matches - Useful location info no longer lost Add 5 new tests covering R8 format, overloads, and line preservation. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add initialization check to clearPendingReports() to prevent runtime error when called before init(). Now silently returns (no-op) like processPendingReports() and captureException(). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Rust: - ProGuard/R8 :origStart:origEnd line range support - Overloaded method differentiation by line range - Line number preservation when mapping missing - Path validation security in MappingStore Electron: - clearPendingReports() guard against uninitialized store Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary
bugstr symbolicateCLI commandPOST /api/symbolicateweb API endpoint--mappingsflag tobugstr serveCloses #10
Test plan
bugstr symbolicate -P python < traceback.txtbugstr serve --mappings ./mappingsthen POST to /api/symbolicate🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.5 noreply@anthropic.com
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.