{"action":"created","comment":{"url":"https://api.github.com/repos/bugsnag/bugsnag-android/pulls/comments/228293449","pull_request_review_id":168534159,"id":228293449,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIyODI5MzQ0OQ==","diff_hunk":"@@ -634,6 +645,33 @@ public void setDelivery(@NonNull Delivery delivery) {\n         return map;\n     }\n \n+    /**\n+     * Add a callback to modify or cancel a report immediately before\n+     * it is delivered to Bugsnag.\n+     *\n+     * Unlike {@link BeforeNotify} callbacks, \"before send\" callbacks are not\n+     * necessarily run in the same app session as when the report was generated,\n+     * as the application may have terminated before delivery or networking\n+     * conditions prevented delivering the report until a later date.\n+     * <p>\n+     * Example usage:\n+     * <pre>\n+     * config.beforeSend((Report report) -&gt; {\n+     *   Error error = report.getError();\n+     *   error.setContext(getImportantField(error));\n+     *   return true;\n+     * });\n+     * </pre>\n+     * @param beforeSend a callback to run before delivering errors to Bugsnag\n+     * @see BeforeSend\n+     * @see Report\n+     */\n+    public void beforeSend(BeforeSend beforeSend) {\n+        if (!beforeSendTasks.contains(beforeSend)) {","path":"sdk/src/main/java/com/bugsnag/android/Configuration.java","position":51,"original_position":51,"commit_id":"4448f2fbc2a4d0181528421eb3a3dea873f49f31","original_commit_id":"4448f2fbc2a4d0181528421eb3a3dea873f49f31","user":{"login":"kattrali","id":333454,"node_id":"MDQ6VXNlcjMzMzQ1NA==","avatar_url":"https://avatars2.githubusercontent.com/u/333454?v=4","gravatar_id":"","url":"https://api.github.com/users/kattrali","html_url":"https://github.com/kattrali","followers_url":"https://api.github.com/users/kattrali/followers","following_url":"https://api.github.com/users/kattrali/following{/other_user}","gists_url":"https://api.github.com/users/kattrali/gists{/gist_id}","starred_url":"https://api.github.com/users/kattrali/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kattrali/subscriptions","organizations_url":"https://api.github.com/users/kattrali/orgs","repos_url":"https://api.github.com/users/kattrali/repos","events_url":"https://api.github.com/users/kattrali/events{/privacy}","received_events_url":"https://api.github.com/users/kattrali/received_events","type":"User","site_admin":false},"body":"At that point people should fix their configuration to resolve it. For example, adding uniqueness checks would not prevent an identical callback from running multiple times if its added like:\r\n\r\n```java\r\nBugsnag.beforeNotify(new BeforeNotify() {\r\n    @Override\r\n    public boolean run(Error error) { ... }\r\n});\r\n```\r\n\r\nin a method which is called multiple times. There is no duplicate references involved to verify uniqueness. ","created_at":"2018-10-25T18:50:10Z","updated_at":"2018-10-25T18:50:10Z","html_url":"https://github.com/bugsnag/bugsnag-android/pull/379#discussion_r228293449","pull_request_url":"https://api.github.com/repos/bugsnag/bugsnag-android/pulls/379","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/bugsnag/bugsnag-android/pulls/comments/228293449"},"html":{"href":"https://github.com/bugsnag/bugsnag-android/pull/379#discussion_r228293449"},"pull_request":{"href":"https://api.github.com/repos/bugsnag/bugsnag-android/pulls/379"}},"in_reply_to_id":227693251},"pull_request":{"url":"https://api.github.com/repos/bugsnag/bugsnag-android/pulls/379","id":225175322,"node_id":"MDExOlB1bGxSZXF1ZXN0MjI1MTc1MzIy","html_url":"https://github.com/bugsnag/bugsnag-android/pull/379","diff_url":"https://github.com/bugsnag/bugsnag-android/pull/379.diff","patch_url":"https://github.com/bugsnag/bugsnag-android/pull/379.patch","issue_url":"https://api.github.com/repos/bugsnag/bugsnag-android/issues/379","number":379,"state":"open","locked":false,"title":"feat: Run report modification callbacks before native crash reports","user":{"login":"kattrali","id":333454,"node_id":"MDQ6VXNlcjMzMzQ1NA==","avatar_url":"https://avatars2.githubusercontent.com/u/333454?v=4","gravatar_id":"","url":"https://api.github.com/users/kattrali","html_url":"https://github.com/kattrali","followers_url":"https://api.github.com/users/kattrali/followers","following_url":"https://api.github.com/users/kattrali/following{/other_user}","gists_url":"https://api.github.com/users/kattrali/gists{/gist_id}","starred_url":"https://api.github.com/users/kattrali/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kattrali/subscriptions","organizations_url":"https://api.github.com/users/kattrali/orgs","repos_url":"https://api.github.com/users/kattrali/repos","events_url":"https://api.github.com/users/kattrali/events{/privacy}","received_events_url":"https://api.github.com/users/kattrali/received_events","type":"User","site_admin":false},"body":"## Goal\r\n\r\nAdded support for modifying all reports (including native crash reports) prior to delivery.\r\n\r\n## Design\r\n\r\nAdded new functionality to convert an Error cached on disk back into an Error object, which is then added to reports. The new callbacks are run on the resulting report object just prior to delivery.\r\n\r\n## Changeset\r\n\r\n|||\r\n|--|--|\r\n|Source| `15 files changed, 423 insertions(+), 38 deletions(-)`|\r\n|Tests| `14 files changed, 945 insertions(+), 5 deletions(-)` (mostly fixtures)|\r\n\r\n### Added\r\n\r\n* `ErrorReader` - A collection of static methods to read a report from a file, throwing an exception if the report is in some way invalid (such as broken JSON or missing required fields)\r\n* `Configuration.beforeSend` - New callbacks are added to the configuration directly before calling `Bugsnag.init`\r\n\r\n### Removed\r\n\r\n* `Report.errorFile` - when constructed with a file, a report then creates an Error object, so every report now has an `Error`\r\n\r\n## Tests\r\n\r\n* Added new unit tests for deserializing an Error using the Reader class\r\n* Added new integration tests for running `beforeSend` callbacks before native/and non-native crashes and notify() calls\r\n\r\n## Discussion\r\n\r\nThis new configuration option bypasses adding convenience methods to Bugsnag/Client to avoid cases where reports may be delivered prior to the callback being added. Something like:\r\n\r\n```java\r\nBugsnag.init(this); // <-- reports start sending\r\nBugsnag.beforeSend( ... ); // <-- already too late\r\n```\r\n\r\n## Review\r\n\r\nThis pull request is ready for final review, in particular:\r\n\r\n- [ ] Performance concerns during serialization\r\n- [ ] Internal consistency with the rest of the library - is there any overlap between existing interfaces and any which have been added?\r\n- [ ] Concurrency concerns - if components are accessed asynchronously, what issues will arise?\r\n- [ ] Thoroughness of added tests and any missing edge cases\r\n- [ ] Idiomatic use of the language\r\n","created_at":"2018-10-23T20:25:35Z","updated_at":"2018-10-25T18:50:10Z","closed_at":null,"merged_at":null,"merge_commit_sha":"9b94543dde4f2266e732a28ea66a70758cafe0e3","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/bugsnag/bugsnag-android/pulls/379/commits","review_comments_url":"https://api.github.com/repos/bugsnag/bugsnag-android/pulls/379/comments","review_comment_url":"https://api.github.com/repos/bugsnag/bugsnag-android/pulls/comments{/number}","comments_url":"https://api.github.com/repos/bugsnag/bugsnag-android/issues/379/comments","statuses_url":"https://api.github.com/repos/bugsnag/bugsnag-android/statuses/4448f2fbc2a4d0181528421eb3a3dea873f49f31","head":{"label":"bugsnag:kattrali/before-send-callback","ref":"kattrali/before-send-callback","sha":"4448f2fbc2a4d0181528421eb3a3dea873f49f31","user":{"login":"bugsnag","id":1058895,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEwNTg4OTU=","avatar_url":"https://avatars2.githubusercontent.com/u/1058895?v=4","gravatar_id":"","url":"https://api.github.com/users/bugsnag","html_url":"https://github.com/bugsnag","followers_url":"https://api.github.com/users/bugsnag/followers","following_url":"https://api.github.com/users/bugsnag/following{/other_user}","gists_url":"https://api.github.com/users/bugsnag/gists{/gist_id}","starred_url":"https://api.github.com/users/bugsnag/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bugsnag/subscriptions","organizations_url":"https://api.github.com/users/bugsnag/orgs","repos_url":"https://api.github.com/users/bugsnag/repos","events_url":"https://api.github.com/users/bugsnag/events{/privacy}","received_events_url":"https://api.github.com/users/bugsnag/received_events","type":"Organization","site_admin":false},"repo":{"id":2406783,"node_id":"MDEwOlJlcG9zaXRvcnkyNDA2Nzgz","name":"bugsnag-android","full_name":"bugsnag/bugsnag-android","private":false,"owner":{"login":"bugsnag","id":1058895,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEwNTg4OTU=","avatar_url":"https://avatars2.githubusercontent.com/u/1058895?v=4","gravatar_id":"","url":"https://api.github.com/users/bugsnag","html_url":"https://github.com/bugsnag","followers_url":"https://api.github.com/users/bugsnag/followers","following_url":"https://api.github.com/users/bugsnag/following{/other_user}","gists_url":"https://api.github.com/users/bugsnag/gists{/gist_id}","starred_url":"https://api.github.com/users/bugsnag/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bugsnag/subscriptions","organizations_url":"https://api.github.com/users/bugsnag/orgs","repos_url":"https://api.github.com/users/bugsnag/repos","events_url":"https://api.github.com/users/bugsnag/events{/privacy}","received_events_url":"https://api.github.com/users/bugsnag/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/bugsnag/bugsnag-android","description":"Bugsnag crash reporting for Android apps","fork":false,"url":"https://api.github.com/repos/bugsnag/bugsnag-android","forks_url":"https://api.github.com/repos/bugsnag/bugsnag-android/forks","keys_url":"https://api.github.com/repos/bugsnag/bugsnag-android/keys{/key_id}","collaborators_url":"https://api.github.com/repos/bugsnag/bugsnag-android/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/bugsnag/bugsnag-android/teams","hooks_url":"https://api.github.com/repos/bugsnag/bugsnag-android/hooks","issue_events_url":"https://api.github.com/repos/bugsnag/bugsnag-android/issues/events{/number}","events_url":"https://api.github.com/repos/bugsnag/bugsnag-android/events","assignees_url":"https://api.github.com/repos/bugsnag/bugsnag-android/assignees{/user}","branches_url":"https://api.github.com/repos/bugsnag/bugsnag-android/branches{/branch}","tags_url":"https://api.github.com/repos/bugsnag/bugsnag-android/tags","blobs_url":"https://api.github.com/repos/bugsnag/bugsnag-android/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/bugsnag/bugsnag-android/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/bugsnag/bugsnag-android/git/refs{/sha}","trees_url":"https://api.github.com/repos/bugsnag/bugsnag-android/git/trees{/sha}","statuses_url":"https://api.github.com/repos/bugsnag/bugsnag-android/statuses/{sha}","languages_url":"https://api.github.com/repos/bugsnag/bugsnag-android/languages","stargazers_url":"https://api.github.com/repos/bugsnag/bugsnag-android/stargazers","contributors_url":"https://api.github.com/repos/bugsnag/bugsnag-android/contributors","subscribers_url":"https://api.github.com/repos/bugsnag/bugsnag-android/subscribers","subscription_url":"https://api.github.com/repos/bugsnag/bugsnag-android/subscription","commits_url":"https://api.github.com/repos/bugsnag/bugsnag-android/commits{/sha}","git_commits_url":"https://api.github.com/repos/bugsnag/bugsnag-android/git/commits{/sha}","comments_url":"https://api.github.com/repos/bugsnag/bugsnag-android/comments{/number}","issue_comment_url":"https://api.github.com/repos/bugsnag/bugsnag-android/issues/comments{/number}","contents_url":"https://api.github.com/repos/bugsnag/bugsnag-android/contents/{+path}","compare_url":"https://api.github.com/repos/bugsnag/bugsnag-android/compare/{base}...{head}","merges_url":"https://api.github.com/repos/bugsnag/bugsnag-android/merges","archive_url":"https://api.github.com/repos/bugsnag/bugsnag-android/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/bugsnag/bugsnag-android/downloads","issues_url":"https://api.github.com/repos/bugsnag/bugsnag-android/issues{/number}","pulls_url":"https://api.github.com/repos/bugsnag/bugsnag-android/pulls{/number}","milestones_url":"https://api.github.com/repos/bugsnag/bugsnag-android/milestones{/number}","notifications_url":"https://api.github.com/repos/bugsnag/bugsnag-android/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/bugsnag/bugsnag-android/labels{/name}","releases_url":"https://api.github.com/repos/bugsnag/bugsnag-android/releases{/id}","deployments_url":"https://api.github.com/repos/bugsnag/bugsnag-android/deployments","created_at":"2011-09-17T21:18:06Z","updated_at":"2018-10-24T00:09:05Z","pushed_at":"2018-10-24T21:35:43Z","git_url":"git://github.com/bugsnag/bugsnag-android.git","ssh_url":"git@github.com:bugsnag/bugsnag-android.git","clone_url":"https://github.com/bugsnag/bugsnag-android.git","svn_url":"https://github.com/bugsnag/bugsnag-android","homepage":"https://www.bugsnag.com/platforms/android/","size":2776,"stargazers_count":851,"watchers_count":851,"language":"Java","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":149,"mirror_url":null,"archived":false,"open_issues_count":9,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":149,"open_issues":9,"watchers":851,"default_branch":"master"}},"base":{"label":"bugsnag:master","ref":"master","sha":"5ba5d22fd3a42dd521bcfbb12884ddb44f363963","user":{"login":"bugsnag","id":1058895,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEwNTg4OTU=","avatar_url":"https://avatars2.githubusercontent.com/u/1058895?v=4","gravatar_id":"","url":"https://api.github.com/users/bugsnag","html_url":"https://github.com/bugsnag","followers_url":"https://api.github.com/users/bugsnag/followers","following_url":"https://api.github.com/users/bugsnag/following{/other_user}","gists_url":"https://api.github.com/users/bugsnag/gists{/gist_id}","starred_url":"https://api.github.com/users/bugsnag/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bugsnag/subscriptions","organizations_url":"https://api.github.com/users/bugsnag/orgs","repos_url":"https://api.github.com/users/bugsnag/repos","events_url":"https://api.github.com/users/bugsnag/events{/privacy}","received_events_url":"https://api.github.com/users/bugsnag/received_events","type":"Organization","site_admin":false},"repo":{"id":2406783,"node_id":"MDEwOlJlcG9zaXRvcnkyNDA2Nzgz","name":"bugsnag-android","full_name":"bugsnag/bugsnag-android","private":false,"owner":{"login":"bugsnag","id":1058895,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEwNTg4OTU=","avatar_url":"https://avatars2.githubusercontent.com/u/1058895?v=4","gravatar_id":"","url":"https://api.github.com/users/bugsnag","html_url":"https://github.com/bugsnag","followers_url":"https://api.github.com/users/bugsnag/followers","following_url":"https://api.github.com/users/bugsnag/following{/other_user}","gists_url":"https://api.github.com/users/bugsnag/gists{/gist_id}","starred_url":"https://api.github.com/users/bugsnag/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bugsnag/subscriptions","organizations_url":"https://api.github.com/users/bugsnag/orgs","repos_url":"https://api.github.com/users/bugsnag/repos","events_url":"https://api.github.com/users/bugsnag/events{/privacy}","received_events_url":"https://api.github.com/users/bugsnag/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/bugsnag/bugsnag-android","description":"Bugsnag crash reporting for Android apps","fork":false,"url":"https://api.github.com/repos/bugsnag/bugsnag-android","forks_url":"https://api.github.com/repos/bugsnag/bugsnag-android/forks","keys_url":"https://api.github.com/repos/bugsnag/bugsnag-android/keys{/key_id}","collaborators_url":"https://api.github.com/repos/bugsnag/bugsnag-android/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/bugsnag/bugsnag-android/teams","hooks_url":"https://api.github.com/repos/bugsnag/bugsnag-android/hooks","issue_events_url":"https://api.github.com/repos/bugsnag/bugsnag-android/issues/events{/number}","events_url":"https://api.github.com/repos/bugsnag/bugsnag-android/events","assignees_url":"https://api.github.com/repos/bugsnag/bugsnag-android/assignees{/user}","branches_url":"https://api.github.com/repos/bugsnag/bugsnag-android/branches{/branch}","tags_url":"https://api.github.com/repos/bugsnag/bugsnag-android/tags","blobs_url":"https://api.github.com/repos/bugsnag/bugsnag-android/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/bugsnag/bugsnag-android/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/bugsnag/bugsnag-android/git/refs{/sha}","trees_url":"https://api.github.com/repos/bugsnag/bugsnag-android/git/trees{/sha}","statuses_url":"https://api.github.com/repos/bugsnag/bugsnag-android/statuses/{sha}","languages_url":"https://api.github.com/repos/bugsnag/bugsnag-android/languages","stargazers_url":"https://api.github.com/repos/bugsnag/bugsnag-android/stargazers","contributors_url":"https://api.github.com/repos/bugsnag/bugsnag-android/contributors","subscribers_url":"https://api.github.com/repos/bugsnag/bugsnag-android/subscribers","subscription_url":"https://api.github.com/repos/bugsnag/bugsnag-android/subscription","commits_url":"https://api.github.com/repos/bugsnag/bugsnag-android/commits{/sha}","git_commits_url":"https://api.github.com/repos/bugsnag/bugsnag-android/git/commits{/sha}","comments_url":"https://api.github.com/repos/bugsnag/bugsnag-android/comments{/number}","issue_comment_url":"https://api.github.com/repos/bugsnag/bugsnag-android/issues/comments{/number}","contents_url":"https://api.github.com/repos/bugsnag/bugsnag-android/contents/{+path}","compare_url":"https://api.github.com/repos/bugsnag/bugsnag-android/compare/{base}...{head}","merges_url":"https://api.github.com/repos/bugsnag/bugsnag-android/merges","archive_url":"https://api.github.com/repos/bugsnag/bugsnag-android/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/bugsnag/bugsnag-android/downloads","issues_url":"https://api.github.com/repos/bugsnag/bugsnag-android/issues{/number}","pulls_url":"https://api.github.com/repos/bugsnag/bugsnag-android/pulls{/number}","milestones_url":"https://api.github.com/repos/bugsnag/bugsnag-android/milestones{/number}","notifications_url":"https://api.github.com/repos/bugsnag/bugsnag-android/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/bugsnag/bugsnag-android/labels{/name}","releases_url":"https://api.github.com/repos/bugsnag/bugsnag-android/releases{/id}","deployments_url":"https://api.github.com/repos/bugsnag/bugsnag-android/deployments","created_at":"2011-09-17T21:18:06Z","updated_at":"2018-10-24T00:09:05Z","pushed_at":"2018-10-24T21:35:43Z","git_url":"git://github.com/bugsnag/bugsnag-android.git","ssh_url":"git@github.com:bugsnag/bugsnag-android.git","clone_url":"https://github.com/bugsnag/bugsnag-android.git","svn_url":"https://github.com/bugsnag/bugsnag-android","homepage":"https://www.bugsnag.com/platforms/android/","size":2776,"stargazers_count":851,"watchers_count":851,"language":"Java","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":149,"mirror_url":null,"archived":false,"open_issues_count":9,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":149,"open_issues":9,"watchers":851,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/bugsnag/bugsnag-android/pulls/379"},"html":{"href":"https://github.com/bugsnag/bugsnag-android/pull/379"},"issue":{"href":"https://api.github.com/repos/bugsnag/bugsnag-android/issues/379"},"comments":{"href":"https://api.github.com/repos/bugsnag/bugsnag-android/issues/379/comments"},"review_comments":{"href":"https://api.github.com/repos/bugsnag/bugsnag-android/pulls/379/comments"},"review_comment":{"href":"https://api.github.com/repos/bugsnag/bugsnag-android/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/bugsnag/bugsnag-android/pulls/379/commits"},"statuses":{"href":"https://api.github.com/repos/bugsnag/bugsnag-android/statuses/4448f2fbc2a4d0181528421eb3a3dea873f49f31"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"kattrali"}}