diff --git a/.craft.yml b/.craft.yml index 882c0c7a..9ffbd892 100644 --- a/.craft.yml +++ b/.craft.yml @@ -1,19 +1,10 @@ -minVersion: "0.15.0" -github: - owner: getsentry - repo: sentry-rust +minVersion: 0.23.1 changelogPolicy: auto - -statusProvider: - name: github artifactProvider: name: none - targets: - name: crates - noDevDeps: true - name: github - name: registry - type: sdk - config: - canonical: "cargo:sentry" + sdks: + cargo:sentry: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index de2a8c9b..13241e9d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,6 +20,8 @@ jobs: token: ${{ secrets.GH_RELEASE_PAT }} fetch-depth: 0 + - run: cargo install cargo-readme + - name: Prepare release uses: getsentry/action-prepare-release@v1 env: diff --git a/CHANGELOG.md b/CHANGELOG.md index 28ae5486..52e9e3a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,64 @@ **Breaking Changes**: +- The `backtrace` feature of `sentry-anyhow` is enabled by default. ([362](https://github.com/getsentry/sentry-rust/pull/362)) +- The `tracing-subscriber` dependency of `sentry-tracing` has been bumped to version `0.3.x`. ([377](https://github.com/getsentry/sentry-rust/pull/377)) +- `Scope::add_event_processor` now takes a generic parameter instead of a boxed function.([380](https://github.com/getsentry/sentry-rust/pull/380)) + +**Features**: + +- Added span/transaction collection to `sentry-tracing`. ([350](https://github.com/getsentry/sentry-rust/pull/350)) +- Added a new crate `sentry-tower` and feature `tower` that enables integration with `tower`. ([356](https://github.com/getsentry/sentry-rust/pull/356)) +- Added a new feature `surf-h1` for using `surf` with the h1 client. ([357](https://github.com/getsentry/sentry-rust/pull/357)) +- Added support for `Span::record` to `sentry-tracing`. ([364](https://github.com/getsentry/sentry-rust/pull/364)) +- Added Windows support for debug images. ([366](https://github.com/getsentry/sentry-rust/pull/366)) + +**Fixes**: + +- The `tokio` dependency is now only required for the `curl`, `reqwest`, and `surf` features. ([363](https://github.com/getsentry/sentry-rust/pull/363)) + +**Thank you**: + +Features, fixes and improvements in this release have been contributed by: + +- [@Tuetuopay](https://github.com/Tuetuopay) +- [@zryambus](https://github.com/zryambus) +- [@Jasper-Bekkers](https://github.com/Jasper-Bekkers) +- [@danielnelson](https://github.com/danielnelson) +- [@leops](https://github.com/leops) +- [@Turbo87](https://github.com/Turbo87) + +## 0.23.0 + +**Breaking Changes**: + - The minium supported Rust version was bumped to **1.46.0** due to requirements from dependencies. +**Features**: + +- Added support for pre-aggregated Sessions using the new `SessionMode::Request` option. This requires **Sentry 21.2**. +- Added a new `Client::flush` method to explicitly flush the transport and use that to make sure events are flushed out when using `panic=abort`. +- Added a new `flush` hook to the `Transport` trait. +- Exposed a new `RateLimiter` utility that transport implementations can use to drop envelopes early when the DSN is being rate limited. +- Optionally allow capturing backtraces from anyhow errors. +- Added new crate `sentry-tracing` and feature `tracing` that enables support to capture Events and Breadcrumbs from tracing logs. + +**Fixes**: + +- Honor the `attach_stacktrace` option correctly when capturing errors. +- Added the missing `addr_mode` property to `Frame`. +- Fixed extracting the error type from a `anyhow::msg`. + +**Thank you**: + +Features, fixes and improvements in this release have been contributed by: + +- [@XX](https://github.com/XX) +- [@Jake-Shadle](https://github.com/Jake-Shadle) +- [@Tuetuopay](https://github.com/Tuetuopay) +- [@irevoire](https://github.com/irevoire) +- [@pbzweihander](https://github.com/pbzweihander) + ## 0.22.0 **Breaking Changes**: diff --git a/Cargo.toml b/Cargo.toml index b52366d1..33d64d85 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ "sentry-log", "sentry-panic", "sentry-slog", + "sentry-tower", "sentry-tracing", "sentry-types", ] diff --git a/LICENSE b/LICENSE index d6456956..d97d9399 100644 --- a/LICENSE +++ b/LICENSE @@ -187,7 +187,8 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2021 Functional Software, Inc. dba Sentry (https://sentry.io) + and individual contributors. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sentry-actix/Cargo.toml b/sentry-actix/Cargo.toml index f5e6b81c..d3291d7d 100644 --- a/sentry-actix/Cargo.toml +++ b/sentry-actix/Cargo.toml @@ -1,22 +1,23 @@ [package] name = "sentry-actix" -version = "0.22.0" +version = "0.23.0" authors = ["Sentry "] license = "Apache-2.0" readme = "README.md" repository = "https://github.com/getsentry/sentry-rust" homepage = "https://sentry.io/welcome/" description = """ -Sentry client extension for actix-web 3. +Sentry client extension for actix-web 4. """ edition = "2018" [dependencies] -sentry-core = { version = "0.22.0", path = "../sentry-core", default-features = false } -actix-web = { version = "3", default-features = false } +sentry-core = { version = "0.23.0", path = "../sentry-core", default-features = false, features = ["client"] } +actix-service = "2.0" +actix-web = { version = "4.0.0-beta.10", default-features = false } futures-util = { version = "0.3.5", default-features = false } [dev-dependencies] -sentry = { version = "0.22.0", path = "../sentry", features = ["test"] } +sentry = { path = "../sentry", features = ["test"] } actix-rt = "2.1.0" futures = "0.3" diff --git a/sentry-actix/LICENSE b/sentry-actix/LICENSE new file mode 100644 index 00000000..d97d9399 --- /dev/null +++ b/sentry-actix/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Functional Software, Inc. dba Sentry (https://sentry.io) + and individual contributors. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sentry-actix/src/lib.rs b/sentry-actix/src/lib.rs index 4bd66b3c..7db639ba 100644 --- a/sentry-actix/src/lib.rs +++ b/sentry-actix/src/lib.rs @@ -70,7 +70,6 @@ use std::pin::Pin; use std::sync::Arc; use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform}; -use actix_web::Error; use futures_util::future::{ok, Future, Ready}; use futures_util::FutureExt; @@ -150,14 +149,13 @@ impl Default for Sentry { } } -impl Transform for Sentry +impl Transform for Sentry where - S: Service, Error = Error>, + S: Service, Error = actix_web::Error>, S::Future: 'static, { - type Request = ServiceRequest; type Response = ServiceResponse; - type Error = Error; + type Error = actix_web::Error; type Transform = SentryMiddleware; type InitError = (); type Future = Ready>; @@ -176,24 +174,23 @@ pub struct SentryMiddleware { inner: Sentry, } -impl Service for SentryMiddleware +impl Service for SentryMiddleware where - S: Service, Error = Error>, + S: Service, Error = actix_web::Error>, S::Future: 'static, { - type Request = ServiceRequest; type Response = ServiceResponse; - type Error = Error; + type Error = actix_web::Error; type Future = Pin>>>; fn poll_ready( - &mut self, + &self, cx: &mut std::task::Context<'_>, ) -> std::task::Poll> { self.service.poll_ready(cx) } - fn call(&mut self, req: ServiceRequest) -> Self::Future { + fn call(&self, req: ServiceRequest) -> Self::Future { let inner = self.inner.clone(); let hub = Arc::new(Hub::new_from_top( inner.hub.clone().unwrap_or_else(Hub::main), @@ -214,9 +211,7 @@ where let (tx, sentry_req) = sentry_request_from_http(&req, with_pii); hub.configure_scope(|scope| { scope.set_transaction(tx.as_deref()); - scope.add_event_processor(Box::new(move |event| { - Some(process_event(event, &sentry_req)) - })) + scope.add_event_processor(move |event| Some(process_event(event, &sentry_req))) }); let fut = self.service.call(req).bind_hub(hub.clone()); @@ -349,7 +344,7 @@ mod tests { HttpResponse::Ok() }; - let mut app = init_service( + let app = init_service( App::new() .wrap(Sentry::builder().with_hub(Hub::current()).finish()) .service(web::resource("/test").to(service)), @@ -359,7 +354,7 @@ mod tests { // Call the service twice (sequentially) to ensure the middleware isn't sticky for _ in 0..2 { let req = TestRequest::get().uri("/test").to_request(); - let res = call_service(&mut app, req).await; + let res = call_service(&app, req).await; assert!(res.status().is_success()); } }) @@ -381,14 +376,14 @@ mod tests { let events = sentry::test::with_captured_events(|| { block_on(async { #[get("/test")] - async fn failing(_req: HttpRequest) -> Result { + async fn failing(_req: HttpRequest) -> Result { // Current hub should have no events _assert_hub_no_events(); Err(io::Error::new(io::ErrorKind::Other, "Test Error").into()) } - let mut app = init_service( + let app = init_service( App::new() .wrap(Sentry::builder().with_hub(Hub::current()).finish()) .service(failing), @@ -398,7 +393,7 @@ mod tests { // Call the service twice (sequentially) to ensure the middleware isn't sticky for _ in 0..2 { let req = TestRequest::get().uri("/test").to_request(); - let res = call_service(&mut app, req).await; + let res = call_service(&app, req).await; assert!(res.status().is_server_error()); } }) @@ -423,7 +418,7 @@ mod tests { block_on(async { let service = || HttpResponse::NotFound(); - let mut app = init_service( + let app = init_service( App::new() .wrap(Sentry::builder().with_hub(Hub::current()).finish()) .service(web::resource("/test").to(service)), @@ -431,7 +426,7 @@ mod tests { .await; let req = TestRequest::get().uri("/test").to_request(); - let res = call_service(&mut app, req).await; + let res = call_service(&app, req).await; assert!(res.status().is_client_error()); }) }); @@ -445,13 +440,15 @@ mod tests { let events = sentry::test::with_captured_events(|| { block_on(async { #[get("/test")] - async fn original_transaction(_req: HttpRequest) -> Result { + async fn original_transaction( + _req: HttpRequest, + ) -> Result { // Override transaction name sentry::configure_scope(|scope| scope.set_transaction(Some("new_transaction"))); Err(io::Error::new(io::ErrorKind::Other, "Test Error").into()) } - let mut app = init_service( + let app = init_service( App::new() .wrap(Sentry::builder().with_hub(Hub::current()).finish()) .service(original_transaction), @@ -459,7 +456,7 @@ mod tests { .await; let req = TestRequest::get().uri("/test").to_request(); - let res = call_service(&mut app, req).await; + let res = call_service(&app, req).await; assert!(res.status().is_server_error()); }) }); @@ -487,11 +484,11 @@ mod tests { let middleware = Sentry::builder().with_hub(Hub::current()).finish(); - let mut app = init_service(App::new().wrap(middleware).service(hello)).await; + let app = init_service(App::new().wrap(middleware).service(hello)).await; for _ in 0..5 { let req = TestRequest::get().uri("/").to_request(); - call_service(&mut app, req).await; + call_service(&app, req).await; } }) }, diff --git a/sentry-anyhow/Cargo.toml b/sentry-anyhow/Cargo.toml index 55677be2..27c45874 100644 --- a/sentry-anyhow/Cargo.toml +++ b/sentry-anyhow/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sentry-anyhow" -version = "0.22.0" +version = "0.23.0" authors = ["Sentry "] license = "Apache-2.0" readme = "README.md" @@ -11,9 +11,14 @@ Sentry integration for anyhow. """ edition = "2018" +[features] +default = ["backtrace"] +backtrace = ["anyhow/backtrace"] + [dependencies] -sentry-core = { version = "0.22.0", path = "../sentry-core" } -anyhow = "1.0.30" +sentry-backtrace = { version = "0.23.0", path = "../sentry-backtrace" } +sentry-core = { version = "0.23.0", path = "../sentry-core" } +anyhow = "1.0.39" [dev-dependencies] -sentry = { version = "0.22.0", path = "../sentry", default-features = false, features = ["test"] } +sentry = { path = "../sentry", default-features = false, features = ["test"] } diff --git a/sentry-anyhow/LICENSE b/sentry-anyhow/LICENSE new file mode 100644 index 00000000..d97d9399 --- /dev/null +++ b/sentry-anyhow/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Functional Software, Inc. dba Sentry (https://sentry.io) + and individual contributors. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sentry-anyhow/README.md b/sentry-anyhow/README.md index edca1f5e..b013cbfb 100644 --- a/sentry-anyhow/README.md +++ b/sentry-anyhow/README.md @@ -1,12 +1,21 @@ -

- - - -

+# sentry-anyhow -# Sentry Rust SDK: sentry-anyhow +Adds support for capturing Sentry errors from [`anyhow::Error`]. -Adds support for capturing Sentry errors from `anyhow::Error`. +This integration adds a new event *source*, which allows you to create events directly +from an [`anyhow::Error`] struct. As it is only an event source it only needs to be +enabled using the `anyhow` cargo feature, it does not need to be enabled in the call to +[`sentry::init`](https://docs.rs/sentry/*/sentry/fn.init.html). + +This integration does not need to be installed, instead it provides an extra function to +capture [`anyhow::Error`], optionally exposing it as a method on the +[`sentry::Hub`](https://docs.rs/sentry/*/sentry/struct.Hub.html) using the +[`AnyhowHubExt`] trait. + +Like a plain [`std::error::Error`] being captured, [`anyhow::Error`] is captured with a +chain of all error sources, if present. See +[`sentry::capture_error`](https://docs.rs/sentry/*/sentry/fn.capture_error.html) for +details of this. ## Example @@ -22,9 +31,16 @@ if let Err(err) = function_that_might_fail() { } ``` -## Resources +## Features -License: Apache-2.0 +The `backtrace` feature will enable the corresponding feature in anyhow and allow you to +capture backtraces with your events. It is enabled by default. + +## Resources - [Discord](https://discord.gg/ez5KZN7) server for project discussions. -- Follow [@getsentry](https://twitter.com/getsentry) on Twitter for updates +- Follow [@getsentry](https://twitter.com/getsentry) on Twitter for updates. + +[`anyhow::Error`]: https://docs.rs/anyhow/*/anyhow/struct.Error.html + +License: Apache-2.0 diff --git a/sentry-anyhow/src/lib.rs b/sentry-anyhow/src/lib.rs index ddfd7c23..c0a398b5 100644 --- a/sentry-anyhow/src/lib.rs +++ b/sentry-anyhow/src/lib.rs @@ -29,6 +29,11 @@ //! } //! ``` //! +//! # Features +//! +//! The `backtrace` feature will enable the corresponding feature in anyhow and allow you to +//! capture backtraces with your events. It is enabled by default. +//! //! [`anyhow::Error`]: https://docs.rs/anyhow/*/anyhow/struct.Error.html #![doc(html_favicon_url = "https://sentry-brand.storage.googleapis.com/favicon.ico")] @@ -64,8 +69,40 @@ pub trait AnyhowHubExt { } impl AnyhowHubExt for Hub { - fn capture_anyhow(&self, e: &anyhow::Error) -> Uuid { - let e: &dyn std::error::Error = e.as_ref(); - self.capture_error(e) + fn capture_anyhow(&self, anyhow_error: &anyhow::Error) -> Uuid { + let dyn_err: &dyn std::error::Error = anyhow_error.as_ref(); + + #[cfg(feature = "backtrace")] + { + let mut event = sentry_core::event_from_error(dyn_err); + + // exception records are sorted in reverse + if let Some(exc) = event.exception.iter_mut().last() { + let backtrace = anyhow_error.backtrace(); + exc.stacktrace = sentry_backtrace::parse_stacktrace(&format!("{:#}", backtrace)); + } + + self.capture_event(event) + } + #[cfg(not(feature = "backtrace"))] + self.capture_error(dyn_err) } } + +#[cfg(all(feature = "backtrace", test))] +#[test] +fn test_has_backtrace() { + std::env::set_var("RUST_BACKTRACE", "1"); + + let events = sentry::test::with_captured_events(|| { + capture_anyhow(&anyhow::anyhow!("Oh jeez")); + }); + + let stacktrace = events[0].exception[0].stacktrace.as_ref().unwrap(); + let found_test_fn = stacktrace.frames.iter().any(|frame| match &frame.function { + Some(f) => f.contains("test_has_backtrace"), + None => false, + }); + + assert!(found_test_fn); +} diff --git a/sentry-backtrace/Cargo.toml b/sentry-backtrace/Cargo.toml index d77facd3..6a548a6c 100644 --- a/sentry-backtrace/Cargo.toml +++ b/sentry-backtrace/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sentry-backtrace" -version = "0.22.0" +version = "0.23.0" authors = ["Sentry "] license = "Apache-2.0" readme = "README.md" @@ -12,7 +12,7 @@ Sentry integration and utilities for dealing with stacktraces. edition = "2018" [dependencies] -sentry-core = { version = "0.22.0", path = "../sentry-core" } +sentry-core = { version = "0.23.0", path = "../sentry-core" } lazy_static = "1.4.0" backtrace = "0.3.44" regex = "1.3.4" diff --git a/sentry-backtrace/LICENSE b/sentry-backtrace/LICENSE new file mode 100644 index 00000000..d97d9399 --- /dev/null +++ b/sentry-backtrace/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Functional Software, Inc. dba Sentry (https://sentry.io) + and individual contributors. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sentry-backtrace/src/integration.rs b/sentry-backtrace/src/integration.rs index 49f68266..0a01d0f4 100644 --- a/sentry-backtrace/src/integration.rs +++ b/sentry-backtrace/src/integration.rs @@ -34,16 +34,16 @@ impl Integration for ProcessStacktraceIntegration { ) -> Option> { for exc in &mut event.exception { if let Some(ref mut stacktrace) = exc.stacktrace { - process_event_stacktrace(stacktrace, &options); + process_event_stacktrace(stacktrace, options); } } for th in &mut event.threads { if let Some(ref mut stacktrace) = th.stacktrace { - process_event_stacktrace(stacktrace, &options); + process_event_stacktrace(stacktrace, options); } } if let Some(ref mut stacktrace) = event.stacktrace { - process_event_stacktrace(stacktrace, &options); + process_event_stacktrace(stacktrace, options); } Some(event) } @@ -73,7 +73,7 @@ impl Integration for AttachStacktraceIntegration { mut event: Event<'static>, options: &ClientOptions, ) -> Option> { - if options.attach_stacktrace && event.exception.is_empty() { + if options.attach_stacktrace && !has_stacktrace(&event) { let thread = current_thread(true); if thread.stacktrace.is_some() { event.threads.values.push(thread); @@ -83,6 +83,12 @@ impl Integration for AttachStacktraceIntegration { } } +fn has_stacktrace(event: &Event) -> bool { + event.stacktrace.is_some() + || event.exception.iter().any(|exc| exc.stacktrace.is_some()) + || event.threads.iter().any(|thrd| thrd.stacktrace.is_some()) +} + /// Captures information about the current thread. /// /// If `with_stack` is set to `true` the current stacktrace is diff --git a/sentry-backtrace/src/parse.rs b/sentry-backtrace/src/parse.rs index 44677e40..1657996a 100644 --- a/sentry-backtrace/src/parse.rs +++ b/sentry-backtrace/src/parse.rs @@ -24,6 +24,7 @@ lazy_static::lazy_static! { \s+at\s # padded "at" in new line (?P[^\r\n]+?) # path to source file (?::(?P\d+))? # optional source line + (?::(?P\d+))? # optional source column )? $ "#).unwrap(); @@ -34,7 +35,7 @@ pub fn parse_stacktrace(bt: &str) -> Option { let mut last_address = None; let frames = FRAME_RE - .captures_iter(&bt) + .captures_iter(bt) .map(|captures| { let abs_path = captures.name("path").map(|m| m.as_str().to_string()); let filename = abs_path.as_ref().map(|p| filename(p).to_string()); @@ -63,6 +64,9 @@ pub fn parse_stacktrace(bt: &str) -> Option { lineno: captures .name("lineno") .map(|x| x.as_str().parse::().unwrap()), + colno: captures + .name("colno") + .map(|x| x.as_str().parse::().unwrap()), ..Default::default() } }) diff --git a/sentry-backtrace/src/trim.rs b/sentry-backtrace/src/trim.rs index 1a2308fe..844eb85c 100644 --- a/sentry-backtrace/src/trim.rs +++ b/sentry-backtrace/src/trim.rs @@ -38,7 +38,7 @@ where .iter() .rev() .position(|frame| match frame.function { - Some(ref func) => is_well_known(&func) || f(frame, stacktrace), + Some(ref func) => is_well_known(func) || f(frame, stacktrace), None => false, }); @@ -59,5 +59,5 @@ pub fn is_sys_function(func: &str) -> bool { fn is_well_known(func: &str) -> bool { WELL_KNOWN_BORDER_FRAMES .iter() - .any(|m| function_starts_with(&func, m)) + .any(|m| function_starts_with(func, m)) } diff --git a/sentry-contexts/Cargo.toml b/sentry-contexts/Cargo.toml index 8e40ea04..62b007cb 100644 --- a/sentry-contexts/Cargo.toml +++ b/sentry-contexts/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sentry-contexts" -version = "0.22.0" +version = "0.23.0" authors = ["Sentry "] license = "Apache-2.0" readme = "README.md" @@ -13,7 +13,7 @@ build = "build.rs" edition = "2018" [dependencies] -sentry-core = { version = "0.22.0", path = "../sentry-core" } +sentry-core = { version = "0.23.0", path = "../sentry-core" } libc = "0.2.66" hostname = "0.3.0" regex = "1.3.4" @@ -23,7 +23,7 @@ lazy_static = "1.4.0" uname = "0.1.1" [build-dependencies] -rustc_version = "0.3.0" +rustc_version = "0.4.0" [dev-dependencies] -sentry = { version = "0.22.0", path = "../sentry", default-features = false, features = ["test"] } +sentry = { path = "../sentry", default-features = false, features = ["test"] } diff --git a/sentry-contexts/LICENSE b/sentry-contexts/LICENSE new file mode 100644 index 00000000..d97d9399 --- /dev/null +++ b/sentry-contexts/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Functional Software, Inc. dba Sentry (https://sentry.io) + and individual contributors. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sentry-contexts/src/integration.rs b/sentry-contexts/src/integration.rs index e86eb250..6f3d842d 100644 --- a/sentry-contexts/src/integration.rs +++ b/sentry-contexts/src/integration.rs @@ -8,8 +8,19 @@ use crate::utils::{device_context, os_context, rust_context, server_name}; /// Adds Contexts to Sentry Events. /// +/// This integration is enabled by default in `sentry` and adds `device`, `os` +/// and `rust` contexts to Events, and also sets a `server_name` if it is not +/// already defined. +/// /// See the [Contexts Interface] documentation for more info. /// +/// # Examples +/// +/// ```rust +/// let integration = sentry_contexts::ContextIntegration::new().add_os(false); +/// let _sentry = sentry::init(sentry::ClientOptions::new().add_integration(integration)); +/// ``` +/// /// [Contexts Interface]: https://develop.sentry.dev/sdk/event-payloads/contexts/ #[derive(Debug)] pub struct ContextIntegration { diff --git a/sentry-contexts/src/lib.rs b/sentry-contexts/src/lib.rs index cbdcd17e..f48b0bfd 100644 --- a/sentry-contexts/src/lib.rs +++ b/sentry-contexts/src/lib.rs @@ -1,14 +1,14 @@ -//! Adds Contexts to Sentry Events +//! Adds Contexts to Sentry Events. //! //! This integration is enabled by default in `sentry` and adds `device`, `os` -//! and `rust` contexts to Events, as well as sets a `server_name` if not +//! and `rust` contexts to Events, and also sets a `server_name` if it is not //! already defined. //! //! See the [Contexts Interface] documentation for more info. //! //! # Examples //! -//! ``` +//! ```rust //! let integration = sentry_contexts::ContextIntegration::new().add_os(false); //! let _sentry = sentry::init(sentry::ClientOptions::new().add_integration(integration)); //! ``` diff --git a/sentry-core/Cargo.toml b/sentry-core/Cargo.toml index cf51c023..49e00a5d 100644 --- a/sentry-core/Cargo.toml +++ b/sentry-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sentry-core" -version = "0.22.0" +version = "0.23.0" authors = ["Sentry "] license = "Apache-2.0" readme = "README.md" @@ -27,9 +27,9 @@ debug-logs = ["log_"] test = ["client"] [dependencies] -sentry-types = { version = "0.22.0", path = "../sentry-types" } +sentry-types = { version = "0.23.0", path = "../sentry-types" } serde = { version = "1.0.104", features = ["derive"] } -chrono = "0.4.13" +chrono = { version = "0.4.13", default-features = false } lazy_static = "1.4.0" rand = { version = "0.8.1", optional = true } serde_json = "1.0.46" @@ -39,7 +39,7 @@ log_ = { package = "log", version = "0.4.8", optional = true, features = ["std"] # Because we re-export all the public API in `sentry`, we actually run all the # doctests using the `sentry` crate. This also takes care of the doctest # limitation documented in https://github.com/rust-lang/rust/issues/45599. -sentry = { version = "0.22.0", path = "../sentry", default-features = false, features = ["test"] } +sentry = { path = "../sentry", default-features = false, features = ["test"] } thiserror = "1.0.15" anyhow = "1.0.30" tokio = { version = "1.0", features = ["rt", "rt-multi-thread", "macros"] } diff --git a/sentry-core/LICENSE b/sentry-core/LICENSE new file mode 100644 index 00000000..d97d9399 --- /dev/null +++ b/sentry-core/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Functional Software, Inc. dba Sentry (https://sentry.io) + and individual contributors. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sentry-core/src/client.rs b/sentry-core/src/client.rs index 346a8dea..44034a2d 100644 --- a/sentry-core/src/client.rs +++ b/sentry-core/src/client.rs @@ -337,6 +337,17 @@ impl Client { random::() <= rate } } + + /// Returns a random boolean with a probability defined + /// by the [`ClientOptions`]'s `traces_sample_rate` + pub fn sample_traces_should_send(&self) -> bool { + let rate = self.options.traces_sample_rate; + if rate >= 1.0 { + true + } else { + random::() <= rate + } + } } // Make this unwind safe. It's not out of the box because of the diff --git a/sentry-core/src/clientoptions.rs b/sentry-core/src/clientoptions.rs index e9789c75..a450b696 100644 --- a/sentry-core/src/clientoptions.rs +++ b/sentry-core/src/clientoptions.rs @@ -72,6 +72,8 @@ pub struct ClientOptions { pub environment: Option>, /// The sample rate for event submission. (0.0 - 1.0, defaults to 1.0) pub sample_rate: f32, + /// The sample rate for tracing transactions. (0.0 - 1.0, defaults to 0.0) + pub traces_sample_rate: f32, /// Maximum number of breadcrumbs. (defaults to 100) pub max_breadcrumbs: usize, /// Attaches stacktraces to messages. @@ -179,6 +181,7 @@ impl fmt::Debug for ClientOptions { .field("release", &self.release) .field("environment", &self.environment) .field("sample_rate", &self.sample_rate) + .field("traces_sample_rate", &self.traces_sample_rate) .field("max_breadcrumbs", &self.max_breadcrumbs) .field("attach_stacktrace", &self.attach_stacktrace) .field("send_default_pii", &self.send_default_pii) @@ -210,6 +213,7 @@ impl Default for ClientOptions { release: None, environment: None, sample_rate: 1.0, + traces_sample_rate: 0.0, max_breadcrumbs: 100, attach_stacktrace: false, send_default_pii: false, diff --git a/sentry-core/src/error.rs b/sentry-core/src/error.rs index 4ee16db1..0a96538d 100644 --- a/sentry-core/src/error.rs +++ b/sentry-core/src/error.rs @@ -98,8 +98,21 @@ pub fn event_from_error(err: &E) -> Event<'static> { fn exception_from_error(err: &E) -> Exception { let dbg = format!("{:?}", err); + let value = err.to_string(); + + // A generic `anyhow::msg` will just `Debug::fmt` the `String` that you feed + // it. Trying to parse the type name from that will result in a leading quote + // and the first word, so quite useless. + // To work around this, we check if the `Debug::fmt` of the complete error + // matches its `Display::fmt`, in which case there is no type to parse and + // we will just be using `Error`. + let ty = if dbg == format!("{:?}", value) { + String::from("Error") + } else { + parse_type_from_debug(&dbg).to_owned() + }; Exception { - ty: parse_type_from_debug(&dbg).to_owned(), + ty, value: Some(err.to_string()), ..Default::default() } @@ -146,3 +159,14 @@ fn test_parse_type_from_debug() { ); assert_eq!(parse(&err), "ParseIntError"); } + +#[test] +fn test_parse_anyhow_as_error() { + let anyhow_err = anyhow::anyhow!("Ooops, something bad happened"); + let err: &dyn Error = anyhow_err.as_ref(); + + let exc = exception_from_error(err); + + assert_eq!(&exc.ty, "Error"); + assert_eq!(exc.value.as_deref(), Some("Ooops, something bad happened")); +} diff --git a/sentry-core/src/lib.rs b/sentry-core/src/lib.rs index d098f934..e16a9cb2 100644 --- a/sentry-core/src/lib.rs +++ b/sentry-core/src/lib.rs @@ -1,11 +1,11 @@ -//! This crate provides the core of the [Sentry](https://sentry.io/) SDK, which -//! can be used to log events and errors. +//! This crate provides the core of the [Sentry] SDK, which can be used to log +//! events and errors. //! -//! This crate is meant for integration authors and third party library authors +//! `sentry-core` is meant for integration authors and third-party library authors //! that want to instrument their code for sentry. //! //! Regular users who wish to integrate sentry into their applications should -//! rather use the [`sentry`] crate, which comes with a default transport, and +//! instead use the [`sentry`] crate, which comes with a default transport and //! a large set of integrations for various third-party libraries. //! //! # Core Concepts @@ -26,15 +26,16 @@ //! //! # Features //! -//! * `feature = "client"`: Activates the [`Client`] type and certain +//! - `feature = "client"`: Activates the [`Client`] type and certain //! [`Hub`] functionality. -//! * `feature = "test"`: Activates the [`test`] module, which can be used to +//! - `feature = "test"`: Activates the [`test`] module, which can be used to //! write integration tests. It comes with a test transport which can capture //! all sent events for inspection. -//! * `feature = "debug-logs"`: Uses the `log` crate for debug output, instead +//! - `feature = "debug-logs"`: Uses the `log` crate for debug output, instead //! of printing to `stderr`. This feature is **deprecated** and will be //! replaced by a dedicated log callback in the future. //! +//! [Sentry]: https://sentry.io/ //! [`sentry`]: https://crates.io/crates/sentry //! [Unified API]: https://develop.sentry.dev/sdk/unified-api/ //! [`Client`]: struct.Client.html diff --git a/sentry-core/src/scope/noop.rs b/sentry-core/src/scope/noop.rs index 82c426a3..629ad80e 100644 --- a/sentry-core/src/scope/noop.rs +++ b/sentry-core/src/scope/noop.rs @@ -95,10 +95,10 @@ impl Scope { } /// Add an event processor to the scope. - pub fn add_event_processor( - &mut self, - f: Box) -> Option> + Send + Sync>, - ) { + pub fn add_event_processor(&mut self, f: F) + where + F: Fn(Event<'static>) -> Option> + Send + Sync + 'static, + { let _f = f; minimal_unreachable!(); } diff --git a/sentry-core/src/scope/real.rs b/sentry-core/src/scope/real.rs index cb4b7627..d4904838 100644 --- a/sentry-core/src/scope/real.rs +++ b/sentry-core/src/scope/real.rs @@ -12,7 +12,7 @@ pub struct Stack { layers: Vec, } -pub type EventProcessor = Box) -> Option> + Send + Sync>; +pub type EventProcessor = Arc) -> Option> + Send + Sync>; /// Holds contextual data for the current scope. /// @@ -42,7 +42,7 @@ pub struct Scope { pub(crate) extra: Arc>, pub(crate) tags: Arc>, pub(crate) contexts: Arc>, - pub(crate) event_processors: Arc>>, + pub(crate) event_processors: Arc>, pub(crate) session: Arc>>, } @@ -215,10 +215,10 @@ impl Scope { } /// Add an event processor to the scope. - pub fn add_event_processor( - &mut self, - f: Box) -> Option> + Send + Sync>, - ) { + pub fn add_event_processor(&mut self, f: F) + where + F: Fn(Event<'static>) -> Option> + Send + Sync + 'static, + { Arc::make_mut(&mut self.event_processors).push(Arc::new(f)); } diff --git a/sentry-core/src/session.rs b/sentry-core/src/session.rs index 2023960d..a93dcc37 100644 --- a/sentry-core/src/session.rs +++ b/sentry-core/src/session.rs @@ -40,7 +40,7 @@ impl Session { pub fn from_stack(stack: &StackLayer) -> Option { let client = stack.client.as_ref()?; let options = client.options(); - let user = stack.scope.user.as_ref(); + let user = stack.scope.user.as_deref(); let distinct_id = user .and_then(|user| { user.id @@ -388,7 +388,7 @@ mod tests { assert!(session.duration.unwrap() > 0.01); assert_eq!(session.errors, 0); assert_eq!(session.attributes.release, "some-release"); - assert_eq!(session.init, true); + assert!(session.init); } else { panic!("expected session"); } @@ -494,7 +494,7 @@ mod tests { assert_eq!(session.status, SessionStatus::Ok); assert_eq!(session.errors, 1); assert_eq!(session.attributes.release, "some-release"); - assert_eq!(session.init, true); + assert!(session.init); } else { panic!("expected session"); } @@ -504,7 +504,7 @@ mod tests { if let Some(EnvelopeItem::SessionUpdate(session)) = items.next() { assert_eq!(session.status, SessionStatus::Exited); assert_eq!(session.errors, 1); - assert_eq!(session.init, false); + assert!(!session.init); } else { panic!("expected session"); } @@ -522,7 +522,7 @@ mod tests { let mut items = envelopes[0].items(); if let Some(EnvelopeItem::SessionUpdate(session)) = items.next() { assert_eq!(session.status, SessionStatus::Abnormal); - assert_eq!(session.init, true); + assert!(session.init); } else { panic!("expected session"); } @@ -594,7 +594,7 @@ mod tests { if let Some(EnvelopeItem::SessionUpdate(session)) = items.next() { assert_eq!(session.status, SessionStatus::Exited); assert_eq!(session.errors, 3); - assert_eq!(session.init, false); + assert!(!session.init); } else { panic!("expected session"); } @@ -635,7 +635,7 @@ mod tests { if let Some(EnvelopeItem::SessionUpdate(session)) = items.next() { assert_eq!(session.status, SessionStatus::Ok); assert_eq!(session.errors, 1); - assert_eq!(session.init, true); + assert!(session.init); } else { panic!("expected session"); } @@ -655,7 +655,7 @@ mod tests { if let Some(EnvelopeItem::SessionUpdate(session)) = items.next() { assert_eq!(session.status, SessionStatus::Exited); assert_eq!(session.errors, 1); - assert_eq!(session.init, false); + assert!(!session.init); } else { panic!("expected session"); } diff --git a/sentry-core/src/test.rs b/sentry-core/src/test.rs index 739fe2e6..6a8b115d 100644 --- a/sentry-core/src/test.rs +++ b/sentry-core/src/test.rs @@ -70,7 +70,7 @@ impl TestTransport { /// Fetches and clears the contained envelopes. pub fn fetch_and_clear_envelopes(&self) -> Vec { let mut guard = self.collected.lock().unwrap(); - std::mem::replace(&mut *guard, vec![]) + std::mem::take(&mut *guard) } } diff --git a/sentry-debug-images/Cargo.toml b/sentry-debug-images/Cargo.toml index 5d350809..eddc9d79 100644 --- a/sentry-debug-images/Cargo.toml +++ b/sentry-debug-images/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sentry-debug-images" -version = "0.22.0" +version = "0.23.0" authors = ["Sentry "] license = "Apache-2.0" readme = "README.md" @@ -12,6 +12,6 @@ Sentry integration that adds the list of loaded libraries to events. edition = "2018" [dependencies] -sentry-core = { version = "0.22.0", path = "../sentry-core" } +sentry-core = { version = "0.23.0", path = "../sentry-core" } lazy_static = "1.4.0" -findshlibs = "0.8.0" +findshlibs = "0.10.1" diff --git a/sentry-debug-images/LICENSE b/sentry-debug-images/LICENSE new file mode 100644 index 00000000..d97d9399 --- /dev/null +++ b/sentry-debug-images/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Functional Software, Inc. dba Sentry (https://sentry.io) + and individual contributors. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sentry-debug-images/src/unix.rs b/sentry-debug-images/src/images.rs similarity index 83% rename from sentry-debug-images/src/unix.rs rename to sentry-debug-images/src/images.rs index 59ae081f..fb4dcd40 100644 --- a/sentry-debug-images/src/unix.rs +++ b/sentry-debug-images/src/images.rs @@ -1,8 +1,7 @@ use std::env; -use sentry_core::protocol::debugid::DebugId; use sentry_core::protocol::{DebugImage, SymbolicDebugImage}; -use sentry_core::types::Uuid; +use sentry_core::types::{CodeId, DebugId, Uuid}; use findshlibs::{SharedLibrary, SharedLibraryId, TargetSharedLibrary, TARGET_SUPPORTED}; @@ -40,9 +39,11 @@ pub fn debug_images() -> Vec { } TargetSharedLibrary::each(|shlib| { - let maybe_debug_id = shlib.id().and_then(|id| match id { + let maybe_debug_id = shlib.debug_id().and_then(|id| match id { SharedLibraryId::Uuid(bytes) => Some(DebugId::from_uuid(Uuid::from_bytes(bytes))), SharedLibraryId::GnuBuildId(ref id) => debug_id_from_build_id(id), + SharedLibraryId::PdbSignature(guid, age) => DebugId::from_guid_age(&guid, age).ok(), + _ => None, }); let debug_id = match maybe_debug_id { @@ -57,14 +58,19 @@ pub fn debug_images() -> Vec { .unwrap_or_else(|_| "
".to_string()); } + let code_id = shlib.id().map(|id| CodeId::new(format!("{}", id))); + let debug_name = shlib.debug_name().map(|n| n.to_string_lossy().to_string()); + images.push( SymbolicDebugImage { + id: debug_id, name, arch: None, image_addr: shlib.actual_load_addr().0.into(), image_size: shlib.len() as u64, image_vmaddr: shlib.stated_load_addr().0.into(), - id: debug_id, + code_id, + debug_file: debug_name, } .into(), ); diff --git a/sentry-debug-images/src/lib.rs b/sentry-debug-images/src/lib.rs index 71536157..d52b904e 100644 --- a/sentry-debug-images/src/lib.rs +++ b/sentry-debug-images/src/lib.rs @@ -1,9 +1,9 @@ -//! The Sentry Debug Images Integration. +//! The Sentry Debug Images integration. //! //! The [`DebugImagesIntegration`] adds metadata about the loaded shared //! libraries to Sentry [`Event`]s. //! -//! This Integration only works on Unix-like OSs right now. Support for Windows +//! This Integration only works on Unix-like OSes right now. Support for Windows //! will be added in the future. //! //! # Configuration @@ -11,7 +11,7 @@ //! The integration by default attaches this information to all [`Event`]s, but //! a custom filter can be defined as well. //! -//! ``` +//! ```rust //! use sentry_core::Level; //! let integration = sentry_debug_images::DebugImagesIntegration::new() //! .filter(|event| event.level >= Level::Warning); @@ -24,17 +24,8 @@ #![warn(missing_docs)] #![deny(unsafe_code)] -#[cfg(unix)] -mod unix; - -#[cfg(unix)] -use unix::debug_images; - -#[cfg(not(unix))] -fn debug_images() -> Vec { - vec![] -} - +mod images; mod integration; +use images::debug_images; pub use integration::DebugImagesIntegration; diff --git a/sentry-log/Cargo.toml b/sentry-log/Cargo.toml index fcff757f..59a8bbee 100644 --- a/sentry-log/Cargo.toml +++ b/sentry-log/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sentry-log" -version = "0.22.0" +version = "0.23.0" authors = ["Sentry "] license = "Apache-2.0" readme = "README.md" @@ -12,9 +12,9 @@ Sentry integration for log and env_logger crates. edition = "2018" [dependencies] -sentry-core = { version = "0.22.0", path = "../sentry-core" } +sentry-core = { version = "0.23.0", path = "../sentry-core" } log = { version = "0.4.8", features = ["std"] } [dev-dependencies] -sentry = { version = "0.22.0", path = "../sentry", default-features = false, features = ["test"] } +sentry = { path = "../sentry", default-features = false, features = ["test"] } pretty_env_logger = "0.4.0" diff --git a/sentry-log/LICENSE b/sentry-log/LICENSE new file mode 100644 index 00000000..d97d9399 --- /dev/null +++ b/sentry-log/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Functional Software, Inc. dba Sentry (https://sentry.io) + and individual contributors. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sentry-log/src/lib.rs b/sentry-log/src/lib.rs index 68dc3000..bbf66776 100644 --- a/sentry-log/src/lib.rs +++ b/sentry-log/src/lib.rs @@ -2,7 +2,7 @@ //! //! The `log` crate is supported in two ways. First, logs can be captured as //! breadcrumbs for later. Secondly, error logs can be captured as events to -//! Sentry. By default anything above `Info` is recorded as breadcrumb and +//! Sentry. By default anything above `Info` is recorded as a breadcrumb and //! anything above `Error` is captured as error event. //! //! # Examples diff --git a/sentry-panic/Cargo.toml b/sentry-panic/Cargo.toml index 09b36fd9..f6baf4c0 100644 --- a/sentry-panic/Cargo.toml +++ b/sentry-panic/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sentry-panic" -version = "0.22.0" +version = "0.23.0" authors = ["Sentry "] license = "Apache-2.0" readme = "README.md" @@ -12,8 +12,8 @@ Sentry integration for capturing panics. edition = "2018" [dependencies] -sentry-core = { version = "0.22.0", path = "../sentry-core" } -sentry-backtrace = { version = "0.22.0", path = "../sentry-backtrace" } +sentry-core = { version = "0.23.0", path = "../sentry-core" } +sentry-backtrace = { version = "0.23.0", path = "../sentry-backtrace" } [dev-dependencies] -sentry = { version = "0.22.0", path = "../sentry", default-features = false, features = ["test"] } +sentry = { path = "../sentry", default-features = false, features = ["test"] } diff --git a/sentry-panic/LICENSE b/sentry-panic/LICENSE new file mode 100644 index 00000000..d97d9399 --- /dev/null +++ b/sentry-panic/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Functional Software, Inc. dba Sentry (https://sentry.io) + and individual contributors. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sentry-panic/src/lib.rs b/sentry-panic/src/lib.rs index 1dfbb4fa..55c9bea9 100644 --- a/sentry-panic/src/lib.rs +++ b/sentry-panic/src/lib.rs @@ -1,4 +1,4 @@ -//! The Sentry Panic handler Integration. +//! The Sentry Panic handler integration. //! //! The `PanicIntegration`, which is enabled by default in `sentry`, installs a //! panic handler that will automatically dispatch all errors to Sentry that diff --git a/sentry-slog/Cargo.toml b/sentry-slog/Cargo.toml index 7c9d4277..39a599f6 100644 --- a/sentry-slog/Cargo.toml +++ b/sentry-slog/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sentry-slog" -version = "0.22.0" +version = "0.23.0" authors = ["Sentry "] license = "Apache-2.0" readme = "README.md" @@ -12,11 +12,11 @@ Sentry integration for the slog crate. edition = "2018" [dependencies] -sentry-core = { version = "0.22.0", path = "../sentry-core" } +sentry-core = { version = "0.23.0", path = "../sentry-core" } slog = { version = "2.5.2", features = ["nested-values"] } serde_json = "1.0.46" [dev-dependencies] -sentry = { version = "0.22.0", path = "../sentry", default-features = false, features = ["test"] } +sentry = { path = "../sentry", default-features = false, features = ["test"] } serde = "1.0.117" erased-serde = "0.3.12" diff --git a/sentry-slog/LICENSE b/sentry-slog/LICENSE new file mode 100644 index 00000000..d97d9399 --- /dev/null +++ b/sentry-slog/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Functional Software, Inc. dba Sentry (https://sentry.io) + and individual contributors. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sentry-tower/Cargo.toml b/sentry-tower/Cargo.toml new file mode 100644 index 00000000..35c5d831 --- /dev/null +++ b/sentry-tower/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "sentry-tower" +version = "0.23.0" +authors = ["Sentry "] +license = "Apache-2.0" +readme = "README.md" +repository = "https://github.com/getsentry/sentry-rust" +homepage = "https://sentry.io/welcome/" +description = """ +Sentry integration for tower-based crates. +""" +edition = "2018" + +[dependencies] +tower-layer = "0.3" +tower-service = "0.3" +sentry-core = { version = "0.23.0", path = "../sentry-core", default-features = false, features = ["client"] } + +[dev-dependencies] +anyhow = "1" +prost = "0.8" +sentry = { path = "../sentry", default-features = false, features = ["test"] } +sentry-anyhow = { path = "../sentry-anyhow" } +tokio = { version = "1", features = ["macros", "rt-multi-thread"] } +tonic = { version = "0.5", features = ["transport"] } +tower = { version = "0.4", features = ["util", "timeout"] } diff --git a/sentry-tower/LICENSE b/sentry-tower/LICENSE new file mode 100644 index 00000000..d97d9399 --- /dev/null +++ b/sentry-tower/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Functional Software, Inc. dba Sentry (https://sentry.io) + and individual contributors. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sentry-tower/src/helloworld.rs b/sentry-tower/src/helloworld.rs new file mode 100644 index 00000000..b78a1677 --- /dev/null +++ b/sentry-tower/src/helloworld.rs @@ -0,0 +1,214 @@ +// Autogenerated from tonic's example proto files using `tonic-build`. +// +// Source proto files can be found at +// https://github.com/hyperium/tonic/blob/master/examples/proto/helloworld/helloworld.proto + +/// The request message containing the user's name. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HelloRequest { + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, +} +/// The response message containing the greetings +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HelloReply { + #[prost(string, tag = "1")] + pub message: ::prost::alloc::string::String, +} +#[doc = r" Generated client implementations."] +pub mod greeter_client { + #![allow(unused_variables, dead_code, missing_docs)] + use tonic::codegen::*; + #[doc = " The greeting service definition."] + #[derive(Debug, Clone)] + pub struct GreeterClient { + inner: tonic::client::Grpc, + } + impl GreeterClient { + #[doc = r" Attempt to create a new client by connecting to a given endpoint."] + pub async fn connect(dst: D) -> Result + where + D: std::convert::TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl GreeterClient + where + T: tonic::client::GrpcService, + T::ResponseBody: Body + Send + Sync + 'static, + T::Error: Into, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> GreeterClient> + where + F: FnMut(tonic::Request<()>) -> Result, tonic::Status>, + T: Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + >>::Error: + Into + Send + Sync, + { + GreeterClient::new(InterceptedService::new(inner, interceptor)) + } + #[doc = r" Compress requests with `gzip`."] + #[doc = r""] + #[doc = r" This requires the server to support it otherwise it might respond with an"] + #[doc = r" error."] + pub fn send_gzip(mut self) -> Self { + self.inner = self.inner.send_gzip(); + self + } + #[doc = r" Enable decompressing responses with `gzip`."] + pub fn accept_gzip(mut self) -> Self { + self.inner = self.inner.accept_gzip(); + self + } + #[doc = " Sends a greeting"] + pub async fn say_hello( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/helloworld.Greeter/SayHello"); + self.inner.unary(request.into_request(), path, codec).await + } + } +} +#[doc = r" Generated server implementations."] +pub mod greeter_server { + #![allow(unused_variables, dead_code, missing_docs)] + use tonic::codegen::*; + #[doc = "Generated trait containing gRPC methods that should be implemented for use with GreeterServer."] + #[async_trait] + pub trait Greeter: Send + Sync + 'static { + #[doc = " Sends a greeting"] + async fn say_hello( + &self, + request: tonic::Request, + ) -> Result, tonic::Status>; + } + #[doc = " The greeting service definition."] + #[derive(Debug)] + pub struct GreeterServer { + inner: _Inner, + accept_compression_encodings: (), + send_compression_encodings: (), + } + struct _Inner(Arc); + impl GreeterServer { + pub fn new(inner: T) -> Self { + let inner = Arc::new(inner); + let inner = _Inner(inner); + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + } + } + pub fn with_interceptor(inner: T, interceptor: F) -> InterceptedService + where + F: FnMut(tonic::Request<()>) -> Result, tonic::Status>, + { + InterceptedService::new(Self::new(inner), interceptor) + } + } + impl Service> for GreeterServer + where + T: Greeter, + B: Body + Send + Sync + 'static, + B::Error: Into + Send + 'static, + { + type Response = http::Response; + type Error = Never; + type Future = BoxFuture; + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + let inner = self.inner.clone(); + match req.uri().path() { + "/helloworld.Greeter/SayHello" => { + #[allow(non_camel_case_types)] + struct SayHelloSvc(pub Arc); + impl tonic::server::UnaryService for SayHelloSvc { + type Response = super::HelloReply; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).say_hello(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = SayHelloSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec).apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => Box::pin(async move { + Ok(http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap()) + }), + } + } + } + impl Clone for GreeterServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + } + } + } + impl Clone for _Inner { + fn clone(&self) -> Self { + Self(self.0.clone()) + } + } + impl std::fmt::Debug for _Inner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } + } + impl tonic::transport::NamedService for GreeterServer { + const NAME: &'static str = "helloworld.Greeter"; + } +} diff --git a/sentry-tower/src/lib.rs b/sentry-tower/src/lib.rs new file mode 100644 index 00000000..8a8b4936 --- /dev/null +++ b/sentry-tower/src/lib.rs @@ -0,0 +1,287 @@ +//! Adds support for automatic hub binding for each request received by the Tower server (or client, +//! though usefulness is limited in this case). +//! +//! This allows breadcrumbs collected during the request handling to land in a specific hub, and +//! avoid having them mixed across requests should a new hub be bound at each request. +//! +//! # Examples +//! +//! ```rust +//! # use tower::ServiceBuilder; +//! # use std::time::Duration; +//! # type Request = String; +//! use sentry_tower::NewSentryLayer; +//! +//! // Compose a Tower service where each request gets its own Sentry hub +//! let service = ServiceBuilder::new() +//! .layer(NewSentryLayer::::new_from_top()) +//! .timeout(Duration::from_secs(30)) +//! .service(tower::service_fn(|req: Request| format!("hello {}", req))); +//! ``` +//! +//! More customization can be achieved through the `new` function, such as passing a [`Hub`] +//! directly. +//! +//! ```rust +//! # use tower::ServiceBuilder; +//! # use std::{sync::Arc, time::Duration}; +//! # type Request = String; +//! use sentry::Hub; +//! use sentry_tower::SentryLayer; +//! +//! // Create a hub dedicated to web requests +//! let hub = Arc::new(Hub::with(|hub| Hub::new_from_top(hub))); +//! +//! // Compose a Tower service +//! let service = ServiceBuilder::new() +//! .layer(SentryLayer::<_, _, Request>::new(hub)) +//! .timeout(Duration::from_secs(30)) +//! .service(tower::service_fn(|req: Request| format!("hello {}", req))); +//! ``` +//! +//! The layer can also accept a closure to return a hub depending on the incoming request. +//! +//! ```rust +//! # use tower::ServiceBuilder; +//! # use std::{sync::Arc, time::Duration}; +//! # type Request = String; +//! use sentry::Hub; +//! use sentry_tower::SentryLayer; +//! +//! // Compose a Tower service +//! let hello = Arc::new(Hub::with(|hub| Hub::new_from_top(hub))); +//! let other = Arc::new(Hub::with(|hub| Hub::new_from_top(hub))); +//! +//! let service = ServiceBuilder::new() +//! .layer(SentryLayer::new(|req: &Request| match req.as_str() { +//! "hello" => hello.clone(), +//! _ => other.clone(), +//! })) +//! .timeout(Duration::from_secs(30)) +//! .service(tower::service_fn(|req: Request| format!("{} world", req))); +//! ``` +//! +//! When using Tonic, the layer can be used directly by the Tonic stack: +//! +//! ```rust,no_run +//! # use anyhow::*; +//! # use sentry_anyhow::capture_anyhow; +//! # use tonic::{Request, Response, Status, transport::Server}; +//! # mod hello_world { +//! # include!("helloworld.rs"); +//! # } +//! use sentry_tower::NewSentryLayer; +//! use hello_world::{*, greeter_server::*}; +//! +//! struct GreeterService; +//! +//! #[tonic::async_trait] +//! impl Greeter for GreeterService { +//! async fn say_hello(&self, req: Request) -> Result, Status> { +//! let HelloRequest { name } = req.into_inner(); +//! if name == "world" { +//! capture_anyhow(&anyhow!("Trying to greet a planet")); +//! return Err(Status::invalid_argument("Cannot greet a planet")); +//! } +//! Ok(Response::new(HelloReply { message: format!("Hello {}", name) })) +//! } +//! } +//! +//! # #[tokio::main] +//! # async fn main() -> Result<()> { +//! Server::builder() +//! .layer(NewSentryLayer::new_from_top()) +//! .add_service(GreeterServer::new(GreeterService)) +//! .serve("127.0.0.1:50051".parse().unwrap()) +//! .await?; +//! # Ok(()) +//! # } +//! ``` + +#![doc(html_favicon_url = "https://sentry-brand.storage.googleapis.com/favicon.ico")] +#![doc(html_logo_url = "https://sentry-brand.storage.googleapis.com/sentry-glyph-black.png")] +#![warn(missing_docs)] + +use sentry_core::{Hub, SentryFuture, SentryFutureExt}; +use std::marker::PhantomData; +use std::sync::Arc; +use std::task::{Context, Poll}; +use tower_layer::Layer; +use tower_service::Service; + +/// Provides a hub for each request +pub trait HubProvider +where + H: Into>, +{ + /// Returns a hub to be bound to the request + fn hub(&self, request: &Request) -> H; +} + +impl HubProvider for F +where + F: Fn(&Request) -> H, + H: Into>, +{ + fn hub(&self, request: &Request) -> H { + (self)(request) + } +} + +impl HubProvider, Request> for Arc { + fn hub(&self, _request: &Request) -> Arc { + self.clone() + } +} + +/// Provides a new hub made from the currently active hub for each request +#[derive(Clone, Copy)] +pub struct NewFromTopProvider; + +impl HubProvider, Request> for NewFromTopProvider { + fn hub(&self, _request: &Request) -> Arc { + // The Clippy lint here is a falste positive, the suggestion to write + // `Hub::with(Hub::new_from_top)` does not compiles: + // 143 | Hub::with(Hub::new_from_top).into() + // | ^^^^^^^^^ implementation of `std::ops::FnOnce` is not general enough + #[allow(clippy::redundant_closure)] + Hub::with(|hub| Hub::new_from_top(hub)).into() + } +} + +/// Tower layer that binds a specific Sentry hub for each request made. +pub struct SentryLayer +where + P: HubProvider, + H: Into>, +{ + provider: P, + _hub: PhantomData<(H, Request)>, +} + +impl Layer for SentryLayer +where + P: HubProvider + Clone, + H: Into>, +{ + type Service = SentryService; + + fn layer(&self, service: S) -> Self::Service { + SentryService { + service, + provider: self.provider.clone(), + _hub: PhantomData, + } + } +} + +impl Clone for SentryLayer +where + P: HubProvider + Clone, + H: Into>, +{ + fn clone(&self) -> Self { + Self { + provider: self.provider.clone(), + _hub: PhantomData, + } + } +} + +impl SentryLayer +where + P: HubProvider + Clone, + H: Into>, +{ + /// Build a new layer with the given Layer provider + pub fn new(provider: P) -> Self { + Self { + provider, + _hub: PhantomData, + } + } +} + +/// Tower service that binds a specific Sentry hub for each request made. +pub struct SentryService +where + P: HubProvider, + H: Into>, +{ + service: S, + provider: P, + _hub: PhantomData<(H, Request)>, +} + +impl Service for SentryService +where + S: Service, + P: HubProvider, + H: Into>, +{ + type Response = S::Response; + type Error = S::Error; + type Future = SentryFuture; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.service.poll_ready(cx) + } + + fn call(&mut self, request: Request) -> Self::Future { + let hub = self.provider.hub(&request); + self.service.call(request).bind_hub(hub) + } +} + +impl Clone for SentryService +where + S: Clone, + P: HubProvider + Clone, + H: Into>, +{ + fn clone(&self) -> Self { + Self { + service: self.service.clone(), + provider: self.provider.clone(), + _hub: PhantomData, + } + } +} + +impl SentryService +where + P: HubProvider + Clone, + H: Into>, +{ + /// Wrap a Tower service with a Tower layer that binds a Sentry hub for each request made. + pub fn new(provider: P, service: S) -> Self { + SentryLayer::::new(provider).layer(service) + } +} + +/// Tower layer that binds a new Sentry hub for each request made +pub type NewSentryLayer = SentryLayer, Request>; + +impl NewSentryLayer { + /// Create a new Sentry layer that binds a new Sentry hub for each request made + pub fn new_from_top() -> Self { + Self { + provider: NewFromTopProvider, + _hub: PhantomData, + } + } +} + +/// Tower service that binds a new Sentry hub for each request made. +pub type NewSentryService = SentryService, Request>; + +impl NewSentryService { + /// Wrap a Tower service with a Tower layer that binds a Sentry hub for each request made. + pub fn new_from_top(service: S) -> Self { + Self { + provider: NewFromTopProvider, + service, + _hub: PhantomData, + } + } +} diff --git a/sentry-tracing/Cargo.toml b/sentry-tracing/Cargo.toml index 5b15550e..bbe8a88f 100644 --- a/sentry-tracing/Cargo.toml +++ b/sentry-tracing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sentry-tracing" -version = "0.22.0" +version = "0.23.0" authors = ["Sentry "] license = "Apache-2.0" readme = "README.md" @@ -12,11 +12,12 @@ Sentry integration for tracing and tracing-subscriber crates. edition = "2018" [dependencies] -sentry-core = { version = "0.22.0", path = "../sentry-core" } +sentry-core = { version = "0.23.0", path = "../sentry-core" } tracing-core = "0.1" -tracing-subscriber = "0.2" +tracing-subscriber = { version = "0.3.1", default-features = false, features = ["std"] } [dev-dependencies] log = "0.4" -sentry = { version = "0.22.0", path = "../sentry", default-features = false, features = ["test"] } +sentry = { path = "../sentry", default-features = false, features = ["test"] } tracing = "0.1" +tokio = { version = "1.8", features = ["rt-multi-thread", "macros", "time"] } diff --git a/sentry-tracing/LICENSE b/sentry-tracing/LICENSE new file mode 100644 index 00000000..d97d9399 --- /dev/null +++ b/sentry-tracing/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Functional Software, Inc. dba Sentry (https://sentry.io) + and individual contributors. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sentry-tracing/README.md b/sentry-tracing/README.md index c38bab5a..ca8c3304 100644 --- a/sentry-tracing/README.md +++ b/sentry-tracing/README.md @@ -6,13 +6,15 @@ # Sentry Rust SDK: sentry-tracing -Adds support for automatic Breadcrumb and Event capturing from tracing events, -similar to the `sentry-log` crate. +Adds support for automatic Breadcrumb, Event and Transaction capturing from +tracing events, similar to the `sentry-log` crate. -The `tracing` crate is supported in two ways. First, events can be captured as -breadcrumbs for later. Secondly, error events can be captured as events to -Sentry. By default, anything above `Info` is recorded as breadcrumb and -anything above `Error` is captured as error event. +The `tracing` crate is supported in three ways. First, events can be captured +as breadcrumbs for later. Secondly, error events can be captured as events +to Sentry. Finally, spans can be recorded as structured transaction events. +By default, events above `Info` are recorded as breadcrumbs, events above +`Error` are captured as error events, and spans above `Info` are recorded +as transactions. By using this crate in combination with `tracing-subscriber` and its `log` integration, `sentry-log` does not need to be used, as logs will be ingested @@ -22,21 +24,49 @@ effectively replaces `sentry-log` when tracing is used. ## Examples ```rust +use std::time::Duration; + +use tokio::time::sleep; use tracing_subscriber::prelude::*; -tracing_subscriber::registry() - .with(tracing_subscriber::fmt::layer()) - .with(sentry_tracing::layer()) - .try_init() - .unwrap(); - -let _sentry = sentry::init(()); - -tracing::info!("Generates a breadcrumb"); -tracing::error!("Generates an event"); -// Also works, since log events are ingested by the tracing system -log::info!("Generates a breadcrumb"); -log::error!("Generates an event"); +#[tokio::main] +async fn main() { + let _guard = sentry::init(sentry::ClientOptions { + // Set this a to lower value in production + traces_sample_rate: 1.0, + ..sentry::ClientOptions::default() + }); + + tracing_subscriber::registry() + .with(tracing_subscriber::fmt::layer()) + .with(sentry_tracing::layer()) + .init(); + + outer().await; +} + +// Functions instrumented by tracing automatically report +// their span as transactions +#[tracing::instrument] +async fn outer() { + tracing::info!("Generates a breadcrumb"); + + for _ in 0..10 { + inner().await; + } + + tracing::error!("Generates an event"); +} + +#[tracing::instrument] +async fn inner() { + // Also works, since log events are ingested by the tracing system + log::info!("Generates a breadcrumb"); + + sleep(Duration::from_millis(100)).await; + + log::error!("Generates an event"); +} ``` Or one might also set an explicit filter, to customize how to treat log @@ -44,11 +74,16 @@ records: ```rust use sentry_tracing::EventFilter; +use tracing_subscriber::prelude::*; -let layer = sentry_tracing::layer().filter(|md| match md.level() { +let layer = sentry_tracing::layer().event_filter(|md| match md.level() { &tracing::Level::ERROR => EventFilter::Event, _ => EventFilter::Ignore, }); + +tracing_subscriber::registry() + .with(layer) + .init(); ``` ## Resources @@ -57,4 +92,3 @@ License: Apache-2.0 - [Discord](https://discord.gg/ez5KZN7) server for project discussions. - Follow [@getsentry](https://twitter.com/getsentry) on Twitter for updates - diff --git a/sentry-tracing/src/converters.rs b/sentry-tracing/src/converters.rs index 9bd98ada..954d3341 100644 --- a/sentry-tracing/src/converters.rs +++ b/sentry-tracing/src/converters.rs @@ -1,8 +1,15 @@ use std::collections::BTreeMap; -use sentry_core::protocol::{Event, Value}; +use sentry_core::protocol::{self, Event, TraceContext, Value}; use sentry_core::{Breadcrumb, Level}; -use tracing_core::field::{Field, Visit}; +use tracing_core::{ + field::{Field, Visit}, + span, Subscriber, +}; +use tracing_subscriber::layer::Context; +use tracing_subscriber::registry::LookupSpan; + +use crate::Trace; /// Converts a [`tracing_core::Level`] to a Sentry [`Level`] pub fn convert_tracing_level(level: &tracing_core::Level) -> Level { @@ -15,7 +22,9 @@ pub fn convert_tracing_level(level: &tracing_core::Level) -> Level { } /// Extracts the message and metadata from an event -pub fn extract_data(event: &tracing_core::Event) -> (Option, BTreeMap) { +pub fn extract_event_data( + event: &tracing_core::Event, +) -> (Option, BTreeMap) { // Find message of the event, if any let mut data = BTreeMapRecorder::default(); event.record(&mut data); @@ -28,9 +37,24 @@ pub fn extract_data(event: &tracing_core::Event) -> (Option, BTreeMap (Option, BTreeMap) { + let mut data = BTreeMapRecorder::default(); + attrs.record(&mut data); + + // Find message of the span, if any + let message = data + .0 + .remove("message") + .map(|v| v.as_str().map(|s| s.to_owned())) + .flatten(); + + (message, data.0) +} + #[derive(Default)] /// Records all fields of [`tracing_core::Event`] for easy access -struct BTreeMapRecorder(pub BTreeMap); +pub(crate) struct BTreeMapRecorder(pub BTreeMap); impl BTreeMapRecorder { fn record>(&mut self, field: &Field, value: T) { @@ -58,7 +82,7 @@ impl Visit for BTreeMapRecorder { /// Creates a [`Breadcrumb`] from a given [`tracing_core::Event`] pub fn breadcrumb_from_event(event: &tracing_core::Event) -> Breadcrumb { - let (message, data) = extract_data(&event); + let (message, data) = extract_event_data(event); Breadcrumb { category: Some(event.metadata().target().to_owned()), ty: "log".into(), @@ -70,22 +94,56 @@ pub fn breadcrumb_from_event(event: &tracing_core::Event) -> Breadcrumb { } /// Creates an [`Event`] from a given [`tracing_core::Event`] -pub fn event_from_event(event: &tracing_core::Event) -> Event<'static> { - let (message, extra) = extract_data(&event); - Event { +pub fn event_from_event(event: &tracing_core::Event, ctx: Context) -> Event<'static> +where + S: Subscriber + for<'a> LookupSpan<'a>, +{ + let (message, extra) = extract_event_data(event); + + let mut result = Event { logger: Some(event.metadata().target().to_owned()), level: convert_tracing_level(event.metadata().level()), message, extra, ..Default::default() + }; + + let parent = event + .parent() + .and_then(|id| ctx.span(id)) + .or_else(|| ctx.lookup_current()); + + if let Some(parent) = parent { + let extensions = parent.extensions(); + if let Some(trace) = extensions.get::() { + let context = protocol::Context::from(TraceContext { + span_id: trace.span.span_id, + trace_id: trace.span.trace_id, + ..TraceContext::default() + }); + + result.contexts.insert(String::from("trace"), context); + + result.transaction = parent + .parent() + .into_iter() + .flat_map(|span| span.scope()) + .last() + .map(|root| root.name().into()); + } } + + result } /// Creates an exception [`Event`] from a given [`tracing_core::Event`] -pub fn exception_from_event(event: &tracing_core::Event) -> Event<'static> { +pub fn exception_from_event(event: &tracing_core::Event, ctx: Context) -> Event<'static> +where + S: Subscriber + for<'a> LookupSpan<'a>, +{ // TODO: Exception records in Sentry need a valid type, value and full stack trace to support // proper grouping and issue metadata generation. tracing_core::Record does not contain sufficient // information for this. However, it may contain a serialized error which we can parse to emit // an exception record. - event_from_event(event) + event_from_event(event, ctx) } diff --git a/sentry-tracing/src/layer.rs b/sentry-tracing/src/layer.rs index 43380628..5f86ce0c 100644 --- a/sentry-tracing/src/layer.rs +++ b/sentry-tracing/src/layer.rs @@ -1,6 +1,18 @@ -use sentry_core::protocol::Breadcrumb; -use tracing_core::{Event, Level, Metadata, Subscriber}; -use tracing_subscriber::layer::{Context, Layer}; +use std::{ + collections::BTreeMap, + time::{Instant, SystemTime}, +}; + +use sentry_core::{ + protocol::{self, Breadcrumb, TraceContext, TraceId, Transaction, Value}, + types::Uuid, + Envelope, Hub, +}; +use tracing_core::{span, Event, Level, Metadata, Subscriber}; +use tracing_subscriber::{ + layer::{Context, Layer}, + registry::{LookupSpan, SpanRef}, +}; use crate::converters::*; @@ -33,7 +45,7 @@ pub enum EventMapping { /// /// By default, an exception event is captured for `error`, a breadcrumb for /// `warning` and `info`, and `debug` and `trace` logs are ignored. -pub fn default_filter(metadata: &Metadata) -> EventFilter { +pub fn default_event_filter(metadata: &Metadata) -> EventFilter { match metadata.level() { &Level::ERROR => EventFilter::Exception, &Level::WARN | &Level::INFO => EventFilter::Breadcrumb, @@ -41,56 +53,229 @@ pub fn default_filter(metadata: &Metadata) -> EventFilter { } } +/// The default span filter. +/// +/// By default, spans at the `error`, `warning`, and `info` +/// levels are captured +pub fn default_span_filter(metadata: &Metadata) -> bool { + matches!( + metadata.level(), + &Level::ERROR | &Level::WARN | &Level::INFO + ) +} + +/// The default span mapper. +/// +/// By default, a new empty span is created with the `op` +/// field set to the name of the span, with the `trace_id` +/// copied from the parent span if any +pub fn default_span_mapper( + span: &SpanRef, + parent: Option<&protocol::Span>, + attrs: &span::Attributes, +) -> protocol::Span +where + S: Subscriber + for<'a> LookupSpan<'a>, +{ + let (description, data) = extract_span_data(attrs); + + let trace_id = parent + .map(|parent| parent.trace_id) + .unwrap_or_else(TraceId::default); + + protocol::Span { + trace_id, + op: Some(span.name().into()), + description, + data, + ..protocol::Span::default() + } +} + +/// The default span on_close hook. +/// +/// By default, this sets the end timestamp of the span, +/// and creates `busy` and `idle` data fields from the timing data +pub fn default_span_on_close(span: &mut protocol::Span, timings: Timings) { + span.data + .insert(String::from("busy"), Value::Number(timings.busy.into())); + + span.data + .insert(String::from("idle"), Value::Number(timings.idle.into())); + + span.timestamp = Some(timings.end_time.into()); +} + +/// The default transaction mapper. +/// +/// By default, this creates a transaction from a root span +/// containing all of its children spans +pub fn default_transaction_mapper( + sentry_span: protocol::Span, + tracing_span: &SpanRef, + spans: Vec, + timings: Timings, +) -> Transaction<'static> +where + S: Subscriber + for<'a> LookupSpan<'a>, +{ + let mut contexts = BTreeMap::new(); + + contexts.insert( + String::from("trace"), + protocol::Context::Trace(Box::new(TraceContext { + span_id: sentry_span.span_id, + trace_id: sentry_span.trace_id, + parent_span_id: sentry_span.parent_span_id, + op: sentry_span.op, + description: sentry_span.description, + status: sentry_span.status, + })), + ); + + Transaction { + event_id: Uuid::new_v4(), + name: Some(tracing_span.name().into()), + start_timestamp: timings.start_time.into(), + timestamp: Some(timings.end_time.into()), + spans, + contexts, + ..Transaction::default() + } +} + +type SpanMapper = Box< + dyn Fn(&SpanRef, Option<&protocol::Span>, &span::Attributes) -> protocol::Span + Send + Sync, +>; + +type SpanOnClose = Box; + +type TransactionMapper = Box< + dyn Fn(protocol::Span, &SpanRef, Vec, Timings) -> Transaction<'static> + + Send + + Sync, +>; + /// Provides a tracing layer that dispatches events to sentry -pub struct SentryLayer { - filter: Box EventFilter + Send + Sync>, - mapper: Option EventMapping + Send + Sync>>, +pub struct SentryLayer { + event_filter: Box EventFilter + Send + Sync>, + event_mapper: Option EventMapping + Send + Sync>>, + + span_filter: Box bool + Send + Sync>, + span_mapper: SpanMapper, + span_on_close: SpanOnClose, + transaction_mapper: TransactionMapper, } -impl SentryLayer { - /// Sets a custom filter function. +impl SentryLayer { + /// Sets a custom event filter function. /// /// The filter classifies how sentry should handle [`Event`]s based /// on their [`Metadata`]. - pub fn filter(mut self, filter: F) -> Self + pub fn event_filter(mut self, filter: F) -> Self where F: Fn(&Metadata) -> EventFilter + Send + Sync + 'static, { - self.filter = Box::new(filter); + self.event_filter = Box::new(filter); self } - /// Sets a custom mapper function. + /// Sets a custom event mapper function. /// /// The mapper is responsible for creating either breadcrumbs or events from /// [`Event`]s. - pub fn mapper(mut self, mapper: F) -> Self + pub fn event_mapper(mut self, mapper: F) -> Self where F: Fn(&Event) -> EventMapping + Send + Sync + 'static, { - self.mapper = Some(Box::new(mapper)); + self.event_mapper = Some(Box::new(mapper)); + self + } + + /// Sets a custom span filter function. + /// + /// The filter classifies whether sentry should handle [`tracing::Span`]s based + /// on their [`Metadata`]. + pub fn span_filter(mut self, filter: F) -> Self + where + F: Fn(&Metadata) -> bool + Send + Sync + 'static, + { + self.span_filter = Box::new(filter); + self + } + + /// Sets a custom span mapper function. + /// + /// The mapper is responsible for creating [`protocol::Span`]s from + /// [`tracing::Span`]s. + pub fn span_mapper(mut self, mapper: F) -> Self + where + F: Fn(&SpanRef, Option<&protocol::Span>, &span::Attributes) -> protocol::Span + + Send + + Sync + + 'static, + { + self.span_mapper = Box::new(mapper); + self + } + + /// Sets a custom span `on_close` hook. + /// + /// The hook is called with [`Timings`] information when a [`tracing::Span`] + /// is closed, and can mutate the associated [`protocol::Span`] accordingly. + pub fn span_on_close(mut self, on_close: F) -> Self + where + F: Fn(&mut protocol::Span, Timings) + Send + Sync + 'static, + { + self.span_on_close = Box::new(on_close); + self + } + + /// Sets a custom transaction mapper function. + /// + /// The mapper is responsible for creating [`Transaction`]s from + /// [`tracing::Span`]s. + pub fn transaction_mapper(mut self, mapper: F) -> Self + where + F: Fn(protocol::Span, &SpanRef, Vec, Timings) -> Transaction<'static> + + Send + + Sync + + 'static, + { + self.transaction_mapper = Box::new(mapper); self } } -impl Default for SentryLayer { +impl Default for SentryLayer +where + S: Subscriber + for<'a> LookupSpan<'a>, +{ fn default() -> Self { Self { - filter: Box::new(default_filter), - mapper: None, + event_filter: Box::new(default_event_filter), + event_mapper: None, + + span_filter: Box::new(default_span_filter), + span_mapper: Box::new(default_span_mapper), + span_on_close: Box::new(default_span_on_close), + transaction_mapper: Box::new(default_transaction_mapper), } } } -impl Layer for SentryLayer { - fn on_event(&self, event: &Event, _ctx: Context<'_, S>) { - let item = match &self.mapper { +impl Layer for SentryLayer +where + S: Subscriber + for<'a> LookupSpan<'a>, +{ + fn on_event(&self, event: &Event, ctx: Context<'_, S>) { + let item = match &self.event_mapper { Some(mapper) => mapper(event), - None => match (self.filter)(event.metadata()) { + None => match (self.event_filter)(event.metadata()) { EventFilter::Ignore => EventMapping::Ignore, EventFilter::Breadcrumb => EventMapping::Breadcrumb(breadcrumb_from_event(event)), - EventFilter::Event => EventMapping::Event(event_from_event(event)), - EventFilter::Exception => EventMapping::Event(exception_from_event(event)), + EventFilter::Event => EventMapping::Event(event_from_event(event, ctx)), + EventFilter::Exception => EventMapping::Event(exception_from_event(event, ctx)), }, }; @@ -102,9 +287,205 @@ impl Layer for SentryLayer { _ => (), } } + + /// When a new Span gets created, run the filter and initialize the trace extension + /// if it passes + fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) { + let span = match ctx.span(id) { + Some(span) => span, + None => return, + }; + + if !(self.span_filter)(span.metadata()) { + return; + } + + let mut extensions = span.extensions_mut(); + if extensions.get_mut::().is_none() { + for parent in span.parent().into_iter().flat_map(|span| span.scope()) { + let parent = parent.extensions(); + let parent = match parent.get::() { + Some(trace) => trace, + None => continue, + }; + + let span = (self.span_mapper)(&span, Some(&parent.span), attrs); + extensions.insert(Trace::new(span)); + return; + } + + let span = (self.span_mapper)(&span, None, attrs); + extensions.insert(Trace::new(span)); + } + } + + /// From the tracing-subscriber implementation of span timings, + /// keep track of when the span was last entered + fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) { + let span = match ctx.span(id) { + Some(span) => span, + None => return, + }; + + let mut extensions = span.extensions_mut(); + if let Some(timings) = extensions.get_mut::() { + let now = Instant::now(); + timings.idle += (now - timings.last).as_nanos() as u64; + timings.last = now; + } + } + + /// From the tracing-subscriber implementation of span timings, + /// keep track of when the span was last exited + fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) { + let span = match ctx.span(id) { + Some(span) => span, + None => return, + }; + + let mut extensions = span.extensions_mut(); + if let Some(timings) = extensions.get_mut::() { + let now = Instant::now(); + timings.busy += (now - timings.last).as_nanos() as u64; + timings.last = now; + timings.last_sys = SystemTime::now(); + } + } + + /// When a span gets closed, if it has a trace extension either + /// attach it to a parent span or submit it as a Transaction if + /// it is a root of the span tree + fn on_close(&self, id: span::Id, ctx: Context<'_, S>) { + let span = match ctx.span(&id) { + Some(span) => span, + None => return, + }; + + let mut extensions = span.extensions_mut(); + let mut trace = match extensions.remove::() { + Some(trace) => trace, + None => return, + }; + + // Construct the timing data and call the on_close hook + trace.idle += (Instant::now() - trace.last).as_nanos() as u64; + + let timings = Timings { + start_time: trace.first, + end_time: trace.last_sys, + idle: trace.idle, + busy: trace.busy, + }; + + (self.span_on_close)(&mut trace.span, timings); + + // Traverse the parents of this span to attach to the nearest one + // that has tracing data (spans ignored by the span_filter do not) + for parent in span.parent().into_iter().flat_map(|span| span.scope()) { + let mut extensions = parent.extensions_mut(); + if let Some(parent) = extensions.get_mut::() { + parent.spans.extend(trace.spans); + + trace.span.parent_span_id = Some(parent.span.span_id); + parent.spans.push(trace.span); + return; + } + } + + // If no parent was found, consider this span a + // transaction root and submit it to Sentry + let span = &span; + Hub::with_active(move |hub| { + let client = match hub.client() { + Some(client) => client, + None => return, + }; + + if !client.sample_traces_should_send() { + return; + } + + let transaction = (self.transaction_mapper)(trace.span, span, trace.spans, timings); + let envelope = Envelope::from(transaction); + client.send_envelope(envelope); + }); + } + + /// Implement the writing of extra data to span + fn on_record(&self, span: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) { + let span = match ctx.span(span) { + Some(s) => s, + _ => return, + }; + + let mut extensions_holder = span.extensions_mut(); + let trace = match extensions_holder.get_mut::() { + Some(t) => t, + _ => return, + }; + + let mut data = BTreeMapRecorder::default(); + values.record(&mut data); + + for (key, value) in data.0 { + trace.span.data.insert(key, value); + } + } +} + +/// Timing informations for a given Span +#[derive(Clone, Copy, Debug)] +pub struct Timings { + /// The time the span was first entered + pub start_time: SystemTime, + /// The time the span was last entered + pub end_time: SystemTime, + /// The total busy time for this span, in nanoseconds + pub busy: u64, + /// The total idle time for this span, in nanoseconds + pub idle: u64, +} + +/// Private internal state for a Span +/// +/// Every Span that passes the `span_filter` has +/// an instance of this struct attached as an extension. +/// It is used to store transient informations while the +/// Span is being built such as the incomplete protocol::Span +/// as well as finished children Spans. +pub(crate) struct Trace { + pub(crate) span: protocol::Span, + spans: Vec, + + // From the tracing-subscriber implementation of span timings, + // with additional SystemTime informations to reconstruct the UTC + // times needed by Sentry + idle: u64, + busy: u64, + last: Instant, + first: SystemTime, + last_sys: SystemTime, +} + +impl Trace { + fn new(span: protocol::Span) -> Self { + Trace { + span, + spans: Vec::new(), + + idle: 0, + busy: 0, + last: Instant::now(), + first: SystemTime::now(), + last_sys: SystemTime::now(), + } + } } /// Creates a default Sentry layer -pub fn layer() -> SentryLayer { +pub fn layer() -> SentryLayer +where + S: Subscriber + for<'a> LookupSpan<'a>, +{ Default::default() } diff --git a/sentry-tracing/src/lib.rs b/sentry-tracing/src/lib.rs index adf0bc37..f7cd8fb7 100644 --- a/sentry-tracing/src/lib.rs +++ b/sentry-tracing/src/lib.rs @@ -1,34 +1,64 @@ -//! Adds support for automatic Breadcrumb and Event capturing from tracing -//! events, similar to the `sentry-log` crate. +//! Adds support for automatic Breadcrumb, Event and Transaction capturing from +//! tracing events, similar to the `sentry-log` crate. //! -//! The `tracing` crate is supported in two ways. First, events can be captured +//! The `tracing` crate is supported in three ways. First, events can be captured //! as breadcrumbs for later. Secondly, error events can be captured as events -//! to Sentry. By default, anything above `Info` is recorded as breadcrumb and -//! anything above `Error` is captured as error event. +//! to Sentry. Finally, spans can be recorded as structured transaction events. +//! By default, events above `Info` are recorded as breadcrumbs, events above +//! `Error` are captured as error events, and spans above `Info` are recorded +//! as transactions. //! //! By using this crate in combination with `tracing-subscriber` and its `log` //! integration, `sentry-log` does not need to be used, as logs will be ingested //! in the tracing system and generate events, thus be relayed to this crate. It //! effectively replaces `sentry-log` when tracing is used. //! -//! ## Examples +//! # Examples //! //! ```rust +//! use std::time::Duration; +//! +//! use tokio::time::sleep; //! use tracing_subscriber::prelude::*; //! -//! tracing_subscriber::registry() -//! .with(tracing_subscriber::fmt::layer()) -//! .with(sentry_tracing::layer()) -//! .try_init() -//! .unwrap(); -//! -//! let _sentry = sentry::init(()); -//! -//! tracing::info!("Generates a breadcrumb"); -//! tracing::error!("Generates an event"); -//! // Also works, since log events are ingested by the tracing system -//! log::info!("Generates a breadcrumb"); -//! log::error!("Generates an event"); +//! #[tokio::main] +//! async fn main() { +//! let _guard = sentry::init(sentry::ClientOptions { +//! // Set this a to lower value in production +//! traces_sample_rate: 1.0, +//! ..sentry::ClientOptions::default() +//! }); +//! +//! tracing_subscriber::registry() +//! .with(tracing_subscriber::fmt::layer()) +//! .with(sentry_tracing::layer()) +//! .init(); +//! +//! outer().await; +//! } +//! +//! // Functions instrumented by tracing automatically report +//! // their span as transactions +//! #[tracing::instrument] +//! async fn outer() { +//! tracing::info!("Generates a breadcrumb"); +//! +//! for _ in 0..10 { +//! inner().await; +//! } +//! +//! tracing::error!("Generates an event"); +//! } +//! +//! #[tracing::instrument] +//! async fn inner() { +//! // Also works, since log events are ingested by the tracing system +//! log::info!("Generates a breadcrumb"); +//! +//! sleep(Duration::from_millis(100)).await; +//! +//! log::error!("Generates an event"); +//! } //! ``` //! //! Or one might also set an explicit filter, to customize how to treat log @@ -36,11 +66,16 @@ //! //! ```rust //! use sentry_tracing::EventFilter; +//! use tracing_subscriber::prelude::*; //! -//! let layer = sentry_tracing::layer().filter(|md| match md.level() { +//! let layer = sentry_tracing::layer().event_filter(|md| match md.level() { //! &tracing::Level::ERROR => EventFilter::Event, //! _ => EventFilter::Ignore, //! }); +//! +//! tracing_subscriber::registry() +//! .with(layer) +//! .init(); //! ``` #![doc(html_favicon_url = "https://sentry-brand.storage.googleapis.com/favicon.ico")] diff --git a/sentry-types/Cargo.toml b/sentry-types/Cargo.toml index 329c1e6b..26f107d6 100644 --- a/sentry-types/Cargo.toml +++ b/sentry-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sentry-types" -version = "0.22.0" +version = "0.23.0" authors = ["Sentry "] license = "Apache-2.0" readme = "README.md" @@ -27,3 +27,5 @@ url = { version = "2.1.1", features = ["serde"] } chrono = { version = "0.4.13", default-features = false, features = ["clock", "std", "serde"] } uuid = { version = "0.8.1", features = ["v4", "serde"] } debugid = { version = "0.7.2", features = ["serde"] } +getrandom = "0.2.3" +hex = "0.4.3" diff --git a/sentry-types/LICENSE b/sentry-types/LICENSE new file mode 100644 index 00000000..d97d9399 --- /dev/null +++ b/sentry-types/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Functional Software, Inc. dba Sentry (https://sentry.io) + and individual contributors. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sentry-types/src/protocol/envelope.rs b/sentry-types/src/protocol/envelope.rs index 3cd29b9f..45749c99 100644 --- a/sentry-types/src/protocol/envelope.rs +++ b/sentry-types/src/protocol/envelope.rs @@ -285,8 +285,8 @@ mod test { #[test] fn test_transaction() { let event_id = Uuid::parse_str("22d00b3f-d1b1-4b5d-8d20-49d138cd8a9c").unwrap(); - let span_id = Uuid::parse_str("d42cee9f-c3e7-4f5c-ada9-47ab601a14d2").unwrap(); - let trace_id = Uuid::parse_str("335e53d6-1447-4acc-9f89-e632b776cc28").unwrap(); + let span_id = "d42cee9fc3e74f5c".parse().unwrap(); + let trace_id = "335e53d614474acc9f89e632b776cc28".parse().unwrap(); let start_timestamp = "2020-07-20T14:51:14.296Z".parse::>().unwrap(); let spans = vec![Span { span_id, @@ -304,8 +304,8 @@ mod test { assert_eq!( to_str(envelope), r#"{"event_id":"22d00b3f-d1b1-4b5d-8d20-49d138cd8a9c"} -{"type":"transaction","length":216} -{"event_id":"22d00b3fd1b14b5d8d2049d138cd8a9c","start_timestamp":1595256674.296,"spans":[{"span_id":"d42cee9fc3e74f5cada947ab601a14d2","trace_id":"335e53d614474acc9f89e632b776cc28","start_timestamp":1595256674.296}]} +{"type":"transaction","length":200} +{"event_id":"22d00b3fd1b14b5d8d2049d138cd8a9c","start_timestamp":1595256674.296,"spans":[{"span_id":"d42cee9fc3e74f5c","trace_id":"335e53d614474acc9f89e632b776cc28","start_timestamp":1595256674.296}]} "# ) } diff --git a/sentry-types/src/protocol/v7.rs b/sentry-types/src/protocol/v7.rs index 75ac12bf..32d51f35 100644 --- a/sentry-types/src/protocol/v7.rs +++ b/sentry-types/src/protocol/v7.rs @@ -7,13 +7,14 @@ use std::borrow::Cow; use std::cmp; +use std::convert::TryFrom; use std::fmt; use std::iter::FromIterator; use std::net::{AddrParseError, IpAddr}; use std::ops; use std::str; -use ::debugid::DebugId; +use ::debugid::{CodeId, DebugId}; use chrono::{DateTime, Utc}; use serde::Serializer; use serde::{Deserialize, Serialize}; @@ -39,7 +40,7 @@ pub mod map { /// Represents a debug ID. pub mod debugid { - pub use debugid::{BreakpadFormat, DebugId, ParseDebugIdError}; + pub use debugid::{BreakpadFormat, CodeId, DebugId, ParseDebugIdError}; } /// An arbitrary (JSON) value. @@ -986,6 +987,13 @@ pub struct SymbolicDebugImage { pub image_vmaddr: Addr, /// The unique debug id of the image. pub id: DebugId, + + /// Identifier of the executable file. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub code_id: Option, + /// Name / File of the debug file. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub debug_file: Option, } /// Represents a proguard mapping file reference. @@ -1255,18 +1263,110 @@ pub struct BrowserContext { pub other: Map, } +/// Holds the identifier for a Span +#[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[serde(try_from = "String", into = "String")] +pub struct SpanId([u8; 8]); + +impl Default for SpanId { + fn default() -> Self { + let mut buf = [0; 8]; + + getrandom::getrandom(&mut buf) + .unwrap_or_else(|err| panic!("could not retrieve random bytes for SpanId: {}", err)); + + Self(buf) + } +} + +impl fmt::Display for SpanId { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}", hex::encode(&self.0)) + } +} + +impl From for String { + fn from(span_id: SpanId) -> Self { + span_id.to_string() + } +} + +impl str::FromStr for SpanId { + type Err = hex::FromHexError; + + fn from_str(input: &str) -> Result { + let mut buf = [0; 8]; + hex::decode_to_slice(input, &mut buf)?; + Ok(Self(buf)) + } +} + +impl TryFrom for SpanId { + type Error = hex::FromHexError; + + fn try_from(value: String) -> Result { + value.parse() + } +} + +/// Holds the identifier for a Trace +#[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[serde(try_from = "String", into = "String")] +pub struct TraceId([u8; 16]); + +impl Default for TraceId { + fn default() -> Self { + let mut buf = [0; 16]; + + getrandom::getrandom(&mut buf) + .unwrap_or_else(|err| panic!("could not retrieve random bytes for TraceId: {}", err)); + + Self(buf) + } +} + +impl fmt::Display for TraceId { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}", hex::encode(&self.0)) + } +} + +impl From for String { + fn from(trace_id: TraceId) -> Self { + trace_id.to_string() + } +} + +impl str::FromStr for TraceId { + type Err = hex::FromHexError; + + fn from_str(input: &str) -> Result { + let mut buf = [0; 16]; + hex::decode_to_slice(input, &mut buf)?; + Ok(Self(buf)) + } +} + +impl TryFrom for TraceId { + type Error = hex::FromHexError; + + fn try_from(value: String) -> Result { + value.parse() + } +} + /// Holds information about a tracing event. #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)] pub struct TraceContext { /// The ID of the trace event - #[serde(default = "event::default_id", serialize_with = "event::serialize_id")] - pub span_id: Uuid, + #[serde(default)] + pub span_id: SpanId, /// Determines which trace the transaction belongs to. - #[serde(default = "event::default_id", serialize_with = "event::serialize_id")] - pub trace_id: Uuid, + #[serde(default)] + pub trace_id: TraceId, /// Determines the parent of this transaction if any. #[serde(default, skip_serializing_if = "Option::is_none")] - pub parent_span_id: Option, + pub parent_span_id: Option, /// Short code identifying the type of operation the transaction is measuring. #[serde(default, skip_serializing_if = "Option::is_none")] pub op: Option, @@ -1275,7 +1375,7 @@ pub struct TraceContext { pub description: Option, /// Describes the status of the span (e.g. `ok`, `cancelled`, etc.) #[serde(default, skip_serializing_if = "Option::is_none")] - pub status: Option, + pub status: Option, } macro_rules! into_context { @@ -1520,14 +1620,14 @@ impl<'a> fmt::Display for Event<'a> { #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct Span { /// The ID of the span - #[serde(default = "event::default_id", serialize_with = "event::serialize_id")] - pub span_id: Uuid, + #[serde(default)] + pub span_id: SpanId, /// Determines which trace the span belongs to. - #[serde(default = "event::default_id", serialize_with = "event::serialize_id")] - pub trace_id: Uuid, + #[serde(default)] + pub trace_id: TraceId, /// Determines the parent of this span, if any. #[serde(default, skip_serializing_if = "Option::is_none")] - pub parent_span_id: Option, + pub parent_span_id: Option, /// Determines whether this span is generated in the same process as its parent, if any. #[serde(default, skip_serializing_if = "Option::is_none")] pub same_process_as_parent: Option, @@ -1546,7 +1646,7 @@ pub struct Span { pub start_timestamp: DateTime, /// Describes the status of the span (e.g. `ok`, `cancelled`, etc.) #[serde(default, skip_serializing_if = "Option::is_none")] - pub status: Option, + pub status: Option, /// Optional tags to be attached to the span. #[serde(default, skip_serializing_if = "Map::is_empty")] pub tags: Map, @@ -1558,8 +1658,8 @@ pub struct Span { impl Default for Span { fn default() -> Self { Span { - span_id: event::default_id(), - trace_id: event::default_id(), + span_id: Default::default(), + trace_id: Default::default(), timestamp: Default::default(), tags: Default::default(), start_timestamp: event::default_timestamp(), @@ -1595,6 +1695,119 @@ impl fmt::Display for Span { } } +/// An error used when parsing `SpanStatus`. +#[derive(Debug, Error)] +#[error("invalid status")] +pub struct ParseStatusError; + +/// The status of a Span. +#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum SpanStatus { + /// The operation completed successfully. + #[serde(rename = "ok")] + Ok, + /// Deadline expired before operation could complete. + #[serde(rename = "deadline_exceeded")] + DeadlineExceeded, + /// 401 Unauthorized (actually does mean unauthenticated according to RFC 7235) + #[serde(rename = "unauthenticated")] + Unauthenticated, + /// 403 Forbidden + #[serde(rename = "permission_denied")] + PermissionDenied, + /// 404 Not Found. Some requested entity (file or directory) was not found. + #[serde(rename = "not_found")] + NotFound, + /// 429 Too Many Requests + #[serde(rename = "resource_exhausted")] + ResourceExhausted, + /// Client specified an invalid argument. 4xx. + #[serde(rename = "invalid_argument")] + InvalidArgument, + /// 501 Not Implemented + #[serde(rename = "unimplemented")] + Unimplemented, + /// 503 Service Unavailable + #[serde(rename = "unavailable")] + Unavailable, + /// Other/generic 5xx. + #[serde(rename = "internal_error")] + InternalError, + /// Unknown. Any non-standard HTTP status code. + #[serde(rename = "unknown_error")] + UnknownError, + /// The operation was cancelled (typically by the user). + #[serde(rename = "cancelled")] + Cancelled, + /// Already exists (409) + #[serde(rename = "already_exists")] + AlreadyExists, + /// Operation was rejected because the system is not in a state required for the operation's + #[serde(rename = "failed_precondition")] + FailedPrecondition, + /// The operation was aborted, typically due to a concurrency issue. + #[serde(rename = "aborted")] + Aborted, + /// Operation was attempted past the valid range. + #[serde(rename = "out_of_range")] + OutOfRange, + /// Unrecoverable data loss or corruption + #[serde(rename = "data_loss")] + DataLoss, +} + +impl str::FromStr for SpanStatus { + type Err = ParseStatusError; + + fn from_str(s: &str) -> Result { + Ok(match s { + "ok" => SpanStatus::Ok, + "deadline_exceeded" => SpanStatus::DeadlineExceeded, + "unauthenticated" => SpanStatus::Unauthenticated, + "permission_denied" => SpanStatus::PermissionDenied, + "not_found" => SpanStatus::NotFound, + "resource_exhausted" => SpanStatus::ResourceExhausted, + "invalid_argument" => SpanStatus::InvalidArgument, + "unimplemented" => SpanStatus::Unimplemented, + "unavailable" => SpanStatus::Unavailable, + "internal_error" => SpanStatus::InternalError, + "unknown_error" => SpanStatus::UnknownError, + "cancelled" => SpanStatus::Cancelled, + "already_exists" => SpanStatus::AlreadyExists, + "failed_precondition" => SpanStatus::FailedPrecondition, + "aborted" => SpanStatus::Aborted, + "out_of_range" => SpanStatus::OutOfRange, + "data_loss" => SpanStatus::DataLoss, + _ => return Err(ParseStatusError), + }) + } +} + +impl fmt::Display for SpanStatus { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SpanStatus::Ok => write!(f, "ok"), + SpanStatus::DeadlineExceeded => write!(f, "deadline_exceeded"), + SpanStatus::Unauthenticated => write!(f, "unauthenticated"), + SpanStatus::PermissionDenied => write!(f, "permission_denied"), + SpanStatus::NotFound => write!(f, "not_found"), + SpanStatus::ResourceExhausted => write!(f, "resource_exhausted"), + SpanStatus::InvalidArgument => write!(f, "invalid_argument"), + SpanStatus::Unimplemented => write!(f, "unimplemented"), + SpanStatus::Unavailable => write!(f, "unavailable"), + SpanStatus::InternalError => write!(f, "internal_error"), + SpanStatus::UnknownError => write!(f, "unknown_error"), + SpanStatus::Cancelled => write!(f, "cancelled"), + SpanStatus::AlreadyExists => write!(f, "already_exists"), + SpanStatus::FailedPrecondition => write!(f, "failed_precondition"), + SpanStatus::Aborted => write!(f, "aborted"), + SpanStatus::OutOfRange => write!(f, "out_of_range"), + SpanStatus::DataLoss => write!(f, "data_loss"), + } + } +} + /// Represents a tracing transaction. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct Transaction<'a> { @@ -1602,7 +1815,11 @@ pub struct Transaction<'a> { #[serde(default = "event::default_id", serialize_with = "event::serialize_id")] pub event_id: Uuid, /// The transaction name. - #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde( + rename = "transaction", + default, + skip_serializing_if = "Option::is_none" + )] pub name: Option, /// Optional tags to be attached to the event. #[serde(default, skip_serializing_if = "Map::is_empty")] diff --git a/sentry-types/tests/test_protocol_v7.rs b/sentry-types/tests/test_protocol_v7.rs index e0056e9b..2d4b110a 100644 --- a/sentry-types/tests/test_protocol_v7.rs +++ b/sentry-types/tests/test_protocol_v7.rs @@ -767,6 +767,8 @@ mod test_debug_meta { image_size: 4096, image_vmaddr: 32768.into(), id: "494f3aea-88fa-4296-9644-fa8ef5d139b6-1234".parse().unwrap(), + code_id: None, + debug_file: None, } .into(), v7::ProguardDebugImage { diff --git a/sentry/Cargo.toml b/sentry/Cargo.toml index de42bf4f..6ecf9b29 100644 --- a/sentry/Cargo.toml +++ b/sentry/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sentry" -version = "0.22.0" +version = "0.23.0" authors = ["Sentry "] license = "Apache-2.0" readme = "README.md" @@ -12,8 +12,12 @@ Sentry (getsentry.com) client for rust ;) edition = "2018" autoexamples = true +# To build locally: +# RUSTDOCFLAGS="--cfg doc_cfg" cargo +nightly doc --all-features --open [package.metadata.docs.rs] all-features = true +# Defines the configuration attribute `doc_cfg` in order to expose feature-gated docs. +rustdoc-args = ["--cfg", "doc_cfg"] [features] default = ["backtrace", "contexts", "panic", "transport"] @@ -27,45 +31,50 @@ anyhow = ["sentry-anyhow"] debug-images = ["sentry-debug-images"] log = ["sentry-log"] slog = ["sentry-slog"] +tower = ["sentry-tower"] tracing = ["sentry-tracing"] # other features test = ["sentry-core/test"] debug-logs = ["log_", "sentry-core/debug-logs"] # transports transport = ["reqwest", "native-tls"] -reqwest = ["reqwest_", "httpdate"] -curl = ["curl_", "httpdate", "serde_json"] -surf = ["surf_", "httpdate"] +reqwest = ["reqwest_", "httpdate", "tokio"] +curl = ["curl_", "httpdate", "serde_json", "tokio"] +surf-h1 = ["surf_/h1-client", "httpdate"] +surf = ["surf_/curl-client", "httpdate", "tokio"] native-tls = ["reqwest_/default-tls"] rustls = ["reqwest_/rustls-tls"] [dependencies] -sentry-core = { version = "0.22.0", path = "../sentry-core", features = ["client"] } -sentry-anyhow = { version = "0.22.0", path = "../sentry-anyhow", optional = true } -sentry-backtrace = { version = "0.22.0", path = "../sentry-backtrace", optional = true } -sentry-contexts = { version = "0.22.0", path = "../sentry-contexts", optional = true } -sentry-debug-images = { version = "0.22.0", path = "../sentry-debug-images", optional = true } -sentry-log = { version = "0.22.0", path = "../sentry-log", optional = true } -sentry-panic = { version = "0.22.0", path = "../sentry-panic", optional = true } -sentry-slog = { version = "0.22.0", path = "../sentry-slog", optional = true } -sentry-tracing = { version = "0.22.0", path = "../sentry-tracing", optional = true } +sentry-core = { version = "0.23.0", path = "../sentry-core", features = ["client"] } +sentry-anyhow = { version = "0.23.0", path = "../sentry-anyhow", optional = true } +sentry-backtrace = { version = "0.23.0", path = "../sentry-backtrace", optional = true } +sentry-contexts = { version = "0.23.0", path = "../sentry-contexts", optional = true } +sentry-debug-images = { version = "0.23.0", path = "../sentry-debug-images", optional = true } +sentry-log = { version = "0.23.0", path = "../sentry-log", optional = true } +sentry-panic = { version = "0.23.0", path = "../sentry-panic", optional = true } +sentry-slog = { version = "0.23.0", path = "../sentry-slog", optional = true } +sentry-tower = { version = "0.23.0", path = "../sentry-tower", optional = true } +sentry-tracing = { version = "0.23.0", path = "../sentry-tracing", optional = true } log_ = { package = "log", version = "0.4.8", optional = true, features = ["std"] } reqwest_ = { package = "reqwest", version = "0.11", optional = true, features = ["blocking", "json"], default-features = false } curl_ = { package = "curl", version = "0.4.25", optional = true } -surf_ = { package = "surf", version = "2.0.0", optional = true } httpdate = { version = "1.0.0", optional = true } +surf_ = { package = "surf", version = "2.0.0", optional = true, default-features = false } serde_json = { version = "1.0.48", optional = true } -tokio = { version = "1.0", features = ["rt"] } +tokio = { version = "1.0", features = ["rt"], optional = true } [dev-dependencies] -sentry-anyhow = { version = "0.22.0", path = "../sentry-anyhow" } -sentry-log = { version = "0.22.0", path = "../sentry-log" } -sentry-slog = { version = "0.22.0", path = "../sentry-slog" } -sentry-tracing = { version = "0.22.0", path = "../sentry-tracing" } +sentry-anyhow = { path = "../sentry-anyhow" } +sentry-log = { path = "../sentry-log" } +sentry-slog = { path = "../sentry-slog" } +sentry-tower = { path = "../sentry-tower" } +sentry-tracing = { path = "../sentry-tracing" } log_ = { package = "log", version = "0.4.8", features = ["std"] } slog_ = { package = "slog", version = "2.5.2" } +tower_ = { package = "tower", version = "0.4", features = ["util"] } tracing_ = { package = "tracing", version = "0.1" } -tracing-subscriber = { version = "0.2", features = ["fmt", "tracing-log"] } +tracing-subscriber = { version = "0.3", features = ["fmt", "tracing-log"] } actix-web = { version = "3", default-features = false } tokio = { version = "1.0", features = ["macros"] } pretty_env_logger = "0.4.0" diff --git a/sentry/LICENSE b/sentry/LICENSE new file mode 100644 index 00000000..d97d9399 --- /dev/null +++ b/sentry/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Functional Software, Inc. dba Sentry (https://sentry.io) + and individual contributors. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sentry/examples/event-processors.rs b/sentry/examples/event-processors.rs index 42e24805..b3078a32 100644 --- a/sentry/examples/event-processors.rs +++ b/sentry/examples/event-processors.rs @@ -2,14 +2,14 @@ fn main() { let _sentry = sentry::init(()); sentry::configure_scope(|scope| { - scope.add_event_processor(Box::new(move |mut event| { + scope.add_event_processor(|mut event| { event.request = Some(sentry::protocol::Request { url: Some("https://example.com/".parse().unwrap()), method: Some("GET".into()), ..Default::default() }); Some(event) - })); + }); }); sentry::configure_scope(|scope| { diff --git a/sentry/src/lib.rs b/sentry/src/lib.rs index f93597d2..51c29c24 100644 --- a/sentry/src/lib.rs +++ b/sentry/src/lib.rs @@ -1,38 +1,49 @@ //! This crate provides support for logging events and errors / panics to the -//! [Sentry](https://sentry.io/) error logging service. It integrates with the standard panic +//! [Sentry] error logging service. It integrates with the standard panic //! system in Rust as well as a few popular error handling setups. //! +//! [Sentry]: https://sentry.io/ +//! //! # Quickstart //! -//! The most convenient way to use this library is the [`sentry::init`] function, +//! The most convenient way to use this library is via the [`sentry::init`] function, //! which starts a sentry client with a default set of integrations, and binds //! it to the current [`Hub`]. //! //! The [`sentry::init`] function returns a guard that when dropped will flush Events that were not -//! yet sent to the sentry service. It has a two second deadline for this so shutdown of -//! applications might slightly delay as a result of this. Keep the guard around or sending events +//! yet sent to the sentry service. It has a two second deadline for this so shutdown of +//! applications might slightly delay as a result of this. Keep the guard around or sending events //! will not work. //! -//! ``` +//! ```rust //! let _guard = sentry::init("https://key@sentry.io/42"); //! sentry::capture_message("Hello World!", sentry::Level::Info); //! // when the guard goes out of scope here, the client will wait up to two //! // seconds to send remaining events to the service. //! ``` //! +//! More complex examples on how to use sentry can also be found in [examples]. Extended instructions +//! may also be found on [Sentry itself]. +//! //! [`sentry::init`]: fn.init.html //! [`Hub`]: struct.Hub.html +//! [examples]: https://github.com/getsentry/sentry-rust/tree/master/sentry/examples +//! [Sentry itself]: https://docs.sentry.io/platforms/rust //! //! # Integrations //! -//! What makes this crate useful are the various integrations that exist. Some of them are enabled -//! by default, some uncommon ones or for deprecated parts of the ecosystem a feature flag needs to -//! be enabled. For the available integrations and how to use them see -//! [integrations](integrations/index.html) and [apply_defaults](fn.apply_defaults.html). +//! What makes this crate useful are its various integrations. Some of them are enabled by +//! default; See [Features]. Uncommon integrations or integrations for deprecated parts of +//! the ecosystem require a feature flag. For available integrations and how to use them, see +//! [integrations] and [apply_defaults]. +//! +//! [Features]: #features +//! [integrations]: integrations/index.html +//! [apply_defaults]: fn.apply_defaults.html //! //! # Minimal API //! -//! This crate comes fully featured. If the goal is to instrument libraries for usage +//! This crate comes fully-featured. If the goal is to instrument libraries for usage //! with sentry, or to extend sentry with a custom [`Integration`] or a [`Transport`], //! one should use the [`sentry-core`] crate instead. //! @@ -42,37 +53,66 @@ //! //! # Features //! -//! Functionality of the crate can be turned on and off by feature flags. This is the current list -//! of feature flags: -//! -//! Default features: -//! -//! * `backtrace`: Enables backtrace support. -//! * `contexts`: Enables capturing device, os, and rust contexts. -//! * `panic`: Enables support for capturing panics. -//! * `transport`: Enables the default transport, which is currently `reqwest` with `native-tls`. -//! -//! Additional features: -//! -//! * `anyhow`: Enables support for the `anyhow` crate. -//! * `debug-images`: Attaches a list of loaded libraries to events (currently only supported on unix). -//! * `log`: Enables support for the `log` and `env_logger` crate. -//! * `slog`: Enables support for the `slog` crate. -//! * `tracing`: Enables support for the `tracing` crate. -//! * `test`: Enables testing support. -//! * `debug-logs`: Uses the `log` crate for internal logging. -//! * `reqwest`: Enables the `reqwest` transport, which is currently the default. -//! * `curl`: Enables the curl transport. -//! * `surf`: Enables the surf transport. -//! * `native-tls`: Uses the `native-tls` crate, which is currently the default. -//! This only has an effect on the `reqwest` transport. -//! * `rustls`: Enables the `rustls` support of the `reqwest` transport. -//! Please note that `native-tls` is a default feature, and one needs to use -//! `default-features = false` to completely disable building `native-tls` dependencies. - +//! Additional functionality and integrations are enabled via feature flags. Some features require +//! extra setup to function properly. +//! +//! | Feature | Default | Is Integration | Deprecated | Additional notes | +//! | -------------- | ------- | -------------- | ---------- | ---------------------------------------------------------------------------------------- | +//! | `backtrace` | ✅ | 🔌 | | | +//! | `contexts` | ✅ | 🔌 | | | +//! | `panic` | ✅ | 🔌 | | | +//! | `transport` | ✅ | | | | +//! | `anyhow` | | 🔌 | | | +//! | `test` | | | | | +//! | `debug-images` | | 🔌 | | | +//! | `log` | | 🔌 | | Requires extra setup; See [`sentry-log`]'s documentation. | +//! | `debug-logs` | | | ❗ | Requires extra setup; See [`sentry-log`]'s documentation. | +//! | `slog` | | 🔌 | | Requires extra setup; See [`sentry-slog`]'s documentation. | +//! | `reqwest` | ✅ | | | | +//! | `native-tls` | ✅ | | | `reqwest` must be enabled. | +//! | `rustls` | | | | `reqwest` must be enabled. `native-tls` must be disabled via `default-features = false`. | +//! | `curl` | | | | | +//! | `surf` | | | | | +//! | `tower` | | 🔌 | | Requires extra setup; See [`sentry-tower`]'s documentation. | +//! +//! [`sentry-log`]: https://crates.io/crates/sentry-log +//! [`sentry-slog`]: https://crates.io/crates/sentry-slog +//! [`sentry-tower`]: https://crates.io/crates/sentry-tower +//! +//! ## Default features +//! - `backtrace`: Enables backtrace support. +//! - `contexts`: Enables capturing device, OS, and Rust contexts. +//! - `panic`: Enables support for capturing panics. +//! - `transport`: Enables the default transport, which is currently `reqwest` with `native-tls`. +//! +//! ## Debugging/Testing +//! - `anyhow`: Enables support for the `anyhow` crate. +//! - `test`: Enables testing support. +//! - `debug-images`: Attaches a list of loaded libraries to events (currently only supported on Unix). +//! +//! ## Logging +//! - `log`: Enables support for the `log` crate. +//! - `slog`: Enables support for the `slog` crate. +//! - `debug-logs`: **Deprecated**. Uses the `log` crate for internal logging. +//! +//! ## Transports +//! - `reqwest`: **Default**. Enables the `reqwest` transport. +//! - `native-tls`: **Default**. Uses the `native-tls` crate. This only affects the `reqwest` transport. +//! - `rustls`: Enables `rustls` support for `reqwest`. Please note that `native-tls` is a default +//! feature, and `default-features = false` must be set to completely disable building `native-tls` +//! dependencies. +//! - `curl`: Enables the curl transport. +//! - `surf`: Enables the surf transport. +//! +//! ## Integrations +//! - `tower`: Enables support for the `tower` crate and those using it. #![doc(html_favicon_url = "https://sentry-brand.storage.googleapis.com/favicon.ico")] #![doc(html_logo_url = "https://sentry-brand.storage.googleapis.com/sentry-glyph-black.png")] #![warn(missing_docs)] +// Only enables the `doc_cfg` feature when the `doc_cfg` configuration attribute +// is defined. Used to expose docs for feature-locked integrations, and other +// feature-gated documentation. +#![cfg_attr(doc_cfg, feature(doc_cfg))] mod defaults; mod init; @@ -89,28 +129,26 @@ pub use crate::init::{init, ClientInitGuard}; /// Available Sentry Integrations. /// /// Integrations extend the functionality of the SDK for some common frameworks and -/// libraries. Integrations come two primary kinds: as event *sources* or as event -/// *processors*. +/// libraries. There are two different kinds of integrations: +/// - Event sources +/// - Event processors /// -/// Integrations which are *sources*, like e.g. the -/// [`sentry::integrations::anyhow`](integrations::anyhow) integration, usually provide one -/// or more functions to create new events. They will usually provide their own extension -/// trait exposing a new method on the [`Hub`]. +/// Integrations which are **event sources** such as +/// [`sentry::integrations::anyhow`] typically provide one or more functions to +/// create new events. These integrations will have an extension trait which exposes +/// a new method on the [`Hub`]. /// -/// Integrations which *process* events in some way usually implement the -/// [`Itegration`](crate::Integration) trait and need to be installed when sentry is -/// initialised. +/// Integrations which **process events** in some way usually implement the +/// [`Integration`] trait and need to be installed when sentry is initialised. /// /// # Installing Integrations /// -/// Processing integrations which implement [`Integration`](crate::Integration) need to be -/// installed when sentry is initialised. This is done using the -/// [`ClientOptions::add_integration`](crate::ClientOptions::add_integration) function, which you can -/// use to add extra integrations. +/// Processing integrations which implement [`Integration`] need to be installed +/// when sentry is initialised. This can be accomplished by using +/// [`ClientOptions::add_integration()`]. /// -/// For example if you disabled the default integrations (see below) but still wanted the -/// [`sentry::integrations::debug_images`](integrations::debug_images) integration enabled, -/// you could do this as such: +/// For example, if one were to disable the default integrations (see below) but +/// still wanted to use [`sentry::integrations::debug_images`]: /// /// ``` /// # #[cfg(feature = "debug-images")] { @@ -127,37 +165,54 @@ pub use crate::init::{init, ClientInitGuard}; /// /// # Default Integrations /// -/// The [`ClientOptions::default_integrations`](crate::ClientOptions::default_integrations) -/// option is a boolean field that when enabled will enable a number of default integrations -/// **before** any integrations provided by -/// [`ClientOptions::integrations`](crate::ClientOptions::integrations) are installed. This -/// is done using the [`apply_defaults`] function, which should be consulted for more -/// details and the list of which integrations are enabled by default. +/// The [`ClientOptions::default_integrations`] option is a boolean field that +/// when enabled will enable all of the default integrations via +/// [`apply_defaults()`] **before** any integrations provided by +/// [`ClientOptions::integrations`] are installed. Those interested in a list +/// of default integrations and how they are applied are advised to visit +/// [`apply_defaults()`]'s implementation. /// -/// [`apply_defaults`]: ../fn.apply_defaults.html +/// [`sentry::integrations::anyhow`]: integrations::anyhow +/// [`Integration`]: crate::Integration +/// [`ClientOptions::add_integration()`]: crate::ClientOptions::add_integration +/// [`sentry::integrations::debug_images`]: integrations::debug_images +/// [`ClientOptions::default_integrations`]: crate::ClientOptions::default_integrations +/// [`apply_defaults()`]: ../fn.apply_defaults.html pub mod integrations { #[cfg(feature = "anyhow")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "anyhow")))] #[doc(inline)] pub use sentry_anyhow as anyhow; #[cfg(feature = "backtrace")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "backtrace")))] #[doc(inline)] pub use sentry_backtrace as backtrace; #[cfg(feature = "contexts")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "contexts")))] #[doc(inline)] pub use sentry_contexts as contexts; #[cfg(feature = "debug-images")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "debug_images")))] #[doc(inline)] pub use sentry_debug_images as debug_images; #[cfg(feature = "log")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "log")))] #[doc(inline)] pub use sentry_log as log; #[cfg(feature = "panic")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "panic")))] #[doc(inline)] pub use sentry_panic as panic; #[cfg(feature = "slog")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "slog")))] #[doc(inline)] pub use sentry_slog as slog; + #[cfg(feature = "tower")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "tower")))] + #[doc(inline)] + pub use sentry_tower as tower; #[cfg(feature = "tracing")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "tracing")))] #[doc(inline)] pub use sentry_tracing as tracing; } diff --git a/sentry/src/transports/curl.rs b/sentry/src/transports/curl.rs index 8a7468e1..560e41b4 100644 --- a/sentry/src/transports/curl.rs +++ b/sentry/src/transports/curl.rs @@ -9,7 +9,10 @@ use crate::{sentry_debug, types::Scheme, ClientOptions, Envelope, Transport}; /// A [`Transport`] that sends events via the [`curl`] library. /// -/// This is enabled by the `curl` flag. +/// This is enabled by the `curl` feature flag. +/// +/// [`curl`]: https://crates.io/crates/curl +#[cfg_attr(doc_cfg, doc(cfg(feature = "curl")))] pub struct CurlHttpTransport { thread: TransportThread, } @@ -43,10 +46,10 @@ impl CurlHttpTransport { match (scheme, &http_proxy, &https_proxy) { (Scheme::Https, _, &Some(ref proxy)) => { - handle.proxy(&proxy).unwrap(); + handle.proxy(proxy).unwrap(); } (_, &Some(ref proxy), _) => { - handle.proxy(&proxy).unwrap(); + handle.proxy(proxy).unwrap(); } _ => {} } diff --git a/sentry/src/transports/reqwest.rs b/sentry/src/transports/reqwest.rs index af986dbf..752a8f7e 100644 --- a/sentry/src/transports/reqwest.rs +++ b/sentry/src/transports/reqwest.rs @@ -10,7 +10,10 @@ use crate::{sentry_debug, ClientOptions, Envelope, Transport}; /// /// When the `transport` feature is enabled this will currently /// be the default transport. This is separately enabled by the -/// `reqwest` flag. +/// `reqwest` feature flag. +/// +/// [`reqwest`]: https://crates.io/crates/reqwest +#[cfg_attr(doc_cfg, doc(cfg(feature = "reqwest")))] pub struct ReqwestHttpTransport { thread: TransportThread, } diff --git a/sentry/src/transports/surf.rs b/sentry/src/transports/surf.rs index 17d41756..4b0eb5f9 100644 --- a/sentry/src/transports/surf.rs +++ b/sentry/src/transports/surf.rs @@ -8,7 +8,10 @@ use crate::{sentry_debug, ClientOptions, Envelope, Transport}; /// A [`Transport`] that sends events via the [`surf`] library. /// -/// This is enabled by the `surf` flag. +/// This is enabled by the `surf` feature flag. +/// +/// [`surf`]: https://crates.io/crates/surf +#[cfg_attr(doc_cfg, doc(cfg(feature = "surf")))] pub struct SurfHttpTransport { thread: TransportThread, } diff --git a/sentry/tests/test_basic.rs b/sentry/tests/test_basic.rs index 33f5607d..ae9a64de 100644 --- a/sentry/tests/test_basic.rs +++ b/sentry/tests/test_basic.rs @@ -139,3 +139,37 @@ fn test_reentrant_configure_scope() { // well, the "outer" `configure_scope` wins assert_eq!(events[0].tags["which_scope"], "scope1"); } + +#[test] +fn test_attached_stacktrace() { + use log_ as log; + + let logger = sentry_log::SentryLogger::new(); + + log::set_boxed_logger(Box::new(logger)) + .map(|()| log::set_max_level(log::LevelFilter::Info)) + .unwrap(); + + let options = sentry::apply_defaults(sentry::ClientOptions { + attach_stacktrace: true, + ..Default::default() + }); + let events = sentry::test::with_captured_events_options( + || { + let error = "thisisnotanumber".parse::().unwrap_err(); + sentry::capture_error(&error); + + sentry::capture_message("some kind of message", sentry::Level::Info); + + log::error!("Shit's on fire yo"); + }, + options, + ); + + assert_eq!(events.len(), 3); + + let stacktraces = events + .into_iter() + .flat_map(|ev| ev.threads.into_iter().filter_map(|thrd| thrd.stacktrace)); + assert_eq!(stacktraces.count(), 3); +} diff --git a/sentry/tests/test_processors.rs b/sentry/tests/test_processors.rs index c6f4d0b7..84fb5bf4 100644 --- a/sentry/tests/test_processors.rs +++ b/sentry/tests/test_processors.rs @@ -7,13 +7,13 @@ fn test_event_processors() { let events = sentry::test::with_captured_events(|| { sentry::configure_scope(|scope| { scope.set_tag("worker", "worker1"); - scope.add_event_processor(Box::new(move |mut event| { + scope.add_event_processor(|mut event| { event.user = Some(sentry::User { email: Some("foo@example.com".into()), ..Default::default() }); Some(event) - })); + }); }); sentry::capture_message("Hello World!", sentry::Level::Warning); }); diff --git a/sentry/tests/test_tower.rs b/sentry/tests/test_tower.rs new file mode 100644 index 00000000..acfb4d95 --- /dev/null +++ b/sentry/tests/test_tower.rs @@ -0,0 +1,80 @@ +#![cfg(feature = "test")] + +use std::sync::Arc; + +use sentry::{ + protocol::{Breadcrumb, Level}, + test::TestTransport, + ClientOptions, Hub, +}; +use sentry_tower::SentryLayer; +use tower_::{ServiceBuilder, ServiceExt}; + +#[test] +fn test_tower_hub() { + // Create a fake transport for new hubs + let transport = TestTransport::new(); + let opts = ClientOptions { + dsn: Some("https://public@sentry.invalid/1".parse().unwrap()), + transport: Some(Arc::new(transport.clone())), + ..Default::default() + }; + + let events = sentry::test::with_captured_events(|| { + // This breadcrumb should be in all subsequent requests + sentry::add_breadcrumb(Breadcrumb { + message: Some("Starting service...".to_owned()), + level: Level::Info, + ..Default::default() + }); + sentry::capture_message("Started service", Level::Info); + + #[allow(clippy::redundant_closure)] + let hub = Arc::new(Hub::with(|hub| Hub::new_from_top(hub))); + hub.bind_client(Some(Arc::new(opts.into()))); + + let service = ServiceBuilder::new() + .layer(SentryLayer::new(hub)) + .service_fn(|req: String| async move { + // This breadcrumb should not be seen in any other hub + sentry::add_breadcrumb(Breadcrumb { + message: Some(format!("Got request with arg: {}", req)), + level: Level::Info, + ..Default::default() + }); + sentry::capture_message("Request failed", Level::Error); + Err::<(), _>(format!("Can't greet {}, sorry.", req)) + }); + + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + let res = rt.block_on(service.oneshot("World".to_owned())); + + assert_eq!(res, Err("Can't greet World, sorry.".to_owned())); + }); + + assert_eq!(events.len(), 1); + let event = events.into_iter().next().unwrap(); + assert_eq!(event.message, Some("Started service".into())); + assert_eq!(event.breadcrumbs.len(), 1); + assert_eq!( + event.breadcrumbs[0].message, + Some("Starting service...".into()) + ); + + let events = transport.fetch_and_clear_events(); + assert_eq!(events.len(), 1); + let event = events.into_iter().next().unwrap(); + assert_eq!(event.message, Some("Request failed".into())); + assert_eq!(event.breadcrumbs.len(), 2); + assert_eq!( + event.breadcrumbs[0].message, + Some("Starting service...".into()) + ); + assert_eq!( + event.breadcrumbs[1].message, + Some("Got request with arg: World".into()) + ); +} diff --git a/sentry/tests/test_tracing.rs b/sentry/tests/test_tracing.rs index 80ffd966..a16feb09 100644 --- a/sentry/tests/test_tracing.rs +++ b/sentry/tests/test_tracing.rs @@ -7,10 +7,9 @@ use tracing_subscriber::prelude::*; #[test] fn test_tracing() { // Don't configure the fmt layer to avoid logging to test output - tracing_subscriber::registry() + let _dispatcher = tracing_subscriber::registry() .with(sentry_tracing::layer()) - .try_init() - .unwrap(); + .set_default(); let events = sentry::test::with_captured_events(|| { sentry::configure_scope(|scope| { @@ -54,3 +53,41 @@ fn test_tracing() { Some("Hello Logging World!".into()) ); } + +#[tracing::instrument(fields(span_field))] +fn function() { + tracing::Span::current().record("span_field", &"some data"); +} + +#[test] +fn test_span_record() { + let _dispatcher = tracing_subscriber::registry() + .with(sentry_tracing::layer()) + .set_default(); + + let options = sentry::ClientOptions { + traces_sample_rate: 1.0, + ..Default::default() + }; + + let envelopes = sentry::test::with_captured_envelopes_options( + || { + let _span = tracing::span!(tracing::Level::INFO, "span").entered(); + function(); + }, + options, + ); + + assert_eq!(envelopes.len(), 1); + + let envelope_item = envelopes[0].items().next().unwrap(); + let transaction = match envelope_item { + sentry::protocol::EnvelopeItem::Transaction(t) => t, + _ => panic!("expected only a transaction item"), + }; + + assert_eq!( + transaction.spans[0].data["span_field"].as_str().unwrap(), + "some data" + ); +}