From 9ea18cb5c801c1528357f2ec5abe800355926b91 Mon Sep 17 00:00:00 2001 From: Travis Long Date: Mon, 12 Feb 2024 08:08:37 -0600 Subject: [PATCH 01/34] Bumped version to 57.0.0 --- .buildconfig.yml | 2 +- CHANGELOG.md | 6 +- Cargo.lock | 4 +- DEPENDENCIES.md | 412 ++++-------------- glean-core/Cargo.toml | 2 +- .../android-native/dependency-licenses.xml | 27 +- glean-core/android/dependency-licenses.xml | 27 +- glean-core/rlb/Cargo.toml | 4 +- .../GleanGradlePlugin.groovy | 2 +- pyproject.toml | 2 +- 10 files changed, 135 insertions(+), 353 deletions(-) diff --git a/.buildconfig.yml b/.buildconfig.yml index 743e441a00..0ec255690b 100644 --- a/.buildconfig.yml +++ b/.buildconfig.yml @@ -1,4 +1,4 @@ -libraryVersion: 56.1.0 +libraryVersion: 57.0.0 groupId: org.mozilla.telemetry projects: glean: diff --git a/CHANGELOG.md b/CHANGELOG.md index 194a9db841..cd5cbc040f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Unreleased changes -[Full changelog](https://github.com/mozilla/glean/compare/v56.1.0...main) +[Full changelog](https://github.com/mozilla/glean/compare/v57.0.0...main) + +# v57.0.0 (2024-02-12) + +[Full changelog](https://github.com/mozilla/glean/compare/v56.1.0...v57.0.0) * General * Added an experimental event listener API ([#2719](https://github.com/mozilla/glean/pull/2719)) diff --git a/Cargo.lock b/Cargo.lock index 17998f3d67..0835a139ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -316,7 +316,7 @@ dependencies = [ [[package]] name = "glean" -version = "56.1.0" +version = "57.0.0" dependencies = [ "chrono", "crossbeam-channel", @@ -361,7 +361,7 @@ dependencies = [ [[package]] name = "glean-core" -version = "56.1.0" +version = "57.0.0" dependencies = [ "android_logger", "bincode", diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index d46bdd0697..64e9ce5ff8 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -415,7 +415,7 @@ The following text applies to code linked from these dependencies: The following text applies to code linked from these dependencies: -* [rkv 0.18.4]( https://github.com/mozilla/rkv ) +* [rkv 0.19.0]( https://github.com/mozilla/rkv ) * [static_assertions 1.1.0]( https://github.com/nvzqz/static-assertions-rs ) ``` @@ -2105,6 +2105,7 @@ The following text applies to code linked from these dependencies: * [crossbeam-channel 0.5.11]( https://github.com/crossbeam-rs/crossbeam ) * [crossbeam-utils 0.8.19]( https://github.com/crossbeam-rs/crossbeam ) * [env_logger 0.10.0]( https://github.com/rust-cli/env_logger/ ) +* [errno 0.3.3]( https://github.com/lambda-fairy/rust-errno ) * [fastrand 2.0.0]( https://github.com/smol-rs/fastrand ) * [flate2 1.0.26]( https://github.com/rust-lang/flate2-rs ) * [form_urlencoded 1.1.0]( https://github.com/servo/rust-url ) @@ -2115,7 +2116,7 @@ The following text applies to code linked from these dependencies: * [itoa 1.0.4]( https://github.com/dtolnay/itoa ) * [lazy_static 1.4.0]( https://github.com/rust-lang-nursery/lazy-static.rs ) * [linux-raw-sys 0.4.10]( https://github.com/sunfishcode/linux-raw-sys ) -* [log 0.4.18]( https://github.com/rust-lang/log ) +* [log 0.4.20]( https://github.com/rust-lang/log ) * [mime 0.3.16]( https://github.com/hyperium/mime ) * [num-integer 0.1.45]( https://github.com/rust-num/num-integer ) * [num-traits 0.2.15]( https://github.com/rust-num/num-traits ) @@ -4687,385 +4688,164 @@ SOFTWARE. The following text applies to code linked from these dependencies: -* [glean 56.1.0]( https://github.com/mozilla/glean ) -* [glean-build 11.0.1]( https://github.com/mozilla/glean ) -* [glean-core 56.1.0]( https://github.com/mozilla/glean ) -* [zeitstempel 0.1.1]( https://github.com/badboy/zeitstempel ) +* [embedded-uniffi-bindgen 0.1.0]( https://crates.io/crates/embedded-uniffi-bindgen ) +* [glean-bundle 1.0.0]( https://github.com/mozilla/glean ) +* [glean-bundle-android 1.0.0]( https://github.com/mozilla/glean ) +* [uniffi 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [uniffi_bindgen 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [uniffi_build 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [uniffi_checksum_derive 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [uniffi_core 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [uniffi_macros 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [uniffi_meta 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [uniffi_testing 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [uniffi_udl 0.25.3]( https://github.com/mozilla/uniffi-rs ) ``` Mozilla Public License Version 2.0 -================================== 1. Definitions --------------- -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. + 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. + 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. -1.3. "Contribution" - means Covered Software of a particular Contributor. + 1.3. "Contribution" means Covered Software of a particular Contributor. -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. + 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. -1.5. "Incompatible With Secondary Licenses" - means + 1.5. "Incompatible With Secondary Licenses" means - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or + (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. + (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. -1.6. "Executable Form" - means any form of the work other than Source Code Form. + 1.6. "Executable Form" means any form of the work other than Source Code Form. -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. + 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. -1.8. "License" - means this document. + 1.8. "License" means this document. -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. + 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. -1.10. "Modifications" - means any of the following: + 1.10. "Modifications" means any of the following: - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or + (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or - (b) any new file in Source Code Form that contains any Covered - Software. + (b) any new file in Source Code Form that contains any Covered Software. -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. + 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. + 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. -1.13. "Source Code Form" - means the form of the work preferred for making modifications. + 1.13. "Source Code Form" means the form of the work preferred for making modifications. -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. + 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions --------------------------------- -2.1. Grants + 2.1. Grants + Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: + (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and + (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. + 2.2. Effective Date + The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. -2.2. Effective Date + 2.3. Limitations on Grant Scope + The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. + (a) for any code that a Contributor has removed from Covered Software; or -2.3. Limitations on Grant Scope + (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: + (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. + This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). -2.6. Fair Use + 2.4. Subsequent Licenses + No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. + 2.5. Representation + Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. -2.7. Conditions + 2.6. Fair Use + This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. + 2.7. Conditions + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities -------------------- -3.1. Distribution of Source Form + 3.1. Distribution of Source Form + All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. + 3.2. Distribution of Executable Form + If You distribute Covered Software in Executable Form then: -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). + (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and -3.4. Notices + (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. + 3.3. Distribution of a Larger Work + You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). -3.5. Application of Additional Terms + 3.4. Notices + You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. + 3.5. Application of Additional Terms + You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. +If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination --------------- -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. + 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. + 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. + 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ +6. Disclaimer of Warranty +Covered Software is provided under this License on an "as is" basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ +7. Limitation of Liability +Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. 8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. +Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. +This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. -10.3. Modified Versions + 10.1. New Versions + Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). + 10.2. Effect of New Versions + You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses + 10.3. Modified Versions + If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. + 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice -------------------------------------------- - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. +If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. + This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. ``` ## Mozilla Public License 2.0 @@ -5073,18 +4853,10 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice The following text applies to code linked from these dependencies: -* [embedded-uniffi-bindgen 0.1.0]( https://crates.io/crates/embedded-uniffi-bindgen ) -* [glean-bundle 1.0.0]( https://github.com/mozilla/glean ) -* [glean-bundle-android 1.0.0]( https://github.com/mozilla/glean ) -* [uniffi 0.25.3]( https://github.com/mozilla/uniffi-rs ) -* [uniffi_bindgen 0.25.3]( https://github.com/mozilla/uniffi-rs ) -* [uniffi_build 0.25.3]( https://github.com/mozilla/uniffi-rs ) -* [uniffi_checksum_derive 0.25.3]( https://github.com/mozilla/uniffi-rs ) -* [uniffi_core 0.25.3]( https://github.com/mozilla/uniffi-rs ) -* [uniffi_macros 0.25.3]( https://github.com/mozilla/uniffi-rs ) -* [uniffi_meta 0.25.3]( https://github.com/mozilla/uniffi-rs ) -* [uniffi_testing 0.25.3]( https://github.com/mozilla/uniffi-rs ) -* [uniffi_udl 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [glean 57.0.0]( https://github.com/mozilla/glean ) +* [glean-build 11.0.1]( https://github.com/mozilla/glean ) +* [glean-core 57.0.0]( https://github.com/mozilla/glean ) +* [zeitstempel 0.1.1]( https://github.com/badboy/zeitstempel ) ``` Mozilla Public License Version 2.0 @@ -5124,7 +4896,7 @@ Mozilla Public License Version 2.0 means any form of the work other than Source Code Form. 1.7. "Larger Work" - means a work that combines Covered Software with other material, in + means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" @@ -5446,7 +5218,7 @@ Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at https://mozilla.org/MPL/2.0/. + file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE diff --git a/glean-core/Cargo.toml b/glean-core/Cargo.toml index d0105ac35e..fbfe15909b 100644 --- a/glean-core/Cargo.toml +++ b/glean-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "glean-core" -version = "56.1.0" +version = "57.0.0" authors = ["Jan-Erik Rediger ", "The Glean Team "] description = "A modern Telemetry library" repository = "https://github.com/mozilla/glean" diff --git a/glean-core/android-native/dependency-licenses.xml b/glean-core/android-native/dependency-licenses.xml index 4a56a39a25..25a22bdba5 100644 --- a/glean-core/android-native/dependency-licenses.xml +++ b/glean-core/android-native/dependency-licenses.xml @@ -105,6 +105,9 @@ the details of which are reproduced below. Apache License 2.0: env_logger https://github.com/rust-cli/env_logger/ + + Apache License 2.0: errno + https://github.com/lambda-fairy/rust-errno Apache License 2.0: fastrand https://github.com/smol-rs/fastrand @@ -294,18 +297,6 @@ the details of which are reproduced below. MIT License: bincode https://github.com/servo/bincode - - Mozilla Public License 2.0: glean - https://github.com/mozilla/glean - - Mozilla Public License 2.0: glean-build - https://github.com/mozilla/glean - - Mozilla Public License 2.0: glean-core - https://github.com/mozilla/glean - - Mozilla Public License 2.0: zeitstempel - https://github.com/badboy/zeitstempel Mozilla Public License 2.0: embedded-uniffi-bindgen https://crates.io/crates/embedded-uniffi-bindgen @@ -342,6 +333,18 @@ the details of which are reproduced below. Mozilla Public License 2.0: uniffi_udl https://github.com/mozilla/uniffi-rs + + Mozilla Public License 2.0: glean + https://github.com/mozilla/glean + + Mozilla Public License 2.0: glean-build + https://github.com/mozilla/glean + + Mozilla Public License 2.0: glean-core + https://github.com/mozilla/glean + + Mozilla Public License 2.0: zeitstempel + https://github.com/badboy/zeitstempel Unicode License Agreement - Data Files and Software (2016): unicode-ident https://github.com/dtolnay/unicode-ident diff --git a/glean-core/android/dependency-licenses.xml b/glean-core/android/dependency-licenses.xml index 4a56a39a25..25a22bdba5 100644 --- a/glean-core/android/dependency-licenses.xml +++ b/glean-core/android/dependency-licenses.xml @@ -105,6 +105,9 @@ the details of which are reproduced below. Apache License 2.0: env_logger https://github.com/rust-cli/env_logger/ + + Apache License 2.0: errno + https://github.com/lambda-fairy/rust-errno Apache License 2.0: fastrand https://github.com/smol-rs/fastrand @@ -294,18 +297,6 @@ the details of which are reproduced below. MIT License: bincode https://github.com/servo/bincode - - Mozilla Public License 2.0: glean - https://github.com/mozilla/glean - - Mozilla Public License 2.0: glean-build - https://github.com/mozilla/glean - - Mozilla Public License 2.0: glean-core - https://github.com/mozilla/glean - - Mozilla Public License 2.0: zeitstempel - https://github.com/badboy/zeitstempel Mozilla Public License 2.0: embedded-uniffi-bindgen https://crates.io/crates/embedded-uniffi-bindgen @@ -342,6 +333,18 @@ the details of which are reproduced below. Mozilla Public License 2.0: uniffi_udl https://github.com/mozilla/uniffi-rs + + Mozilla Public License 2.0: glean + https://github.com/mozilla/glean + + Mozilla Public License 2.0: glean-build + https://github.com/mozilla/glean + + Mozilla Public License 2.0: glean-core + https://github.com/mozilla/glean + + Mozilla Public License 2.0: zeitstempel + https://github.com/badboy/zeitstempel Unicode License Agreement - Data Files and Software (2016): unicode-ident https://github.com/dtolnay/unicode-ident diff --git a/glean-core/rlb/Cargo.toml b/glean-core/rlb/Cargo.toml index fc88a1890b..19baea550d 100644 --- a/glean-core/rlb/Cargo.toml +++ b/glean-core/rlb/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "glean" -version = "56.1.0" +version = "57.0.0" authors = ["Jan-Erik Rediger ", "The Glean Team "] description = "Glean SDK Rust language bindings" repository = "https://github.com/mozilla/glean" @@ -23,7 +23,7 @@ maintenance = { status = "actively-developed" } [dependencies.glean-core] path = ".." -version = "56.1.0" +version = "57.0.0" [dependencies] crossbeam-channel = "0.5" diff --git a/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy b/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy index 8fcd160c3d..958dd46cb3 100644 --- a/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy +++ b/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy @@ -552,7 +552,7 @@ except: void apply(Project project) { isOffline = project.gradle.startParameter.offline - project.ext.glean_version = "56.1.0" + project.ext.glean_version = "57.0.0" def parserVersion = gleanParserVersion(project) // Print the required glean_parser version to the console. This is diff --git a/pyproject.toml b/pyproject.toml index 79e753feac..f9793c9eab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "glean-sdk" -version = "56.1.0" +version = "57.0.0" requires-python = ">=3.8" classifiers = [ "Intended Audience :: Developers", From 27f35b24a40cc244f3f6e1b3969280853d3c52a3 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Mon, 22 Jan 2024 11:56:35 +0100 Subject: [PATCH 02/34] Rust: Remove `OnceCell`s around Mutexes Now that Mutex, Vec and String have const `new` methods, we don't need the OnceCell anymore and can just use the statics directly. This should still be safe: * Everything still behind a Mutex, and thus thread-safe * We previously didn't reset those values, and we still don't other than setting the Mutex-locked wrapped value --- glean-core/src/lib.rs | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/glean-core/src/lib.rs b/glean-core/src/lib.rs index a54e57a95b..b7f9d73beb 100644 --- a/glean-core/src/lib.rs +++ b/glean-core/src/lib.rs @@ -91,12 +91,12 @@ pub(crate) const DELETION_REQUEST_PINGS_DIRECTORY: &str = "deletion_request"; static INITIALIZE_CALLED: AtomicBool = AtomicBool::new(false); /// Keep track of the debug features before Glean is initialized. -static PRE_INIT_DEBUG_VIEW_TAG: OnceCell> = OnceCell::new(); +static PRE_INIT_DEBUG_VIEW_TAG: Mutex = Mutex::new(String::new()); static PRE_INIT_LOG_PINGS: AtomicBool = AtomicBool::new(false); -static PRE_INIT_SOURCE_TAGS: OnceCell>> = OnceCell::new(); +static PRE_INIT_SOURCE_TAGS: Mutex> = Mutex::new(Vec::new()); /// Keep track of pings registered before Glean is initialized. -static PRE_INIT_PING_REGISTRATION: OnceCell>> = OnceCell::new(); +static PRE_INIT_PING_REGISTRATION: Mutex> = Mutex::new(Vec::new()); /// Global singleton of the handles of the glean.init threads. /// For joining. For tests. @@ -396,11 +396,9 @@ fn initialize_inner( core::with_glean_mut(|glean| { // The debug view tag might have been set before initialize, // get the cached value and set it. - if let Some(tag) = PRE_INIT_DEBUG_VIEW_TAG.get() { - let lock = tag.try_lock(); - if let Ok(ref debug_tag) = lock { - glean.set_debug_view_tag(debug_tag); - } + let debug_tag = PRE_INIT_DEBUG_VIEW_TAG.lock().unwrap(); + if debug_tag.len() > 0 { + glean.set_debug_view_tag(&debug_tag); } // The log pings debug option might have been set before initialize, @@ -412,11 +410,9 @@ fn initialize_inner( // The source tags might have been set before initialize, // get the cached value and set them. - if let Some(tags) = PRE_INIT_SOURCE_TAGS.get() { - let lock = tags.try_lock(); - if let Ok(ref source_tags) = lock { - glean.set_source_tags(source_tags.to_vec()); - } + let source_tags = PRE_INIT_SOURCE_TAGS.lock().unwrap(); + if source_tags.len() > 0 { + glean.set_source_tags(source_tags.to_vec()); } // Get the current value of the dirty flag so we know whether to @@ -428,13 +424,9 @@ fn initialize_inner( // Perform registration of pings that were attempted to be // registered before init. - if let Some(tags) = PRE_INIT_PING_REGISTRATION.get() { - let lock = tags.try_lock(); - if let Ok(pings) = lock { - for ping in &*pings { - glean.register_ping_type(ping); - } - } + let pings = PRE_INIT_PING_REGISTRATION.lock().unwrap(); + for ping in pings.iter() { + glean.register_ping_type(ping); } // If this is the first time ever the Glean SDK runs, make sure to set @@ -861,7 +853,7 @@ pub(crate) fn register_ping_type(ping: &PingType) { // if ping registration is attempted before Glean initializes. // This state is kept across Glean resets, which should only ever happen in test mode. // It's a set and keeping them around forever should not have much of an impact. - let m = PRE_INIT_PING_REGISTRATION.get_or_init(Default::default); + let m = &PRE_INIT_PING_REGISTRATION; let mut lock = m.lock().unwrap(); lock.push(ping.clone()); } @@ -956,7 +948,7 @@ pub fn glean_set_debug_view_tag(tag: String) -> bool { true } else { // Glean has not been initialized yet. Cache the provided tag value. - let m = PRE_INIT_DEBUG_VIEW_TAG.get_or_init(Default::default); + let m = &PRE_INIT_DEBUG_VIEW_TAG; let mut lock = m.lock().unwrap(); *lock = tag; // When setting the debug view tag before initialization, @@ -984,7 +976,7 @@ pub fn glean_set_source_tags(tags: Vec) -> bool { true } else { // Glean has not been initialized yet. Cache the provided source tags. - let m = PRE_INIT_SOURCE_TAGS.get_or_init(Default::default); + let m = &PRE_INIT_SOURCE_TAGS; let mut lock = m.lock().unwrap(); *lock = tags; // When setting the source tags before initialization, From 5e395545cb1104ba7870ea2464a2df0868b48a03 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Sat, 10 Feb 2024 17:37:45 +0100 Subject: [PATCH 03/34] Remove some direct dependencies from RLB These are unused or only used in tests. --- Cargo.lock | 5 ----- glean-core/rlb/Cargo.toml | 13 ++++--------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0835a139ed..6553fc8370 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -318,7 +318,6 @@ dependencies = [ name = "glean" version = "57.0.0" dependencies = [ - "chrono", "crossbeam-channel", "env_logger", "flate2", @@ -328,12 +327,8 @@ dependencies = [ "libc", "log", "once_cell", - "serde", "serde_json", "tempfile", - "thiserror", - "time", - "uuid", "whatsys", ] diff --git a/glean-core/rlb/Cargo.toml b/glean-core/rlb/Cargo.toml index 19baea550d..930c0a2344 100644 --- a/glean-core/rlb/Cargo.toml +++ b/glean-core/rlb/Cargo.toml @@ -26,24 +26,19 @@ path = ".." version = "57.0.0" [dependencies] -crossbeam-channel = "0.5" inherent = "1" log = "0.4.8" once_cell = "1.18.0" -thiserror = "1.0.4" -serde_json = "1.0.44" -serde = { version = "1.0.104", features = ["derive"] } -uuid = { version = "1.0", features = ["v4"] } -chrono = { version = "0.4.10", features = ["serde"] } -time = "0.1.40" whatsys = "0.3.0" [dev-dependencies] +crossbeam-channel = "0.5" env_logger = { version = "0.10.0", default-features = false, features = ["humantime"] } -tempfile = "3.1.0" -jsonschema-valid = "0.5.0" flate2 = "1.0.19" +jsonschema-valid = "0.5.0" libc = "0.2" +serde_json = "1.0.44" +tempfile = "3.1.0" [features] preinit_million_queue = ["glean-core/preinit_million_queue"] From 8dcaa8aae3d7d1ac93385f55b10905d920f2e2b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 05:09:36 +0000 Subject: [PATCH 04/34] Bump black from 24.1.1 to 24.2.0 in /glean-core/python Bumps [black](https://github.com/psf/black) from 24.1.1 to 24.2.0. - [Release notes](https://github.com/psf/black/releases) - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - [Commits](https://github.com/psf/black/compare/24.1.1...24.2.0) --- updated-dependencies: - dependency-name: black dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- glean-core/python/requirements_dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glean-core/python/requirements_dev.txt b/glean-core/python/requirements_dev.txt index 0513ab5bf7..cbafca4c2c 100644 --- a/glean-core/python/requirements_dev.txt +++ b/glean-core/python/requirements_dev.txt @@ -1,5 +1,5 @@ auditwheel==6.0.0 -black==24.1.1 +black==24.2.0 coverage[toml]==7.2.2 flake8==7.0.0; python_version >= '3.8' flake8-bugbear==24.2.6; python_version >= '3.8' From c12bd14cb4497c92c7b0f399c9e61228e911e259 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Wed, 14 Feb 2024 12:09:45 +0100 Subject: [PATCH 05/34] Docs: Remove note about earlier versions of Gradle plugin This is looooong gone, noone should be on that script anymore. [doc only] --- docs/user/user/adding-glean-to-your-project/kotlin.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/user/user/adding-glean-to-your-project/kotlin.md b/docs/user/user/adding-glean-to-your-project/kotlin.md index 4c44961304..ebd429fd46 100644 --- a/docs/user/user/adding-glean-to-your-project/kotlin.md +++ b/docs/user/user/adding-glean-to-your-project/kotlin.md @@ -122,12 +122,6 @@ ext.gleanGenerateMarkdownDocs = true apply plugin: "org.mozilla.telemetry.glean-gradle-plugin" ``` -{{#include ../../../shared/blockquote-warning.html}} - -##### Earlier versions - -> **Note:** Earlier versions of Glean used a Gradle script (`sdk_generator.gradle`) rather than a Gradle plugin. Its use is deprecated and projects should be updated to use the Gradle plugin as described above. - {{#include ../../../shared/blockquote-info.html}} ##### Offline builds From 4c5363c5c05691dcd41a98101e7a35be3800a72d Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Wed, 14 Feb 2024 12:14:57 +0100 Subject: [PATCH 06/34] Docs: Document requirement for Rosetta 2 [doc only] --- .dictionary | 4 +++- docs/user/user/adding-glean-to-your-project/kotlin.md | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.dictionary b/.dictionary index fce8feaf46..846d2a1394 100644 --- a/.dictionary +++ b/.dictionary @@ -1,4 +1,4 @@ -personal_ws-1.1 en 270 utf-8 +personal_ws-1.1 en 272 utf-8 AAR AARs ABI @@ -54,6 +54,7 @@ LLDB LMDB Lockwise MPL +MacBooks Makefile Mingw Miniconda @@ -167,6 +168,7 @@ gzipped homescreen hotfix html +iMacs illumos init inlined diff --git a/docs/user/user/adding-glean-to-your-project/kotlin.md b/docs/user/user/adding-glean-to-your-project/kotlin.md index ebd429fd46..8ee0aac069 100644 --- a/docs/user/user/adding-glean-to-your-project/kotlin.md +++ b/docs/user/user/adding-glean-to-your-project/kotlin.md @@ -124,6 +124,15 @@ apply plugin: "org.mozilla.telemetry.glean-gradle-plugin" {{#include ../../../shared/blockquote-info.html}} +##### Rosetta 2 required on Apple Silicon + +> On Apple Silicon machines (M1/M2/M3 MacBooks and iMacs) Rosetta 2 is required for the bundled Python. +> See the [Apple documentation about Rosetta 2](https://support.apple.com/en-us/HT211861) +> and [Bug 1775420](https://bugzilla.mozilla.org/show_bug.cgi?id=1775420) for details. +> You can install it with `softwareupdate --install-rosetta` + +{{#include ../../../shared/blockquote-info.html}} + ##### Offline builds > The Glean Gradle plugin has limited support for [offline builds](../../language-bindings/android/android-offline-builds.md) of applications that use the Glean SDK. From 162e84f224ddd2d9efc2bdbbdbad7e2a0a30d82a Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Wed, 14 Feb 2024 12:03:30 +0100 Subject: [PATCH 07/34] Docs: Type changes are allowed, but discouraged [doc only] --- docs/user/reference/yaml/metrics.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/user/reference/yaml/metrics.md b/docs/user/reference/yaml/metrics.md index 675aac515d..96c9d3f050 100644 --- a/docs/user/reference/yaml/metrics.md +++ b/docs/user/reference/yaml/metrics.md @@ -104,12 +104,13 @@ See the list of [supported metric types](../metrics/index.md). {{#include ../../../shared/blockquote-warning.html}} -##### Types must not be changed after release +##### Types should not be changed after release -> Once a metric is defined in a product, its `type` must not be changed. -> The ingestion pipeline will not be able to handle such a change. -> If a type change is required a new metric must be added with a new name and the new type. -> This will require an additional data review, in which you can also reference the old data review. +> Once a metric is defined in a product, its `type` should only be changed in rare circumstances. +> It's better to rename the metric with the new type instead. +> The ingestion pipeline will create a new column for a metric with a changed type. +> Any new analysis will need to use the new column going forward. +> The old column will still be populated with data from old clients. #### `description` From 28e3fa4031509f1c22c32ec50dc1ff77bc30d551 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Fri, 26 May 2023 15:05:12 +0200 Subject: [PATCH 08/34] New metric type: Object --- CHANGELOG.md | 5 +- docs/user/SUMMARY.md | 1 + docs/user/reference/metrics/object.md | 155 ++++++++++++++++++++++++ glean-core/rlb/src/private/mod.rs | 2 + glean-core/rlb/src/private/object.rs | 166 ++++++++++++++++++++++++++ glean-core/src/lib_unit_tests.rs | 2 + glean-core/src/metrics/mod.rs | 8 ++ glean-core/src/metrics/object.rs | 155 ++++++++++++++++++++++++ glean-core/src/traits/mod.rs | 2 + glean-core/src/traits/object.rs | 54 +++++++++ glean-core/tests/object.rs | 104 ++++++++++++++++ 11 files changed, 653 insertions(+), 1 deletion(-) create mode 100644 docs/user/reference/metrics/object.md create mode 100644 glean-core/rlb/src/private/object.rs create mode 100644 glean-core/src/metrics/object.rs create mode 100644 glean-core/src/traits/object.rs create mode 100644 glean-core/tests/object.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index cd5cbc040f..a7ef5a2d1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,15 @@ [Full changelog](https://github.com/mozilla/glean/compare/v57.0.0...main) +* Rust + * New metric type: Object ([#2489](https://github.com/mozilla/glean/pull/2489)) + # v57.0.0 (2024-02-12) [Full changelog](https://github.com/mozilla/glean/compare/v56.1.0...v57.0.0) * General - * Added an experimental event listener API ([#2719](https://github.com/mozilla/glean/pull/2719)) + * Added an experimental event listener API ([#2719](https://github.com/mozilla/glean/pull/2719)) * Android * BREAKING CHANGE: Update JNA to version 5.14.0. Projects using older JNA releases may encounter errors until they update. ([#2727](https://github.com/mozilla/glean/pull/2727)) * Set the target Android SDK to version 34 ([#2709](https://github.com/mozilla/glean/pull/2709)) diff --git a/docs/user/SUMMARY.md b/docs/user/SUMMARY.md index e80322d865..3e74d9e3f7 100644 --- a/docs/user/SUMMARY.md +++ b/docs/user/SUMMARY.md @@ -73,6 +73,7 @@ - [Quantity](reference/metrics/quantity.md) - [Rate](reference/metrics/rate.md) - [Text](reference/metrics/text.md) + - [Object](reference/metrics/object.md) - [Pings](reference/pings/index.md) # SDK Specific Information diff --git a/docs/user/reference/metrics/object.md b/docs/user/reference/metrics/object.md new file mode 100644 index 0000000000..4c3a31b639 --- /dev/null +++ b/docs/user/reference/metrics/object.md @@ -0,0 +1,155 @@ +# Object + +Record structured data. + +{{#include ../../../shared/blockquote-warning.html}} + +## Recording API + +### `set` + +Sets an object metric to a specific value. + +{{#include ../../../shared/tab_header.md}} + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +**C++** + +Not yet implemented. + +**JavaScript** + +```js +let balloons = [ + { colour: "red", diameter: 5 }, + { colour: "blue", diameter: 7 }, +]; +Glean.testOnly.balloons.set(balloons); +``` + +
+ +{{#include ../../../shared/tab_footer.md}} + +#### Limits + +* Only objects matching the specified structure will be recorded + +#### Recorded errors + +* [`invalid_value`](../../user/metrics/error-reporting.md): if the passed value doesn't match the predefined structure + +## Testing API + +### `testGetValue` + +Gets the recorded value for a given object metric. +Returns the data as a JSON object if data is stored. +Returns `null` if no data is stored. +Has an optional argument to specify the name of the ping you wish to retrieve data from, except +in Rust where it's required. `None` or no argument will default to the first value found for `send_in_pings`. + +{{#include ../../../shared/tab_header.md}} + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +**C++** + +Not yet implemented. + +**JavaScript** + +```js +// testGetValue will throw a data error on invalid value. +Assert.equal( + [ + { colour: "red", diameter: 5 }, + { colour: "blue", diameter: 7 }, + ], + Glean.testOnly.balloons.testGetValue() +); +``` + +
+ +{{#include ../../../shared/tab_footer.md}} + +### `testGetNumRecordedErrors` + +Gets the number of errors recorded for a given text metric. + +{{#include ../../../shared/tab_header.md}} + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +{{#include ../../../shared/tab_footer.md}} + +## Metric parameters + +Example text metric definition: + +```yaml +party: + balloons: + type: object + description: A collection of balloons + bugs: + - https://bugzilla.mozilla.org/TODO + data_reviews: + - http://example.com/reviews + notification_emails: + - CHANGE-ME@example.com + expires: never + structure: + type: array + items: + type: object + properties: + colour: + type: string + diameter: + type: number +``` + +For a full reference on metrics parameters common to all metric types, +refer to the [metrics YAML registry format](../yaml/metrics.md) reference page. + +## Data questions + diff --git a/glean-core/rlb/src/private/mod.rs b/glean-core/rlb/src/private/mod.rs index 8a5c304193..575707cf59 100644 --- a/glean-core/rlb/src/private/mod.rs +++ b/glean-core/rlb/src/private/mod.rs @@ -5,6 +5,7 @@ //! The different metric types supported by the Glean SDK to handle data. mod event; +mod object; mod ping; pub use event::EventMetric; @@ -26,6 +27,7 @@ pub use glean_core::UrlMetric; pub use glean_core::UuidMetric; pub use glean_core::{AllowLabeled, LabeledMetric}; pub use glean_core::{Datetime, DatetimeMetric}; +pub use object::ObjectMetric; pub use ping::PingType; // Re-export types that are used by the glean_parser-generated code. diff --git a/glean-core/rlb/src/private/object.rs b/glean-core/rlb/src/private/object.rs new file mode 100644 index 0000000000..31366af712 --- /dev/null +++ b/glean-core/rlb/src/private/object.rs @@ -0,0 +1,166 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use std::marker::PhantomData; + +use glean_core::traits; + +use crate::ErrorType; + +// We need to wrap the glean-core type: otherwise if we try to implement +// the trait for the metric in `glean_core::metrics` we hit error[E0117]: +// only traits defined in the current crate can be implemented for arbitrary +// types. + +/// Developer-facing API for recording object metrics. +/// +/// Instances of this class type are automatically generated by the parsers +/// at build time, allowing developers to record values that were previously +/// registered in the metrics.yaml file. +#[derive(Clone)] +pub struct ObjectMetric { + pub(crate) inner: glean_core::metrics::ObjectMetric, + object_type: PhantomData, +} + +impl ObjectMetric { + /// The public constructor used by automatically generated metrics. + pub fn new(meta: glean_core::CommonMetricData) -> Self { + let inner = glean_core::metrics::ObjectMetric::new(meta); + Self { + inner, + object_type: PhantomData, + } + } + + /// Sets to the specified structure. + /// + /// # Arguments + /// + /// * `object` - the object to set. + pub fn set(&self, object: K) { + let obj = object + .into_serialized_object() + .expect("failed to serialize object. This should be impossible."); + self.inner.set(obj); + } + + /// Sets to the specified structure. + /// + /// Parses the passed JSON string. + /// If it can't be parsed into a valid object it records an invalid value error. + /// + /// # Arguments + /// + /// * `object` - JSON representation of the object to set. + pub fn set_str(&self, object: String) { + let data = match K::from_str(&object) { + Ok(data) => data, + Err(_) => { + self.inner.record_schema_error(); + return; + } + }; + self.set(data) + } + + /// **Test-only API (exported for FFI purposes).** + /// + /// Gets the currently stored value as JSON-encoded string. + /// + /// This doesn't clear the stored value. + // TODO: Return the deserialized object instead. + pub fn test_get_value<'a, S: Into>>(&self, ping_name: S) -> Option { + let ping_name = ping_name.into().map(|s| s.to_string()); + self.inner.test_get_value(ping_name) + } + + /// **Exported for test purposes.** + /// + /// Gets the number of recorded errors for the given metric and error type. + /// + /// # Arguments + /// + /// * `error` - The type of error + /// + /// # Returns + /// + /// The number of errors reported. + pub fn test_get_num_recorded_errors(&self, error: ErrorType) -> i32 { + self.inner.test_get_num_recorded_errors(error) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::common_test::{lock_test, new_glean}; + use crate::CommonMetricData; + + #[test] + fn simple_array() { + let _lock = lock_test(); + let _t = new_glean(None, true); + + type SimpleArray = Vec; + + let metric: ObjectMetric = ObjectMetric::new(CommonMetricData { + name: "object".into(), + category: "test".into(), + send_in_pings: vec!["test1".into()], + ..Default::default() + }); + + let arr = SimpleArray::from([1, 2, 3]); + metric.set(arr); + + let data = metric.test_get_value(None).expect("no object recorded"); + assert_eq!("[1,2,3]", data); + } + + #[test] + fn complex_nested_object() { + let _lock = lock_test(); + let _t = new_glean(None, true); + + type BalloonsObject = Vec; + + #[derive( + Debug, Hash, Eq, PartialEq, traits::__serde::Deserialize, traits::__serde::Serialize, + )] + #[serde(crate = "traits::__serde")] + #[serde(deny_unknown_fields)] + struct BalloonsObjectItem { + #[serde(skip_serializing_if = "Option::is_none")] + colour: Option, + #[serde(skip_serializing_if = "Option::is_none")] + diameter: Option, + } + + let metric: ObjectMetric = ObjectMetric::new(CommonMetricData { + name: "object".into(), + category: "test".into(), + send_in_pings: vec!["test1".into()], + ..Default::default() + }); + + let balloons = BalloonsObject::from([ + BalloonsObjectItem { + colour: Some("red".to_string()), + diameter: Some(5), + }, + BalloonsObjectItem { + colour: Some("green".to_string()), + diameter: None, + }, + ]); + metric.set(balloons); + + let data = metric.test_get_value(None).expect("no object recorded"); + assert_eq!( + "[{\"colour\":\"red\",\"diameter\":5},{\"colour\":\"green\"}]", + data + ); + } +} diff --git a/glean-core/src/lib_unit_tests.rs b/glean-core/src/lib_unit_tests.rs index 0fc85b4602..7d34e2613f 100644 --- a/glean-core/src/lib_unit_tests.rs +++ b/glean-core/src/lib_unit_tests.rs @@ -423,6 +423,7 @@ fn correct_order() { Jwe("eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg.48V1_ALb6US04U3b.5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ".into()), Rate(0, 0), Text(long_string), + Object("{}".into()), ]; for metric in all_metrics { @@ -451,6 +452,7 @@ fn correct_order() { Rate(..) => assert_eq!(14, disc), Url(..) => assert_eq!(15, disc), Text(..) => assert_eq!(16, disc), + Object(..) => assert_eq!(17, disc), } } } diff --git a/glean-core/src/metrics/mod.rs b/glean-core/src/metrics/mod.rs index 43253b9aa7..1980c16c00 100644 --- a/glean-core/src/metrics/mod.rs +++ b/glean-core/src/metrics/mod.rs @@ -23,6 +23,7 @@ mod memory_distribution; mod memory_unit; mod metrics_enabled_config; mod numerator; +mod object; mod ping; mod quantity; mod rate; @@ -54,6 +55,7 @@ pub use self::labeled::{LabeledBoolean, LabeledCounter, LabeledMetric, LabeledSt pub use self::memory_distribution::MemoryDistributionMetric; pub use self::memory_unit::MemoryUnit; pub use self::numerator::NumeratorMetric; +pub use self::object::ObjectMetric; pub use self::ping::PingType; pub use self::quantity::QuantityMetric; pub use self::rate::{Rate, RateMetric}; @@ -141,6 +143,8 @@ pub enum Metric { Url(String), /// A Text metric. See [`TextMetric`] for more information. Text(String), + /// An Object metric. See [`ObjectMetric`] for more information. + Object(String), } /// A [`MetricType`] describes common behavior across all metrics. @@ -251,6 +255,7 @@ impl Metric { Metric::MemoryDistribution(_) => "memory_distribution", Metric::Jwe(_) => "jwe", Metric::Text(_) => "text", + Metric::Object(_) => "object", } } @@ -280,6 +285,9 @@ impl Metric { Metric::MemoryDistribution(hist) => json!(memory_distribution::snapshot(hist)), Metric::Jwe(s) => json!(s), Metric::Text(s) => json!(s), + Metric::Object(s) => { + serde_json::from_str(s).expect("object storage should have been json") + } } } } diff --git a/glean-core/src/metrics/object.rs b/glean-core/src/metrics/object.rs new file mode 100644 index 0000000000..d2269519af --- /dev/null +++ b/glean-core/src/metrics/object.rs @@ -0,0 +1,155 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use std::sync::Arc; + +use crate::common_metric_data::CommonMetricDataInternal; +use crate::error_recording::{record_error, test_get_num_recorded_errors, ErrorType}; +use crate::metrics::Metric; +use crate::metrics::MetricType; +use crate::storage::StorageManager; +use crate::CommonMetricData; +use crate::Glean; + +use serde_json::Value as JsonValue; + +/// An object metric. +/// +/// Record structured data. +/// The value must adhere to a predefined structure and is serialized into JSON. +#[derive(Clone, Debug)] +pub struct ObjectMetric { + meta: Arc, +} + +impl MetricType for ObjectMetric { + fn meta(&self) -> &CommonMetricDataInternal { + &self.meta + } +} + +// IMPORTANT: +// +// When changing this implementation, make sure all the operations are +// also declared in the related trait in `../traits/`. +impl ObjectMetric { + /// Creates a new object metric. + pub fn new(meta: CommonMetricData) -> Self { + Self { + meta: Arc::new(meta.into()), + } + } + + /// Sets to the specified structure. + /// + /// # Arguments + /// + /// * `glean` - the Glean instance this metric belongs to. + /// * `value` - the value to set. + #[doc(hidden)] + pub fn set_sync(&self, glean: &Glean, value: JsonValue) { + let value = Metric::Object(serde_json::to_string(&value).unwrap()); + glean.storage().record(glean, &self.meta, &value) + } + + /// Sets to the specified structure. + /// + /// No additional verification is done. + /// The shape needs to be externally verified. + /// + /// # Arguments + /// + /// * `value` - the value to set. + pub fn set(&self, value: JsonValue) { + let metric = self.clone(); + crate::launch_with_glean(move |glean| metric.set_sync(glean, value)) + } + + /// Record an `InvalidValue` error for this metric. + /// + /// Only to be used by the RLB. + // TODO(bug 1691073): This can probably go once we have a more generic mechanism to record + // errors + pub fn record_schema_error(&self) { + let metric = self.clone(); + crate::launch_with_glean(move |glean| { + let msg = "Value did not match predefined schema"; + record_error(glean, &metric.meta, ErrorType::InvalidValue, msg, None); + }); + } + + /// Sets to the specified structure from a string in JSON encoding + /// + /// # Arguments + /// + /// * `glean` - the Glean instance this metric belongs to. + /// * `value` - the value to set. + pub fn set_str(&self, value: String) { + let metric = self.clone(); + crate::launch_with_glean(move |glean| { + let value = match serde_json::from_str(&value) { + Ok(s) => s, + Err(_) => { + let msg = "Cannot set invalid json"; + record_error(glean, &metric.meta, ErrorType::InvalidValue, msg, None); + return; + } + }; + metric.set_sync(glean, value) + }) + } + + /// Get current value + #[doc(hidden)] + pub fn get_value<'a, S: Into>>( + &self, + glean: &Glean, + ping_name: S, + ) -> Option { + let queried_ping_name = ping_name + .into() + .unwrap_or_else(|| &self.meta().inner.send_in_pings[0]); + + match StorageManager.snapshot_metric_for_test( + glean.storage(), + queried_ping_name, + &self.meta.identifier(glean), + self.meta.inner.lifetime, + ) { + Some(Metric::Object(o)) => Some(o), + _ => None, + } + } + + /// **Test-only API (exported for FFI purposes).** + /// + /// Gets the currently stored value as JSON-encoded string. + /// + /// This doesn't clear the stored value. + pub fn test_get_value(&self, ping_name: Option) -> Option { + crate::block_on_dispatcher(); + crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())) + } + + /// **Exported for test purposes.** + /// + /// Gets the number of recorded errors for the given metric and error type. + /// + /// # Arguments + /// + /// * `error` - The type of error + /// * `ping_name` - represents the optional name of the ping to retrieve the + /// metric for. inner to the first value in `send_in_pings`. + /// + /// # Returns + /// + /// The number of errors reported. + pub fn test_get_num_recorded_errors(&self, error: ErrorType) -> i32 { + crate::block_on_dispatcher(); + + crate::core::with_glean(|glean| { + test_get_num_recorded_errors(glean, self.meta(), error).unwrap_or(0) + }) + } +} diff --git a/glean-core/src/traits/mod.rs b/glean-core/src/traits/mod.rs index c4bcf7cdd6..2f0b9320b7 100644 --- a/glean-core/src/traits/mod.rs +++ b/glean-core/src/traits/mod.rs @@ -15,6 +15,7 @@ mod event; mod labeled; mod memory_distribution; mod numerator; +mod object; mod ping; mod quantity; mod rate; @@ -37,6 +38,7 @@ pub use self::event::NoExtraKeys; pub use self::labeled::Labeled; pub use self::memory_distribution::MemoryDistribution; pub use self::numerator::Numerator; +pub use self::object::{ObjectError, ObjectSerialize}; pub use self::ping::Ping; pub use self::quantity::Quantity; pub use self::rate::Rate; diff --git a/glean-core/src/traits/object.rs b/glean-core/src/traits/object.rs new file mode 100644 index 0000000000..cf68b0c472 --- /dev/null +++ b/glean-core/src/traits/object.rs @@ -0,0 +1,54 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use std::fmt::Display; + +use serde::Deserialize; +pub use serde::Serialize; +use serde_json::Value as JsonValue; + +/// This type represents all possible errors that can occur when serializing or deserializing an object from/to JSON. +#[derive(Debug)] +pub struct ObjectError(serde_json::Error); + +impl Display for ObjectError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Display::fmt(&self.0, f) + } +} + +impl std::error::Error for ObjectError {} + +/// An object that can be serialized into JSON. +/// +/// Objects are defined by their structure in the metrics definition. +/// +/// This is essentially a wrapper around serde's `Serialize`/`Deserialize`, +/// but in a way we can name it for our JSON (de)serialization. +pub trait ObjectSerialize { + /// Deserialize the object from its JSON representation. + /// + /// Returns an error if deserialization fails. + /// This should not happen for glean_parser-generated and later serialized objects. + fn from_str(obj: &str) -> Result + where + Self: Sized; + + /// Serialize this object into a JSON string. + fn into_serialized_object(self) -> Result; +} + +impl ObjectSerialize for V +where + V: Serialize, + V: for<'de> Deserialize<'de>, +{ + fn from_str(obj: &str) -> Result { + serde_json::from_str(obj).map_err(ObjectError) + } + + fn into_serialized_object(self) -> Result { + serde_json::to_value(self).map_err(ObjectError) + } +} diff --git a/glean-core/tests/object.rs b/glean-core/tests/object.rs new file mode 100644 index 0000000000..1e734e99d2 --- /dev/null +++ b/glean-core/tests/object.rs @@ -0,0 +1,104 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +mod common; +use crate::common::*; + +use serde_json::json; + +use glean_core::metrics::*; +use glean_core::storage::StorageManager; +use glean_core::{CommonMetricData, Lifetime}; + +#[test] +fn object_serializer_should_correctly_serialize_objects() { + let (mut tempdir, _) = tempdir(); + + { + // We give tempdir to the `new_glean` function... + let (glean, dir) = new_glean(Some(tempdir)); + // And then we get it back once that function returns. + tempdir = dir; + + let metric = ObjectMetric::new(CommonMetricData { + name: "object_metric".into(), + category: "telemetry".into(), + send_in_pings: vec!["store1".into()], + disabled: false, + lifetime: Lifetime::User, + ..Default::default() + }); + + let obj = serde_json::from_str("{ \"value\": 1 }").unwrap(); + metric.set_sync(&glean, obj); + + let snapshot = StorageManager + .snapshot_as_json(glean.storage(), "store1", true) + .unwrap(); + assert_eq!( + json!({"object": {"telemetry.object_metric": { "value": 1 }}}), + snapshot + ); + } + + // Make a new Glean instance here, which should force reloading of the data from disk + // so we can ensure it persisted, because it has User lifetime + { + let (glean, _t) = new_glean(Some(tempdir)); + let snapshot = StorageManager + .snapshot_as_json(glean.storage(), "store1", true) + .unwrap(); + assert_eq!( + json!({"object": {"telemetry.object_metric": { "value": 1 }}}), + snapshot + ); + } +} + +#[test] +fn set_value_properly_sets_the_value_in_all_stores() { + let (glean, _t) = new_glean(None); + let store_names: Vec = vec!["store1".into(), "store2".into()]; + + let metric = ObjectMetric::new(CommonMetricData { + name: "object_metric".into(), + category: "telemetry".into(), + send_in_pings: store_names.clone(), + disabled: false, + lifetime: Lifetime::Ping, + ..Default::default() + }); + + let obj = serde_json::from_str("{ \"value\": 1 }").unwrap(); + metric.set_sync(&glean, obj); + + for store_name in store_names { + let snapshot = StorageManager + .snapshot_as_json(glean.storage(), &store_name, true) + .unwrap(); + + assert_eq!( + json!({"object": {"telemetry.object_metric": { "value": 1 }}}), + snapshot + ); + } +} + +#[test] +fn getting_data_json_encoded() { + let (glean, _t) = new_glean(None); + + let object: ObjectMetric = ObjectMetric::new(CommonMetricData { + name: "transformation".into(), + category: "local".into(), + send_in_pings: vec!["store1".into()], + ..Default::default() + }); + + let obj_str = "{\"value\":1}"; + let obj = serde_json::from_str(obj_str).unwrap(); + object.set_sync(&glean, obj); + + assert_eq!(obj_str, object.get_value(&glean, Some("store1")).unwrap()); +} From 84055c5655e8673f0e7cc2928ca10a141174f715 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Tue, 13 Feb 2024 13:38:51 +0100 Subject: [PATCH 09/34] Rust: Re-export serde for use in generated code --- glean-core/src/traits/mod.rs | 4 ++++ glean-core/src/traits/object.rs | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/glean-core/src/traits/mod.rs b/glean-core/src/traits/mod.rs index 2f0b9320b7..4115609fdd 100644 --- a/glean-core/src/traits/mod.rs +++ b/glean-core/src/traits/mod.rs @@ -7,6 +7,10 @@ //! Individual metric types implement this trait to expose the specific metrics API. //! It can be used by wrapping implementations to guarantee API conformance. +/// Re-export for use in generated code. +#[doc(hidden)] +pub extern crate serde as __serde; + mod boolean; mod counter; mod custom_distribution; diff --git a/glean-core/src/traits/object.rs b/glean-core/src/traits/object.rs index cf68b0c472..c579efeac7 100644 --- a/glean-core/src/traits/object.rs +++ b/glean-core/src/traits/object.rs @@ -4,8 +4,7 @@ use std::fmt::Display; -use serde::Deserialize; -pub use serde::Serialize; +use serde::{Deserialize, Serialize}; use serde_json::Value as JsonValue; /// This type represents all possible errors that can occur when serializing or deserializing an object from/to JSON. From 1f4eec469b2035bf8ae8b092a256075fb4568620 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Tue, 13 Feb 2024 11:49:41 +0100 Subject: [PATCH 10/34] Rust sample: Use new object metric type --- samples/rust/metrics.yaml | 24 ++++++++++++++++++++++++ samples/rust/src/main.rs | 13 +++++++++++++ 2 files changed, 37 insertions(+) diff --git a/samples/rust/metrics.yaml b/samples/rust/metrics.yaml index 9de283ac61..ae04571369 100644 --- a/samples/rust/metrics.yaml +++ b/samples/rust/metrics.yaml @@ -24,3 +24,27 @@ test.metrics: expires: never send_in_pings: - prototype + +party: + balloons: + type: object + description: | + Just testing objects + bugs: + - https://bugzilla.mozilla.org/1839640 + data_reviews: + - N/A + notification_emails: + - CHANGE-ME@example.com + expires: never + send_in_pings: + - prototype + structure: + type: array + items: + type: object + properties: + color: + type: string + diameter: + type: number diff --git a/samples/rust/src/main.rs b/samples/rust/src/main.rs index 437e302e78..a515dce050 100644 --- a/samples/rust/src/main.rs +++ b/samples/rust/src/main.rs @@ -54,6 +54,19 @@ fn main() { glean_metrics::test_metrics::sample_boolean.set(true); + use glean_metrics::party::{BalloonsObject, BalloonsObjectItem}; + let balloons = BalloonsObject::from([ + BalloonsObjectItem { + color: Some("red".to_string()), + diameter: Some(5), + }, + BalloonsObjectItem { + color: Some("blue".to_string()), + diameter: None, + }, + ]); + glean_metrics::party::balloons.set(balloons); + glean_metrics::prototype.submit(None); // Need to wait a short time for Glean to actually act. thread::sleep(Duration::from_millis(100)); From 35bd000fbe73e208710e7facb65e5089b29555d7 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Tue, 13 Feb 2024 11:21:50 +0100 Subject: [PATCH 11/34] Update to glean_parser v12.0.1 --- CHANGELOG.md | 2 ++ Cargo.lock | 2 +- Makefile | 2 +- glean-core/Cargo.toml | 2 +- glean-core/build/Cargo.toml | 2 +- glean-core/build/src/lib.rs | 2 +- glean-core/ios/sdk_generator.sh | 2 +- glean-core/python/glean/__init__.py | 2 +- .../telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy | 2 +- pyproject.toml | 2 +- 10 files changed, 11 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7ef5a2d1b..57d6417c96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ [Full changelog](https://github.com/mozilla/glean/compare/v57.0.0...main) +* General + * Update `glean_parser` to v12.0.1 ([release notes](https://github.com/mozilla/glean_parser/releases/tag/v12.0.0)) * Rust * New metric type: Object ([#2489](https://github.com/mozilla/glean/pull/2489)) diff --git a/Cargo.lock b/Cargo.lock index 6553fc8370..cdab38b914 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -334,7 +334,7 @@ dependencies = [ [[package]] name = "glean-build" -version = "11.0.1" +version = "12.0.1" dependencies = [ "tempfile", "xshell-venv", diff --git a/Makefile b/Makefile index f74e2a85d1..4cd21d334f 100644 --- a/Makefile +++ b/Makefile @@ -151,7 +151,7 @@ docs-python: build-python ## Build the Python documentation .PHONY: docs rust-docs swift-docs docs-metrics: setup-python ## Build the internal metrics documentation - $(GLEAN_PYENV)/bin/pip install glean_parser~=11.0 + $(GLEAN_PYENV)/bin/pip install glean_parser~=12.0 $(GLEAN_PYENV)/bin/glean_parser translate --allow-reserved \ -f markdown \ -o ./docs/user/user/collected-metrics \ diff --git a/glean-core/Cargo.toml b/glean-core/Cargo.toml index fbfe15909b..7709047f81 100644 --- a/glean-core/Cargo.toml +++ b/glean-core/Cargo.toml @@ -21,7 +21,7 @@ include = [ rust-version = "1.66" [package.metadata.glean] -glean-parser = "11.0.1" +glean-parser = "12.0.1" [badges] circle-ci = { repository = "mozilla/glean", branch = "main" } diff --git a/glean-core/build/Cargo.toml b/glean-core/build/Cargo.toml index 0c8d640634..c846a921d3 100644 --- a/glean-core/build/Cargo.toml +++ b/glean-core/build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "glean-build" -version = "11.0.1" +version = "12.0.1" edition = "2021" description = "Glean SDK Rust build helper" repository = "https://github.com/mozilla/glean" diff --git a/glean-core/build/src/lib.rs b/glean-core/build/src/lib.rs index b1dadd9d09..68eab20c2a 100644 --- a/glean-core/build/src/lib.rs +++ b/glean-core/build/src/lib.rs @@ -39,7 +39,7 @@ use std::env; use xshell_venv::{Result, Shell, VirtualEnv}; -const GLEAN_PARSER_VERSION: &str = "11.0.1"; +const GLEAN_PARSER_VERSION: &str = "12.0.1"; /// A Glean Rust bindings generator. pub struct Builder { diff --git a/glean-core/ios/sdk_generator.sh b/glean-core/ios/sdk_generator.sh index 78ca3cadd0..d101534ca8 100755 --- a/glean-core/ios/sdk_generator.sh +++ b/glean-core/ios/sdk_generator.sh @@ -25,7 +25,7 @@ set -e -GLEAN_PARSER_VERSION=11.0 +GLEAN_PARSER_VERSION=12.0 # CMDNAME is used in the usage text below. # shellcheck disable=SC2034 diff --git a/glean-core/python/glean/__init__.py b/glean-core/python/glean/__init__.py index e7f97a49f9..27cf16b60a 100644 --- a/glean-core/python/glean/__init__.py +++ b/glean-core/python/glean/__init__.py @@ -31,7 +31,7 @@ __email__ = "glean-team@mozilla.com" -GLEAN_PARSER_VERSION = "11.0.1" +GLEAN_PARSER_VERSION = "12.0.1" parser_version = VersionInfo.parse(GLEAN_PARSER_VERSION) parser_version_next_major = parser_version.bump_major() diff --git a/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy b/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy index 958dd46cb3..6521a8d45b 100644 --- a/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy +++ b/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy @@ -50,7 +50,7 @@ abstract class GleanMetricsYamlTransform implements TransformAction { // The version of glean_parser to install from PyPI. - private String GLEAN_PARSER_VERSION = "11.0" + private String GLEAN_PARSER_VERSION = "12.0" // The version of Miniconda is explicitly specified. // Miniconda3-4.5.12 is known to not work on Windows. private String MINICONDA_VERSION = "4.5.11" diff --git a/pyproject.toml b/pyproject.toml index f9793c9eab..4fb5a35531 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ maintainers = [ dependencies = [ "semver>=2.13.0", - "glean_parser~=11.0", + "glean_parser~=12.0", ] [project.urls] From 78e85acb5525f4bbcf4bcb08ea30025d0192eb14 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Tue, 13 Feb 2024 11:50:37 +0100 Subject: [PATCH 12/34] Rust sample: Use an uploader that write to a file This allows to actually inspect the files after they have been sent. --- Cargo.lock | 1 + samples/rust/Cargo.toml | 1 + samples/rust/metrics.yaml | 2 +- samples/rust/src/main.rs | 71 +++++++++++++++++++++++++++++---------- 4 files changed, 56 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cdab38b914..2c9b2ee4aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -770,6 +770,7 @@ name = "sample" version = "0.1.0" dependencies = [ "env_logger", + "flate2", "glean", "glean-build", "tempfile", diff --git a/samples/rust/Cargo.toml b/samples/rust/Cargo.toml index 6b453156a1..6c397056db 100644 --- a/samples/rust/Cargo.toml +++ b/samples/rust/Cargo.toml @@ -7,6 +7,7 @@ license = "MIT" [dependencies] env_logger = { version = "0.10.0", default-features = false, features = ["humantime"] } +flate2 = "1.0.19" glean = { path = "../../glean-core/rlb" } tempfile = "3.3.0" diff --git a/samples/rust/metrics.yaml b/samples/rust/metrics.yaml index ae04571369..f1cbf928ea 100644 --- a/samples/rust/metrics.yaml +++ b/samples/rust/metrics.yaml @@ -44,7 +44,7 @@ party: items: type: object properties: - color: + colour: type: string diameter: type: number diff --git a/samples/rust/src/main.rs b/samples/rust/src/main.rs index a515dce050..5f4e3ee982 100644 --- a/samples/rust/src/main.rs +++ b/samples/rust/src/main.rs @@ -3,18 +3,62 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use std::env; +use std::fs::File; +use std::io::{Read, Write}; use std::path::PathBuf; use std::thread; use std::time::Duration; use tempfile::Builder; -use glean::{ClientInfoMetrics, Configuration}; +use flate2::read::GzDecoder; +use glean::{net, ClientInfoMetrics, ConfigurationBuilder}; pub mod glean_metrics { include!(concat!(env!("OUT_DIR"), "/glean_metrics.rs")); } +#[derive(Debug)] +struct MovingUploader(String); + +impl net::PingUploader for MovingUploader { + fn upload( + &self, + url: String, + body: Vec, + headers: Vec<(String, String)>, + ) -> net::UploadResult { + let mut gzip_decoder = GzDecoder::new(&body[..]); + let mut s = String::with_capacity(body.len()); + + let data = gzip_decoder + .read_to_string(&mut s) + .ok() + .map(|_| &s[..]) + .or_else(|| std::str::from_utf8(&body).ok()) + .unwrap(); + + let mut out_path = PathBuf::from(&self.0); + out_path.push("sent_pings"); + std::fs::create_dir_all(&out_path).unwrap(); + + let docid = url.rsplit('/').next().unwrap(); + out_path.push(format!("{docid}.json")); + let mut fp = File::create(out_path).unwrap(); + + // pseudo-JSON, let's hope this works. + writeln!(fp, "{{").unwrap(); + writeln!(fp, " \"url\": {url},").unwrap(); + for (key, val) in headers { + writeln!(fp, " \"{key}\": \"{val}\",").unwrap(); + } + writeln!(fp, "}}").unwrap(); + writeln!(fp, "{data}").unwrap(); + + net::UploadResult::http_status(200) + } +} + fn main() { env_logger::init(); @@ -27,21 +71,12 @@ fn main() { root.path().to_path_buf() }; - let cfg = Configuration { - data_path, - application_id: "org.mozilla.glean_core.example".into(), - upload_enabled: true, - max_events: None, - delay_ping_lifetime_io: false, - server_endpoint: Some("invalid-test-host".into()), - uploader: None, - use_core_mps: true, - trim_data_to_registered_pings: false, - log_level: None, - rate_limit: None, - enable_event_timestamps: false, - experimentation_id: None, - }; + let uploader = MovingUploader(data_path.display().to_string()); + let cfg = ConfigurationBuilder::new(true, data_path, "org.mozilla.glean_core.example") + .with_server_endpoint("invalid-test-host") + .with_use_core_mps(true) + .with_uploader(uploader) + .build(); let client_info = ClientInfoMetrics { app_build: env!("CARGO_PKG_VERSION").to_string(), @@ -57,11 +92,11 @@ fn main() { use glean_metrics::party::{BalloonsObject, BalloonsObjectItem}; let balloons = BalloonsObject::from([ BalloonsObjectItem { - color: Some("red".to_string()), + colour: Some("red".to_string()), diameter: Some(5), }, BalloonsObjectItem { - color: Some("blue".to_string()), + colour: Some("blue".to_string()), diameter: None, }, ]); From 630d6f35ca3c6379cbe9519960f38395afc6e73d Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Mon, 12 Feb 2024 17:26:27 +0100 Subject: [PATCH 13/34] CI: Pass crates.io token as argument directly --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 689f8f470a..dcfa570456 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -395,7 +395,7 @@ jobs: name: Publish Cargo Package command: | # Login to crates.io so the following commands work - cargo login -- "$CRATES_IO_TOKEN" + cargo login "$CRATES_IO_TOKEN" # Publish all crates from CI. # The token is set in CircleCI settings. From 9513945ac7d4959380ab64f7e99510f88e4e8e38 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Mon, 12 Feb 2024 17:31:09 +0100 Subject: [PATCH 14/34] CI: Don't sleep between crate publish, cargo does that --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index dcfa570456..08a7b49fab 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -404,7 +404,6 @@ jobs: pushd glean-core cargo publish --verbose - sleep 30 pushd rlb cargo publish --verbose From 8af6f63f255754ea68ef36ae54a06701e883b71f Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Wed, 8 Nov 2023 14:30:14 +0100 Subject: [PATCH 15/34] Rust: Fix docs for all core metric implementations [doc only] --- glean-core/src/metrics/boolean.rs | 12 +++++++++--- glean-core/src/metrics/counter.rs | 12 +++++++++--- glean-core/src/metrics/custom_distribution.rs | 11 +++++++++-- glean-core/src/metrics/datetime.rs | 10 ++++------ glean-core/src/metrics/denominator.rs | 11 +++++++++-- glean-core/src/metrics/event.rs | 7 +++++-- glean-core/src/metrics/experiment.rs | 9 +++++++++ glean-core/src/metrics/labeled.rs | 2 -- glean-core/src/metrics/memory_distribution.rs | 11 +++++++++-- glean-core/src/metrics/numerator.rs | 8 +++++--- glean-core/src/metrics/quantity.rs | 11 +++++++++-- glean-core/src/metrics/rate.rs | 11 +++++++++-- glean-core/src/metrics/string.rs | 11 +++++++++-- glean-core/src/metrics/string_list.rs | 11 +++++++++-- glean-core/src/metrics/text.rs | 11 +++++++++-- glean-core/src/metrics/timespan.rs | 11 +++++++++-- glean-core/src/metrics/timing_distribution.rs | 11 +++++++++-- glean-core/src/metrics/url.rs | 11 +++++++++-- glean-core/src/metrics/uuid.rs | 11 +++++++++-- 19 files changed, 149 insertions(+), 43 deletions(-) diff --git a/glean-core/src/metrics/boolean.rs b/glean-core/src/metrics/boolean.rs index 71ed2372c2..ade4a22bfc 100644 --- a/glean-core/src/metrics/boolean.rs +++ b/glean-core/src/metrics/boolean.rs @@ -74,7 +74,6 @@ impl BooleanMetric { /// /// # Arguments /// - /// * `glean` - the Glean instance this metric belongs to. /// * `value` - the value to set. pub fn set(&self, value: bool) { let metric = self.clone(); @@ -106,6 +105,15 @@ impl BooleanMetric { /// Gets the currently stored value as an integer. /// /// This doesn't clear the stored value. + /// + /// # Arguments + /// + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. + /// + /// # Returns + /// + /// The stored value or `None` if nothing stored. pub fn test_get_value(&self, ping_name: Option) -> Option { crate::block_on_dispatcher(); crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())) @@ -118,8 +126,6 @@ impl BooleanMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. inner to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/counter.rs b/glean-core/src/metrics/counter.rs index 8f0a01cc3e..7e262c7d68 100644 --- a/glean-core/src/metrics/counter.rs +++ b/glean-core/src/metrics/counter.rs @@ -105,7 +105,6 @@ impl CounterMetric { /// /// # Arguments /// - /// * `glean` - The Glean instance this metric belongs to. /// * `amount` - The amount to increase by. Should be positive. /// /// ## Notes @@ -143,6 +142,15 @@ impl CounterMetric { /// Gets the currently stored value as an integer. /// /// This doesn't clear the stored value. + /// + /// # Arguments + /// + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. + /// + /// # Returns + /// + /// The stored value or `None` if nothing stored. pub fn test_get_value(&self, ping_name: Option) -> Option { crate::block_on_dispatcher(); crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())) @@ -155,8 +163,6 @@ impl CounterMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. inner to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/custom_distribution.rs b/glean-core/src/metrics/custom_distribution.rs index 929e4863ec..d14be78dc0 100644 --- a/glean-core/src/metrics/custom_distribution.rs +++ b/glean-core/src/metrics/custom_distribution.rs @@ -194,6 +194,15 @@ impl CustomDistributionMetric { /// Gets the currently stored value as an integer. /// /// This doesn't clear the stored value. + /// + /// # Arguments + /// + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. + /// + /// # Returns + /// + /// The stored value or `None` if nothing stored. pub fn test_get_value(&self, ping_name: Option) -> Option { crate::block_on_dispatcher(); crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())) @@ -206,8 +215,6 @@ impl CustomDistributionMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. inner to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/datetime.rs b/glean-core/src/metrics/datetime.rs index 3ef846a32c..e04f7fc051 100644 --- a/glean-core/src/metrics/datetime.rs +++ b/glean-core/src/metrics/datetime.rs @@ -262,8 +262,8 @@ impl DatetimeMetric { /// /// # Arguments /// - /// * `glean` - the Glean instance this metric belongs to. - /// * `storage_name` - the storage name to look into. + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. /// /// # Returns /// @@ -284,8 +284,8 @@ impl DatetimeMetric { /// /// # Arguments /// - /// * `glean` - the Glean instance this metric belongs to. - /// * `storage_name` - the storage name to look into. + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. /// /// # Returns /// @@ -311,8 +311,6 @@ impl DatetimeMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. inner to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/denominator.rs b/glean-core/src/metrics/denominator.rs index fb80874924..3083d6e78a 100644 --- a/glean-core/src/metrics/denominator.rs +++ b/glean-core/src/metrics/denominator.rs @@ -91,6 +91,15 @@ impl DenominatorMetric { /// Gets the currently stored value as an integer. /// /// This doesn't clear the stored value. + /// + /// # Arguments + /// + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. + /// + /// # Returns + /// + /// The stored value or `None` if nothing stored. pub fn test_get_value(&self, ping_name: Option) -> Option { crate::block_on_dispatcher(); crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())) @@ -124,8 +133,6 @@ impl DenominatorMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - the optional name of the ping to retrieve the metric - /// for. inner to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/event.rs b/glean-core/src/metrics/event.rs index 5ad6e6d50c..c7aefd9cd6 100644 --- a/glean-core/src/metrics/event.rs +++ b/glean-core/src/metrics/event.rs @@ -185,6 +185,11 @@ impl EventMetric { /// Get the vector of currently stored events for this event metric. /// /// This doesn't clear the stored value. + /// + /// # Arguments + /// + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. pub fn test_get_value(&self, ping_name: Option) -> Option> { crate::block_on_dispatcher(); crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())) @@ -197,8 +202,6 @@ impl EventMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. inner to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/experiment.rs b/glean-core/src/metrics/experiment.rs index 23e6c41ce2..5695bf942e 100644 --- a/glean-core/src/metrics/experiment.rs +++ b/glean-core/src/metrics/experiment.rs @@ -195,6 +195,15 @@ impl ExperimentMetric { /// the RecordedExperiment. /// /// This doesn't clear the stored value. + /// + /// # Arguments + /// + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. + /// + /// # Returns + /// + /// The stored value or `None` if nothing stored. pub fn test_get_value(&self, glean: &Glean) -> Option { match StorageManager.snapshot_metric_for_test( glean.storage(), diff --git a/glean-core/src/metrics/labeled.rs b/glean-core/src/metrics/labeled.rs index fa3e6a6a75..f9f6a28880 100644 --- a/glean-core/src/metrics/labeled.rs +++ b/glean-core/src/metrics/labeled.rs @@ -205,8 +205,6 @@ where /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. Defaults to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/memory_distribution.rs b/glean-core/src/metrics/memory_distribution.rs index ac9eda1a90..7b5e5ee192 100644 --- a/glean-core/src/metrics/memory_distribution.rs +++ b/glean-core/src/metrics/memory_distribution.rs @@ -254,6 +254,15 @@ impl MemoryDistributionMetric { /// Gets the currently stored value. /// /// This doesn't clear the stored value. + /// + /// # Arguments + /// + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. + /// + /// # Returns + /// + /// The stored value or `None` if nothing stored. pub fn test_get_value(&self, ping_name: Option) -> Option { crate::block_on_dispatcher(); crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())) @@ -266,8 +275,6 @@ impl MemoryDistributionMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. Defaults to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/numerator.rs b/glean-core/src/metrics/numerator.rs index 3c340cab1d..de29338a5c 100644 --- a/glean-core/src/metrics/numerator.rs +++ b/glean-core/src/metrics/numerator.rs @@ -55,12 +55,16 @@ impl NumeratorMetric { /// /// Gets the currently stored value as a pair of integers. /// + /// This doesn't clear the stored value. + /// /// # Arguments /// /// * `ping_name` - the optional name of the ping to retrieve the metric /// for. Defaults to the first value in `send_in_pings`. /// - /// This doesn't clear the stored value. + /// # Returns + /// + /// The stored value or `None` if nothing stored. pub fn test_get_value(&self, ping_name: Option) -> Option { crate::block_on_dispatcher(); crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())) @@ -82,8 +86,6 @@ impl NumeratorMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - the optional name of the ping to retrieve the metric - /// for. Defaults to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/quantity.rs b/glean-core/src/metrics/quantity.rs index c59d3a4a21..92216625d6 100644 --- a/glean-core/src/metrics/quantity.rs +++ b/glean-core/src/metrics/quantity.rs @@ -98,6 +98,15 @@ impl QuantityMetric { /// Gets the currently stored value as an integer. /// /// This doesn't clear the stored value. + /// + /// # Arguments + /// + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. + /// + /// # Returns + /// + /// The stored value or `None` if nothing stored. pub fn test_get_value(&self, ping_name: Option) -> Option { crate::block_on_dispatcher(); crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())) @@ -110,8 +119,6 @@ impl QuantityMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. Defaults to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/rate.rs b/glean-core/src/metrics/rate.rs index ba7f085b55..843d35002e 100644 --- a/glean-core/src/metrics/rate.rs +++ b/glean-core/src/metrics/rate.rs @@ -141,6 +141,15 @@ impl RateMetric { /// Gets the currently stored value as a pair of integers. /// /// This doesn't clear the stored value. + /// + /// # Arguments + /// + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. + /// + /// # Returns + /// + /// The stored value or `None` if nothing stored. pub fn test_get_value(&self, ping_name: Option) -> Option { crate::block_on_dispatcher(); crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())) @@ -175,8 +184,6 @@ impl RateMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. Defaults to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/string.rs b/glean-core/src/metrics/string.rs index 5ed7b2c7f1..4aa30a8d7e 100644 --- a/glean-core/src/metrics/string.rs +++ b/glean-core/src/metrics/string.rs @@ -112,6 +112,15 @@ impl StringMetric { /// Gets the currently stored value as a string. /// /// This doesn't clear the stored value. + /// + /// # Arguments + /// + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. + /// + /// # Returns + /// + /// The stored value or `None` if nothing stored. pub fn test_get_value(&self, ping_name: Option) -> Option { crate::block_on_dispatcher(); crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())) @@ -124,8 +133,6 @@ impl StringMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. Defaults to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/string_list.rs b/glean-core/src/metrics/string_list.rs index 75b2df7f80..cd4e71b885 100644 --- a/glean-core/src/metrics/string_list.rs +++ b/glean-core/src/metrics/string_list.rs @@ -171,6 +171,15 @@ impl StringListMetric { /// Gets the currently-stored values. /// /// This doesn't clear the stored value. + /// + /// # Arguments + /// + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. + /// + /// # Returns + /// + /// The stored value or `None` if nothing stored. pub fn test_get_value(&self, ping_name: Option) -> Option> { crate::block_on_dispatcher(); crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())) @@ -183,8 +192,6 @@ impl StringListMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. Defaults to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/text.rs b/glean-core/src/metrics/text.rs index 06ad5c0d78..baa8e88d75 100644 --- a/glean-core/src/metrics/text.rs +++ b/glean-core/src/metrics/text.rs @@ -116,6 +116,15 @@ impl TextMetric { /// Gets the currently stored value as a string. /// /// This doesn't clear the stored value. + /// + /// # Arguments + /// + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. + /// + /// # Returns + /// + /// The stored value or `None` if nothing stored. pub fn test_get_value(&self, ping_name: Option) -> Option { crate::block_on_dispatcher(); crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())) @@ -128,8 +137,6 @@ impl TextMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. Defaults to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/timespan.rs b/glean-core/src/metrics/timespan.rs index b4d3bd5902..ee63fb52f8 100644 --- a/glean-core/src/metrics/timespan.rs +++ b/glean-core/src/metrics/timespan.rs @@ -253,6 +253,15 @@ impl TimespanMetric { /// Gets the currently stored value as an integer. /// /// This doesn't clear the stored value. + /// + /// # Arguments + /// + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. + /// + /// # Returns + /// + /// The stored value or `None` if nothing stored. pub fn test_get_value(&self, ping_name: Option) -> Option { crate::block_on_dispatcher(); crate::core::with_glean(|glean| { @@ -292,8 +301,6 @@ impl TimespanMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. Defaults to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/timing_distribution.rs b/glean-core/src/metrics/timing_distribution.rs index e339ef8882..076942b1d3 100644 --- a/glean-core/src/metrics/timing_distribution.rs +++ b/glean-core/src/metrics/timing_distribution.rs @@ -464,6 +464,15 @@ impl TimingDistributionMetric { /// Gets the currently stored value as an integer. /// /// This doesn't clear the stored value. + /// + /// # Arguments + /// + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. + /// + /// # Returns + /// + /// The stored value or `None` if nothing stored. pub fn test_get_value(&self, ping_name: Option) -> Option { crate::block_on_dispatcher(); crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())) @@ -476,8 +485,6 @@ impl TimingDistributionMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. Defaults to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/url.rs b/glean-core/src/metrics/url.rs index c9eb824a3e..48b3f9e7ae 100644 --- a/glean-core/src/metrics/url.rs +++ b/glean-core/src/metrics/url.rs @@ -131,6 +131,15 @@ impl UrlMetric { /// Gets the currently stored value as a string. /// /// This doesn't clear the stored value. + /// + /// # Arguments + /// + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. + /// + /// # Returns + /// + /// The stored value or `None` if nothing stored. pub fn test_get_value(&self, ping_name: Option) -> Option { crate::block_on_dispatcher(); crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())) @@ -143,8 +152,6 @@ impl UrlMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. Defaults to the first value in `send_in_pings`. /// /// # Returns /// diff --git a/glean-core/src/metrics/uuid.rs b/glean-core/src/metrics/uuid.rs index e78d15ad3b..77d0f82320 100644 --- a/glean-core/src/metrics/uuid.rs +++ b/glean-core/src/metrics/uuid.rs @@ -128,6 +128,15 @@ impl UuidMetric { /// Gets the currently stored value as a string. /// /// This doesn't clear the stored value. + /// + /// # Arguments + /// + /// * `ping_name` - the optional name of the ping to retrieve the metric + /// for. Defaults to the first value in `send_in_pings`. + /// + /// # Returns + /// + /// The stored value or `None` if nothing stored. pub fn test_get_value(&self, ping_name: Option) -> Option { crate::block_on_dispatcher(); crate::core::with_glean(|glean| { @@ -143,8 +152,6 @@ impl UuidMetric { /// # Arguments /// /// * `error` - The type of error - /// * `ping_name` - represents the optional name of the ping to retrieve the - /// metric for. Defaults to the first value in `send_in_pings`. /// /// # Returns /// From c0eddd4f63a032d8818d1298f514288ca1dac229 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Sun, 18 Feb 2024 14:34:02 -0500 Subject: [PATCH 16/34] Use a Gradle version catalog for managing dependencies --- build.gradle | 44 +++---------- glean-core/android-native/build.gradle | 14 +++- glean-core/android/build.gradle | 52 ++++++++------- gradle/libs.versions.toml | 90 ++++++++++++++++++++++++++ samples/android/app/build.gradle | 23 ++++--- 5 files changed, 151 insertions(+), 72 deletions(-) create mode 100644 gradle/libs.versions.toml diff --git a/build.gradle b/build.gradle index 148269db97..ad0c6645d0 100644 --- a/build.gradle +++ b/build.gradle @@ -7,33 +7,6 @@ // https://github.com/mozilla/application-services/blob/84e077d1534dc287bbd472da658ce22eea5af032/build.gradle buildscript { - // Define the version of the used dependencies in a single place, to ease - // changing them. Please note that, for using in Android-Components, the - // versions below must match the ones in that repository. - ext.versions = [ - android_gradle_plugin: '8.0.2', - coroutines: '1.7.2', - jna: '5.14.0', - junit: '4.13.2', - mockito: '5.10.0', - mockwebserver: '4.11.0', // This is different than a-c, but we're fine, it's only tests. - kotlin: '1.8.22', - robolectric: '4.11.1', - rust_android_plugin: '0.9.3', - - // Android X dependencies - androidx_annotation: '1.7.1', - androidx_appcompat: '1.6.1', - androidx_browser: '1.7.0', - androidx_core: '1.12.0', - androidx_espresso: '3.5.1', - androidx_junit: '1.1.5', - androidx_lifecycle: '2.6.2', - androidx_test: '1.5.0', - androidx_work: '2.7.1', - androidx_uiautomator: '2.2.0', - ] - ext.build = [ ndkVersion: "25.2.9519653", // Keep it in sync in TC Dockerfile. compileSdkVersion: 34, @@ -50,22 +23,21 @@ buildscript { } } dependencies { - classpath "com.android.tools.build:gradle:$versions.android_gradle_plugin" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin" + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files - classpath "org.mozilla.rust-android-gradle:plugin:$versions.rust_android_plugin" + classpath libs.kotlin.gradle.plugin + classpath libs.mozilla.rust.android.gradle + classpath libs.tools.android.plugin // Yes, this is unusual. We want to access some host-specific // computation at build time. - classpath "net.java.dev.jna:jna:$versions.jna" - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files + classpath libs.jna } } plugins { - id("io.gitlab.arturbosch.detekt").version("1.23.5") + alias libs.plugins.detekt } allprojects { @@ -200,7 +172,7 @@ configurations { } dependencies { - ktlint("com.pinterest:ktlint:0.50.0") { + ktlint(libs.ktlint) { attributes { attribute(Bundling.BUNDLING_ATTRIBUTE, getObjects().named(Bundling, Bundling.EXTERNAL)) } diff --git a/glean-core/android-native/build.gradle b/glean-core/android-native/build.gradle index fe95a840da..3a2c9af864 100644 --- a/glean-core/android-native/build.gradle +++ b/glean-core/android-native/build.gradle @@ -99,8 +99,18 @@ configurations { } dependencies { - jnaForTest "net.java.dev.jna:jna:$versions.jna@jar" - implementation "net.java.dev.jna:jna:$versions.jna@aar" + jnaForTest(libs.jna) { + artifact { + extension ="jar" + type = "jar" + } + } + implementation(libs.jna) { + artifact { + extension ="aar" + type = "aar" + } + } } afterEvaluate { diff --git a/glean-core/android/build.gradle b/glean-core/android/build.gradle index 6a513a8f1d..bf62a3af05 100644 --- a/glean-core/android/build.gradle +++ b/glean-core/android/build.gradle @@ -8,7 +8,7 @@ import groovy.json.JsonOutput plugins { - id "com.jetbrains.python.envs" version "0.0.26" + alias libs.plugins.gradle.python.envs } apply plugin: 'com.android.library' @@ -98,7 +98,7 @@ android { afterEvaluate { if (project.hasProperty("coverage")) { jacoco { - toolVersion = "0.8.10" + toolVersion = libs.versions.jacoco } task jacocoTestReport(type: JacocoReport) { @@ -148,18 +148,26 @@ configurations { } dependencies { - jnaForTest "net.java.dev.jna:jna:$versions.jna@jar" - implementation "net.java.dev.jna:jna:$versions.jna@aar" + jnaForTest(libs.jna) { + artifact { + extension ="jar" + type = "jar" + } + } + implementation(libs.jna) { + artifact { + extension ="aar" + type = "aar" + } + } implementation project(":glean-native") - // Note: the following version must be kept in sync - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$versions.coroutines" - - implementation "androidx.annotation:annotation:$versions.androidx_annotation" - implementation "androidx.lifecycle:lifecycle-common:$versions.androidx_lifecycle" - implementation "androidx.lifecycle:lifecycle-process:$versions.androidx_lifecycle" - implementation "androidx.work:work-runtime-ktx:$versions.androidx_work" + implementation libs.androidx.annotation + implementation libs.androidx.lifecycle.common + implementation libs.androidx.lifecycle.process + implementation libs.androidx.work + implementation libs.kotlinx.coroutines // We need a compileOnly dependency on the following block of testing // libraries in order to expose the GleanTestRule to applications/libraries @@ -167,8 +175,8 @@ dependencies { // We can't simply create a separate package otherwise we would need // to provide a public API for the testing package to access the // Glean internals, which is something we would not want to do. - compileOnly "junit:junit:$versions.junit" - compileOnly "androidx.work:work-testing:$versions.androidx_work" + compileOnly libs.junit + compileOnly libs.test.work // For reasons unknown, resolving the jnaForTest configuration directly // trips a nasty issue with the Android-Gradle plugin 3.2.1, like `Cannot @@ -178,15 +186,15 @@ dependencies { // causing it to be resolved. Cloning first dissociates the configuration, // avoiding other configurations from being resolved. Tricky! testImplementation files(configurations.jnaForTest.copyRecursive().files) - testImplementation "androidx.test.ext:junit:$versions.androidx_junit" - testImplementation "org.robolectric:robolectric:$versions.robolectric" - testImplementation "org.mockito:mockito-core:$versions.mockito" - testImplementation "androidx.test:core-ktx:$versions.androidx_test" - testImplementation "com.squareup.okhttp3:mockwebserver:$versions.mockwebserver" - testImplementation "androidx.work:work-testing:$versions.androidx_work" - - androidTestImplementation "androidx.test:runner:$versions.androidx_test" - androidTestImplementation "androidx.test.espresso:espresso-core:$versions.androidx_espresso" + testImplementation libs.mockito + testImplementation libs.mockwebserver + testImplementation libs.robolectric + testImplementation libs.test.core + testImplementation libs.test.junit.ext + testImplementation libs.test.work + + androidTestImplementation libs.test.espresso.core + androidTestImplementation libs.test.runner } evaluationDependsOn(":glean-native") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000000..93d0624729 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,90 @@ +# In general, these versions should be kept in sync with AC to avoid introducing +# possible conflicts and compatibility issues. This primarily applies to dependencies +# for shipping code, however. Libraries used only for the build system or testing +# can be safely bumped when convenient. + +[versions] +# AGP +android-plugin = "8.0.2" + +# Kotlin +kotlin-compiler = "1.8.22" +kotlinx-coroutines = "1.7.2" + +# Mozilla +rust-android-gradle = "0.9.3" + +# AndroidX +androidx-annotation = "1.7.1" +androidx-appcompat = "1.6.1" +androidx-browser = "1.7.0" +androidx-lifecycle = "2.6.2" +androidx-work = "2.7.1" + +# JNA +jna = "5.14.0" + +# Linting and Static Analysis +detekt = "1.23.5" +ktlint = "0.50.0" + +# AndroidX Testing +androidx-test-espresso = "3.5.1" +androidx-test-core = "1.5.0" +androidx-test-junit = "1.1.5" +androidx-test-runner = "1.5.2" +androidx-test-uiautomator = "2.2.0" + +# Third Party Testing +junit = "4.13.2" +mockito = "5.10.0" +mockwebserver = "4.12.0" +robolectric = "4.11.1" + +# Miscellaneous Gradle plugins +jacoco = "0.8.11" +python-envs = "0.0.31" + +[libraries] +# AGP +tools-android-plugin = { group = "com.android.tools.build", name = "gradle", version.ref = "android-plugin" } + +# Kotlin +kotlin-gradle-plugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin-compiler" } +kotlinx-coroutines = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } + +# Mozilla +mozilla-rust-android-gradle = { group = "org.mozilla.rust-android-gradle", name = "plugin", version.ref = "rust-android-gradle" } + +# AndroidX +androidx-annotation = { group = "androidx.annotation", name = "annotation", version.ref = "androidx-annotation" } +androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } +androidx-browser = { group = "androidx.browser", name = "browser", version.ref = "androidx-browser" } +androidx-lifecycle-common = { group = "androidx.lifecycle", name = "lifecycle-common", version.ref = "androidx-lifecycle" } +androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "androidx-lifecycle" } +androidx-work = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "androidx-work" } + +# JNA +jna = { group = "net.java.dev.jna", name = "jna", version.ref = "jna" } + +# Linting and Static Analysis +ktlint = { module = "com.pinterest:ktlint", version.ref = "ktlint" } + +# AndroidX Testing +test-core = { group = "androidx.test", name = "core-ktx", version.ref = "androidx-test-core" } +test-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "androidx-test-espresso" } +test-junit-ext = { group = "androidx.test.ext", name = "junit-ktx", version.ref = "androidx-test-junit" } +test-rules = { group = "androidx.test", name = "rules", version.ref = "androidx-test-core" } +test-runner = { group = "androidx.test", name = "runner", version.ref = "androidx-test-runner" } +test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidx-test-uiautomator" } +test-work = { group = "androidx.work", name = "work-testing", version.ref = "androidx-work" } + +# Third Party Testing +junit = { group = "junit", name = "junit", version.ref = "junit" } +mockito = { group = "org.mockito", name = "mockito-core", version.ref = "mockito" } +mockwebserver = { group = "com.squareup.okhttp3", name = "mockwebserver", version.ref = "mockwebserver" } +robolectric = { group = "org.robolectric", name = "robolectric", version.ref = "robolectric" } + +[plugins] +detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } +gradle-python-envs = { id = "com.jetbrains.python.envs", version.ref = "python-envs" } diff --git a/samples/android/app/build.gradle b/samples/android/app/build.gradle index 5d8bae83c2..3d6233d74b 100644 --- a/samples/android/app/build.gradle +++ b/samples/android/app/build.gradle @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ plugins { - id "com.jetbrains.python.envs" version "0.0.26" + alias libs.plugins.gradle.python.envs } apply plugin: 'com.android.application' @@ -41,18 +41,17 @@ android { dependencies { implementation project(':glean') - implementation "androidx.appcompat:appcompat:$rootProject.versions.androidx_appcompat" - implementation "androidx.browser:browser:$rootProject.versions.androidx_browser" + implementation libs.androidx.appcompat + implementation libs.androidx.browser - - androidTestImplementation "androidx.test:core-ktx:$rootProject.versions.androidx_test" - androidTestImplementation "androidx.test:runner:$rootProject.versions.androidx_test" - androidTestImplementation "androidx.test:rules:$rootProject.versions.androidx_test" - androidTestImplementation "androidx.test.ext:junit:$rootProject.versions.androidx_junit" - androidTestImplementation "androidx.test.uiautomator:uiautomator:$rootProject.versions.androidx_uiautomator" - androidTestImplementation "androidx.test.espresso:espresso-core:$rootProject.versions.androidx_espresso" - androidTestImplementation "androidx.work:work-testing:$rootProject.versions.androidx_work" - androidTestImplementation "com.squareup.okhttp3:mockwebserver:$rootProject.versions.mockwebserver" + androidTestImplementation libs.mockwebserver + androidTestImplementation libs.test.core + androidTestImplementation libs.test.espresso.core + androidTestImplementation libs.test.junit.ext + androidTestImplementation libs.test.rules + androidTestImplementation libs.test.runner + androidTestImplementation libs.test.uiautomator + androidTestImplementation libs.test.work } ext.gleanNamespace = "mozilla.telemetry.glean" From 024d00604d93133c63710c9008c9505c356fb5b1 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Thu, 22 Feb 2024 13:21:50 +0100 Subject: [PATCH 17/34] Ensure glean-build's test location is inside the workspace's target directory That folder is definitely ignored. --- glean-core/build/src/lib.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/glean-core/build/src/lib.rs b/glean-core/build/src/lib.rs index 68eab20c2a..6dda9e2dca 100644 --- a/glean-core/build/src/lib.rs +++ b/glean-core/build/src/lib.rs @@ -134,17 +134,21 @@ mod test { #[test] fn test_builder() { - let package_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + // We know this package's location, and it's up 2 folders from there. + let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let package_root = manifest_dir.parent().unwrap().parent().unwrap(); + // Ensure xshell-venv create the venv in the expected directory. + env::set_var( + "CARGO_TARGET_DIR", + package_root.join("target").display().to_string(), + ); + // clean out the previous venv, if it exists let venv_dir = package_root.join("target").join("venv-py3-glean_parser"); if venv_dir.exists() { fs::remove_dir_all(venv_dir).unwrap(); } let metrics_yaml = package_root - .parent() - .unwrap() - .parent() - .unwrap() .join("samples") .join("rust") .join("metrics.yaml"); From fb1d6382613f9c92b9b74b215ca90a7eed2a31cc Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Thu, 22 Feb 2024 13:24:05 +0100 Subject: [PATCH 18/34] Update xshell-venv Now comes with a lock on the venv directory --- Cargo.lock | 16 ++++++++++++++-- supply-chain/audits.toml | 12 ++++++++++++ supply-chain/imports.lock | 18 ++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c9b2ee4aa..2b4a06494c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -278,6 +278,17 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +[[package]] +name = "fd-lock" +version = "3.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" +dependencies = [ + "cfg-if", + "rustix", + "windows-sys", +] + [[package]] name = "flate2" version = "1.0.26" @@ -1255,10 +1266,11 @@ checksum = "88301b56c26dd9bf5c43d858538f82d6f3f7764767defbc5d34e59459901c41a" [[package]] name = "xshell-venv" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43c2e9236bfd40d392b5ef2c073ef2719f7c69a758293cec4d8eff909a8917c" +checksum = "64b35c51b31637878412ae8c4107f260f3fe0a40b6cc6bddf47d868403d77d4c" dependencies = [ + "fd-lock", "xshell", ] diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index 02cb39beed..f989a88d11 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -262,6 +262,12 @@ who = "Jan-Erik Rediger " criteria = "safe-to-run" delta = "0.2.2 -> 0.2.4" +[[audits.fd-lock]] +who = "Jan-Erik Rediger " +criteria = "safe-to-deploy" +delta = "3.0.12 -> 3.0.13" +notes = "Dependency updates only" + [[audits.flate2]] who = "Jan-Erik Rediger " criteria = "safe-to-deploy" @@ -397,6 +403,12 @@ criteria = "safe-to-deploy" delta = "1.3.0 -> 1.4.1" notes = "Internal refactoring, new target support" +[[audits.xshell-venv]] +who = "Jan-Erik Rediger " +criteria = "safe-to-deploy" +delta = "1.1.0 -> 1.2.0" +notes = "Added a file lock on the created directory" + [[trusted.is-terminal]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index cfff0d5eb1..4fc461232a 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -163,6 +163,24 @@ criteria = "safe-to-deploy" version = "0.1.2" notes = "This should be portable to any POSIX system and seems like it should be part of the libc crate, but at any rate it's safe as is." +[[audits.bytecode-alliance.audits.fd-lock]] +who = "Pat Hickey " +criteria = "safe-to-deploy" +version = "3.0.9" +notes = "This crate uses unsafe to make Windows syscalls, to borrow an Fd with an appropriate lifetime, and to zero a windows API structure that appears to have a valid representation with zeroed memory." + +[[audits.bytecode-alliance.audits.fd-lock]] +who = "Pat Hickey " +criteria = "safe-to-deploy" +delta = "3.0.9 -> 3.0.10" +notes = "Just a dependency version bump" + +[[audits.bytecode-alliance.audits.fd-lock]] +who = "Dan Gohman " +criteria = "safe-to-deploy" +delta = "3.0.10 -> 3.0.12" +notes = "Just a dependency version bump" + [[audits.bytecode-alliance.audits.form_urlencoded]] who = "Alex Crichton " criteria = "safe-to-deploy" From c251f2b6f69edc86923861c32b2cc3759a3cecb3 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Thu, 22 Feb 2024 13:37:36 +0100 Subject: [PATCH 19/34] Object: Default to returning a JSON value --- glean-core/rlb/src/private/object.rs | 18 +++++++++++------- glean-core/src/metrics/mod.rs | 3 ++- glean-core/src/metrics/object.rs | 11 ++++++----- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/glean-core/rlb/src/private/object.rs b/glean-core/rlb/src/private/object.rs index 31366af712..7e2e8fb48f 100644 --- a/glean-core/rlb/src/private/object.rs +++ b/glean-core/rlb/src/private/object.rs @@ -4,6 +4,7 @@ use std::marker::PhantomData; +use glean_core::metrics::JsonValue; use glean_core::traits; use crate::ErrorType; @@ -70,8 +71,7 @@ impl ObjectMetric { /// Gets the currently stored value as JSON-encoded string. /// /// This doesn't clear the stored value. - // TODO: Return the deserialized object instead. - pub fn test_get_value<'a, S: Into>>(&self, ping_name: S) -> Option { + pub fn test_get_value<'a, S: Into>>(&self, ping_name: S) -> Option { let ping_name = ping_name.into().map(|s| s.to_string()); self.inner.test_get_value(ping_name) } @@ -98,6 +98,8 @@ mod test { use crate::common_test::{lock_test, new_glean}; use crate::CommonMetricData; + use serde_json::json; + #[test] fn simple_array() { let _lock = lock_test(); @@ -116,7 +118,8 @@ mod test { metric.set(arr); let data = metric.test_get_value(None).expect("no object recorded"); - assert_eq!("[1,2,3]", data); + let expected = json!([1, 2, 3]); + assert_eq!(expected, data); } #[test] @@ -158,9 +161,10 @@ mod test { metric.set(balloons); let data = metric.test_get_value(None).expect("no object recorded"); - assert_eq!( - "[{\"colour\":\"red\",\"diameter\":5},{\"colour\":\"green\"}]", - data - ); + let expected = json!([ + { "colour": "red", "diameter": 5 }, + { "colour": "green" }, + ]); + assert_eq!(expected, data); } } diff --git a/glean-core/src/metrics/mod.rs b/glean-core/src/metrics/mod.rs index 1980c16c00..92001efd2a 100644 --- a/glean-core/src/metrics/mod.rs +++ b/glean-core/src/metrics/mod.rs @@ -9,7 +9,8 @@ use std::sync::atomic::Ordering; use chrono::{DateTime, FixedOffset}; use serde::{Deserialize, Serialize}; -use serde_json::{json, Value as JsonValue}; +use serde_json::json; +pub use serde_json::Value as JsonValue; mod boolean; mod counter; diff --git a/glean-core/src/metrics/object.rs b/glean-core/src/metrics/object.rs index d2269519af..f00f11922a 100644 --- a/glean-core/src/metrics/object.rs +++ b/glean-core/src/metrics/object.rs @@ -6,14 +6,13 @@ use std::sync::Arc; use crate::common_metric_data::CommonMetricDataInternal; use crate::error_recording::{record_error, test_get_num_recorded_errors, ErrorType}; +use crate::metrics::JsonValue; use crate::metrics::Metric; use crate::metrics::MetricType; use crate::storage::StorageManager; use crate::CommonMetricData; use crate::Glean; -use serde_json::Value as JsonValue; - /// An object metric. /// /// Record structured data. @@ -124,12 +123,14 @@ impl ObjectMetric { /// **Test-only API (exported for FFI purposes).** /// - /// Gets the currently stored value as JSON-encoded string. + /// Gets the currently stored value as JSON. /// /// This doesn't clear the stored value. - pub fn test_get_value(&self, ping_name: Option) -> Option { + pub fn test_get_value(&self, ping_name: Option) -> Option { crate::block_on_dispatcher(); - crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())) + let value = crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref())); + // We only store valid JSON + value.map(|val| serde_json::from_str(&val).unwrap()) } /// **Exported for test purposes.** From b7516675adc62389b3d993de2661ae34b09f565f Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Sun, 18 Feb 2024 15:09:38 -0500 Subject: [PATCH 20/34] Explicitly use the minSdkVersion for setting the NDK API level --- glean-core/android-native/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glean-core/android-native/build.gradle b/glean-core/android-native/build.gradle index 3a2c9af864..48769651f6 100644 --- a/glean-core/android-native/build.gradle +++ b/glean-core/android-native/build.gradle @@ -61,7 +61,7 @@ cargo { module = '../bundle-android' // The Android NDK API level to target. - apiLevel = 21 + apiLevel = rootProject.ext.build['minSdkVersion'] // Where Cargo writes its outputs. targetDirectory = '../../target' From 46a308a8f6e2399be1fc01e674db35319b67a19b Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Thu, 15 Feb 2024 19:44:56 -0500 Subject: [PATCH 21/34] Update Android SDK build tools to the latest releases --- .circleci/config.yml | 6 +++--- docs/dev/android/sdk-ndk-versions.md | 18 +++++++++--------- taskcluster/docker/linux/Dockerfile | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 08a7b49fab..f512c9b6fb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -109,7 +109,7 @@ commands: name: Install missing Android SDK & NDK command: | sdkmanager \ - "build-tools;33.0.2" \ + "build-tools;34.0.0" \ "ndk;25.2.9519653" android-setup: @@ -412,7 +412,7 @@ jobs: Lint Android with ktlint and detekt: docker: - - image: cimg/android:2023.06-browsers + - image: cimg/android:2024.01.1-browsers steps: - checkout - android-setup @@ -422,7 +422,7 @@ jobs: Android tests: docker: - - image: cimg/android:2023.06-browsers + - image: cimg/android:2024.01.1-browsers steps: - checkout - skip-if-doc-only diff --git a/docs/dev/android/sdk-ndk-versions.md b/docs/dev/android/sdk-ndk-versions.md index f6c5c65abc..d66d39067f 100644 --- a/docs/dev/android/sdk-ndk-versions.md +++ b/docs/dev/android/sdk-ndk-versions.md @@ -2,11 +2,11 @@ The Glean SDK implementation is currently build against the following versions: -* SDK API 33 - * Look for `android-33` in the SDK manager - * or install with: `sdkmanager --verbose "platforms;android-33"` +* SDK API 34 + * Look for `android-34` in the SDK manager + * or install with: `sdkmanager --verbose "platforms;android-34"` * Android Command line tools - * Download link: + * Download link: * NDK r25 * Download link: @@ -20,10 +20,10 @@ All locations need to be updated on upgrades: * `dev/android/setup-android-build-environment.md` * CI configuration * `.circleci/config.yml` - * `sdkmanager 'build-tools;33.0.2'` - * `image: circleci/android:2023.02.1` + * `sdkmanager 'build-tools;34.0.0'` + * `image: circleci/android:2024.01.1-browsers` * `taskcluster/docker/linux/Dockerfile`. - * `ENV ANDROID_BUILD_TOOLS "33.0.2"` - * `ENV ANDROID_SDK_VERSION "9477386"` - * `ENV ANDROID_PLATFORM_VERSION "33"` + * `ENV ANDROID_BUILD_TOOLS "34.0.0"` + * `ENV ANDROID_SDK_VERSION "11076708"` + * `ENV ANDROID_PLATFORM_VERSION "34"` * `ENV ANDROID_NDK_VERSION "25.2.9519653"` diff --git a/taskcluster/docker/linux/Dockerfile b/taskcluster/docker/linux/Dockerfile index e9b5b6f9ed..f450961dab 100644 --- a/taskcluster/docker/linux/Dockerfile +++ b/taskcluster/docker/linux/Dockerfile @@ -22,9 +22,9 @@ WORKDIR /builds/worker/ # Configuration -ENV ANDROID_BUILD_TOOLS "33.0.2" -ENV ANDROID_TOOLS_VERSION "9477386" -ENV ANDROID_PLATFORM_VERSION "33" +ENV ANDROID_BUILD_TOOLS "34.0.0" +ENV ANDROID_TOOLS_VERSION "11076708" +ENV ANDROID_PLATFORM_VERSION "34" ENV ANDROID_NDK_VERSION "25.2.9519653" # Set up the language variables to avoid problems (we run locale-gen later). From 8ded69dd0c317177811372d9fd035a3210fb1cfd Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Thu, 15 Feb 2024 19:56:57 -0500 Subject: [PATCH 22/34] Update NDK to r26c --- .circleci/config.yml | 2 +- CHANGELOG.md | 2 ++ build.gradle | 2 +- docs/dev/android/sdk-ndk-versions.md | 6 +++--- taskcluster/docker/linux/Dockerfile | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f512c9b6fb..7abeb4257a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -110,7 +110,7 @@ commands: command: | sdkmanager \ "build-tools;34.0.0" \ - "ndk;25.2.9519653" + "ndk;26.2.11394342" android-setup: steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index 57d6417c96..4cb2facee0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ * Update `glean_parser` to v12.0.1 ([release notes](https://github.com/mozilla/glean_parser/releases/tag/v12.0.0)) * Rust * New metric type: Object ([#2489](https://github.com/mozilla/glean/pull/2489)) +* Android + * Upgrade Android NDK to r26c ([#2745](https://github.com/mozilla/glean/pull/2745)) # v57.0.0 (2024-02-12) diff --git a/build.gradle b/build.gradle index ad0c6645d0..7dc15a06d4 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ buildscript { ext.build = [ - ndkVersion: "25.2.9519653", // Keep it in sync in TC Dockerfile. + ndkVersion: "26.2.11394342", // Keep it in sync in TC Dockerfile. compileSdkVersion: 34, targetSdkVersion: 34, minSdkVersion: 21, diff --git a/docs/dev/android/sdk-ndk-versions.md b/docs/dev/android/sdk-ndk-versions.md index d66d39067f..f76a3cde0c 100644 --- a/docs/dev/android/sdk-ndk-versions.md +++ b/docs/dev/android/sdk-ndk-versions.md @@ -7,8 +7,8 @@ The Glean SDK implementation is currently build against the following versions: * or install with: `sdkmanager --verbose "platforms;android-34"` * Android Command line tools * Download link: -* NDK r25 - * Download link: +* NDK r26 + * Download link: For the full setup see [Setup the Android Build Environment](setup-android-build-environment.html). @@ -26,4 +26,4 @@ All locations need to be updated on upgrades: * `ENV ANDROID_BUILD_TOOLS "34.0.0"` * `ENV ANDROID_SDK_VERSION "11076708"` * `ENV ANDROID_PLATFORM_VERSION "34"` - * `ENV ANDROID_NDK_VERSION "25.2.9519653"` + * `ENV ANDROID_NDK_VERSION "26.2.11394342"` diff --git a/taskcluster/docker/linux/Dockerfile b/taskcluster/docker/linux/Dockerfile index f450961dab..a0b7158644 100644 --- a/taskcluster/docker/linux/Dockerfile +++ b/taskcluster/docker/linux/Dockerfile @@ -25,7 +25,7 @@ WORKDIR /builds/worker/ ENV ANDROID_BUILD_TOOLS "34.0.0" ENV ANDROID_TOOLS_VERSION "11076708" ENV ANDROID_PLATFORM_VERSION "34" -ENV ANDROID_NDK_VERSION "25.2.9519653" +ENV ANDROID_NDK_VERSION "26.2.11394342" # Set up the language variables to avoid problems (we run locale-gen later). ENV LANG en_US.UTF-8 From 8e03c8bc5912e39b7ff091abb3e5e676ec705a05 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Sun, 18 Feb 2024 15:46:55 -0500 Subject: [PATCH 23/34] Update SnakeYAML to version 2.2 --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 555f813b12..23a74d7ed9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,7 +5,7 @@ import org.yaml.snakeyaml.Yaml buildscript { dependencies { - classpath 'org.yaml:snakeyaml:2.0' + classpath 'org.yaml:snakeyaml:2.2' } repositories { mavenCentral() From 2b4086507f69b2338756e62d403acbb8e6f31c0d Mon Sep 17 00:00:00 2001 From: Chris H-C Date: Mon, 26 Feb 2024 14:57:02 -0500 Subject: [PATCH 24/34] Update glean_parser version to v13.0.0 --- CHANGELOG.md | 2 +- Cargo.lock | 2 +- Makefile | 2 +- glean-core/Cargo.toml | 2 +- glean-core/build/Cargo.toml | 2 +- glean-core/build/src/lib.rs | 2 +- glean-core/ios/sdk_generator.sh | 2 +- glean-core/python/glean/__init__.py | 2 +- .../telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy | 2 +- pyproject.toml | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cb2facee0..6d4d5c5ed7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ [Full changelog](https://github.com/mozilla/glean/compare/v57.0.0...main) * General - * Update `glean_parser` to v12.0.1 ([release notes](https://github.com/mozilla/glean_parser/releases/tag/v12.0.0)) + * Update `glean_parser` to v13.0.0 ([release notes](https://github.com/mozilla/glean_parser/releases/tag/v13.0.0)) * Rust * New metric type: Object ([#2489](https://github.com/mozilla/glean/pull/2489)) * Android diff --git a/Cargo.lock b/Cargo.lock index 2b4a06494c..94280323cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -345,7 +345,7 @@ dependencies = [ [[package]] name = "glean-build" -version = "12.0.1" +version = "13.0.0" dependencies = [ "tempfile", "xshell-venv", diff --git a/Makefile b/Makefile index 4cd21d334f..d7f35b10c2 100644 --- a/Makefile +++ b/Makefile @@ -151,7 +151,7 @@ docs-python: build-python ## Build the Python documentation .PHONY: docs rust-docs swift-docs docs-metrics: setup-python ## Build the internal metrics documentation - $(GLEAN_PYENV)/bin/pip install glean_parser~=12.0 + $(GLEAN_PYENV)/bin/pip install glean_parser~=13.0 $(GLEAN_PYENV)/bin/glean_parser translate --allow-reserved \ -f markdown \ -o ./docs/user/user/collected-metrics \ diff --git a/glean-core/Cargo.toml b/glean-core/Cargo.toml index 7709047f81..b4c1058a40 100644 --- a/glean-core/Cargo.toml +++ b/glean-core/Cargo.toml @@ -21,7 +21,7 @@ include = [ rust-version = "1.66" [package.metadata.glean] -glean-parser = "12.0.1" +glean-parser = "13.0.0" [badges] circle-ci = { repository = "mozilla/glean", branch = "main" } diff --git a/glean-core/build/Cargo.toml b/glean-core/build/Cargo.toml index c846a921d3..bac7602cd6 100644 --- a/glean-core/build/Cargo.toml +++ b/glean-core/build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "glean-build" -version = "12.0.1" +version = "13.0.0" edition = "2021" description = "Glean SDK Rust build helper" repository = "https://github.com/mozilla/glean" diff --git a/glean-core/build/src/lib.rs b/glean-core/build/src/lib.rs index 6dda9e2dca..f6f8115652 100644 --- a/glean-core/build/src/lib.rs +++ b/glean-core/build/src/lib.rs @@ -39,7 +39,7 @@ use std::env; use xshell_venv::{Result, Shell, VirtualEnv}; -const GLEAN_PARSER_VERSION: &str = "12.0.1"; +const GLEAN_PARSER_VERSION: &str = "13.0.0"; /// A Glean Rust bindings generator. pub struct Builder { diff --git a/glean-core/ios/sdk_generator.sh b/glean-core/ios/sdk_generator.sh index d101534ca8..e1eaff06df 100755 --- a/glean-core/ios/sdk_generator.sh +++ b/glean-core/ios/sdk_generator.sh @@ -25,7 +25,7 @@ set -e -GLEAN_PARSER_VERSION=12.0 +GLEAN_PARSER_VERSION=13.0 # CMDNAME is used in the usage text below. # shellcheck disable=SC2034 diff --git a/glean-core/python/glean/__init__.py b/glean-core/python/glean/__init__.py index 27cf16b60a..3b5953894a 100644 --- a/glean-core/python/glean/__init__.py +++ b/glean-core/python/glean/__init__.py @@ -31,7 +31,7 @@ __email__ = "glean-team@mozilla.com" -GLEAN_PARSER_VERSION = "12.0.1" +GLEAN_PARSER_VERSION = "13.0.0" parser_version = VersionInfo.parse(GLEAN_PARSER_VERSION) parser_version_next_major = parser_version.bump_major() diff --git a/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy b/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy index 6521a8d45b..167d306b92 100644 --- a/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy +++ b/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy @@ -50,7 +50,7 @@ abstract class GleanMetricsYamlTransform implements TransformAction { // The version of glean_parser to install from PyPI. - private String GLEAN_PARSER_VERSION = "12.0" + private String GLEAN_PARSER_VERSION = "13.0" // The version of Miniconda is explicitly specified. // Miniconda3-4.5.12 is known to not work on Windows. private String MINICONDA_VERSION = "4.5.11" diff --git a/pyproject.toml b/pyproject.toml index 4fb5a35531..fe493176ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ maintainers = [ dependencies = [ "semver>=2.13.0", - "glean_parser~=12.0", + "glean_parser~=13.0", ] [project.urls] From 75457effa4e9f4717256b1051048651ca5ed4671 Mon Sep 17 00:00:00 2001 From: Chris H-C Date: Wed, 21 Feb 2024 15:07:37 -0500 Subject: [PATCH 25/34] bug 1866559 - Consume new include_info_sections ping parameter --- docs/user/user/pings/index.md | 15 ++- .../telemetry/glean/private/PingType.kt | 2 + .../java/mozilla/telemetry/glean/GleanTest.kt | 2 + .../glean/debug/GleanDebugActivityTest.kt | 1 + .../telemetry/glean/pings/CustomPingTest.kt | 3 + .../glean/private/EventMetricTypeTest.kt | 1 + .../telemetry/glean/private/PingTypeTest.kt | 5 + glean-core/ios/Glean/Metrics/Ping.swift | 2 + glean-core/ios/GleanTests/GleanTests.swift | 2 + .../ios/GleanTests/Metrics/PingTests.swift | 4 + glean-core/python/glean/_loader.py | 1 + glean-core/python/glean/metrics/ping.py | 8 +- glean-core/python/tests/test_glean.py | 8 ++ glean-core/rlb/examples/crashing-threads.rs | 2 +- glean-core/rlb/examples/long-running.rs | 2 +- glean-core/rlb/examples/prototype.rs | 2 +- glean-core/rlb/src/lib.rs | 2 +- glean-core/rlb/src/private/ping.rs | 2 + glean-core/rlb/src/test.rs | 14 +-- glean-core/rlb/tests/init_fails.rs | 2 +- glean-core/rlb/tests/never_init.rs | 2 +- glean-core/rlb/tests/no_time_to_init.rs | 2 +- glean-core/rlb/tests/schema.rs | 2 +- glean-core/rlb/tests/simple.rs | 2 +- glean-core/rlb/tests/upload_timing.rs | 2 +- glean-core/src/core/mod.rs | 2 +- glean-core/src/glean.udl | 2 +- glean-core/src/internal_pings.rs | 4 + glean-core/src/metrics/ping.rs | 9 ++ glean-core/src/ping/mod.rs | 26 +++-- glean-core/src/upload/directory.rs | 6 +- glean-core/src/upload/mod.rs | 108 ++++++++++++++++-- glean-core/tests/event.rs | 2 + glean-core/tests/ping.rs | 14 +-- glean-core/tests/ping_maker.rs | 22 ++-- 35 files changed, 219 insertions(+), 66 deletions(-) diff --git a/docs/user/user/pings/index.md b/docs/user/user/pings/index.md index f12de0d83c..068ce88d90 100644 --- a/docs/user/user/pings/index.md +++ b/docs/user/user/pings/index.md @@ -16,11 +16,14 @@ that are assembled out of the box without any developer intervention. Every ping payload has the following keys at the top-level: - The [`ping_info` section](#the-ping_info-section) contains core metadata - that is included in **every** ping. + that is included in every ping that doesn't set the + `metadata.include_info_sections` property to `false`. - The [`client_info` section](#the-client_info-section) contains information that identifies the client. - It is included in most pings (including all built-in pings), but may be excluded from pings - where we don't want to connect client information with the other metrics in the ping. + It is included in every ping that doesn't set the + `metadata.include_info_sections` property to `false`. + When included, it contains a persistent client identifier `client_id`, + except when the `include_client_id` property is set to `false`. The following keys are only present if any metrics or events were recorded for the given ping: @@ -36,7 +39,8 @@ for more details for each metric type in the `metrics` and `events` section. ### The `ping_info` section Metadata about the ping itself. -This section is included in **every** ping. +This section is included in every ping that doesn't set the +`metadata.include_info_sections` property to `false`. The following fields are included in the `ping_info` section. Optional fields are marked accordingly. @@ -103,6 +107,9 @@ The data is provided by the embedding application or automatically fetched by th It is collected at initialization time and sent in every ping afterwards. For historical reasons it contains metrics that are only useful on a certain platform. +This section is included in every ping that doesn't set the +`metadata.include_info_sections` property to `false`. + {{#include ../../../shared/blockquote-info.html}} ##### Additional metrics require a proposal diff --git a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/PingType.kt b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/PingType.kt index 349c3bdab5..19518b433c 100644 --- a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/PingType.kt +++ b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/PingType.kt @@ -49,6 +49,7 @@ class PingType ( includeClientId: Boolean, sendIfEmpty: Boolean, preciseTimestamps: Boolean, + includeInfoSections: Boolean, val reasonCodes: List, ) where ReasonCodesEnum : Enum, ReasonCodesEnum : ReasonCode { private var testCallback: ((ReasonCodesEnum?) -> Unit)? = null @@ -60,6 +61,7 @@ class PingType ( includeClientId = includeClientId, sendIfEmpty = sendIfEmpty, preciseTimestamps = preciseTimestamps, + includeInfoSections = includeInfoSections, reasonCodes = reasonCodes, ) } diff --git a/glean-core/android/src/test/java/mozilla/telemetry/glean/GleanTest.kt b/glean-core/android/src/test/java/mozilla/telemetry/glean/GleanTest.kt index d68c1ba326..f6317dc116 100644 --- a/glean-core/android/src/test/java/mozilla/telemetry/glean/GleanTest.kt +++ b/glean-core/android/src/test/java/mozilla/telemetry/glean/GleanTest.kt @@ -479,6 +479,7 @@ class GleanTest { includeClientId = true, sendIfEmpty = false, preciseTimestamps = true, + includeInfoSections = true, reasonCodes = listOf(), ) val stringMetric = StringMetricType( @@ -845,6 +846,7 @@ class GleanTest { includeClientId = true, sendIfEmpty = false, preciseTimestamps = true, + includeInfoSections = true, reasonCodes = listOf(), ) val stringMetric = StringMetricType( diff --git a/glean-core/android/src/test/java/mozilla/telemetry/glean/debug/GleanDebugActivityTest.kt b/glean-core/android/src/test/java/mozilla/telemetry/glean/debug/GleanDebugActivityTest.kt index 001c834702..e70ad9aa94 100644 --- a/glean-core/android/src/test/java/mozilla/telemetry/glean/debug/GleanDebugActivityTest.kt +++ b/glean-core/android/src/test/java/mozilla/telemetry/glean/debug/GleanDebugActivityTest.kt @@ -249,6 +249,7 @@ class GleanDebugActivityTest { includeClientId = false, sendIfEmpty = true, preciseTimestamps = true, + includeInfoSections = true, reasonCodes = listOf(), ) diff --git a/glean-core/android/src/test/java/mozilla/telemetry/glean/pings/CustomPingTest.kt b/glean-core/android/src/test/java/mozilla/telemetry/glean/pings/CustomPingTest.kt index 800c6df942..9b8d29d6cc 100644 --- a/glean-core/android/src/test/java/mozilla/telemetry/glean/pings/CustomPingTest.kt +++ b/glean-core/android/src/test/java/mozilla/telemetry/glean/pings/CustomPingTest.kt @@ -77,6 +77,7 @@ class CustomPingTest { includeClientId = true, sendIfEmpty = true, preciseTimestamps = true, + includeInfoSections = true, reasonCodes = emptyList(), ) @@ -106,6 +107,7 @@ class CustomPingTest { includeClientId = true, sendIfEmpty = true, preciseTimestamps = true, + includeInfoSections = true, reasonCodes = emptyList(), ) @@ -179,6 +181,7 @@ class CustomPingTest { includeClientId = true, sendIfEmpty = true, preciseTimestamps = true, + includeInfoSections = true, reasonCodes = emptyList(), ) diff --git a/glean-core/android/src/test/java/mozilla/telemetry/glean/private/EventMetricTypeTest.kt b/glean-core/android/src/test/java/mozilla/telemetry/glean/private/EventMetricTypeTest.kt index d42f0c92d9..ca1675452f 100644 --- a/glean-core/android/src/test/java/mozilla/telemetry/glean/private/EventMetricTypeTest.kt +++ b/glean-core/android/src/test/java/mozilla/telemetry/glean/private/EventMetricTypeTest.kt @@ -507,6 +507,7 @@ class EventMetricTypeTest { includeClientId = true, sendIfEmpty = false, preciseTimestamps = true, + includeInfoSections = true, reasonCodes = listOf(), ) diff --git a/glean-core/android/src/test/java/mozilla/telemetry/glean/private/PingTypeTest.kt b/glean-core/android/src/test/java/mozilla/telemetry/glean/private/PingTypeTest.kt index 10656a1c94..61e40b90c2 100644 --- a/glean-core/android/src/test/java/mozilla/telemetry/glean/private/PingTypeTest.kt +++ b/glean-core/android/src/test/java/mozilla/telemetry/glean/private/PingTypeTest.kt @@ -54,6 +54,7 @@ class PingTypeTest { includeClientId = true, sendIfEmpty = false, preciseTimestamps = true, + includeInfoSections = true, reasonCodes = listOf(), ) @@ -120,6 +121,7 @@ class PingTypeTest { includeClientId = true, sendIfEmpty = false, preciseTimestamps = true, + includeInfoSections = true, reasonCodes = listOf(), ) @@ -167,6 +169,7 @@ class PingTypeTest { includeClientId = true, sendIfEmpty = false, preciseTimestamps = true, + includeInfoSections = true, reasonCodes = listOf(), ) @@ -214,6 +217,7 @@ class PingTypeTest { includeClientId = false, sendIfEmpty = false, preciseTimestamps = true, + includeInfoSections = true, reasonCodes = listOf(), ) @@ -263,6 +267,7 @@ class PingTypeTest { sendIfEmpty = false, reasonCodes = listOf(), preciseTimestamps = true, + includeInfoSections = true, ) val counter = CounterMetricType( diff --git a/glean-core/ios/Glean/Metrics/Ping.swift b/glean-core/ios/Glean/Metrics/Ping.swift index 867a7a2cdd..cfd4981c10 100644 --- a/glean-core/ios/Glean/Metrics/Ping.swift +++ b/glean-core/ios/Glean/Metrics/Ping.swift @@ -40,6 +40,7 @@ public class Ping { includeClientId: Bool, sendIfEmpty: Bool, preciseTimestamps: Bool, + includeInfoSections: Bool, reasonCodes: [String] ) { self.name = name @@ -49,6 +50,7 @@ public class Ping { includeClientId, sendIfEmpty, preciseTimestamps, + includeInfoSections, reasonCodes ) } diff --git a/glean-core/ios/GleanTests/GleanTests.swift b/glean-core/ios/GleanTests/GleanTests.swift index 93542751b4..2b01219bc7 100644 --- a/glean-core/ios/GleanTests/GleanTests.swift +++ b/glean-core/ios/GleanTests/GleanTests.swift @@ -258,6 +258,7 @@ class GleanTests: XCTestCase { includeClientId: true, sendIfEmpty: false, preciseTimestamps: true, + includeInfoSections: true, reasonCodes: [] ) @@ -415,6 +416,7 @@ class GleanTests: XCTestCase { includeClientId: true, sendIfEmpty: false, preciseTimestamps: true, + includeInfoSections: true, reasonCodes: [] ) diff --git a/glean-core/ios/GleanTests/Metrics/PingTests.swift b/glean-core/ios/GleanTests/Metrics/PingTests.swift index e693384de6..477ef0870c 100644 --- a/glean-core/ios/GleanTests/Metrics/PingTests.swift +++ b/glean-core/ios/GleanTests/Metrics/PingTests.swift @@ -40,6 +40,7 @@ class PingTests: XCTestCase { includeClientId: true, sendIfEmpty: false, preciseTimestamps: true, + includeInfoSections: true, reasonCodes: [] ) @@ -86,6 +87,7 @@ class PingTests: XCTestCase { includeClientId: false, sendIfEmpty: false, preciseTimestamps: true, + includeInfoSections: true, reasonCodes: [] ) @@ -122,6 +124,7 @@ class PingTests: XCTestCase { includeClientId: false, sendIfEmpty: true, preciseTimestamps: true, + includeInfoSections: true, reasonCodes: [] ) @@ -213,6 +216,7 @@ class PingTests: XCTestCase { includeClientId: true, sendIfEmpty: true, preciseTimestamps: true, + includeInfoSections: true, reasonCodes: ["was_tested"] ) diff --git a/glean-core/python/glean/_loader.py b/glean-core/python/glean/_loader.py index 70da8f02ca..e4390153a7 100644 --- a/glean-core/python/glean/_loader.py +++ b/glean-core/python/glean/_loader.py @@ -61,6 +61,7 @@ "reason_codes", "send_in_pings", "precise_timestamps", + "include_info_sections", "time_unit", ] diff --git a/glean-core/python/glean/metrics/ping.py b/glean-core/python/glean/metrics/ping.py index 07a5ca3807..2372a93e14 100644 --- a/glean-core/python/glean/metrics/ping.py +++ b/glean-core/python/glean/metrics/ping.py @@ -16,6 +16,7 @@ def __init__( include_client_id: bool, send_if_empty: bool, precise_timestamps: bool, + include_info_sections: bool, reason_codes: List[str], ): """ @@ -26,7 +27,12 @@ def __init__( """ self._reason_codes = reason_codes self._inner = GleanPingType( - name, include_client_id, send_if_empty, precise_timestamps, reason_codes + name, + include_client_id, + send_if_empty, + precise_timestamps, + include_info_sections, + reason_codes, ) self._test_callback = None # type: Optional[Callable[[Optional[str]], None]] diff --git a/glean-core/python/tests/test_glean.py b/glean-core/python/tests/test_glean.py index 010898d32c..2d74daee41 100644 --- a/glean-core/python/tests/test_glean.py +++ b/glean-core/python/tests/test_glean.py @@ -279,6 +279,7 @@ def test_dont_schedule_pings_if_metrics_disabled(safe_httpserver): include_client_id=True, send_if_empty=False, precise_timestamps=True, + include_info_sections=True, reason_codes=[], ) @@ -299,6 +300,7 @@ def test_dont_schedule_pings_if_there_is_no_ping_content(safe_httpserver): include_client_id=True, send_if_empty=False, precise_timestamps=True, + include_info_sections=True, reason_codes=[], ) @@ -365,6 +367,7 @@ def test_ping_collection_must_happen_after_currently_scheduled_metrics_recording include_client_id=True, send_if_empty=False, precise_timestamps=True, + include_info_sections=True, reason_codes=[], ) string_metric = StringMetricType( @@ -694,6 +697,7 @@ def broken_process(*args, **kwargs): include_client_id=True, send_if_empty=True, precise_timestamps=True, + include_info_sections=True, reason_codes=[], ) @@ -766,6 +770,7 @@ def test_presubmit_makes_a_valid_ping(tmpdir, ping_schema_url, monkeypatch): include_client_id=True, send_if_empty=True, precise_timestamps=True, + include_info_sections=True, reason_codes=[], ) @@ -828,6 +833,7 @@ def test_flipping_upload_enabled_respects_order_of_events(tmpdir, monkeypatch): include_client_id=True, send_if_empty=True, precise_timestamps=True, + include_info_sections=True, reason_codes=[], ) @@ -936,6 +942,7 @@ def test_sending_of_custom_pings(safe_httpserver): include_client_id=True, send_if_empty=False, precise_timestamps=True, + include_info_sections=True, reason_codes=[], ) @@ -1019,6 +1026,7 @@ def test_glean_shutdown(safe_httpserver): include_client_id=True, send_if_empty=False, precise_timestamps=False, + include_info_sections=True, reason_codes=[], ) diff --git a/glean-core/rlb/examples/crashing-threads.rs b/glean-core/rlb/examples/crashing-threads.rs index c1afcbf680..5d165c4fda 100644 --- a/glean-core/rlb/examples/crashing-threads.rs +++ b/glean-core/rlb/examples/crashing-threads.rs @@ -88,7 +88,7 @@ pub mod glean_metrics { #[allow(non_upper_case_globals)] pub static PrototypePing: Lazy = - Lazy::new(|| PingType::new("prototype", true, true, true, vec![])); + Lazy::new(|| PingType::new("prototype", true, true, true, true, vec![])); fn main() { env_logger::init(); diff --git a/glean-core/rlb/examples/long-running.rs b/glean-core/rlb/examples/long-running.rs index 018ce07f0b..6ae8c8036b 100644 --- a/glean-core/rlb/examples/long-running.rs +++ b/glean-core/rlb/examples/long-running.rs @@ -46,7 +46,7 @@ impl net::PingUploader for FakeUploader { #[allow(non_upper_case_globals)] pub static PrototypePing: Lazy = - Lazy::new(|| PingType::new("prototype", true, true, true, vec![])); + Lazy::new(|| PingType::new("prototype", true, true, true, true, vec![])); fn main() { env_logger::init(); diff --git a/glean-core/rlb/examples/prototype.rs b/glean-core/rlb/examples/prototype.rs index a38154b946..00f3f98b90 100644 --- a/glean-core/rlb/examples/prototype.rs +++ b/glean-core/rlb/examples/prototype.rs @@ -29,7 +29,7 @@ pub mod glean_metrics { #[allow(non_upper_case_globals)] pub static PrototypePing: Lazy = - Lazy::new(|| PingType::new("prototype", true, true, true, vec![])); + Lazy::new(|| PingType::new("prototype", true, true, true, true, vec![])); fn main() { env_logger::init(); diff --git a/glean-core/rlb/src/lib.rs b/glean-core/rlb/src/lib.rs index 538b8c590d..5c5b945a95 100644 --- a/glean-core/rlb/src/lib.rs +++ b/glean-core/rlb/src/lib.rs @@ -23,7 +23,7 @@ //! let cfg = ConfigurationBuilder::new(true, "/tmp/data", "org.mozilla.glean_core.example").build(); //! glean::initialize(cfg, ClientInfoMetrics::unknown()); //! -//! let prototype_ping = PingType::new("prototype", true, true, true, vec!()); +//! let prototype_ping = PingType::new("prototype", true, true, true, true, vec!()); //! //! prototype_ping.submit(None); //! ``` diff --git a/glean-core/rlb/src/private/ping.rs b/glean-core/rlb/src/private/ping.rs index c9c68a10a2..6c126992bc 100644 --- a/glean-core/rlb/src/private/ping.rs +++ b/glean-core/rlb/src/private/ping.rs @@ -33,6 +33,7 @@ impl PingType { include_client_id: bool, send_if_empty: bool, precise_timestamps: bool, + include_info_sections: bool, reason_codes: Vec, ) -> Self { let inner = glean_core::metrics::PingType::new( @@ -40,6 +41,7 @@ impl PingType { include_client_id, send_if_empty, precise_timestamps, + include_info_sections, reason_codes, ); diff --git a/glean-core/rlb/src/test.rs b/glean-core/rlb/src/test.rs index cb41b49b66..7e6e7996a7 100644 --- a/glean-core/rlb/src/test.rs +++ b/glean-core/rlb/src/test.rs @@ -55,7 +55,7 @@ fn send_a_ping() { // Define a new ping and submit it. const PING_NAME: &str = "test-ping"; - let custom_ping = private::PingType::new(PING_NAME, true, true, true, vec![]); + let custom_ping = private::PingType::new(PING_NAME, true, true, true, true, vec![]); custom_ping.submit(None); // Wait for the ping to arrive. @@ -577,7 +577,7 @@ fn ping_collection_must_happen_after_concurrently_scheduled_metrics_recordings() ); let ping_name = "custom_ping_1"; - let ping = private::PingType::new(ping_name, true, false, true, vec![]); + let ping = private::PingType::new(ping_name, true, false, true, true, vec![]); let metric = private::StringMetric::new(CommonMetricData { name: "string_metric".into(), category: "telemetry".into(), @@ -1118,7 +1118,7 @@ fn flipping_upload_enabled_respects_order_of_events() { .build(); // We create a ping and a metric before we initialize Glean - let sample_ping = PingType::new("sample-ping-1", true, false, true, vec![]); + let sample_ping = PingType::new("sample-ping-1", true, false, true, true, vec![]); let metric = private::StringMetric::new(CommonMetricData { name: "string_metric".into(), category: "telemetry".into(), @@ -1167,7 +1167,7 @@ fn registering_pings_before_init_must_work() { } // Create a custom ping and attempt its registration. - let sample_ping = PingType::new("pre-register", true, true, true, vec![]); + let sample_ping = PingType::new("pre-register", true, true, true, true, vec![]); // Create a custom configuration to use a fake uploader. let dir = tempfile::tempdir().unwrap(); @@ -1224,7 +1224,7 @@ fn test_a_ping_before_submission() { let _t = new_glean(Some(cfg), true); // Create a custom ping and register it. - let sample_ping = PingType::new("custom1", true, true, true, vec![]); + let sample_ping = PingType::new("custom1", true, true, true, true, vec![]); let metric = CounterMetric::new(CommonMetricData { name: "counter_metric".into(), @@ -1346,7 +1346,7 @@ fn signaling_done() { // Define a new ping and submit it. const PING_NAME: &str = "test-ping"; - let custom_ping = private::PingType::new(PING_NAME, true, true, true, vec![]); + let custom_ping = private::PingType::new(PING_NAME, true, true, true, true, vec![]); custom_ping.submit(None); custom_ping.submit(None); @@ -1422,7 +1422,7 @@ fn configure_ping_throttling() { // Define a new ping. const PING_NAME: &str = "test-ping"; - let custom_ping = private::PingType::new(PING_NAME, true, true, true, vec![]); + let custom_ping = private::PingType::new(PING_NAME, true, true, true, true, vec![]); // Submit and receive it `pings_per_interval` times. for _ in 0..pings_per_interval { diff --git a/glean-core/rlb/tests/init_fails.rs b/glean-core/rlb/tests/init_fails.rs index def5acc4b9..a0c23ca277 100644 --- a/glean-core/rlb/tests/init_fails.rs +++ b/glean-core/rlb/tests/init_fails.rs @@ -43,7 +43,7 @@ mod pings { #[allow(non_upper_case_globals)] pub static validation: Lazy = - Lazy::new(|| glean::private::PingType::new("validation", true, true, true, vec![])); + Lazy::new(|| glean::private::PingType::new("validation", true, true, true, true, vec![])); } /// Test scenario: Glean initialization fails. diff --git a/glean-core/rlb/tests/never_init.rs b/glean-core/rlb/tests/never_init.rs index 3df472ee31..0d0d3768ff 100644 --- a/glean-core/rlb/tests/never_init.rs +++ b/glean-core/rlb/tests/never_init.rs @@ -39,7 +39,7 @@ mod pings { #[allow(non_upper_case_globals)] pub static validation: Lazy = - Lazy::new(|| glean::private::PingType::new("validation", true, true, true, vec![])); + Lazy::new(|| glean::private::PingType::new("validation", true, true, true, true, vec![])); } /// Test scenario: Glean is never initialized. diff --git a/glean-core/rlb/tests/no_time_to_init.rs b/glean-core/rlb/tests/no_time_to_init.rs index 763835f2f3..c312b397af 100644 --- a/glean-core/rlb/tests/no_time_to_init.rs +++ b/glean-core/rlb/tests/no_time_to_init.rs @@ -41,7 +41,7 @@ mod pings { #[allow(non_upper_case_globals)] pub static validation: Lazy = - Lazy::new(|| glean::private::PingType::new("validation", true, true, true, vec![])); + Lazy::new(|| glean::private::PingType::new("validation", true, true, true, true, vec![])); } /// Test scenario: Glean initialization fails. diff --git a/glean-core/rlb/tests/schema.rs b/glean-core/rlb/tests/schema.rs index 0a1bf4d2e8..d31ff6b567 100644 --- a/glean-core/rlb/tests/schema.rs +++ b/glean-core/rlb/tests/schema.rs @@ -176,7 +176,7 @@ fn validate_against_schema() { text_metric.set("loooooong text".repeat(100)); // Define a new ping and submit it. - let custom_ping = glean::private::PingType::new(PING_NAME, true, true, true, vec![]); + let custom_ping = glean::private::PingType::new(PING_NAME, true, true, true, true, vec![]); custom_ping.submit(None); // Wait for the ping to arrive. diff --git a/glean-core/rlb/tests/simple.rs b/glean-core/rlb/tests/simple.rs index 3685d44faa..3baa4df14e 100644 --- a/glean-core/rlb/tests/simple.rs +++ b/glean-core/rlb/tests/simple.rs @@ -41,7 +41,7 @@ mod pings { #[allow(non_upper_case_globals)] pub static validation: Lazy = - Lazy::new(|| glean::private::PingType::new("validation", true, true, true, vec![])); + Lazy::new(|| glean::private::PingType::new("validation", true, true, true, true, vec![])); } /// Test scenario: A clean run diff --git a/glean-core/rlb/tests/upload_timing.rs b/glean-core/rlb/tests/upload_timing.rs index 9e77fc3eb5..cca5da02a1 100644 --- a/glean-core/rlb/tests/upload_timing.rs +++ b/glean-core/rlb/tests/upload_timing.rs @@ -97,7 +97,7 @@ mod pings { #[allow(non_upper_case_globals)] pub static validation: Lazy = - Lazy::new(|| glean::private::PingType::new("validation", true, true, true, vec![])); + Lazy::new(|| glean::private::PingType::new("validation", true, true, true, true, vec![])); } // Define a fake uploader that sleeps. diff --git a/glean-core/src/core/mod.rs b/glean-core/src/core/mod.rs index 5a8dd56cde..85691b496c 100644 --- a/glean-core/src/core/mod.rs +++ b/glean-core/src/core/mod.rs @@ -122,7 +122,7 @@ where /// experimentation_id: None, /// }; /// let mut glean = Glean::new(cfg).unwrap(); -/// let ping = PingType::new("sample", true, false, true, vec![]); +/// let ping = PingType::new("sample", true, false, true, true, vec![]); /// glean.register_ping_type(&ping); /// /// let call_counter: CounterMetric = CounterMetric::new(CommonMetricData { diff --git a/glean-core/src/glean.udl b/glean-core/src/glean.udl index e531f64a26..29dbeced6b 100644 --- a/glean-core/src/glean.udl +++ b/glean-core/src/glean.udl @@ -287,7 +287,7 @@ enum ErrorType { }; interface PingType { - constructor(string name, boolean include_client_id, boolean send_if_empty, boolean precise_timestamps, sequence reason_codes); + constructor(string name, boolean include_client_id, boolean send_if_empty, boolean precise_timestamps, boolean include_info_sections, sequence reason_codes); void submit(optional string? reason = null); }; diff --git a/glean-core/src/internal_pings.rs b/glean-core/src/internal_pings.rs index 076a1f7485..07c3849006 100644 --- a/glean-core/src/internal_pings.rs +++ b/glean-core/src/internal_pings.rs @@ -26,6 +26,7 @@ impl InternalPings { true, true, true, + true, vec![ "active".to_string(), "dirty_startup".to_string(), @@ -37,6 +38,7 @@ impl InternalPings { true, false, true, + true, vec![ "overdue".to_string(), "reschedule".to_string(), @@ -50,6 +52,7 @@ impl InternalPings { true, false, true, + true, vec![ "startup".to_string(), "inactive".to_string(), @@ -61,6 +64,7 @@ impl InternalPings { true, true, true, + true, vec!["at_init".to_string(), "set_upload_enabled".to_string()], ), } diff --git a/glean-core/src/metrics/ping.rs b/glean-core/src/metrics/ping.rs index dc37d76a45..c052b33154 100644 --- a/glean-core/src/metrics/ping.rs +++ b/glean-core/src/metrics/ping.rs @@ -26,6 +26,8 @@ struct InnerPing { pub send_if_empty: bool, /// Whether to use millisecond-precise start/end times. pub precise_timestamps: bool, + /// Whether to include the {client|ping}_info sections on assembly. + pub include_info_sections: bool, /// The "reason" codes that this ping can send pub reason_codes: Vec, } @@ -37,6 +39,7 @@ impl fmt::Debug for PingType { .field("include_client_id", &self.0.include_client_id) .field("send_if_empty", &self.0.send_if_empty) .field("precise_timestamps", &self.0.precise_timestamps) + .field("include_info_sections", &self.0.include_info_sections) .field("reason_codes", &self.0.reason_codes) .finish() } @@ -61,6 +64,7 @@ impl PingType { include_client_id: bool, send_if_empty: bool, precise_timestamps: bool, + include_info_sections: bool, reason_codes: Vec, ) -> Self { let this = Self(Arc::new(InnerPing { @@ -68,6 +72,7 @@ impl PingType { include_client_id, send_if_empty, precise_timestamps, + include_info_sections, reason_codes, })); @@ -94,6 +99,10 @@ impl PingType { self.0.precise_timestamps } + pub(crate) fn include_info_sections(&self) -> bool { + self.0.include_info_sections + } + /// Submits the ping for eventual uploading. /// /// The ping content is assembled as soon as possible, but upload is not diff --git a/glean-core/src/ping/mod.rs b/glean-core/src/ping/mod.rs index c22a890aa2..e00b6ac4ed 100644 --- a/glean-core/src/ping/mod.rs +++ b/glean-core/src/ping/mod.rs @@ -30,6 +30,8 @@ pub struct Ping<'a> { pub content: JsonValue, /// The headers to upload with the payload. pub headers: HeaderMap, + /// Whether the content contains {client|ping}_info sections. + pub includes_info_sections: bool, } /// Collect a ping's data, assemble it into its full payload and store it on disk. @@ -237,9 +239,9 @@ impl PingMaker { .snapshot_as_json(glean, ping.name(), true); // Due to the way the experimentation identifier could link datasets that are intentionally unlinked, - // it will not be included in pings that specifically exclude the Glean client-id and those pings that - // should not be sent if empty. - if (!ping.include_client_id() || !ping.send_if_empty()) + // it will not be included in pings that specifically exclude the Glean client-id, those pings that + // should not be sent if empty, or pings that exclude the {client|ping}_info sections wholesale. + if (!ping.include_client_id() || !ping.send_if_empty() || !ping.include_info_sections()) && glean.test_get_experimentation_id().is_some() && metrics_data.is_some() { @@ -285,13 +287,18 @@ impl PingMaker { TimeUnit::Minute }; - let ping_info = self.get_ping_info(glean, ping.name(), reason, precision); - let client_info = self.get_client_info(glean, ping.include_client_id()); + let mut json = if ping.include_info_sections() { + let ping_info = self.get_ping_info(glean, ping.name(), reason, precision); + let client_info = self.get_client_info(glean, ping.include_client_id()); + + json!({ + "ping_info": ping_info, + "client_info": client_info + }) + } else { + json!({}) + }; - let mut json = json!({ - "ping_info": ping_info, - "client_info": client_info - }); let json_obj = json.as_object_mut()?; if let Some(metrics_data) = metrics_data { json_obj.insert("metrics".to_string(), metrics_data); @@ -306,6 +313,7 @@ impl PingMaker { doc_id, url_path, headers: self.get_headers(glean), + includes_info_sections: ping.include_info_sections(), }) } diff --git a/glean-core/src/upload/directory.rs b/glean-core/src/upload/directory.rs index a78bbf0bdb..cfd3c956d7 100644 --- a/glean-core/src/upload/directory.rs +++ b/glean-core/src/upload/directory.rs @@ -303,7 +303,7 @@ mod test { let (mut glean, dir) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, true, true, vec![]); + let ping_type = PingType::new("test", true, true, true, true, vec![]); glean.register_ping_type(&ping_type); // Submit the ping to populate the pending_pings directory @@ -329,7 +329,7 @@ mod test { let (mut glean, dir) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, true, true, vec![]); + let ping_type = PingType::new("test", true, true, true, true, vec![]); glean.register_ping_type(&ping_type); // Submit the ping to populate the pending_pings directory @@ -364,7 +364,7 @@ mod test { let (mut glean, dir) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, true, true, vec![]); + let ping_type = PingType::new("test", true, true, true, true, vec![]); glean.register_ping_type(&ping_type); // Submit the ping to populate the pending_pings directory diff --git a/glean-core/src/upload/mod.rs b/glean-core/src/upload/mod.rs index d764dcd29e..df39e7a299 100644 --- a/glean-core/src/upload/mod.rs +++ b/glean-core/src/upload/mod.rs @@ -979,7 +979,14 @@ mod test { let (mut glean, _t) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, /* send_if_empty */ true, true, vec![]); + let ping_type = PingType::new( + "test", + true, + /* send_if_empty */ true, + true, + true, + vec![], + ); glean.register_ping_type(&ping_type); // Submit the ping multiple times @@ -1011,7 +1018,14 @@ mod test { let (mut glean, dir) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, /* send_if_empty */ true, true, vec![]); + let ping_type = PingType::new( + "test", + true, + /* send_if_empty */ true, + true, + true, + vec![], + ); glean.register_ping_type(&ping_type); // Submit the ping multiple times @@ -1041,7 +1055,14 @@ mod test { let (mut glean, dir) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, /* send_if_empty */ true, true, vec![]); + let ping_type = PingType::new( + "test", + true, + /* send_if_empty */ true, + true, + true, + vec![], + ); glean.register_ping_type(&ping_type); // Submit a ping @@ -1071,7 +1092,14 @@ mod test { let (mut glean, dir) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, /* send_if_empty */ true, true, vec![]); + let ping_type = PingType::new( + "test", + true, + /* send_if_empty */ true, + true, + true, + vec![], + ); glean.register_ping_type(&ping_type); // Submit a ping @@ -1101,7 +1129,14 @@ mod test { let (mut glean, _t) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, /* send_if_empty */ true, true, vec![]); + let ping_type = PingType::new( + "test", + true, + /* send_if_empty */ true, + true, + true, + vec![], + ); glean.register_ping_type(&ping_type); // Submit a ping @@ -1133,7 +1168,14 @@ mod test { let (mut glean, dir) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, /* send_if_empty */ true, true, vec![]); + let ping_type = PingType::new( + "test", + true, + /* send_if_empty */ true, + true, + true, + vec![], + ); glean.register_ping_type(&ping_type); // Submit a ping @@ -1221,7 +1263,14 @@ mod test { glean.set_debug_view_tag("valid-tag"); // Register a ping for testing - let ping_type = PingType::new("test", true, /* send_if_empty */ true, true, vec![]); + let ping_type = PingType::new( + "test", + true, + /* send_if_empty */ true, + true, + true, + vec![], + ); glean.register_ping_type(&ping_type); // Submit a ping @@ -1267,7 +1316,14 @@ mod test { let (mut glean, dir) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, /* send_if_empty */ true, true, vec![]); + let ping_type = PingType::new( + "test", + true, + /* send_if_empty */ true, + true, + true, + vec![], + ); glean.register_ping_type(&ping_type); // Submit the ping multiple times @@ -1317,7 +1373,14 @@ mod test { let (mut glean, dir) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, /* send_if_empty */ true, true, vec![]); + let ping_type = PingType::new( + "test", + true, + /* send_if_empty */ true, + true, + true, + vec![], + ); glean.register_ping_type(&ping_type); // Submit the ping multiple times @@ -1385,7 +1448,14 @@ mod test { let (mut glean, dir) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, /* send_if_empty */ true, true, vec![]); + let ping_type = PingType::new( + "test", + true, + /* send_if_empty */ true, + true, + true, + vec![], + ); glean.register_ping_type(&ping_type); // How many pings we allow at maximum @@ -1457,7 +1527,14 @@ mod test { let (mut glean, dir) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, /* send_if_empty */ true, true, vec![]); + let ping_type = PingType::new( + "test", + true, + /* send_if_empty */ true, + true, + true, + vec![], + ); glean.register_ping_type(&ping_type); let expected_number_of_pings = 3; @@ -1531,7 +1608,14 @@ mod test { let (mut glean, dir) = new_glean(None); // Register a ping for testing - let ping_type = PingType::new("test", true, /* send_if_empty */ true, true, vec![]); + let ping_type = PingType::new( + "test", + true, + /* send_if_empty */ true, + true, + true, + vec![], + ); glean.register_ping_type(&ping_type); let expected_number_of_pings = 2; diff --git a/glean-core/tests/event.rs b/glean-core/tests/event.rs index ed8f7d807f..c83e225ca2 100644 --- a/glean-core/tests/event.rs +++ b/glean-core/tests/event.rs @@ -166,6 +166,7 @@ fn test_sending_of_event_ping_when_it_fills_up() { true, false, true, + true, vec!["max_capacity".to_string()], )); } @@ -450,6 +451,7 @@ fn event_storage_trimming() { true, false, true, + true, vec![], )); diff --git a/glean-core/tests/ping.rs b/glean-core/tests/ping.rs index 0ee3736168..17944b4c24 100644 --- a/glean-core/tests/ping.rs +++ b/glean-core/tests/ping.rs @@ -15,7 +15,7 @@ use glean_core::Lifetime; fn write_ping_to_disk() { let (mut glean, _temp) = new_glean(None); - let ping = PingType::new("metrics", true, false, true, vec![]); + let ping = PingType::new("metrics", true, false, true, true, vec![]); glean.register_ping_type(&ping); // We need to store a metric as an empty ping is not stored. @@ -36,7 +36,7 @@ fn write_ping_to_disk() { fn disabling_upload_clears_pending_pings() { let (mut glean, _t) = new_glean(None); - let ping = PingType::new("metrics", true, false, true, vec![]); + let ping = PingType::new("metrics", true, false, true, true, vec![]); glean.register_ping_type(&ping); // We need to store a metric as an empty ping is not stored. @@ -105,9 +105,9 @@ fn deletion_request_only_when_toggled_from_on_to_off() { fn empty_pings_with_flag_are_sent() { let (mut glean, _t) = new_glean(None); - let ping1 = PingType::new("custom-ping1", true, true, true, vec![]); + let ping1 = PingType::new("custom-ping1", true, true, true, true, vec![]); glean.register_ping_type(&ping1); - let ping2 = PingType::new("custom-ping2", true, false, true, vec![]); + let ping2 = PingType::new("custom-ping2", true, false, true, true, vec![]); glean.register_ping_type(&ping2); // No data is stored in either of the custom pings @@ -139,10 +139,10 @@ fn test_pings_submitted_metric() { None, ); - let metrics_ping = PingType::new("metrics", true, false, true, vec![]); + let metrics_ping = PingType::new("metrics", true, false, true, true, vec![]); glean.register_ping_type(&metrics_ping); - let baseline_ping = PingType::new("baseline", true, false, true, vec![]); + let baseline_ping = PingType::new("baseline", true, false, true, true, vec![]); glean.register_ping_type(&baseline_ping); // We need to store a metric as an empty ping is not stored. @@ -218,7 +218,7 @@ fn test_pings_submitted_metric() { fn events_ping_with_metric_but_no_events_is_not_sent() { let (mut glean, _t) = new_glean(None); - let events_ping = PingType::new("events", true, true, true, vec![]); + let events_ping = PingType::new("events", true, true, true, true, vec![]); glean.register_ping_type(&events_ping); let counter = CounterMetric::new(CommonMetricData { name: "counter".into(), diff --git a/glean-core/tests/ping_maker.rs b/glean-core/tests/ping_maker.rs index 29b6bccaca..a7eba0ea84 100644 --- a/glean-core/tests/ping_maker.rs +++ b/glean-core/tests/ping_maker.rs @@ -13,7 +13,7 @@ fn set_up_basic_ping() -> (Glean, PingMaker, PingType, tempfile::TempDir) { let (tempdir, _) = tempdir(); let (mut glean, t) = new_glean(Some(tempdir)); let ping_maker = PingMaker::new(); - let ping_type = PingType::new("store1", true, false, true, vec![]); + let ping_type = PingType::new("store1", true, false, true, true, vec![]); glean.register_ping_type(&ping_type); // Record something, so the ping will have data @@ -94,7 +94,7 @@ fn test_metrics_must_report_experimentation_id() { }) .unwrap(); let ping_maker = PingMaker::new(); - let ping_type = PingType::new("store1", true, false, true, vec![]); + let ping_type = PingType::new("store1", true, false, true, true, vec![]); glean.register_ping_type(&ping_type); // Record something, so the ping will have data @@ -147,7 +147,7 @@ fn experimentation_id_is_removed_if_send_if_empty_is_false() { .unwrap(); let ping_maker = PingMaker::new(); - let unknown_ping_type = PingType::new("unknown", true, false, true, vec![]); + let unknown_ping_type = PingType::new("unknown", true, false, true, true, vec![]); glean.register_ping_type(&unknown_ping_type); assert!(ping_maker @@ -163,7 +163,7 @@ fn collect_must_report_none_when_no_data_is_stored() { let (mut glean, ping_maker, ping_type, _t) = set_up_basic_ping(); - let unknown_ping_type = PingType::new("unknown", true, false, true, vec![]); + let unknown_ping_type = PingType::new("unknown", true, false, true, true, vec![]); glean.register_ping_type(&ping_type); assert!(ping_maker @@ -187,7 +187,7 @@ fn seq_number_must_be_sequential() { for i in 0..=1 { for ping_name in ["store1", "store2"].iter() { - let ping_type = PingType::new(*ping_name, true, false, true, vec![]); + let ping_type = PingType::new(*ping_name, true, false, true, true, vec![]); let ping = ping_maker .collect(&glean, &ping_type, None, "", "") .unwrap(); @@ -200,7 +200,7 @@ fn seq_number_must_be_sequential() { // Test that ping sequence numbers increase independently. { - let ping_type = PingType::new("store1", true, false, true, vec![]); + let ping_type = PingType::new("store1", true, false, true, true, vec![]); // 3rd ping of store1 let ping = ping_maker @@ -218,7 +218,7 @@ fn seq_number_must_be_sequential() { } { - let ping_type = PingType::new("store2", true, false, true, vec![]); + let ping_type = PingType::new("store2", true, false, true, true, vec![]); // 3rd ping of store2 let ping = ping_maker @@ -229,7 +229,7 @@ fn seq_number_must_be_sequential() { } { - let ping_type = PingType::new("store1", true, false, true, vec![]); + let ping_type = PingType::new("store1", true, false, true, true, vec![]); // 5th ping of store1 let ping = ping_maker @@ -244,7 +244,7 @@ fn seq_number_must_be_sequential() { fn clear_pending_pings() { let (mut glean, _t) = new_glean(None); let ping_maker = PingMaker::new(); - let ping_type = PingType::new("store1", true, false, true, vec![]); + let ping_type = PingType::new("store1", true, false, true, true, vec![]); glean.register_ping_type(&ping_type); // Record something, so the ping will have data @@ -272,7 +272,7 @@ fn no_pings_submitted_if_upload_disabled() { // Regression test, bug 1603571 let (mut glean, _t) = new_glean(None); - let ping_type = PingType::new("store1", true, true, true, vec![]); + let ping_type = PingType::new("store1", true, true, true, true, vec![]); glean.register_ping_type(&ping_type); assert!(ping_type.submit_sync(&glean, None)); @@ -290,7 +290,7 @@ fn no_pings_submitted_if_upload_disabled() { fn metadata_is_correctly_added_when_necessary() { let (mut glean, _t) = new_glean(None); glean.set_debug_view_tag("valid-tag"); - let ping_type = PingType::new("store1", true, true, true, vec![]); + let ping_type = PingType::new("store1", true, true, true, true, vec![]); glean.register_ping_type(&ping_type); assert!(ping_type.submit_sync(&glean, None)); From f0a4fcca7027f4ed8ab7b4895651e3cd18023011 Mon Sep 17 00:00:00 2001 From: Chris H-C Date: Fri, 23 Feb 2024 09:57:26 -0500 Subject: [PATCH 26/34] bug 1866559 - Store and load include_info_sections with pings --- glean-core/src/ping/mod.rs | 18 +++++--- glean-core/src/upload/directory.rs | 66 ++++++++++++++++++++++-------- glean-core/src/upload/mod.rs | 55 +++++++++++++++++++------ 3 files changed, 104 insertions(+), 35 deletions(-) diff --git a/glean-core/src/ping/mod.rs b/glean-core/src/ping/mod.rs index e00b6ac4ed..d1a67ae360 100644 --- a/glean-core/src/ping/mod.rs +++ b/glean-core/src/ping/mod.rs @@ -14,7 +14,7 @@ use serde_json::{json, Value as JsonValue}; use crate::common_metric_data::{CommonMetricData, Lifetime}; use crate::metrics::{CounterMetric, DatetimeMetric, Metric, MetricType, PingType, TimeUnit}; use crate::storage::{StorageManager, INTERNAL_STORAGE}; -use crate::upload::HeaderMap; +use crate::upload::{HeaderMap, PingMetadata}; use crate::util::{get_iso_time_string, local_now_with_offset}; use crate::{Glean, Result, DELETION_REQUEST_PINGS_DIRECTORY, PENDING_PINGS_DIRECTORY}; @@ -363,11 +363,17 @@ impl PingMaker { file.write_all(ping.url_path.as_bytes())?; file.write_all(b"\n")?; file.write_all(::serde_json::to_string(&ping.content)?.as_bytes())?; - if !ping.headers.is_empty() { - file.write_all(b"\n{\"headers\":")?; - file.write_all(::serde_json::to_string(&ping.headers)?.as_bytes())?; - file.write_all(b"}")?; - } + file.write_all(b"\n")?; + let metadata = PingMetadata { + // We don't actually need to clone the headers except to match PingMetadata's ownership. + // But since we're going to write a file to disk in a sec, + // and HeaderMaps tend to have only like two things in them, tops, + // the cost is bearable. + headers: Some(ping.headers.clone()), + body_has_info_sections: Some(ping.includes_info_sections), + ping_name: Some(ping.name.to_string()), + }; + file.write_all(::serde_json::to_string(&metadata)?.as_bytes())?; } if let Err(e) = std::fs::rename(&temp_ping_path, &ping_path) { diff --git a/glean-core/src/upload/directory.rs b/glean-core/src/upload/directory.rs index cfd3c956d7..9530e39383 100644 --- a/glean-core/src/upload/directory.rs +++ b/glean-core/src/upload/directory.rs @@ -9,15 +9,22 @@ use std::fs::{self, File}; use std::io::{BufRead, BufReader}; use std::path::{Path, PathBuf}; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::request::HeaderMap; use crate::{DELETION_REQUEST_PINGS_DIRECTORY, PENDING_PINGS_DIRECTORY}; /// A representation of the data extracted from a ping file, -/// this will contain the document_id, path, JSON encoded body of a ping and the persisted headers. -pub type PingPayload = (String, String, String, Option); +#[derive(Clone, Debug, Default)] +pub struct PingPayload { + pub document_id: String, + pub upload_path: String, + pub json_body: String, + pub headers: Option, + pub body_has_info_sections: bool, + pub ping_name: String, +} /// A struct to hold the result of scanning all pings directories. #[derive(Clone, Debug, Default)] @@ -62,20 +69,28 @@ fn get_file_name_as_str(path: &Path) -> Option<&str> { } } +/// A ping's metadata, as (optionally) represented on disk. +/// +/// Anything that isn't the upload path or the ping body. +#[derive(Default, Deserialize, Serialize)] +pub struct PingMetadata { + /// HTTP headers to include when uploading the ping. + pub headers: Option, + /// Whether the body has {client|ping}_info sections. + pub body_has_info_sections: Option, + /// The name of the ping. + pub ping_name: Option, +} + /// Processes a ping's metadata. /// /// The metadata is an optional third line in the ping file, /// currently it contains only additonal headers to be added to each ping request. /// Therefore, we will process the contents of this line /// and return a HeaderMap of the persisted headers. -fn process_metadata(path: &str, metadata: &str) -> Option { - #[derive(Deserialize)] - struct PingMetadata { - pub headers: HeaderMap, - } - +fn process_metadata(path: &str, metadata: &str) -> Option { if let Ok(metadata) = serde_json::from_str::(metadata) { - return Some(metadata.headers); + return Some(metadata); } else { log::warn!("Error while parsing ping metadata: {}", path); } @@ -171,8 +186,23 @@ impl PingDirectoryManager { if let (Some(Ok(path)), Some(Ok(body)), Ok(metadata)) = (lines.next(), lines.next(), lines.next().transpose()) { - let headers = metadata.and_then(|m| process_metadata(&path, &m)); - return Some((document_id.into(), path, body, headers)); + let PingMetadata { + headers, + body_has_info_sections, + ping_name, + } = metadata + .and_then(|m| process_metadata(&path, &m)) + .unwrap_or_default(); + let ping_name = + ping_name.unwrap_or_else(|| path.split('/').nth(3).unwrap_or("").into()); + return Some(PingPayload { + document_id: document_id.into(), + upload_path: path, + json_body: body, + headers, + body_has_info_sections: body_has_info_sections.unwrap_or(true), + ping_name, + }); } else { log::warn!( "Error processing ping file: {}. Ping file is not formatted as expected.", @@ -320,7 +350,8 @@ mod test { // Verify request was returned for the "test" ping let ping = &data.pending_pings[0].1; - let request_ping_type = ping.1.split('/').nth(3).unwrap(); + let request_ping_type = ping.upload_path.split('/').nth(3).unwrap(); + assert_eq!(request_ping_type, ping.ping_name); assert_eq!(request_ping_type, "test"); } @@ -352,7 +383,8 @@ mod test { // Verify request was returned for the "test" ping let ping = &data.pending_pings[0].1; - let request_ping_type = ping.1.split('/').nth(3).unwrap(); + let request_ping_type = ping.upload_path.split('/').nth(3).unwrap(); + assert_eq!(request_ping_type, ping.ping_name); assert_eq!(request_ping_type, "test"); // Verify that file was indeed deleted @@ -387,7 +419,8 @@ mod test { // Verify request was returned for the "test" ping let ping = &data.pending_pings[0].1; - let request_ping_type = ping.1.split('/').nth(3).unwrap(); + let request_ping_type = ping.upload_path.split('/').nth(3).unwrap(); + assert_eq!(request_ping_type, ping.ping_name); assert_eq!(request_ping_type, "test"); // Verify that file was indeed deleted @@ -414,7 +447,8 @@ mod test { // Verify request was returned for the "deletion-request" ping let ping = &data.deletion_request_pings[0].1; - let request_ping_type = ping.1.split('/').nth(3).unwrap(); + let request_ping_type = ping.upload_path.split('/').nth(3).unwrap(); + assert_eq!(request_ping_type, ping.ping_name); assert_eq!(request_ping_type, "deletion-request"); } } diff --git a/glean-core/src/upload/mod.rs b/glean-core/src/upload/mod.rs index df39e7a299..0bc4980bc4 100644 --- a/glean-core/src/upload/mod.rs +++ b/glean-core/src/upload/mod.rs @@ -26,10 +26,11 @@ use chrono::Utc; use crate::error::ErrorKind; use crate::TimerId; use crate::{internal_metrics::UploadMetrics, Glean}; -use directory::{PingDirectoryManager, PingPayloadsByDirectory}; +use directory::{PingDirectoryManager, PingPayload, PingPayloadsByDirectory}; use policy::Policy; use request::create_date_header_value; +pub use directory::PingMetadata; pub use request::{HeaderMap, PingRequest}; pub use result::{UploadResult, UploadTaskAction}; @@ -455,7 +456,7 @@ impl PingUploadManager { // Thus, we reverse the order of the pending pings vector, // so that we iterate in descending order (newest -> oldest). cached_pings.pending_pings.reverse(); - cached_pings.pending_pings.retain(|(file_size, (document_id, _, _, _))| { + cached_pings.pending_pings.retain(|(file_size, PingPayload {document_id, ..})| { pending_pings_count += 1; pending_pings_directory_size += file_size; @@ -494,12 +495,32 @@ impl PingUploadManager { // Enqueue the remaining pending pings and // enqueue all deletion-request pings. let deletion_request_pings = cached_pings.deletion_request_pings.drain(..); - for (_, (document_id, path, body, headers)) in deletion_request_pings { - self.enqueue_ping(glean, &document_id, &path, &body, headers); + for ( + _, + PingPayload { + document_id, + upload_path, + json_body, + headers, + .. + }, + ) in deletion_request_pings + { + self.enqueue_ping(glean, &document_id, &upload_path, &json_body, headers); } let pending_pings = cached_pings.pending_pings.drain(..); - for (_, (document_id, path, body, headers)) in pending_pings { - self.enqueue_ping(glean, &document_id, &path, &body, headers); + for ( + _, + PingPayload { + document_id, + upload_path, + json_body, + headers, + .. + }, + ) in pending_pings + { + self.enqueue_ping(glean, &document_id, &upload_path, &json_body, headers); } } } @@ -532,10 +553,15 @@ impl PingUploadManager { /// * `glean` - The Glean object holding the database. /// * `document_id` - The UUID of the ping in question. pub fn enqueue_ping_from_file(&self, glean: &Glean, document_id: &str) { - if let Some((doc_id, path, body, headers)) = - self.directory_manager.process_file(document_id) + if let Some(PingPayload { + document_id, + upload_path, + json_body, + headers, + .. + }) = self.directory_manager.process_file(document_id) { - self.enqueue_ping(glean, &doc_id, &path, &body, headers) + self.enqueue_ping(glean, &document_id, &upload_path, &json_body, headers) } } @@ -1394,7 +1420,10 @@ mod test { // The pending pings array is sorted by date in ascending order, // the newest element is the last one. let (_, newest_ping) = &pending_pings.last().unwrap(); - let (newest_ping_id, _, _, _) = &newest_ping; + let PingPayload { + document_id: newest_ping_id, + .. + } = &newest_ping; // Create a new upload manager pointing to the same data_path as the glean instance. let mut upload_manager = PingUploadManager::no_policy(dir.path()); @@ -1476,7 +1505,7 @@ mod test { .iter() .rev() .take(count_quota) - .map(|(_, ping)| ping.0.clone()) + .map(|(_, ping)| ping.document_id.clone()) .collect::>(); // Create a new upload manager pointing to the same data_path as the glean instance. @@ -1554,7 +1583,7 @@ mod test { .iter() .rev() .take(expected_number_of_pings) - .map(|(_, ping)| ping.0.clone()) + .map(|(_, ping)| ping.document_id.clone()) .collect::>(); // Create a new upload manager pointing to the same data_path as the glean instance. @@ -1635,7 +1664,7 @@ mod test { .iter() .rev() .take(expected_number_of_pings) - .map(|(_, ping)| ping.0.clone()) + .map(|(_, ping)| ping.document_id.clone()) .collect::>(); // Create a new upload manager pointing to the same data_path as the glean instance. From d6e2951cb7401016d359160cc4468483bacf33a3 Mon Sep 17 00:00:00 2001 From: Chris H-C Date: Fri, 23 Feb 2024 12:01:41 -0500 Subject: [PATCH 27/34] bug 1866559 - Enqueue and build pings as PingPayloads --- glean-core/src/metrics/ping.rs | 19 ++- glean-core/src/upload/directory.rs | 6 + glean-core/src/upload/mod.rs | 245 ++++++++++++++++++++--------- 3 files changed, 189 insertions(+), 81 deletions(-) diff --git a/glean-core/src/metrics/ping.rs b/glean-core/src/metrics/ping.rs index c052b33154..e60284b1e2 100644 --- a/glean-core/src/metrics/ping.rs +++ b/glean-core/src/metrics/ping.rs @@ -6,6 +6,7 @@ use std::fmt; use std::sync::Arc; use crate::ping::PingMaker; +use crate::upload::PingPayload; use crate::Glean; use uuid::Uuid; @@ -195,13 +196,17 @@ impl PingType { // so both scenarios should be impossible. let content = ::serde_json::to_string(&ping.content).expect("ping serialization failed"); - glean.upload_manager.enqueue_ping( - glean, - ping.doc_id, - ping.url_path, - &content, - Some(ping.headers), - ); + // TODO: Shouldn't we consolidate on a single collected Ping representation? + let ping = PingPayload { + document_id: ping.doc_id.to_string(), + upload_path: ping.url_path.to_string(), + json_body: content, + headers: Some(ping.headers), + body_has_info_sections: self.0.include_info_sections, + ping_name: self.0.name.to_string(), + }; + + glean.upload_manager.enqueue_ping(glean, ping); return true; } diff --git a/glean-core/src/upload/directory.rs b/glean-core/src/upload/directory.rs index 9530e39383..706550fe6c 100644 --- a/glean-core/src/upload/directory.rs +++ b/glean-core/src/upload/directory.rs @@ -18,11 +18,17 @@ use crate::{DELETION_REQUEST_PINGS_DIRECTORY, PENDING_PINGS_DIRECTORY}; /// A representation of the data extracted from a ping file, #[derive(Clone, Debug, Default)] pub struct PingPayload { + /// The ping's doc_id. pub document_id: String, + /// The path to upload the ping to. pub upload_path: String, + /// The ping body as JSON-encoded string. pub json_body: String, + /// HTTP headers to include in the upload request. pub headers: Option, + /// Whether the ping body contains {client|ping}_info pub body_has_info_sections: bool, + /// The ping's name. (Also likely in the upload_path.) pub ping_name: String, } diff --git a/glean-core/src/upload/mod.rs b/glean-core/src/upload/mod.rs index 0bc4980bc4..c3f2463e57 100644 --- a/glean-core/src/upload/mod.rs +++ b/glean-core/src/upload/mod.rs @@ -26,11 +26,11 @@ use chrono::Utc; use crate::error::ErrorKind; use crate::TimerId; use crate::{internal_metrics::UploadMetrics, Glean}; -use directory::{PingDirectoryManager, PingPayload, PingPayloadsByDirectory}; +use directory::{PingDirectoryManager, PingPayloadsByDirectory}; use policy::Policy; use request::create_date_header_value; -pub use directory::PingMetadata; +pub use directory::{PingMetadata, PingPayload}; pub use request::{HeaderMap, PingRequest}; pub use result::{UploadResult, UploadTaskAction}; @@ -323,19 +323,19 @@ impl PingUploadManager { /// /// Returns the `PingRequest` or `None` if unable to build, /// in which case it will delete the ping file and record an error. - fn build_ping_request( - &self, - glean: &Glean, - document_id: &str, - path: &str, - body: &str, - headers: Option, - ) -> Option { + fn build_ping_request(&self, glean: &Glean, ping: PingPayload) -> Option { + let PingPayload { + document_id, + upload_path: path, + json_body: body, + headers, + .. + } = ping; let mut request = PingRequest::builder( &self.language_binding_name, self.policy.max_ping_body_size(), ) - .document_id(document_id) + .document_id(&document_id) .path(path) .body(body); @@ -347,7 +347,7 @@ impl PingUploadManager { Ok(request) => Some(request), Err(e) => { log::warn!("Error trying to build ping request: {}", e); - self.directory_manager.delete_file(document_id); + self.directory_manager.delete_file(&document_id); // Record the error. // Currently the only possible error is PingBodyOverflow. @@ -363,23 +363,21 @@ impl PingUploadManager { } /// Enqueue a ping for upload. - pub fn enqueue_ping( - &self, - glean: &Glean, - document_id: &str, - path: &str, - body: &str, - headers: Option, - ) { + pub fn enqueue_ping(&self, glean: &Glean, ping: PingPayload) { let mut queue = self .queue .write() .expect("Can't write to pending pings queue."); + let PingPayload { + ref document_id, + upload_path: ref path, + .. + } = ping; // Checks if a ping with this `document_id` is already enqueued. if queue .iter() - .any(|request| request.document_id == document_id) + .any(|request| request.document_id.as_str() == document_id) { log::warn!( "Attempted to enqueue a duplicate ping {} at {}.", @@ -405,7 +403,7 @@ impl PingUploadManager { } log::trace!("Enqueuing ping {} at {}", document_id, path); - if let Some(request) = self.build_ping_request(glean, document_id, path, body, headers) { + if let Some(request) = self.build_ping_request(glean, ping) { queue.push_back(request) } } @@ -494,34 +492,14 @@ impl PingUploadManager { // Enqueue the remaining pending pings and // enqueue all deletion-request pings. - let deletion_request_pings = cached_pings.deletion_request_pings.drain(..); - for ( - _, - PingPayload { - document_id, - upload_path, - json_body, - headers, - .. - }, - ) in deletion_request_pings - { - self.enqueue_ping(glean, &document_id, &upload_path, &json_body, headers); - } - let pending_pings = cached_pings.pending_pings.drain(..); - for ( - _, - PingPayload { - document_id, - upload_path, - json_body, - headers, - .. - }, - ) in pending_pings - { - self.enqueue_ping(glean, &document_id, &upload_path, &json_body, headers); - } + cached_pings + .deletion_request_pings + .drain(..) + .for_each(|(_, ping)| self.enqueue_ping(glean, ping)); + cached_pings + .pending_pings + .drain(..) + .for_each(|(_, ping)| self.enqueue_ping(glean, ping)); } } @@ -553,15 +531,8 @@ impl PingUploadManager { /// * `glean` - The Glean object holding the database. /// * `document_id` - The UUID of the ping in question. pub fn enqueue_ping_from_file(&self, glean: &Glean, document_id: &str) { - if let Some(PingPayload { - document_id, - upload_path, - json_body, - headers, - .. - }) = self.directory_manager.process_file(document_id) - { - self.enqueue_ping(glean, &document_id, &upload_path, &json_body, headers) + if let Some(ping) = self.directory_manager.process_file(document_id) { + self.enqueue_ping(glean, ping); } } @@ -909,7 +880,17 @@ mod test { let upload_manager = PingUploadManager::no_policy(dir.path()); // Enqueue a ping - upload_manager.enqueue_ping(&glean, &Uuid::new_v4().to_string(), PATH, "", None); + upload_manager.enqueue_ping( + &glean, + PingPayload { + document_id: Uuid::new_v4().to_string(), + upload_path: PATH.into(), + json_body: "".into(), + headers: None, + body_has_info_sections: true, + ping_name: "ping-name".into(), + }, + ); // Try and get the next request. // Verify request was returned @@ -926,7 +907,17 @@ mod test { // Enqueue a ping multiple times let n = 10; for _ in 0..n { - upload_manager.enqueue_ping(&glean, &Uuid::new_v4().to_string(), PATH, "", None); + upload_manager.enqueue_ping( + &glean, + PingPayload { + document_id: Uuid::new_v4().to_string(), + upload_path: PATH.into(), + json_body: "".into(), + headers: None, + body_has_info_sections: true, + ping_name: "ping-name".into(), + }, + ); } // Verify a request is returned for each submitted ping @@ -954,7 +945,17 @@ mod test { // Enqueue the max number of pings allowed per uploading window for _ in 0..max_pings_per_interval { - upload_manager.enqueue_ping(&glean, &Uuid::new_v4().to_string(), PATH, "", None); + upload_manager.enqueue_ping( + &glean, + PingPayload { + document_id: Uuid::new_v4().to_string(), + upload_path: PATH.into(), + json_body: "".into(), + headers: None, + body_has_info_sections: true, + ping_name: "ping-name".into(), + }, + ); } // Verify a request is returned for each submitted ping @@ -964,7 +965,17 @@ mod test { } // Enqueue just one more ping - upload_manager.enqueue_ping(&glean, &Uuid::new_v4().to_string(), PATH, "", None); + upload_manager.enqueue_ping( + &glean, + PingPayload { + document_id: Uuid::new_v4().to_string(), + upload_path: PATH.into(), + json_body: "".into(), + headers: None, + body_has_info_sections: true, + ping_name: "ping-name".into(), + }, + ); // Verify that we are indeed told to wait because we are at capacity match upload_manager.get_upload_task(&glean, false) { @@ -987,7 +998,17 @@ mod test { // Enqueue a ping multiple times for _ in 0..10 { - upload_manager.enqueue_ping(&glean, &Uuid::new_v4().to_string(), PATH, "", None); + upload_manager.enqueue_ping( + &glean, + PingPayload { + document_id: Uuid::new_v4().to_string(), + upload_path: PATH.into(), + json_body: "".into(), + headers: None, + body_has_info_sections: true, + ping_name: "ping-name".into(), + }, + ); } // Clear the queue @@ -1242,7 +1263,17 @@ mod test { let path2 = format!("/submit/app_id/test-ping/1/{}", doc2); // Enqueue a ping - upload_manager.enqueue_ping(&glean, &doc1, &path1, "", None); + upload_manager.enqueue_ping( + &glean, + PingPayload { + document_id: doc1.clone(), + upload_path: path1, + json_body: "".into(), + headers: None, + body_has_info_sections: true, + ping_name: "test-ping".into(), + }, + ); // Try and get the first request. let req = match upload_manager.get_upload_task(&glean, false) { @@ -1252,7 +1283,17 @@ mod test { assert_eq!(doc1, req.document_id); // Schedule the next one while the first one is "in progress" - upload_manager.enqueue_ping(&glean, &doc2, &path2, "", None); + upload_manager.enqueue_ping( + &glean, + PingPayload { + document_id: doc2.clone(), + upload_path: path2, + json_body: "".into(), + headers: None, + body_has_info_sections: true, + ping_name: "test-ping".into(), + }, + ); // Mark as processed upload_manager.process_ping_upload_response( @@ -1323,8 +1364,28 @@ mod test { let path = format!("/submit/app_id/test-ping/1/{}", doc_id); // Try to enqueue a ping with the same doc_id twice - upload_manager.enqueue_ping(&glean, &doc_id, &path, "", None); - upload_manager.enqueue_ping(&glean, &doc_id, &path, "", None); + upload_manager.enqueue_ping( + &glean, + PingPayload { + document_id: doc_id.clone(), + upload_path: path.clone(), + json_body: "".into(), + headers: None, + body_has_info_sections: true, + ping_name: "test-ping".into(), + }, + ); + upload_manager.enqueue_ping( + &glean, + PingPayload { + document_id: doc_id, + upload_path: path, + json_body: "".into(), + headers: None, + body_has_info_sections: true, + ping_name: "test-ping".into(), + }, + ); // Get a task once let task = upload_manager.get_upload_task(&glean, false); @@ -1735,8 +1796,28 @@ mod test { upload_manager.set_rate_limiter(secs_per_interval, max_pings_per_interval); // Enqueue two pings - upload_manager.enqueue_ping(&glean, &Uuid::new_v4().to_string(), PATH, "", None); - upload_manager.enqueue_ping(&glean, &Uuid::new_v4().to_string(), PATH, "", None); + upload_manager.enqueue_ping( + &glean, + PingPayload { + document_id: Uuid::new_v4().to_string(), + upload_path: PATH.into(), + json_body: "".into(), + headers: None, + body_has_info_sections: true, + ping_name: "ping-name".into(), + }, + ); + upload_manager.enqueue_ping( + &glean, + PingPayload { + document_id: Uuid::new_v4().to_string(), + upload_path: PATH.into(), + json_body: "".into(), + headers: None, + body_has_info_sections: true, + ping_name: "ping-name".into(), + }, + ); // Get the first ping, it should be returned normally. match upload_manager.get_upload_task(&glean, false) { @@ -1792,12 +1873,28 @@ mod test { let upload_manager = PingUploadManager::no_policy(dir.path()); // Enqueue a ping and start processing it - let identifier = &Uuid::new_v4().to_string(); - upload_manager.enqueue_ping(&glean, identifier, PATH, "", None); + let identifier = &Uuid::new_v4(); + let ping = PingPayload { + document_id: identifier.to_string(), + upload_path: PATH.into(), + json_body: "".into(), + headers: None, + body_has_info_sections: true, + ping_name: "ping-name".into(), + }; + upload_manager.enqueue_ping(&glean, ping); assert!(upload_manager.get_upload_task(&glean, false).is_upload()); // Attempt to re-enqueue the same ping - upload_manager.enqueue_ping(&glean, identifier, PATH, "", None); + let ping = PingPayload { + document_id: identifier.to_string(), + upload_path: PATH.into(), + json_body: "".into(), + headers: None, + body_has_info_sections: true, + ping_name: "ping-name".into(), + }; + upload_manager.enqueue_ping(&glean, ping); // No new pings should have been enqueued so the upload task is Done. assert_eq!( @@ -1808,7 +1905,7 @@ mod test { // Process the upload response upload_manager.process_ping_upload_response( &glean, - identifier, + &identifier.to_string(), UploadResult::http_status(200), ); } From 2130ad1ec659112a878b1377bd8736e4e826612d Mon Sep 17 00:00:00 2001 From: Chris H-C Date: Fri, 23 Feb 2024 15:43:50 -0500 Subject: [PATCH 28/34] bug 1866559 - Enrich PingRequest with body_has_info_sections and ping_name --- glean-core/src/glean.udl | 4 ++++ glean-core/src/upload/mod.rs | 7 ++++-- glean-core/src/upload/request.rs | 37 ++++++++++++++++++++++++++------ 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/glean-core/src/glean.udl b/glean-core/src/glean.udl index 29dbeced6b..e31de42e70 100644 --- a/glean-core/src/glean.udl +++ b/glean-core/src/glean.udl @@ -201,6 +201,10 @@ dictionary PingRequest { sequence body; // A map with all the headers to be sent with the request. record headers; + // Whether the body has {client|ping}_info sections. + boolean body_has_info_sections; + // The ping's name. Likely also somewhere in `path`. + string ping_name; }; // An enum representing the possible upload tasks to be performed by an uploader. diff --git a/glean-core/src/upload/mod.rs b/glean-core/src/upload/mod.rs index c3f2463e57..e51a9d9508 100644 --- a/glean-core/src/upload/mod.rs +++ b/glean-core/src/upload/mod.rs @@ -329,7 +329,8 @@ impl PingUploadManager { upload_path: path, json_body: body, headers, - .. + body_has_info_sections, + ping_name, } = ping; let mut request = PingRequest::builder( &self.language_binding_name, @@ -337,7 +338,9 @@ impl PingUploadManager { ) .document_id(&document_id) .path(path) - .body(body); + .body(body) + .body_has_info_sections(body_has_info_sections) + .ping_name(ping_name); if let Some(headers) = headers { request = request.headers(headers); diff --git a/glean-core/src/upload/request.rs b/glean-core/src/upload/request.rs index 0fd5ec5713..b4ac6eba97 100644 --- a/glean-core/src/upload/request.rs +++ b/glean-core/src/upload/request.rs @@ -62,6 +62,8 @@ pub struct Builder { body: Option>, headers: HeaderMap, body_max_size: usize, + body_has_info_sections: Option, + ping_name: Option, } impl Builder { @@ -87,6 +89,8 @@ impl Builder { body: None, headers, body_max_size, + body_has_info_sections: None, + ping_name: None, } } @@ -138,6 +142,18 @@ impl Builder { self } + /// Sets whether the request body has {client|ping}_info sections. + pub fn body_has_info_sections(mut self, body_has_info_sections: bool) -> Self { + self.body_has_info_sections = Some(body_has_info_sections); + self + } + + /// Sets the ping's name aka doctype. + pub fn ping_name>(mut self, ping_name: S) -> Self { + self.ping_name = Some(ping_name.into()); + self + } + /// Sets a header for this request. pub fn header>(mut self, key: S, value: S) -> Self { self.headers.insert(key.into(), value.into()); @@ -174,6 +190,12 @@ impl Builder { .expect("path must be set before attempting to build PingRequest"), body, headers: self.headers, + body_has_info_sections: self.body_has_info_sections.expect( + "body_has_info_sections must be set before attempting to build PingRequest", + ), + ping_name: self + .ping_name + .expect("ping_name must be set before attempting to build PingRequest"), }) } } @@ -192,6 +214,10 @@ pub struct PingRequest { pub body: Vec, /// A map with all the headers to be sent with the request. pub headers: HeaderMap, + /// Whether the body has {client|ping}_info sections. + pub body_has_info_sections: bool, + /// The ping's name. Likely also somewhere in `path`. + pub ping_name: String, } impl PingRequest { @@ -208,12 +234,7 @@ impl PingRequest { /// Verifies if current request is for a deletion-request ping. pub fn is_deletion_request(&self) -> bool { - // The path format should be `/submit///` - self.path - .split('/') - .nth(3) - .map(|url| url == "deletion-request") - .unwrap_or(false) + self.ping_name == "deletion-request" } /// Decompresses and pretty-format the ping payload @@ -257,11 +278,15 @@ mod test { .document_id("woop") .path("/random/path/doesnt/matter") .body("{}") + .body_has_info_sections(false) + .ping_name("whatevs") .build() .unwrap(); assert_eq!(request.document_id, "woop"); assert_eq!(request.path, "/random/path/doesnt/matter"); + assert!(!request.body_has_info_sections); + assert_eq!(request.ping_name, "whatevs"); // Make sure all the expected headers were added. assert!(request.headers.contains_key("X-Telemetry-Agent")); From cf85e6ab28161ee68d0ded1075cab3bf75ad52db Mon Sep 17 00:00:00 2001 From: Chris H-C Date: Wed, 28 Feb 2024 13:37:10 -0500 Subject: [PATCH 29/34] Change PingUploader::upload to past a struct not a bunch of args And update some tests to check it out. --- CHANGELOG.md | 1 + glean-core/rlb/examples/long-running.rs | 7 +- glean-core/rlb/src/net/http_uploader.rs | 11 +- glean-core/rlb/src/net/mod.rs | 25 ++- glean-core/rlb/src/test.rs | 201 ++++++++++-------------- glean-core/rlb/tests/schema.rs | 11 +- glean-core/rlb/tests/upload_timing.rs | 8 +- samples/rust/src/main.rs | 10 +- 8 files changed, 118 insertions(+), 156 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d4d5c5ed7..dff639de90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Update `glean_parser` to v13.0.0 ([release notes](https://github.com/mozilla/glean_parser/releases/tag/v13.0.0)) * Rust * New metric type: Object ([#2489](https://github.com/mozilla/glean/pull/2489)) + * BREAKING CHANGE: Support pings without `{client|ping}_info` sections ([#2756](https://github.com/mozilla/glean/pull/2756)) * Android * Upgrade Android NDK to r26c ([#2745](https://github.com/mozilla/glean/pull/2745)) diff --git a/glean-core/rlb/examples/long-running.rs b/glean-core/rlb/examples/long-running.rs index 6ae8c8036b..a1c9836530 100644 --- a/glean-core/rlb/examples/long-running.rs +++ b/glean-core/rlb/examples/long-running.rs @@ -33,12 +33,7 @@ pub mod glean_metrics { struct FakeUploader; impl net::PingUploader for FakeUploader { - fn upload( - &self, - _url: String, - _body: Vec, - _headers: Vec<(String, String)>, - ) -> net::UploadResult { + fn upload(&self, _upload_request: net::PingUploadRequest) -> net::UploadResult { thread::sleep(time::Duration::from_millis(100)); net::UploadResult::http_status(200) } diff --git a/glean-core/rlb/src/net/http_uploader.rs b/glean-core/rlb/src/net/http_uploader.rs index 4646fe61b4..4ca1687acf 100644 --- a/glean-core/rlb/src/net/http_uploader.rs +++ b/glean-core/rlb/src/net/http_uploader.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use crate::net::{PingUploader, UploadResult}; +use crate::net::{PingUploadRequest, PingUploader, UploadResult}; /// A simple mechanism to upload pings over HTTPS. #[derive(Debug)] @@ -13,12 +13,9 @@ impl PingUploader for HttpUploader { /// /// # Arguments /// - /// * `url` - the URL path to upload the data to. - /// * `body` - the serialized text data to send. - /// * `headers` - a vector of tuples containing the headers to send with - /// the request, i.e. (Name, Value). - fn upload(&self, url: String, _body: Vec, _headers: Vec<(String, String)>) -> UploadResult { - log::debug!("TODO bug 1675468: submitting to {:?}", url); + /// * `upload_request` - the requested upload. + fn upload(&self, upload_request: PingUploadRequest) -> UploadResult { + log::debug!("TODO bug 1675468: submitting to {:?}", upload_request.url); UploadResult::http_status(200) } } diff --git a/glean-core/rlb/src/net/mod.rs b/glean-core/rlb/src/net/mod.rs index 5571d30e67..5546078e63 100644 --- a/glean-core/rlb/src/net/mod.rs +++ b/glean-core/rlb/src/net/mod.rs @@ -19,6 +19,20 @@ use thread_state::{AtomicState, State}; mod http_uploader; +/// Everything you need to request a ping to be uploaded. +pub struct PingUploadRequest { + /// The URL the Glean SDK expects you to use to upload the ping. + pub url: String, + /// The body, already content-encoded, for upload. + pub body: Vec, + /// The HTTP headers, including any Content-Encoding. + pub headers: Vec<(String, String)>, + /// Whether the body has {client|ping}_info sections in it. + pub body_has_info_sections: bool, + /// The name (aka doctype) of the ping. + pub ping_name: String, +} + /// A description of a component used to upload pings. pub trait PingUploader: std::fmt::Debug + Send + Sync { /// Uploads a ping to a server. @@ -29,7 +43,7 @@ pub trait PingUploader: std::fmt::Debug + Send + Sync { /// * `body` - the serialized text data to send. /// * `headers` - a vector of tuples containing the headers to send with /// the request, i.e. (Name, Value). - fn upload(&self, url: String, body: Vec, headers: Vec<(String, String)>) -> UploadResult; + fn upload(&self, upload_request: PingUploadRequest) -> UploadResult; } /// The logic for uploading pings: this leaves the actual upload mechanism as @@ -105,7 +119,14 @@ impl UploadManager { let upload_url = format!("{}{}", inner.server_endpoint, request.path); let headers: Vec<(String, String)> = request.headers.into_iter().collect(); - let result = inner.uploader.upload(upload_url, request.body, headers); + let upload_request = PingUploadRequest { + url: upload_url, + body: request.body, + headers, + body_has_info_sections: request.body_has_info_sections, + ping_name: request.ping_name, + }; + let result = inner.uploader.upload(upload_request); // Process the upload response. match glean_core::glean_process_ping_upload_response(doc_id, result) { UploadTaskAction::Next => (), diff --git a/glean-core/rlb/src/test.rs b/glean-core/rlb/src/test.rs index 7e6e7996a7..16d6d05447 100644 --- a/glean-core/rlb/src/test.rs +++ b/glean-core/rlb/src/test.rs @@ -22,22 +22,16 @@ use crate::common_test::{lock_test, new_glean, GLOBAL_APPLICATION_ID}; fn send_a_ping() { let _lock = lock_test(); - let (s, r) = crossbeam_channel::bounded::(1); + let (s, r) = crossbeam_channel::bounded::(1); - // Define a fake uploader that reports back the submission URL - // using a crossbeam channel. + // Define a fake uploader that reports back the ping upload request. #[derive(Debug)] pub struct FakeUploader { - sender: crossbeam_channel::Sender, + sender: crossbeam_channel::Sender, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - url: String, - _body: Vec, - _headers: Vec<(String, String)>, - ) -> net::UploadResult { - self.sender.send(url).unwrap(); + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + self.sender.send(upload_request).unwrap(); net::UploadResult::http_status(200) } } @@ -59,8 +53,50 @@ fn send_a_ping() { custom_ping.submit(None); // Wait for the ping to arrive. - let url = r.recv().unwrap(); - assert!(url.contains(PING_NAME)); + let upload_request = r.recv().unwrap(); + assert!(upload_request.body_has_info_sections); + assert_eq!(upload_request.ping_name, PING_NAME); + assert!(upload_request.url.contains(PING_NAME)); +} + +#[test] +fn send_a_ping_without_info_sections() { + let _lock = lock_test(); + + let (s, r) = crossbeam_channel::bounded::(1); + + // Define a fake uploader that reports back the ping upload request. + #[derive(Debug)] + pub struct FakeUploader { + sender: crossbeam_channel::Sender, + } + impl net::PingUploader for FakeUploader { + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + self.sender.send(upload_request).unwrap(); + net::UploadResult::http_status(200) + } + } + + // Create a custom configuration to use a fake uploader. + let dir = tempfile::tempdir().unwrap(); + let tmpname = dir.path().to_path_buf(); + + let cfg = ConfigurationBuilder::new(true, tmpname, GLOBAL_APPLICATION_ID) + .with_server_endpoint("invalid-test-host") + .with_uploader(FakeUploader { sender: s }) + .build(); + + let _t = new_glean(Some(cfg), true); + + // Define a new ping and submit it. + const PING_NAME: &str = "noinfo-ping"; + let custom_ping = private::PingType::new(PING_NAME, true, true, true, false, vec![]); + custom_ping.submit(None); + + // Wait for the ping to arrive. + let upload_request = r.recv().unwrap(); + assert!(!upload_request.body_has_info_sections); + assert_eq!(upload_request.ping_name, PING_NAME); } #[test] @@ -190,13 +226,8 @@ fn sending_of_foreground_background_pings() { sender: crossbeam_channel::Sender, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - url: String, - _body: Vec, - _headers: Vec<(String, String)>, - ) -> net::UploadResult { - self.sender.send(url).unwrap(); + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + self.sender.send(upload_request.url).unwrap(); net::UploadResult::http_status(200) } } @@ -263,13 +294,8 @@ fn sending_of_startup_baseline_ping() { sender: crossbeam_channel::Sender, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - url: String, - _body: Vec, - _headers: Vec<(String, String)>, - ) -> net::UploadResult { - self.sender.send(url).unwrap(); + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + self.sender.send(upload_request.url).unwrap(); net::UploadResult::http_status(200) } } @@ -315,13 +341,8 @@ fn no_dirty_baseline_on_clean_shutdowns() { sender: crossbeam_channel::Sender, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - url: String, - _body: Vec, - _headers: Vec<(String, String)>, - ) -> net::UploadResult { - self.sender.send(url).unwrap(); + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + self.sender.send(upload_request.url).unwrap(); net::UploadResult::http_status(200) } } @@ -543,12 +564,8 @@ fn ping_collection_must_happen_after_concurrently_scheduled_metrics_recordings() sender: crossbeam_channel::Sender<(String, JsonValue)>, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - url: String, - body: Vec, - _headers: Vec<(String, String)>, - ) -> net::UploadResult { + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + let net::PingUploadRequest { body, url, .. } = upload_request; // Decode the gzipped body. let mut gzip_decoder = GzDecoder::new(&body[..]); let mut s = String::with_capacity(body.len()); @@ -681,13 +698,8 @@ fn sending_deletion_ping_if_disabled_outside_of_run() { sender: crossbeam_channel::Sender, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - url: String, - _body: Vec, - _headers: Vec<(String, String)>, - ) -> net::UploadResult { - self.sender.send(url).unwrap(); + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + self.sender.send(upload_request.url).unwrap(); net::UploadResult::http_status(200) } } @@ -731,13 +743,8 @@ fn no_sending_of_deletion_ping_if_unchanged_outside_of_run() { sender: crossbeam_channel::Sender, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - url: String, - _body: Vec, - _headers: Vec<(String, String)>, - ) -> net::UploadResult { - self.sender.send(url).unwrap(); + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + self.sender.send(upload_request.url).unwrap(); net::UploadResult::http_status(200) } } @@ -779,12 +786,8 @@ fn deletion_request_ping_contains_experimentation_id() { sender: crossbeam_channel::Sender, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - _url: String, - body: Vec, - _headers: Vec<(String, String)>, - ) -> net::UploadResult { + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + let body = upload_request.body; let mut gzip_decoder = GzDecoder::new(&body[..]); let mut body_str = String::with_capacity(body.len()); let data: JsonValue = gzip_decoder @@ -847,12 +850,8 @@ fn test_sending_of_startup_baseline_ping_with_application_lifetime_metric() { sender: crossbeam_channel::Sender<(String, JsonValue)>, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - url: String, - body: Vec, - _headers: Vec<(String, String)>, - ) -> net::UploadResult { + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + let net::PingUploadRequest { url, body, .. } = upload_request; // Decode the gzipped body. let mut gzip_decoder = GzDecoder::new(&body[..]); let mut s = String::with_capacity(body.len()); @@ -932,13 +931,8 @@ fn setting_debug_view_tag_before_initialization_should_not_crash() { sender: crossbeam_channel::Sender>, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - _url: String, - _body: Vec, - headers: Vec<(String, String)>, - ) -> net::UploadResult { - self.sender.send(headers).unwrap(); + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + self.sender.send(upload_request.headers).unwrap(); net::UploadResult::http_status(200) } } @@ -983,13 +977,8 @@ fn setting_source_tags_before_initialization_should_not_crash() { sender: crossbeam_channel::Sender>, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - _url: String, - _body: Vec, - headers: Vec<(String, String)>, - ) -> net::UploadResult { - self.sender.send(headers).unwrap(); + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + self.sender.send(upload_request.headers).unwrap(); net::UploadResult::http_status(200) } } @@ -1033,13 +1022,8 @@ fn setting_source_tags_after_initialization_should_not_crash() { sender: crossbeam_channel::Sender>, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - _url: String, - _body: Vec, - headers: Vec<(String, String)>, - ) -> net::UploadResult { - self.sender.send(headers).unwrap(); + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + self.sender.send(upload_request.headers).unwrap(); net::UploadResult::http_status(200) } } @@ -1097,13 +1081,8 @@ fn flipping_upload_enabled_respects_order_of_events() { sender: crossbeam_channel::Sender, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - url: String, - _body: Vec, - _headers: Vec<(String, String)>, - ) -> net::UploadResult { - self.sender.send(url).unwrap(); + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + self.sender.send(upload_request.url).unwrap(); net::UploadResult::http_status(200) } } @@ -1155,13 +1134,8 @@ fn registering_pings_before_init_must_work() { sender: crossbeam_channel::Sender, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - url: String, - _body: Vec, - _headers: Vec<(String, String)>, - ) -> net::UploadResult { - self.sender.send(url).unwrap(); + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + self.sender.send(upload_request.url).unwrap(); net::UploadResult::http_status(200) } } @@ -1201,13 +1175,8 @@ fn test_a_ping_before_submission() { sender: crossbeam_channel::Sender, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - url: String, - _body: Vec, - _headers: Vec<(String, String)>, - ) -> net::UploadResult { - self.sender.send(url).unwrap(); + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + self.sender.send(upload_request.url).unwrap(); net::UploadResult::http_status(200) } } @@ -1308,12 +1277,7 @@ fn signaling_done() { counter: Arc>>, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - _url: String, - _body: Vec, - _headers: Vec<(String, String)>, - ) -> net::UploadResult { + fn upload(&self, _upload_request: net::PingUploadRequest) -> net::UploadResult { let mut map = self.counter.lock().unwrap(); *map.entry(thread::current().id()).or_insert(0) += 1; @@ -1385,17 +1349,12 @@ fn configure_ping_throttling() { done: Arc, } impl net::PingUploader for FakeUploader { - fn upload( - &self, - url: String, - _body: Vec, - _headers: Vec<(String, String)>, - ) -> net::UploadResult { + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { if self.done.load(std::sync::atomic::Ordering::SeqCst) { // If we've outlived the test, just lie. return net::UploadResult::http_status(200); } - self.sender.send(url).unwrap(); + self.sender.send(upload_request.url).unwrap(); net::UploadResult::http_status(200) } } diff --git a/glean-core/rlb/tests/schema.rs b/glean-core/rlb/tests/schema.rs index d31ff6b567..01a2108b3c 100644 --- a/glean-core/rlb/tests/schema.rs +++ b/glean-core/rlb/tests/schema.rs @@ -10,7 +10,7 @@ use glean_core::TextMetric; use jsonschema_valid::{self, schemas::Draft}; use serde_json::Value; -use glean::net::UploadResult; +use glean::net::{PingUploadRequest, UploadResult}; use glean::private::*; use glean::{ traits, ClientInfoMetrics, CommonMetricData, ConfigurationBuilder, HistogramType, MemoryUnit, @@ -60,13 +60,8 @@ fn validate_against_schema() { sender: crossbeam_channel::Sender>, } impl glean::net::PingUploader for ValidatingUploader { - fn upload( - &self, - _url: String, - body: Vec, - _headers: Vec<(String, String)>, - ) -> UploadResult { - self.sender.send(body).unwrap(); + fn upload(&self, ping_request: PingUploadRequest) -> UploadResult { + self.sender.send(ping_request.body).unwrap(); UploadResult::http_status(200) } } diff --git a/glean-core/rlb/tests/upload_timing.rs b/glean-core/rlb/tests/upload_timing.rs index cca5da02a1..ba0eee3402 100644 --- a/glean-core/rlb/tests/upload_timing.rs +++ b/glean-core/rlb/tests/upload_timing.rs @@ -108,13 +108,9 @@ struct FakeUploader { } impl net::PingUploader for FakeUploader { - fn upload( - &self, - _url: String, - body: Vec, - _headers: Vec<(String, String)>, - ) -> net::UploadResult { + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { let calls = self.calls.fetch_add(1, Ordering::SeqCst); + let body = upload_request.body; let decode = |body: Vec| { let mut gzip_decoder = GzDecoder::new(&body[..]); let mut s = String::with_capacity(body.len()); diff --git a/samples/rust/src/main.rs b/samples/rust/src/main.rs index 5f4e3ee982..a221cb31a9 100644 --- a/samples/rust/src/main.rs +++ b/samples/rust/src/main.rs @@ -22,12 +22,10 @@ pub mod glean_metrics { struct MovingUploader(String); impl net::PingUploader for MovingUploader { - fn upload( - &self, - url: String, - body: Vec, - headers: Vec<(String, String)>, - ) -> net::UploadResult { + fn upload(&self, upload_request: net::PingUploadRequest) -> net::UploadResult { + let net::PingUploadRequest { + body, url, headers, .. + } = upload_request; let mut gzip_decoder = GzDecoder::new(&body[..]); let mut s = String::with_capacity(body.len()); From 825e38faa99b6356c0c52a0c3119ec2d533a5fb6 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Wed, 28 Feb 2024 12:19:51 -0500 Subject: [PATCH 30/34] Update AndroidX WorkManager to version 2.9.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 93d0624729..24e071141f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,7 +19,7 @@ androidx-annotation = "1.7.1" androidx-appcompat = "1.6.1" androidx-browser = "1.7.0" androidx-lifecycle = "2.6.2" -androidx-work = "2.7.1" +androidx-work = "2.9.0" # JNA jna = "5.14.0" From fabcb2b4aebf53acaa1090d9b7146e3d11fd2401 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Wed, 28 Feb 2024 12:20:24 -0500 Subject: [PATCH 31/34] Update AndroidX Lifecycle to version 2.7.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 24e071141f..68ef3c7a7c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ rust-android-gradle = "0.9.3" androidx-annotation = "1.7.1" androidx-appcompat = "1.6.1" androidx-browser = "1.7.0" -androidx-lifecycle = "2.6.2" +androidx-lifecycle = "2.7.0" androidx-work = "2.9.0" # JNA From 979da4c50154efdb6597325c44ddc56bcd2e676e Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Wed, 28 Feb 2024 12:21:24 -0500 Subject: [PATCH 32/34] Update AndroidX Test Uiautomator to version 2.3.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 68ef3c7a7c..beb75f0f8f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -33,7 +33,7 @@ androidx-test-espresso = "3.5.1" androidx-test-core = "1.5.0" androidx-test-junit = "1.1.5" androidx-test-runner = "1.5.2" -androidx-test-uiautomator = "2.2.0" +androidx-test-uiautomator = "2.3.0" # Third Party Testing junit = "4.13.2" From 4999a2d7c79f533976a5a65d554466813930cd3c Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Tue, 27 Feb 2024 16:14:21 +0100 Subject: [PATCH 33/34] Rust: Rename API to to reflect that it takes in a string, not a reference This also removes the API from glean-core because it's not needed there. --- glean-core/rlb/src/private/object.rs | 24 +++++++++++++++++++++++- glean-core/src/metrics/object.rs | 21 --------------------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/glean-core/rlb/src/private/object.rs b/glean-core/rlb/src/private/object.rs index 7e2e8fb48f..f7403ec889 100644 --- a/glean-core/rlb/src/private/object.rs +++ b/glean-core/rlb/src/private/object.rs @@ -55,7 +55,7 @@ impl ObjectMetric { /// # Arguments /// /// * `object` - JSON representation of the object to set. - pub fn set_str(&self, object: String) { + pub fn set_string(&self, object: String) { let data = match K::from_str(&object) { Ok(data) => data, Err(_) => { @@ -167,4 +167,26 @@ mod test { ]); assert_eq!(expected, data); } + + #[test] + fn set_string_api() { + let _lock = lock_test(); + let _t = new_glean(None, true); + + type SimpleArray = Vec; + + let metric: ObjectMetric = ObjectMetric::new(CommonMetricData { + name: "object".into(), + category: "test".into(), + send_in_pings: vec!["test1".into()], + ..Default::default() + }); + + let arr_str = String::from("[1, 2, 3]"); + metric.set_string(arr_str); + + let data = metric.test_get_value(None).expect("no object recorded"); + let expected = json!([1, 2, 3]); + assert_eq!(expected, data); + } } diff --git a/glean-core/src/metrics/object.rs b/glean-core/src/metrics/object.rs index f00f11922a..6071e2b33a 100644 --- a/glean-core/src/metrics/object.rs +++ b/glean-core/src/metrics/object.rs @@ -78,27 +78,6 @@ impl ObjectMetric { }); } - /// Sets to the specified structure from a string in JSON encoding - /// - /// # Arguments - /// - /// * `glean` - the Glean instance this metric belongs to. - /// * `value` - the value to set. - pub fn set_str(&self, value: String) { - let metric = self.clone(); - crate::launch_with_glean(move |glean| { - let value = match serde_json::from_str(&value) { - Ok(s) => s, - Err(_) => { - let msg = "Cannot set invalid json"; - record_error(glean, &metric.meta, ErrorType::InvalidValue, msg, None); - return; - } - }; - metric.set_sync(glean, value) - }) - } - /// Get current value #[doc(hidden)] pub fn get_value<'a, S: Into>>( From c5f0aa7782264c4a306042526619821f665d399b Mon Sep 17 00:00:00 2001 From: Chris H-C Date: Thu, 29 Feb 2024 09:52:54 -0500 Subject: [PATCH 34/34] Bumped version to 58.0.0 --- .buildconfig.yml | 2 +- CHANGELOG.md | 6 +- Cargo.lock | 4 +- DEPENDENCIES.md | 620 +++++++++++++++--- glean-core/Cargo.toml | 2 +- .../android-native/dependency-licenses.xml | 30 +- glean-core/android/dependency-licenses.xml | 30 +- glean-core/rlb/Cargo.toml | 4 +- .../GleanGradlePlugin.groovy | 2 +- pyproject.toml | 2 +- 10 files changed, 567 insertions(+), 135 deletions(-) diff --git a/.buildconfig.yml b/.buildconfig.yml index 0ec255690b..3ca25555d3 100644 --- a/.buildconfig.yml +++ b/.buildconfig.yml @@ -1,4 +1,4 @@ -libraryVersion: 57.0.0 +libraryVersion: 58.0.0 groupId: org.mozilla.telemetry projects: glean: diff --git a/CHANGELOG.md b/CHANGELOG.md index dff639de90..6a2d4277ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Unreleased changes -[Full changelog](https://github.com/mozilla/glean/compare/v57.0.0...main) +[Full changelog](https://github.com/mozilla/glean/compare/v58.0.0...main) + +# v58.0.0 (2024-02-29) + +[Full changelog](https://github.com/mozilla/glean/compare/v57.0.0...v58.0.0) * General * Update `glean_parser` to v13.0.0 ([release notes](https://github.com/mozilla/glean_parser/releases/tag/v13.0.0)) diff --git a/Cargo.lock b/Cargo.lock index 94280323cb..c9960fe047 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -327,7 +327,7 @@ dependencies = [ [[package]] name = "glean" -version = "57.0.0" +version = "58.0.0" dependencies = [ "crossbeam-channel", "env_logger", @@ -367,7 +367,7 @@ dependencies = [ [[package]] name = "glean-core" -version = "57.0.0" +version = "58.0.0" dependencies = [ "android_logger", "bincode", diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index 64e9ce5ff8..f1f5e6e177 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -1688,6 +1688,206 @@ The following text applies to code linked from these dependencies: The following text applies to code linked from these dependencies: +* [fd-lock 3.0.13]( https://github.com/yoshuawuyts/fd-lock ) + +``` + 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 + + Copyright 2019 Yoshua Wuyts + + 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. + +``` +## Apache License 2.0 + + +The following text applies to code linked from these dependencies: + * [anyhow 1.0.71]( https://github.com/dtolnay/anyhow ) * [basic-toml 0.1.2]( https://github.com/dtolnay/basic-toml ) * [inherent 1.0.9]( https://github.com/dtolnay/inherent ) @@ -2105,7 +2305,6 @@ The following text applies to code linked from these dependencies: * [crossbeam-channel 0.5.11]( https://github.com/crossbeam-rs/crossbeam ) * [crossbeam-utils 0.8.19]( https://github.com/crossbeam-rs/crossbeam ) * [env_logger 0.10.0]( https://github.com/rust-cli/env_logger/ ) -* [errno 0.3.3]( https://github.com/lambda-fairy/rust-errno ) * [fastrand 2.0.0]( https://github.com/smol-rs/fastrand ) * [flate2 1.0.26]( https://github.com/rust-lang/flate2-rs ) * [form_urlencoded 1.1.0]( https://github.com/servo/rust-url ) @@ -4564,7 +4763,7 @@ THE SOFTWARE. The following text applies to code linked from these dependencies: -* [xshell-venv 1.1.0]( https://github.com/badboy/xshell-venv ) +* [xshell-venv 1.2.0]( https://github.com/badboy/xshell-venv ) ``` The MIT License (MIT) @@ -4688,164 +4887,385 @@ SOFTWARE. The following text applies to code linked from these dependencies: -* [embedded-uniffi-bindgen 0.1.0]( https://crates.io/crates/embedded-uniffi-bindgen ) -* [glean-bundle 1.0.0]( https://github.com/mozilla/glean ) -* [glean-bundle-android 1.0.0]( https://github.com/mozilla/glean ) -* [uniffi 0.25.3]( https://github.com/mozilla/uniffi-rs ) -* [uniffi_bindgen 0.25.3]( https://github.com/mozilla/uniffi-rs ) -* [uniffi_build 0.25.3]( https://github.com/mozilla/uniffi-rs ) -* [uniffi_checksum_derive 0.25.3]( https://github.com/mozilla/uniffi-rs ) -* [uniffi_core 0.25.3]( https://github.com/mozilla/uniffi-rs ) -* [uniffi_macros 0.25.3]( https://github.com/mozilla/uniffi-rs ) -* [uniffi_meta 0.25.3]( https://github.com/mozilla/uniffi-rs ) -* [uniffi_testing 0.25.3]( https://github.com/mozilla/uniffi-rs ) -* [uniffi_udl 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [glean 58.0.0]( https://github.com/mozilla/glean ) +* [glean-build 13.0.0]( https://github.com/mozilla/glean ) +* [glean-core 58.0.0]( https://github.com/mozilla/glean ) +* [zeitstempel 0.1.1]( https://github.com/badboy/zeitstempel ) ``` Mozilla Public License Version 2.0 +================================== 1. Definitions +-------------- - 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. - - 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. - - 1.3. "Contribution" means Covered Software of a particular Contributor. - - 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. - - 1.5. "Incompatible With Secondary Licenses" means +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. - (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. - (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. +1.3. "Contribution" + means Covered Software of a particular Contributor. - 1.6. "Executable Form" means any form of the work other than Source Code Form. +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. - 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. +1.5. "Incompatible With Secondary Licenses" + means - 1.8. "License" means this document. + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or - 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. - 1.10. "Modifications" means any of the following: +1.6. "Executable Form" + means any form of the work other than Source Code Form. - (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. - (b) any new file in Source Code Form that contains any Covered Software. +1.8. "License" + means this document. - 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. - 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. +1.10. "Modifications" + means any of the following: - 1.13. "Source Code Form" means the form of the work preferred for making modifications. + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or - 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. + (b) any new file in Source Code Form that contains any Covered + Software. -2. License Grants and Conditions +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and - 2.1. Grants - Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. - (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and +2.2. Effective Date - (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. - 2.2. Effective Date - The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. +2.3. Limitations on Grant Scope - 2.3. Limitations on Grant Scope - The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: - (a) for any code that a Contributor has removed from Covered Software; or +(a) for any code that a Contributor has removed from Covered Software; + or - (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). - (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. +2.5. Representation - This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. - 2.4. Subsequent Licenses - No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). +2.6. Fair Use - 2.5. Representation - Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. - 2.6. Fair Use - This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. +2.7. Conditions - 2.7. Conditions - Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. 3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and - 3.1. Distribution of Source Form - All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. - 3.2. Distribution of Executable Form - If You distribute Covered Software in Executable Form then: +3.3. Distribution of a Larger Work - (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). - (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. +3.4. Notices - 3.3. Distribution of a Larger Work - You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. - 3.4. Notices - You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. +3.5. Application of Additional Terms - 3.5. Application of Additional Terms - You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. 4. Inability to Comply Due to Statute or Regulation -If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. 5. Termination +-------------- - 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. - 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. - 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. -6. Disclaimer of Warranty -Covered Software is provided under this License on an "as is" basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ -7. Limitation of Liability -Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ 8. Litigation -Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. 9. Miscellaneous -This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. 10. Versions of the License +--------------------------- + +10.1. New Versions - 10.1. New Versions - Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions - 10.2. Effect of New Versions - You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). - 10.3. Modified Versions - If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses - 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses - If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice +------------------------------------------- - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. -If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- - This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. ``` ## Mozilla Public License 2.0 @@ -4853,10 +5273,18 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice The following text applies to code linked from these dependencies: -* [glean 57.0.0]( https://github.com/mozilla/glean ) -* [glean-build 11.0.1]( https://github.com/mozilla/glean ) -* [glean-core 57.0.0]( https://github.com/mozilla/glean ) -* [zeitstempel 0.1.1]( https://github.com/badboy/zeitstempel ) +* [embedded-uniffi-bindgen 0.1.0]( https://crates.io/crates/embedded-uniffi-bindgen ) +* [glean-bundle 1.0.0]( https://github.com/mozilla/glean ) +* [glean-bundle-android 1.0.0]( https://github.com/mozilla/glean ) +* [uniffi 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [uniffi_bindgen 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [uniffi_build 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [uniffi_checksum_derive 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [uniffi_core 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [uniffi_macros 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [uniffi_meta 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [uniffi_testing 0.25.3]( https://github.com/mozilla/uniffi-rs ) +* [uniffi_udl 0.25.3]( https://github.com/mozilla/uniffi-rs ) ``` Mozilla Public License Version 2.0 @@ -4896,7 +5324,7 @@ Mozilla Public License Version 2.0 means any form of the work other than Source Code Form. 1.7. "Larger Work" - means a work that combines Covered Software with other material, in + means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" @@ -5218,7 +5646,7 @@ Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. + file, You can obtain one at https://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE diff --git a/glean-core/Cargo.toml b/glean-core/Cargo.toml index b4c1058a40..cdc2808ebb 100644 --- a/glean-core/Cargo.toml +++ b/glean-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "glean-core" -version = "57.0.0" +version = "58.0.0" authors = ["Jan-Erik Rediger ", "The Glean Team "] description = "A modern Telemetry library" repository = "https://github.com/mozilla/glean" diff --git a/glean-core/android-native/dependency-licenses.xml b/glean-core/android-native/dependency-licenses.xml index 25a22bdba5..25741454db 100644 --- a/glean-core/android-native/dependency-licenses.xml +++ b/glean-core/android-native/dependency-licenses.xml @@ -39,6 +39,9 @@ the details of which are reproduced below.
Apache License 2.0: humantime https://github.com/tailhook/humantime + + Apache License 2.0: fd-lock + https://github.com/yoshuawuyts/fd-lock Apache License 2.0: anyhow https://github.com/dtolnay/anyhow @@ -105,9 +108,6 @@ the details of which are reproduced below. Apache License 2.0: env_logger https://github.com/rust-cli/env_logger/ - - Apache License 2.0: errno - https://github.com/lambda-fairy/rust-errno Apache License 2.0: fastrand https://github.com/smol-rs/fastrand @@ -297,6 +297,18 @@ the details of which are reproduced below. MIT License: bincode https://github.com/servo/bincode + + Mozilla Public License 2.0: glean + https://github.com/mozilla/glean + + Mozilla Public License 2.0: glean-build + https://github.com/mozilla/glean + + Mozilla Public License 2.0: glean-core + https://github.com/mozilla/glean + + Mozilla Public License 2.0: zeitstempel + https://github.com/badboy/zeitstempel Mozilla Public License 2.0: embedded-uniffi-bindgen https://crates.io/crates/embedded-uniffi-bindgen @@ -333,18 +345,6 @@ the details of which are reproduced below. Mozilla Public License 2.0: uniffi_udl https://github.com/mozilla/uniffi-rs - - Mozilla Public License 2.0: glean - https://github.com/mozilla/glean - - Mozilla Public License 2.0: glean-build - https://github.com/mozilla/glean - - Mozilla Public License 2.0: glean-core - https://github.com/mozilla/glean - - Mozilla Public License 2.0: zeitstempel - https://github.com/badboy/zeitstempel Unicode License Agreement - Data Files and Software (2016): unicode-ident https://github.com/dtolnay/unicode-ident diff --git a/glean-core/android/dependency-licenses.xml b/glean-core/android/dependency-licenses.xml index 25a22bdba5..25741454db 100644 --- a/glean-core/android/dependency-licenses.xml +++ b/glean-core/android/dependency-licenses.xml @@ -39,6 +39,9 @@ the details of which are reproduced below. Apache License 2.0: humantime https://github.com/tailhook/humantime + + Apache License 2.0: fd-lock + https://github.com/yoshuawuyts/fd-lock Apache License 2.0: anyhow https://github.com/dtolnay/anyhow @@ -105,9 +108,6 @@ the details of which are reproduced below. Apache License 2.0: env_logger https://github.com/rust-cli/env_logger/ - - Apache License 2.0: errno - https://github.com/lambda-fairy/rust-errno Apache License 2.0: fastrand https://github.com/smol-rs/fastrand @@ -297,6 +297,18 @@ the details of which are reproduced below. MIT License: bincode https://github.com/servo/bincode + + Mozilla Public License 2.0: glean + https://github.com/mozilla/glean + + Mozilla Public License 2.0: glean-build + https://github.com/mozilla/glean + + Mozilla Public License 2.0: glean-core + https://github.com/mozilla/glean + + Mozilla Public License 2.0: zeitstempel + https://github.com/badboy/zeitstempel Mozilla Public License 2.0: embedded-uniffi-bindgen https://crates.io/crates/embedded-uniffi-bindgen @@ -333,18 +345,6 @@ the details of which are reproduced below. Mozilla Public License 2.0: uniffi_udl https://github.com/mozilla/uniffi-rs - - Mozilla Public License 2.0: glean - https://github.com/mozilla/glean - - Mozilla Public License 2.0: glean-build - https://github.com/mozilla/glean - - Mozilla Public License 2.0: glean-core - https://github.com/mozilla/glean - - Mozilla Public License 2.0: zeitstempel - https://github.com/badboy/zeitstempel Unicode License Agreement - Data Files and Software (2016): unicode-ident https://github.com/dtolnay/unicode-ident diff --git a/glean-core/rlb/Cargo.toml b/glean-core/rlb/Cargo.toml index 930c0a2344..d4b2c36e69 100644 --- a/glean-core/rlb/Cargo.toml +++ b/glean-core/rlb/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "glean" -version = "57.0.0" +version = "58.0.0" authors = ["Jan-Erik Rediger ", "The Glean Team "] description = "Glean SDK Rust language bindings" repository = "https://github.com/mozilla/glean" @@ -23,7 +23,7 @@ maintenance = { status = "actively-developed" } [dependencies.glean-core] path = ".." -version = "57.0.0" +version = "58.0.0" [dependencies] inherent = "1" diff --git a/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy b/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy index 167d306b92..49d4ddac7f 100644 --- a/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy +++ b/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy @@ -552,7 +552,7 @@ except: void apply(Project project) { isOffline = project.gradle.startParameter.offline - project.ext.glean_version = "57.0.0" + project.ext.glean_version = "58.0.0" def parserVersion = gleanParserVersion(project) // Print the required glean_parser version to the console. This is diff --git a/pyproject.toml b/pyproject.toml index fe493176ba..66d3d18cad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "glean-sdk" -version = "57.0.0" +version = "58.0.0" requires-python = ">=3.8" classifiers = [ "Intended Audience :: Developers",