diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /toolkit/components/glean/docs | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/glean/docs')
22 files changed, 3208 insertions, 0 deletions
diff --git a/toolkit/components/glean/docs/dev/builtin_pings.md b/toolkit/components/glean/docs/dev/builtin_pings.md new file mode 100644 index 0000000000..cbfff8c559 --- /dev/null +++ b/toolkit/components/glean/docs/dev/builtin_pings.md @@ -0,0 +1,13 @@ +# Built-in Pings + +FOG embeds the Glean SDK so +[its documentation on pings is authoritative](https://mozilla.github.io/glean/book/user/pings/index.html). +The only detail FOG adds is to clarify +[the "baseline" ping's schedule](https://mozilla.github.io/glean/book/user/pings/baseline.html#scheduling). +Specifically, in Firefox Desktop, the application is considered +* "active" when started, + or when a user interacts with Firefox after a 20min period of inactivity, +* "inactive" after the user stops interacting with Firefox after 2min of activity. + +For more details about why, see the bug tree around +[bug 1635242](https://bugzilla.mozilla.org/show_bug.cgi?id=1635242). diff --git a/toolkit/components/glean/docs/dev/code_organization.md b/toolkit/components/glean/docs/dev/code_organization.md new file mode 100644 index 0000000000..e943dbfd50 --- /dev/null +++ b/toolkit/components/glean/docs/dev/code_organization.md @@ -0,0 +1,56 @@ +# FOG code organization + +![Modules of Project FOG](images/fog-modules.svg) + +The diagram shows the different modules of Project FOG. + +## FOG control + +This module is the glue between Firefox and Glean. + +* The code lives in `toolkit/components/glean/src`. +* It is written in Rust. +* The crate is named `fog_control`. +* It is not published to crates.io. +* It is not consumed by other Rust crates inside mozilla-central. + +This module is responsible for + +* collecting and assembling the [client information](https://mozilla.github.io/glean/book/user/pings/index.html#the-client_info-section) +* configuring the Glean SDK via the Rust Language Binding +* watching the Firefox Telemetry data upload preference (`datareporting.healthreport.uploadEnabled`) +* scheduling builtin pings +* controling ping upload workers +* passing IPC buffers + +It calls into `glean` (the Glean SDK Rust Language Binding) to: + +* configure and initialize Glean +* toggle `upload_enabled` +* get upload tasks + +It calls into `fog` to: + +* pass IPC buffers +* record to its own metrics + +## FOG API + +This module provides the user-facing API for Glean inside mozilla-central. + +* The code lives in `toolkit/components/glean/api`. +* It is written in Rust. +* The crate is named `fog`. +* It is not published to crates.io. +* It can be consumed by other Rust crates inside mozilla-central for their Glean usage. + +This module is responsible for + +* exposing a specific metric API in Rust +* wrapping metric implementations for handling IPC +* exposing FFI functionality to implement other language APIs on top. + See also [Adding a New Metric Type](new_metric_types.md). + +It calls into `glean` (the Glean SDK Rust Language Binding) for: + +* metric types (including pings) diff --git a/toolkit/components/glean/docs/dev/images/fog-modules.svg b/toolkit/components/glean/docs/dev/images/fog-modules.svg new file mode 100644 index 0000000000..c0271e9f6e --- /dev/null +++ b/toolkit/components/glean/docs/dev/images/fog-modules.svg @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- 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/. --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" version="1.1" width="601px" height="511px" viewBox="-0.5 -0.5 601 511" content="<mxfile host="app.diagrams.net" modified="2020-03-27T09:36:49.445Z" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:76.0) Gecko/20100101 Firefox/76.0" etag="_te5ruI7nKv5hlBG0WM7" version="12.9.3" type="device"><diagram id="02tFoor6QwIjLFNeosYU" name="Page-1">7Vtbd6M2EP41fkyPQYDxo+NcmnbbpOvu2eZRBtmmxYgVsmP311eAZC6SDU4AX5ok5wSNLsA334xGI9ED4+XmkcBw8Rt2kd/T++6mB+56uq4NLYP9iyVbLtHsYSqZE8/lskww8f5FXNjn0pXnoqjQkGLsUy8sCh0cBMihBRkkBL8Vm82wX7xrCOdIEkwc6MvS755LF6nUNvuZ/GfkzRfizlqf1yyhaMwF0QK6+C0nAvc9MCYY0/RquRkjP0ZP4JL2e9hTu3swggJap0P/YUNGP0L/5QvY+N8XzwT/Y93wUdbQX/EX5g9LtwIBgleBi+JB+j1w+7bwKJqE0Ilr35jSmWxBlz4raexy5vn+GPuYJH3BbDbTHYfJI8puh3I1rjW1TIvVyK8hngkRijY5EX+tR4SXiJItayJqBcScZBYvvmUKs4RaFnlliX6Qk2S+GzrDkV1wKI+AVW8XVtdEtmuoYLX1KbBaglWza+IKQFu4AgWuls9ue+t66/iGvjcPkgrrxyo2rFuSPNauyK7m/H/SbYYZPHm9iIZxxU2UuKMRa6BZ4UYe5Q6tkY9DRGLPAh0vmItx2dulQxdvx8TJgwppiRNMMbSo+KKCAxygEhu4SLx4+rrgNtayx7zYiMuXnuvGd1ESrUjFBphj2pUGqRkq4rTFG6OCN0frv2umPQUUkQD60SfBEoINq12TBrpkmGZKYCOXRRK8iAld4DlmGrzPpCVcsjZfMA65fv5GlG55WARXFBe1hzYe/Svu/pPJS6+5mrsNHzkpbEUhYO+b6xQXX/N1WbektK1SW4RXxEEHsLF43AbJHPGuT9/MP23zj8lo8818CbSvweDGFsFIjNtBEhDkQ+qtixGaSqNJ1xEhcJtrEGIvoFFu5JdYkHELDErcGpbiqlJ73TjYnl2kT5Bxa/cq76ebJTk0Ns5t8tdk+GY7SB2+TW3TMBsyZqAVARwqbFlX2LLVli0PJXB/gWs4cYgX0qNdah6sffAK5+qg2M2f3Lsa9ukUonQMxqdv3Tvv6BflXM3DzvI8nKvAtJ4DOMrBXrh1quGyPs1zLzYiZ5UzT3VDcBb2qfdL9jaosM/D7VuyT1XWKrecSxc/X1cRrbks+lAuBiJ7poyRLMdG01lDuRjj3IxeTsU8PD8ywejlieEMlzFqwTQK08Vpqdy/AhXs1pInC4tqZBk7cMTvd44CrErnqDcevHwsu9vfw/0xZtMG9q+A3IZxagejy07+0UcwYKLJ3a8XCLE+PDuIZQeSTpoXh+1uG6IKy/Z2fOT58HIzMlYpqqs707WHrimh+/Qyzr3mg4zyAi+nq6iTJVk5g7UDIgeYrcDLbg2vQY3QIHBH8QY5Kzk+jCLPKS2w3rlYes/C7AMxhNl0DJHTmanQmZAdtw6TFk5GycTMspdP35z3OrACM8zSQFppoBQZaaCmFmO63STVCkTLeFdBNS1HtIx2TVNNLHmqqWZ+Uq0VqsmJ+df7icS2j29ynkkeHpTw3k0zOd6ottFbm4ZFHJBTwO/PV4x/KWLXFRF7t/i3fVzLjH+VwXry00tPK+Tk6U87iW1V2KmrNvV3ScjmAa+TYmk7juogihKoVk5toG6a+n8ytR29/1V2KVYH+XJwmg2azjdbQN0ADRg1WdxNPhHIuQNKYBDNkoOFKHCwmxwtvLi0jAlKbB/IHr3bRAKwT2IKF7FXKayi2nzqrm86Mh/5dGeaHIrY1NxsfNRJ9q1sNaqwv1urMcCn1VQZQ7XVDM/LavalVAly1tdgNapD591aTY3V2lnvzzbP2D3Bdyl9bgy6Cb6NisMt+56r3WBdTnLlgkEXXU0waJx8z86QV/epC/ThNkb7WvNaVo2TLIOWFHHobKriPFftr2Y01VczsS7T80jqb2YubpLbqUBorr2MMCtm36amzi37xBfc/wc=</diagram></mxfile>"><defs/><g><rect x="0" y="60" width="600" height="120" fill="#fff2cc" stroke="#d6b656" pointer-events="all"/><rect x="0" y="180" width="600" height="330" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/><rect x="460" y="60" width="140" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 138px; height: 1px; padding-top: 75px; margin-left: 460px;"><div style="box-sizing: border-box; font-size: 0; text-align: right; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><div align="right"><font style="font-size: 16px">Developer facing</font></div></div></div></div></foreignObject><text x="598" y="79" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="end">Developer facing</text></switch></g><rect x="470" y="180" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 128px; height: 1px; padding-top: 195px; margin-left: 470px;"><div style="box-sizing: border-box; font-size: 0; text-align: right; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><div style="font-size: 16px" align="right"><font style="font-size: 16px">Internals</font></div></div></div></div></foreignObject><text x="598" y="199" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="end">Internals</text></switch></g><path d="M 250 150 L 250 190 L 120 190 L 120 203.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 120 208.88 L 116.5 201.88 L 120 203.63 L 123.5 201.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="190" y="90" width="120" height="60" fill="#f8cecc" stroke="#b85450" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 120px; margin-left: 191px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">C++</div></div></div></foreignObject><text x="250" y="124" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">C++</text></switch></g><rect x="360" y="90" width="120" height="60" fill="#f8cecc" stroke="#b85450" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 120px; margin-left: 361px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">JavaScript</div></div></div></foreignObject><text x="420" y="124" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">JavaScript</text></switch></g><path d="M 420 150 L 420 190 L 120 190 L 120 203.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 120 208.88 L 116.5 201.88 L 120 203.63 L 123.5 201.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="360" y="90" width="120" height="60" fill="#ffffff" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 120px; margin-left: 361px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">JavaScript</div></div></div></foreignObject><text x="420" y="124" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">JavaScript</text></switch></g><path d="M 80 150 L 80 170 L 80 223.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 80 228.88 L 76.5 221.88 L 80 223.63 L 83.5 221.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="20" y="90" width="120" height="60" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 120px; margin-left: 21px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><div>Rust</div></div></div></div></foreignObject><text x="80" y="124" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Rust</text></switch></g><rect x="20" y="230" width="120" height="60" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 260px; margin-left: 21px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">FOG API </div></div></div></foreignObject><text x="80" y="264" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">FOG API </text></switch></g><path d="M 140 470 L 160 470 L 150 470 L 163.63 470" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 168.88 470 L 161.88 473.5 L 163.63 470 L 161.88 466.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="20" y="440" width="120" height="60" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 470px; margin-left: 21px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">FOG Control</div></div></div></foreignObject><text x="80" y="474" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">FOG Control</text></switch></g><rect x="170" y="440" width="120" height="60" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 470px; margin-left: 171px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Glean SDK</div></div></div></foreignObject><text x="230" y="474" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Glean SDK</text></switch></g><rect x="480" y="0" width="120" height="20" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 10px; margin-left: 481px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Rust</div></div></div></foreignObject><text x="540" y="14" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Rust</text></switch></g><rect x="480" y="30" width="120" height="20" fill="#f8cecc" stroke="#b85450" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 40px; margin-left: 481px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">C++</div></div></div></foreignObject><text x="540" y="44" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">C++</text></switch></g><path d="M 230 220 L 270 260 L 230 300 L 190 260 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 260px; margin-left: 191px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">IPC parent?</div></div></div></foreignObject><text x="230" y="264" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">IPC parent?</text></switch></g><path d="M 230 300 L 230 433.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 230 438.88 L 226.5 431.88 L 230 433.63 L 233.5 431.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 140 260 L 183.63 260" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 188.88 260 L 181.88 263.5 L 183.63 260 L 181.88 256.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="230" y="310" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 320px; margin-left: 231px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">YES</div></div></div></foreignObject><text x="250" y="324" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">YES</text></switch></g><rect x="270" y="240" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 250px; margin-left: 271px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">NO</div></div></div></foreignObject><text x="290" y="254" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">NO</text></switch></g><rect x="360" y="230" width="230" height="200" fill="#f5f5f5" stroke="#666666" pointer-events="all"/><path d="M 270 260 L 460 260 Q 470 260 470 261.82 L 470 263.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 470 268.88 L 466.5 261.88 L 470 263.63 L 473.5 261.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 470 290 L 470 310 L 470 290 L 470 303.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 470 308.88 L 466.5 301.88 L 470 303.63 L 473.5 301.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="410" y="270" width="120" height="20" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 280px; margin-left: 411px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">transfer encoding</div></div></div></foreignObject><text x="470" y="284" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">transfer encoding</text></switch></g><path d="M 470 330 L 470 353.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 470 358.88 L 466.5 351.88 L 470 353.63 L 473.5 351.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="410" y="310" width="120" height="20" fill="#f8cecc" stroke="#b85450" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 320px; margin-left: 411px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">IPC send</div></div></div></foreignObject><text x="470" y="324" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">IPC send</text></switch></g><path d="M 470 380 L 470 393.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 470 398.88 L 466.5 391.88 L 470 393.63 L 473.5 391.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="410" y="360" width="120" height="20" fill="#f8cecc" stroke="#b85450" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 370px; margin-left: 411px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">IPC recv</div></div></div></foreignObject><text x="470" y="374" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">IPC recv</text></switch></g><path d="M 470 420 L 470 470 L 296.37 470" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 291.12 470 L 298.12 466.5 L 296.37 470 L 298.12 473.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="410" y="400" width="120" height="20" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 410px; margin-left: 411px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">transfer decoding</div></div></div></foreignObject><text x="470" y="414" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">transfer decoding</text></switch></g><rect x="520" y="230" width="70" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 240px; margin-left: 521px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">IPC layer</div></div></div></foreignObject><text x="555" y="244" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">IPC layer</text></switch></g><rect x="100" y="210" width="40" height="20" fill="#f8cecc" stroke="#b85450" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 220px; margin-left: 101px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><font style="font-size: 11px">C API</font></div></div></div></foreignObject><text x="120" y="224" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">C API</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" href="https://desk.draw.io/support/solutions/articles/16000042487" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg>
\ No newline at end of file diff --git a/toolkit/components/glean/docs/dev/index.md b/toolkit/components/glean/docs/dev/index.md new file mode 100644 index 0000000000..334f040ed9 --- /dev/null +++ b/toolkit/components/glean/docs/dev/index.md @@ -0,0 +1,15 @@ +# Developing Firefox on Glean + +This section of docs is designed to be helpful to people developing FOG. +If you're not touching code, tests, or documentation in `toolkit/components/glean`, +and you're not interested in implementation details, you probably want +[the user docs instead](../user/index). + +```{toctree} +:titlesonly: +:maxdepth: 1 +:glob: + +* +Glean SDK Source <https://github.com/mozilla/glean/> +``` diff --git a/toolkit/components/glean/docs/dev/ipc.md b/toolkit/components/glean/docs/dev/ipc.md new file mode 100644 index 0000000000..1d6bf5366d --- /dev/null +++ b/toolkit/components/glean/docs/dev/ipc.md @@ -0,0 +1,184 @@ +# Inter-process Communication (IPC) + +Firefox Desktop is a multi-process desktop application. +Code requiring instrumentation may be on any of its processes, +so FOG provide facilities to do just that. + +## Design + +The IPC Design of FOG was worked out in +[bug 1618253](https://bugzilla.mozilla.org/show_bug.cgi?id=1618253). + +It centred around a few specific concepts: + +### Forbidding Non-Commutative Operations + +Because we cannot nicely impose a canonical ordering of metric operations across all processes, +FOG forbids non-[commutative](https://en.wikipedia.org/wiki/Commutative_property) +metric operations in some circumstances. + +For example, +`Add()`-ing to a Counter metric works from multiple processes because the order doesn't matter. +However, given a String metric being `Set()` from multiple processes simultaneously, +which value should it take? + +This ambiguity is not a good foundation to build trust on, +so we forbid setting a String metric from multiple processes. + +#### List of Forbidden Operations + +* Boolean's `set` (this is the metric type's only operation) +* Labeled Boolean's `set` (this is the metric type's only operation) +* String's `set` (this is the metric type's only operation) +* Labeled String's `set` (this is the metric type's only operation) +* String List's `set` + * `add` is permitted (order and uniqueness are not guaranteed) +* Timespan's `start`, `stop`, and `cancel` (these are the metric type's only operations) +* UUID's `set` and `generateAndSet` (these are the metric type's only operations) +* Datetime's `set` (this is the metric type's only operation) +* Quantity's `set` (this is the metric type's only operation) + +This list may grow over time as new metric types are added. +If there's an operation/metric type on this list that you need to use in a non-parent process, +please reach out +[on the #glean channel](https://chat.mozilla.org/#/room/#glean:mozilla.org) +and we'll help you out. + +### Process Agnosticism + +For metric types that can be used cross-process, +FOG provides no facility for identifying which process the instrumentation is on. + +What this means is that if you accumulate to a +[Timing Distribution](https://mozilla.github.io/glean/book/user/metrics/timing_distribution.html) +in multiple processes, +all the samples from all the processes will be combined in the same metric. + +If you wish to distinguish samples from different process types, +you will need multiple metrics and inline code to select the proper one for the given process. +For example: + +```C++ +if (XRE_GetProcessType() == GeckoProcessType_Default) { + mozilla::glean::performance::cache_size.Accumulate(numBytes / 1024); +} else { + mozilla::glean::performance::non_main_process_cache_size.Accumulate(numBytes / 1024); +} +``` + +### Scheduling + +FOG makes no guarantee about when non-main-process metric values are sent across IPC. +FOG will try its best to schedule opportunistically in idle moments, +and during orderly shutdowns. + +There are a few cases where we provide more firm guarantees: + +#### Tests + +There are test-only APIs in Rust, C++, and Javascript. +These do not await a flush of child process metric values. +You can use the test-only method `testFlushAllChildren` on the `FOG` +XPCOM component to await child data's arrival: +```js +await Services.fog.testFlushAllChildren(); +``` +See [the test documentation](testing.md) for more details on testing FOG. +For writing tests about instrumentation, see +[the instrumentation test documentation](../user/instrumentation_tests). + +#### Pings + +We do not guarantee that non-main-process data has made it into a specific ping. + +[Built-in pings](https://mozilla.github.io/glean/book/user/pings/index.html) +are submitted by the Rust Glean SDK at times FOG doesn't directly control, +so there may be data not present in the parent process when a built-in ping is submitted. +We don't anticipate this causing a problem since child-process data that +"misses" a given ping will be included in the next one. + +At this time, +[Custom Pings](https://mozilla.github.io/glean/book/user/pings/custom.html) +must be sent in the parent process and have no mechanism +to schedule their submission for after child-process data arrives in the parent process. +[bug 1732118](https://bugzilla.mozilla.org/show_bug.cgi?id=1732118) +tracks the addition of such a mechanism or guarantee. + +#### Shutdown + +We will make a best effort during an orderly shutdown to flush all pending data in child processes. +This means a disorderly shutdown (usually a crash) +may result in child process data being lost. + +#### Size + +We don't measure or keep an up-to-date calculation of the size of the IPC Payload. +We do, however, keep a count of the number of times the IPC Payload has been accessed. +This is used as a (very) conservative estimate of the size of the IPC Payload so we do not exceed the +[IPC message size limit](https://searchfox.org/mozilla-central/search?q=kMaximumMessageSize). + +See [bug 1745660](https://bugzilla.mozilla.org/show_bug.cgi?id=1745660). + +### Mechanics + +The rough design is that the parent process can request an immediate flush of pending data, +and each child process can decide to flush its pending data whenever it wishes. +The former is via `FlushFOGData() returns (ByteBuf)` and the latter via `FOGData(ByteBuf)`. + +Pending Data is a buffer of bytes generated by `bincode` in Rust in the Child, +handed off to C++, passed over IPC, +then given back to `bincode` in Rust on the Parent. + +Rust is then responsible for turning the pending data into +[metrics API][glean-metrics] calls on the metrics in the parent process. + +#### Supported Process Types + +FOG supports messaging between the following types of child process and the parent process: +* content children (via `PContent` + (for now. See [bug 1641989](https://bugzilla.mozilla.org/show_bug.cgi?id=1641989)) +* gmp children (via `PGMP`) +* gpu children (via `PGPU`) +* rdd children (via `PRDD`) +* socket children (via `PSocketProcess`) +* utility children (via `PUtilityProcess`) + +See +[the process model docs](/dom/ipc/process_model.rst) +for more information about what that means. + +### Adding Support for a new Process Type + +Adding support for a new process type is a matter of extending the two messages +mentioned above in "Mechanics" to another process type's protocol (ipdl file). + +1. Add two messages to the appropriate sections in `P<ProcessType>.ipdl` + * (( **Note:** `PGPU` _should_ be the only ipdl where `parent` + means the non-parent/-main/-UI process, + but double-check that you get this correct.)) + * Add `async FOGData(ByteBuf&& aBuf);` to the parent/main/UI process side of things + (most often `parent:`). + * Add `async FlushFOGData() returns (ByteBuf buf);` to the non-parent/-main/-UI side + (most often `child:`). +2. Implement the protocol endpoints in `P<ProcessType>{Child|Parent}.{h|cpp}` + * The message added to the `parent: ` section goes in + `P<ProcessType>Parent.{h|cpp}` and vice versa. +3. Add to `FOGIPC.cpp`'s `FlushAllChildData` code that + 1. Enumerates all processes of the newly-supported type (there may only be one), + 2. Calls `SendFlushFOGData on each, and + 3. Adds the resulting promise to the array. +4. Add to `FOGIPC.cpp`'s `SendFOGData` the correct `GeckoProcessType_*` + enum value, and appropriate code for getting the parent process singleton and calling + `SendFOGData` on it. +5. Add to the fog crate's `register_process_shutdown` function + handling for at-shutdown flushing of IPC data. + If this isn't added, we will log (but not panic) + on the first use of Glean APIs on an unsupported process type. + * "Handling" might be an empty block with a comment explaining where to find it + (like how `PROCESS_TYPE_DEFAULT` is handled) + * Or it might be custom code + (like `PROCESS_TYPE_CONTENT`'s) +6. Add to the documented [list of supported process types](#supported-process-types) + the process type you added support for. + +[glean-metrics]: https://mozilla.github.io/glean/book/reference/metrics/index.html diff --git a/toolkit/components/glean/docs/dev/jog.md b/toolkit/components/glean/docs/dev/jog.md new file mode 100644 index 0000000000..c8d0549cd4 --- /dev/null +++ b/toolkit/components/glean/docs/dev/jog.md @@ -0,0 +1,91 @@ +# Runtime Metric Definition Subsystem: JOG + +```{admonition} I'm Sorry +Why is it caled JOG? Because it's concerned with... run... time. +``` + +The normal mechanism for registering metrics, +for reasons as varied from ease-of-impl to performance, +happens at compile time. +However, this doesn't support use cases like +* [Artifact Builds][artifact-build] + (Where only the JavaScript of Firefox Desktop is repackaged at build time, + so there is no compile environment) +* Dynamic Telemetry + (A theorized system for instrumenting Firefox Desktop without shipping code) +* Web Extensions + (Or at least the kind that can't or won't use + [the Glean JS SDK][glean-js]) + +Thus we need a subsystem that supports the runtime registration of metrics. +We call it JOG and it was implemented in [bug 1698184][impl-bug]. + +## JavaScript Only + +Metrics in C++ and Rust are identified by identifiers which we can't swap out at runtime. +Thus, in order for changes to metrics to be visible to instrumented systems in C++ or Rust, you must compile. + +JavaScript, on the other hand, we supply instances to on-demand. +It not only supports the specific use cases driving this project, +it's the only environment that can benefit from runtime metric definition in Firefox Desktop. + +## Design + +The original design was done as part of +[bug 1662863][design-bug]. +Things have mostly just been refined from there. + +## Architecture + +We silo as much of the subsystem as we can into the +`jog` module located in `toolkit/components/glean/bindings/jog/`. +This includes the metrics construction factory and storage for metrics instances and their names and ids. + +Unfortunately, so that the metrics instances can be accessed by FFI, +the Rust metrics instances created by the `jog` crate are stored within the `fog` crate. + +Speaking of FFI, the `jog` crate is using cbindgen to be accessible to C++. + +If necessary or pleasant, it is probably possible to do away with the C++ storage, +moving the category set and metrics id map to Rust and moving information over FFI as needed. + +Test methods are run from `nsIFOG` (so we can use them in JS in xpcshell) +to static `JOG::` functions. + +### Build Integration + +If JOG detects we're an artifact build (by checking `MOZ_ARTIFACT_BUILDS`), +it generates `jogfile.json` and ensures it is placed in `GreD` +(next to the `firefox` binary). + +`jogfile.json` includes only the metric and ping information necessary to register them at runtime. +(It doesn't know about tags or descriptions, just the shapes and names of things) + +This file is read the first time JS tries to get a metric category from the +`Glean` global or a ping from the `GleanPings` global. + +Yes, this is on the main thread. Yes, this is synchronous. Yes, this is file I/O. + +Since this is a developer build, we think this is worth it to support Artifact Builds. + +If we're wrong about this and there are additional conditions we should place JOG under, +please [contact us][glean-channel]. + +#### If things get weird, delete `objdir/dist/bin/jogfile.json` + +Sometimes, metrics or pings you've added may not appear when you run Firefox. +For these and other odd cases, the solution is the same: +delete `jogfile.json` from the `dist/bin` directory of your objdir, then try again. + +This shouldn't happen if you keep your artifact and non-artifact objdirs segregated +(as is good practice). + +If, despite doing things properly you still see this or something else odd, then that's a bug. +Please [file it in Toolkit :: Telemetry][file-bug] + +[artifact-build]: https://firefox-source-docs.mozilla.org/contributing/build/artifact_builds.html +[glean-js]: https://mozilla.github.io/glean/book/user/adding-glean-to-your-project/javascript.html +[impl-bug]: https://bugzilla.mozilla.org/show_bug.cgi?id=1698184 +[design-bug]: https://bugzilla.mozilla.org/show_bug.cgi?id=1662863 +[glean-channel]: https://chat.mozilla.org/#/room/#glean:mozilla.org +[file-bug]: https://bugzilla.mozilla.org/enter_bug.cgi?assigned_to=nobody%40mozilla.org&bug_ignored=0&bug_severity=--&bug_status=NEW&bug_type=defect&cf_a11y_review_project_flag=---&cf_fx_iteration=---&cf_fx_points=---&cf_performance_impact=---&cf_status_firefox106=---&cf_status_firefox107=---&cf_status_firefox108=---&cf_status_firefox_esr102=---&cf_status_thunderbird_esr102=---&cf_status_thunderbird_esr91=---&cf_tracking_firefox106=---&cf_tracking_firefox107=---&cf_tracking_firefox108=---&cf_tracking_firefox_esr102=---&cf_tracking_firefox_relnote=---&cf_tracking_thunderbird_esr102=---&cf_tracking_thunderbird_esr91=---&cf_webcompat_priority=---&component=Telemetry&contenttypemethod=list&contenttypeselection=text%2Fplain&defined_groups=1&filed_via=standard_form&flag_type-203=X&flag_type-37=X&flag_type-41=X&flag_type-607=X&flag_type-721=X&flag_type-737=X&flag_type-787=X&flag_type-799=X&flag_type-800=X&flag_type-803=X&flag_type-846=X&flag_type-855=X&flag_type-864=X&flag_type-930=X&flag_type-936=X&flag_type-937=X&flag_type-952=X&form_name=enter_bug&maketemplate=Remember%20values%20as%20bookmarkable%20template&op_sys=Unspecified&priority=--&product=Toolkit&rep_platform=Unspecified&short_desc=Problem%20with%20JOG%3A%20&target_milestone=---&version=unspecified diff --git a/toolkit/components/glean/docs/dev/local_glean.md b/toolkit/components/glean/docs/dev/local_glean.md new file mode 100644 index 0000000000..046cf6e79c --- /dev/null +++ b/toolkit/components/glean/docs/dev/local_glean.md @@ -0,0 +1,100 @@ +# Developing with a local Glean build + +FOG uses a release version of Glean, as published on [crates.io][cratesio-glean]. + +For local development and try runs you can replace this Glean implementation with a local or remote version. + +1. To tell `mach` where to find your Glean, patch the [top-level `Cargo.toml`][cargo-toml]. E.g. like this: + + ```toml + [patches.crates-io] + glean = { git = "https://github.com/myfork/glean", branch = "my-feature-branch" } + glean-core = { git = "https://github.com/myfork/glean", branch = "my-feature-branch" } + ``` + + Both crates are required to ensure they are in sync. + + You can specify the exact code to use by `branch`, `tag` or `rev` (Git commit). + See the [cargo documentation for details][cargo-doc]. + + You can also use a path dependency: + + ```toml + [patches.crates-io] + glean = { path = "../glean/glean-core/rlb" } + glean-core = { path = "../glean/glean-core" } + ``` + +2. If the crate version in the patched repository is not + [semver]-compatible with the version required by the + `fog` and `fog_control` crates, + you need to change the version in the following files to match the ones in your + `glean` repo: + + ``` + toolkit/components/glean/Cargo.toml + toolkit/components/glean/api/Cargo.toml + ``` + + This tells FOG's crates that it needs your local Glean's version. + +3. Update the Cargo lockfile: + + ``` + cargo update -p glean + ``` + +4. Mozilla's supply-chain management policy requires that third-party software + (which includes the Glean SDK because it is distributed as though it is third-party) + be audited and certified as safe. + Your local Glean SDK probably hasn't been vetted. If you try to vendor right now, + `./mach vendor rust` will complain something like: + + ``` + Vet error: There are some issues with your policy.audit-as-crates-io entries + ``` + + This is because your local Glean SDK is neither of a version nor is from a source that has been vetted. + To allow your local Glean crates to be treated as crates.io-sourced crates for vetting, + add the following sections to the top of `supply-chain/config.toml`: + + ```toml + [policy.glean] + audit-as-crates-io = true + + [policy.glean-core] + audit-as-crates-io = true + ``` + + If your local Glean is of a non-vetted version, you can update `glean` and + `glean-core`'s entries in `supply-chain/audits.toml` to the version you're using. + If you don't, `./mach vendor rust` will complain and not complete. + + **Note:** Do not attempt to check these changes in. + These changes bypass supply chain defenses. + `@supply-chain-reviewers` may become cross as they `r-` your patch. + +5. Vendor the changed crates: + + ``` + ./mach vendor rust + ``` + + **Note:** If you're using a path dependency, `mach vendor rust` doesn't actually change files. + Instead it pulls the files directly from the location on disk you specify. + +6. Finally, build Firefox: + + ``` + ./mach build + ``` + +A remote reference works for try runs as well, +but a path dependency will not. + +Please ensure to not land a non-release version of Glean. + +[cratesio-glean]: https://crates.io/crates/glean +[cargo-toml]: https://searchfox.org/mozilla-central/rev/f07a609a76136ef779c65185165ff5ac513cc172/Cargo.toml#76 +[cargo-doc]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-dependencies-from-git-repositories +[semver]: https://semver.org/ diff --git a/toolkit/components/glean/docs/dev/new_metric_types.md b/toolkit/components/glean/docs/dev/new_metric_types.md new file mode 100644 index 0000000000..a3bcdc8b54 --- /dev/null +++ b/toolkit/components/glean/docs/dev/new_metric_types.md @@ -0,0 +1,285 @@ +# Adding a New Metric Type + +This document covers how to add a new metric type to FOG. +You should only have to do this if a new metric type is added to the +[Glean SDK](https://mozilla.github.io/glean/book/user/metrics/index.html) +and it is needed in Firefox Desktop. + +## IPC + +For detailed information about the IPC design, +including a list of forbidden operations, +please consult +[the FOG IPC documentation](ipc.md). + +When adding a new metric type, the main IPC considerations are: +* Which operations are forbidden because they are not commutative? + * Most `set`-style operations cannot be reconciled sensibly across multiple processes. +* If there are non-forbidden operations, +what partial representation will this metric have in non-main processes? +Put another way, what shape of storage will this take up in the +[IPC Payload](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/api/src/ipc.rs)? + * For example, Counters can aggregate all partial counts together to a single + "partial sum". So + [its representation](https://searchfox.org/mozilla-central/rev/803b368879fa332e8e2c1840bf1ec164f7ed2c32/toolkit/components/glean/api/src/ipc.rs#45) + in the IPC Payload is just a single number per Counter. + * In contrast, Timing Distributions' bucket arrangements are known only to the core, + so it can't combine sample counts in child processes. + Instead we record durations in the highest resolution (nanos), + and send a stream of high-precision samples across IPC. + +To implement IPC support in a metric type, +we split FOG's Rust implementation of the metric into three pieces: +1. An umbrella `enum` with the name `MetricTypeMetric`. + * It has a `Child` and a `Parent` variant. + * It is IPC-aware and is responsible for + * If on a non-parent-process, + either storing partial representations in the IPC Payload, + or logging errors if forbidden non-test APIs are called. + (Or panicking if test APIs are called.) + * If on the parent process, dispatching API calls on its inner Rust Language Binding metric. +2. The parent-process implementation is supplied by + [the RLB](https://crates.io/crates/glean/). + * For testing, it stores the `MetricId` that identifies this particular metric in a cross-process fashion. + * For testing, it exposes a `child_metric()` function to create its `Child` equivalent. + * For testing and if it supports operations in a non-parent-process, + it exposes a `metric_id()` function to access the stored `MetricId`. +3. The `MetricTypeIpc` is the non-parent-process implementation. + * If it does support operations in non-parent processes it stores the + `MetricId` that identifies this particular metric in a cross-process fashion. + +## Mirrors + +FOG can mirror Glean metrics to Telemetry probes via the +[Glean Interface For Firefox Telemetry](../user/gifft.md). + +Can this metric type be mirrored? +Should it be mirrored? + +If so, add an appropriate Telemetry probe for it to mirror to, +documenting the compatibility in +[the GIFFT docs](../user/gifft.md). + +### GIFFT Tests + +If you add a GIFFT mirror, don't forget to test that the mirror works. +You should be able to do this by adding a task to +[`toolkit/components/glean/tests/xpcshell/test_GIFFT.js`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/tests/xpcshell/test_GIFFT.js). + +### GIFFT C++ State: Typical Locking and Shutdown + +Some metric types (`labeled_*`, `timespan`, `timing_distribution`) +require holding state in C++ to make GIFFT work. +Pings also hold state to support `testBeforeNextSubmit()`. +If your new metric type requires state in C++, +the current state-of-the-art is a `StaticDataMutex`-locked `UniquePtr` to a `nsTHashTable`. +Access to the inner map is guarded by the lock and is controlled and lazily-instantiated through a single access function. +[See Ping's `GetCallbackMapLock()`](https://searchfox.org/mozilla-central/source/toolkit/components/glean/bindings/private/Ping.cpp) +for example. + +It is important to clear this state to avoid leaks. +(See [bug 1752417](https://bugzilla.mozilla.org/show_bug.cgi?id=1752417).) +However, instrumentation may call metrics APIs at any time. + +Therefore, GIFFT explicitly stops supporting these state-requiring operations after the +[`AppShutdownTelemetry` shutdown phase](https://searchfox.org/mozilla-central/source/xpcom/base/ShutdownPhase.h). +This is because during the next phase (`XPCOMWillShutdown`) we clear the state. + +## Rust + +FOG uses the Rust Language Binding APIs (the `glean` crate) with a layer of IPC on top. + +The IPC additions and glean-core trait implementations are in the +[`private` module of the `fog` crate](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/api/src/metrics). + +Each metric type gets its own file, mimicking the structure in +[`glean_core`](https://github.com/mozilla/glean/tree/main/glean-core/src/metrics) +and [`glean`](https://github.com/mozilla/glean/tree/main/glean-core/rlb/src/private). +Unless, of course, that metric is a labeled metric type. +Then the sub metric type gets its own file, +and you need to add "Labeledness" to it by implementing +`Sealed` for your new type following the pattern in +[`api/src/private/labeled.rs`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/api/src/private/labeled.rs). + +Every method on the metric type is public for now, +including test methods, +and is at least all the methods exposed via the +[metric traits](https://github.com/mozilla/glean/tree/main/glean-core/src/traits). + +To support IPC and the MLA FFI (see below) +we identify metric instances by MetricId and store them in maps in +[the `__glean_metric_maps` mod of `metrics.rs`](https://hg.mozilla.org/mozilla-central/toolkit/components/glean/api/src/metrics.rs). +This work is done by the `rust.py` and `rust(_pings).jinja2` extensions to `glean_parser` found +[in the `build_scripts/glean_parser_ext/` folder](https://searchfox.org/mozilla-central/source/toolkit/components/glean/build_scripts/glean_parser_ext). + +You shouldn't have to edit these files for new metric types, +as the original modifications to `glean_parser` for this type should already be generating correct code. + +### Rust Tests + +You should be able to smoke test the basic functionality in Rust unit tests. +You can do this within the metric type implementation file directly. + +## C++ and JS + +The C++ and JS APIs are implemented [atop the Rust API](code_organization.md). +We treat them both together since, though they're different languages, +they're both implemented in C++ and share much of their implementation. + +The overall design is to build the C++ API atop the Multi-Language Architecture's +(MLA's) FFI, then build the JS API atop the C++ API. +This allows features like the +[Glean Interface For Firefox Telemetry (GIFFT)](../user/gifft.md) +that target only C++ and JS to be more simply implemented in the C++ layer. +Exceptions to this (where the JS uses the FFI directly) are discouraged. + +Each metric type has six pieces you'll need to cover: + +### 1. MLA FFI + +- Using our convenient macros, + define the metric type's Multi-Language Architecture FFI layer above the Rust API in + [`api/src/ffi/`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/api/src/ffi/). + +### 2. C++ Impl + +- Implement a type called `XMetric` (e.g. `CounterMetric`) in `mozilla::glean::impl` in + [`bindings/private/`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/bindings/private/). + - Its methods should be named the same as the ones in the Rust API, transformed to `CamelCase`. + - They should all be public. + - Multiplex the FFI's `test_have` and `test_get` functions into a single + `TestGetValue` function that returns a + `mozilla::Maybe` wrapping the C++ type that best fits the metric type. +- Include the new metric type in + [`bindings/MetricTypes.h`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/bindings/MetricTypes.h). +- Include the new files in + [`moz.build`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/moz.build). + The header file should be added to `EXPORTS.mozilla.glean.bindings` and the + `.cpp` file should be added to `UNIFIED_SOURCES`. + +### 3. IDL + +- Duplicate the public API (including its docs) to + {searchfox}`dom/webidl/GleanMetrics.webidl` + with the name `GleanX` (e.g. `GleanCounter`). + - Inherit from `GleanMetric`. + - The naming style for methods here is `lowerCamelCase`. + - If the metric method is a reserved word, prepend it with a `_`. + - Web IDL bindings use + [their own mapping for types](/dom/webIdlBindings/index.md). + If you choose ones that most closely resemble the C++ types, + you'll make your life easier. +- Add a new mapping in `dom/bindings/Bindings.conf`: + ```idl + 'GleanX': { + 'nativeType': 'mozilla::glean::GleanX', + 'headerFile': 'mozilla/glean/bindings/X.h', + }, + ``` + - If you don't, you will get a build error complaining `fatal error: 'mozilla/dom/GleanX.h' file not found`. + +### 4. JS Impl + +- Implement the `GleanX` (e.g. `GleanCounter`) type + in the same header and `.cpp` as `XMetric` in + {searchfox}`toolkit/components/glean/bindings/private/` + - It should own an instance of and delegate method implementations to `XMetric`. + - In the definition of `GleanX`, member identifiers are back to + `CamelCase`. + - Test-only methods can throw `DataError` on failure. + - Review the [Web IDL Bindings documentation](/dom/webIdlBindings/index.html) + for help with optional, nullable, and non-primitive types. + +### 6. Tests + +Two languages means two test suites. + +- Add a never-expiring test-only metric of your type to + [`test_metrics.yaml`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/tests/test_metrics.yaml). + - Feel free to be clever with the name, + but be sure to make clear that it is test-only. +- **C++ Tests (GTest)** - Add a small test case to + [`gtest/TestFog.cpp`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/tests/gtest/TestFog.cpp). + - For more details, peruse the [testing docs](testing.md). +- **JS Tests (xpcshell)** - Add a small test case to + [`xpcshell/test_Glean.js`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/tests/xpcshell/test_Glean.js) + and + [`xpcshell/test_JOG.js`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/tests/xpcshell/test_JOG.js). + If your metric type has supported IPC operations, also add cases to the `IPC` variants of these test files. + - For more details, peruse the [testing docs](testing.md). + +### 7. API Documentation + +Metric API Documentation is centralized in +[the Glean SDK Book](https://mozilla.github.io/glean/book/user/metrics/index.html). + +You will need to craft a Pull Request against +[the SDK](https://github.com/mozilla/glean/) +adding a C++ and JS example to the specific metric type's API docs. + +Add a notice at the top of both examples that these APIs are only available in Firefox Desktop: +````md +<div data-lang="C++" class="tab"> + +> **Note**: C++ APIs are only available in Firefox Desktop. + +```cpp +#include "mozilla/glean/GleanMetrics.h" + +mozilla::glean::category_name::metric_name.Api(args); +``` + +There are test APIs available too: + +```cpp +#include "mozilla/glean/GleanMetrics.h" + +ASSERT_EQ(value, mozilla::glean::category_name::metric_name.TestGetValue().ref()); +``` +</div> + +// and again for <div data-lang="JS"> +```` + +If you're lucky, the Rust API will have already been added. +Otherwise you'll need to write an example for that one too. + +### 8. Labeled metrics (if necessary) + +If your new metric type is Labeled, you have more work to do. +I'm assuming you've already implemented the non-labeled sub metric type following the steps above. +Now you must add "Labeledness" to it. + +There are four pieces to this: + +#### FFI + +- To add the writeable storage Rust will use to store the dynamically-generated sub metric instances, + add your sub metric type's map as a list item in the `submetric_maps` `mod` of + [`rust.jinja2`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/build_scripts/glean_parser_ext/templates/rust.jinja2). +- Following the pattern of the others, add a `fog_{your labeled metric name here}_get()` FFI API to + `api/src/ffi/mod.rs`. + This is what C++ and JS will use to allocate and retrieve sub metric instances by id. + +#### C++ + +- Following the pattern of the others, add a template specialiation for `Labeled<YourSubMetric>::Get` to + [`bindings/private/Labeled.cpp`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/bindings/private/Labeled.cpp). + This will ensure C++ consumers can fetch or create sub metric instances. + +#### JS + +- Already handled for you since the JS types all inherit from `GleanMetric` + and the JS template knows to add your new type to `NewSubMetricFromIds(...)` + (see `GleanLabeled::NamedGetter` if you're curious). + +#### Tests + +- The labeled variant will need tests the same as Step #6. + A tip: be sure to test two labels with different values. + +## Python Tests + +We have a suite of tests for ensuring code generation generates appropriate code. +You should add a metric to [that suite](testing.md) for your new metric type. +You will need to regenerate the expected files. diff --git a/toolkit/components/glean/docs/dev/preferences.md b/toolkit/components/glean/docs/dev/preferences.md new file mode 100644 index 0000000000..732e25c5c9 --- /dev/null +++ b/toolkit/components/glean/docs/dev/preferences.md @@ -0,0 +1,105 @@ +# Preferences and Defines + +## User Preferences + +`datareporting.healthreport.uploadEnabled` + +This determines whether the Glean SDK is enabled. +It can be controlled by users via `about:preferences#privacy`. +If this is set to false from true, we send a +["deletion-request" ping](https://mozilla.github.io/glean/book/user/pings/deletion_request.html) +and no data collections will be persisted or reported from that point. + +## Test-only Preferences + +`telemetry.fog.test.localhost_port` + +If set to a value `port` which is greater than 0, pings will be sent to +`http://localhost:port` instead of `https://incoming.telemetry.mozilla.org`. +If set to a value `port` which is less than 0, FOG will: +1) Tell Glean that upload is enabled, even if it isn't. +2) Take all pings scheduled for upload and drop them on the floor, + telling the Glean SDK that it was sent successfully. + +This is how you emulate "recording enabled but upload disabled" +like developer builds have in Firefox Telemetry. +When switching from `port < 0` to `port >= 0`, +Glean will be told (if just temporarily) that upload is disabled. +This clears the stores of recorded-but-not-reported data. +Defaults to 0. + +`telemetry.fog.test.activity_limit` +`telemetry.fog.test.inactivity_limit` + +This pair of prefs control the length of time of activity before inactivity +(or vice versa) +needed before FOG informs the SDK's Client Activity API that the client was (in)active. +Present to allow testing without figuring out how to mock Rust's clock. +Their values are integer seconds. +Defaults to 120 (activity), 1200 (inactivity). + +## Internal Preferences + +`telemetry.fog.artifact_build` + +Read-only. This pref is `true` only if `MOZ_ARTIFACT_BUILDS` was set during configure. +If true, [JOG](./jog) is enabled so that artifact builds will exhibit changes to their Glean metrics. + +## Defines + +`MOZ_AUTOMATION` + +If set, and `GLEAN_SOURCE_TAGS` isn't set, FOG will set a +[Glean source tag](https://mozilla.github.io/glean/book/reference/debug/sourceTags.html) +of `automation`. + +If `GLEAN_SOURCE_TAGS` is set, the `automation` source tag will not be added automatically. + +If not set, any tags set by `GLEAN_SOURCE_TAGS` will be present. + +`MOZ_GLEAN_ANDROID` + +If set, the Glean SDK is assumed to be managed by something other than FOG, meaning: +* [GIFFT][gifft] is disabled. +* FOG doesn't initialize Glean +* FOG doesn't relay (in)activity or experiment annotations to Glean + +`MOZILLA_OFFICIAL` + +If unset, we set a `glean_disable_upload` Rust feature in +`gkrust` and `gkrust-shared` which is forwarded to `fog_control` as `disable_upload`. +This feature defaults FOG to an "upload disabled" +mode where collection on the client proceeds as normal but no ping is sent. +This mode can be overridden at runtime in two ways: +* If the ping has a + [Debug Tag](https://mozilla.github.io/glean/book/user/debugging/index.html) + then it is sent so that it may be inspected in the + [Glean Debug Ping Viewer](https://debug-ping-preview.firebaseapp.com/). +* If the preference `telemetry.fog.test.localhost_port` is set to a value greater than 0, + then pings are sent to a server operating locally at that port + (even if the ping has a Debug Tag), to enable testing. + +`MOZILLA_OFFICIAL` tends to be set on most builds released to users, +including builds distributed by Linux distributions. +It tends to not be set on local developer builds. +See [bug 1680025](https://bugzilla.mozilla.org/show_bug.cgi?id=1680025) for details. + +`MOZ_ARTIFACT_BUILDS` + +If `MOZ_ARTIFACT_BUILDS` is set in the build config, +[JOG](./jog) will generate a file for the runtime-registration of metrics and pings. +This is to support [Artifact Builds](/contributing/build/artifact_builds). + +See also `telemetry.fog.artifact_build`. + +`OS_TARGET` + +If not set to `'Android'` we set a `glean_million_queue` Rust feature +([see gkrust-features.mozbuild][gkrust-features]) +which, when passed to the Glean SDK, +opts us into a preinit queue that doesn't discard tasks until there are 10^6 of them. + +See [bug 1797494](https://bugzilla.mozilla.org/show_bug.cgi?id=1797494) for details. + +[gkrust-features]: https://searchfox.org/mozilla-central/source/toolkit/library/rust/gkrust-features.mozbuild +[gifft]: ../user/gifft diff --git a/toolkit/components/glean/docs/dev/storage.md b/toolkit/components/glean/docs/dev/storage.md new file mode 100644 index 0000000000..00464c6173 --- /dev/null +++ b/toolkit/components/glean/docs/dev/storage.md @@ -0,0 +1,14 @@ +# Storage + +Both FOG and the Glean SDK require some storage in the +[Firefox Profile Directory](https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Multiple_profiles). + +## FOG + +At present FOG's storage is limited to its [preferences](preferences.md). + +## Glean SDK + +The Glean SDK stores things in the +[Glean Data Directory](https://mozilla.github.io/glean/book/dev/core/internal/directory-structure.html) +which can be found at `<profile_dir>/datareporting/glean`. diff --git a/toolkit/components/glean/docs/dev/style_guide.md b/toolkit/components/glean/docs/dev/style_guide.md new file mode 100644 index 0000000000..d96766da9f --- /dev/null +++ b/toolkit/components/glean/docs/dev/style_guide.md @@ -0,0 +1,49 @@ +# FOG Documentation Style Guide + +FOG's Documentation is written in Markdown. +You can find its source at `toolkit/components/glean/docs`. + +## Line breaks + +We will use [semantic linefeeds]: +* Break anywhere before 80-100 characters +* Break after any punctuation when it makes sense +* Break before or after any markdown when it makes sense + +**Tip:** To keep lines narrow, use markdown's [reference link] +feature whenever it makes sense (or all the time. Up to you.). + +## Linking to other documentation + +Linking to other external documentation is [easy][reference link]. +Linking to other pieces of documentation in the source docs requires a +link to the source file in the sphinx tree. + +Links can be relative e.g. to link to the [preferences] docs: + +```md +[preferences](preferences.md) +``` + +Or they can be absolute e.g. to link to the [Telemetry] docs: +```md +[Telemetry](/toolkit/components/telemetry/index.rst) +``` + +Sphinx will automagically transform that to an +appropriately-base-url'd url with a `.html` suffix. + + +## Use of "Main" versus "Parent" for processes + +When talking about Glean, it is helpeful to distinguish when we are on the main +process specifically. This is because there is only one main process, and there is only one Glean. +However, "parent" is a relative term, and it may refer to a process +that is the parent of another process, but is not itself the main process. +Prefer use of "main" when it is accurate. + +[semantic linefeeds]: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ +[reference link]: https://spec.commonmark.org/0.29/#reference-link +[Telemetry]: /toolkit/components/telemetry/index.rst +[#firefox-source-docs:mozilla.org]: https://chat.mozilla.org/#/room/#firefox-source-docs:mozilla.org +[bug 1621950]: https://bugzilla.mozilla.org/show_bug.cgi?id=1621950 diff --git a/toolkit/components/glean/docs/dev/testing.md b/toolkit/components/glean/docs/dev/testing.md new file mode 100644 index 0000000000..fe6c3e0fe7 --- /dev/null +++ b/toolkit/components/glean/docs/dev/testing.md @@ -0,0 +1,240 @@ +# Testing + +```{admonition} This documentation is about testing FOG itself +This document contains information about how FOG tests itself, +how to add new tests, how and what to log, and stuff like that. +If you're interested in learning how to test instrumentation you added, +you'll want to read +[the instrumetnation testing docs](../user/instrumentation_tests) instead. +``` + +Given the multiple API languages, processes, and dependencies, +testing FOG is a matter of choosing the right tool for the situation. + +## One Big Command + +To run all the things, here's the tl;dr: + +`./mach build && ./mach lint -W -w -o --fix +&& ./mach rusttests && ./mach gtest "FOG*" +&& python3 ./mach python-test toolkit/components/glean/tests/pytest +&& ./mach test toolkit/components/glean/tests/xpcshell +&& ./mach telemetry-tests-client toolkit/components/telemetry/tests/marionette/tests/client/test_fog* --gecko-log "-" +&& ./mach test toolkit/components/glean/tests/browser +` + +## Logging + +An often-overlooked first line of testing is "what do the logs say?". +To turn on logging for FOG, use any of the following: +* Run Firefox with `RUST_LOG="fog_control,fog,glean_core"`. + * On some platforms this will use terminal colours to indicate log level. +* Run Firefox with `MOZ_LOG="timestamp,sync,glean::*:5,fog::*:5,fog_control::*:5,glean_core::*:5"`. +* Set the following prefs: + * `logging.config.timestamp` to `true` + * `logging.config.sync` to `true` + * `logging.fog_control::*` to `5` + * `logging.fog::*` to `5` + * `logging.glean::*` to `5` + * `logging.glean_core::*` to `5` + * `logging.config.clear_on_startup` to `false` (or all these prefs will be cleared on startup) + +For more information on logging in Gecko, see the +[Gecko Logging docs](/xpcom/logging). + +User-destined logs (of the "You did something wrong" variety) might output to the +[Browser Console](/devtools-user/browser_console/index) +if they originate in JS land. Open via +<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>J</kbd>, or +<kbd>Cmd</kbd>+<kbd>Shift</kbd>+<kbd>J</kbd>. + +```{admonition} Note +At present, Rust logging in non-main processes just doesn't work. +``` + +### What to log, and to where? + +FOG covers a lot a ground (languages, layers): +where you are determines what logging you have available. + +Here are some common situtations for logging: + +#### JS to C++ + +If your logging is aimed at the user using the JS API +(e.g. because the type provided isn't convertable to the necessary C++ type) +then use the Browser Console via +[FOG's Common's `LogToBrowserConsole`](https://searchfox.org/mozilla-central/rev/d107bc8aeadcc816ba85cb21c1a6a1aac1d4ef9f/toolkit/components/glean/bindings/private/Common.cpp#19). + +#### C++ + +If you are in C++ and didn't come from JS, use `MOZ_LOG` with module `fog`. + +#### Rust + +Use the logging macros from `log`, e.g. `log::info!` or `log::error!`. +Remember that, no matter the log level, `log::debug!` and `log::trace!` +[will not appear in non-debug builds](/testing-rust-code/index.md#gecko-logging) + +If you are logging due to a situation caused by and fixable by a developer using the API, +use `log::error!(...)`. Otherwise, use a quieter level. + +## `about:glean` + +`about:glean` is a page in a running Firefox that allows you to +[debug the Glean SDK](https://mozilla.github.io/glean/book/user/debugging/index.html) +in Firefox Desktop. +It does this through the displayed user interface (just follow the instructions). + +## Linting + +To keep in accordance with Mozilla's various and several Coding Styles, +we rely on `mach lint`. + +To lint the code in the "usual" way, automatically fixing where possible, run: +`./mach lint -W -w -o --fix` + +This should keep you from checking in code that will automatically be backed out. + +## Rust + +Not all of our Rust code can be tested in a single fashion, unfortunately. + +### Using `rusttests` (Treeherder symbol `Br` (a build task)) + +If the crate you're testing has no Gecko symbols you can write standard +[Rust tests](https://doc.rust-lang.org/book/ch11-01-writing-tests.html). + +This supports both unit tests +(inline in the file under test) and integration tests +(in the `tests/` folder in the crate root). +Metric type tests are currently written as unit tests inline in the file, +as they require access to the metric ID, which should only be exposed in tests. + +To run FOG's `rusttests` suite use `mach rusttests` + +If the crate uses only a few Gecko symbols, they may use the +`with_gecko` feature to conditionally use them. +This allows the crate to test its non-Gecko-adjacent code using Rust tests. +(You will need to cover the Gecko-adjacent code via another means.) + +**Note:** Some FOG rusttests panic on purpose. They print stack traces to stdout. +If the rusttests fail and you see a stack trace, +double-check it isn't from a purposefully-panicking test. + +**Note:** If a test fails, it is very likely they'll poison the test lock. +This will cause all subsequent tests that attempt to take the test lock +(which is all of them) +to also fail due to `PoisonError`s. They can be safely ignored. + +### Using `gtest` (Treeherder symbol `GTest` (a build task)) + +Because Gecko symbols aren't built for the +`rusttests` build, +any test that is written for code that uses Gecko symbols should be written as a +[`gtest`](https://github.com/google/googletest) +in `toolkit/components/glean/tests/gtest/`. +You can write the actual test code in Rust. +It needs to be accompanied by a C++ GTest that calls a C FFI-exported Rust function. +See [Testing & Debugging Rust Code](/testing-rust-code/index.md) for more. +See [`toolkit/components/glean/tests/gtest/TestFog.cpp`](https://searchfox.org/mozilla-central/source/toolkit/components/glean/tests/gtest/TestFog.cpp) +and [`toolkit/components/glean/tests/gtest/test.rs`](https://searchfox.org/mozilla-central/source/toolkit/components/glean/tests/gtest/test.rs) +for an example. + +By necessity these can only be integration tests against the compiled crate. + +**Note:** When adding a new test file, don't forget to add it to +`toolkit/components/glean/tests/gtest/moz.build` and use the +`FOG` prefix in your test names +(e.g. `TEST(FOG, YourTestName) { ... }`). + +To run FOG's Rust `gtest` suite use `mach gtest FOG.*` + +## Python (Treeherder symbol `py3(fp)` aka `source-test-python-fog`) + +The [Glean Parser](https://github.com/mozilla/glean_parser/) +has been augmented to generate FOG-specific APIs for Glean metrics. +This augmentation is tested by running: + +`mach test toolkit/components/glean/tests/pytest` + +These tests require Python 3+. +If your default Python is Python 2, you may need to instead run: + +`python3 mach python-test toolkit/components/glean/tests/pytest` + +These tests check the code generator output against known good file contents. +If you change the code generator the files will need an update. +Run the test suite with the `UPDATE_EXPECT` environment variable set to do that automatically: + +`UPDATE_EXPECT=1 mach test toolkit/components/glean/tests/pytest` + +## C++ (Treeherder symbol `GTest` (a build task)) + +To test the C++ parts of FOG's implementation +(like metric types) +you should use `gtest`. +FOG's `gtest` tests are in +[`gtest/`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/tests/gtest/). + +You can either add a test case to an existing file or add a new file. +If you add a new file, remember to add it to the +[`moz.build`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/tests/gtest/moz.build)) +or the test runner won't be able to find it. + +All tests should start with `FOG` so that all tests are run with +`./mach gtest FOG*`. + +## JS (Treeherder symbol `X(Xn)` for some number `n`) + +To test the JS parts of FOG's implementation +(like metric types) +you should use `xpcshell`. +FOG's `xpcshell` tests are in +[`xpcshell/`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/tests/xpcshell). + +You can either add a test case to an existing file or add a new file. +If you add a new file, remember to add it to the +[`xpcshell.ini`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/tests/xpcshell/xpcshell.ini) +or the test runner will not be able to find it. + +To run FOG's JS tests, run: +`./mach test toolkit/components/glean/tests/xpcshell` + +## Non-content-process multiprocess (Browser Chrome Mochitests with Treeherder symbol `M(bcN)` for some number `N`) + +To test e.g. the GPU process support you need a full Firefox browser: +xpcshell doesn't have the flexibility. +To test that and have access to privileged JS (i.e. `Glean` and `FOG` APIs), +we use browser-chrome-flavoured mochitests you can find in +[`browser/`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/tests/browser). + +If you need to add a new test file, remember to add it to the +[`browser.ini`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/glean/tests/browser/browser.ini) +manifest, or the test runner will not be able to find it. + +To run FOG's browser chrome tests, run: +`./mach test toolkit/components/glean/tests/browser` + +## Integration (Marionette, borrowing `telemetry-tests-client` Treeherder symbol `tt(c)`) + +To test pings (See [bug 1681742](https://bugzilla.mozilla.org/show_bug.cgi?id=1681742)) +or anything that requires one or more full browsers running, +we use the `telemetry-tests-client` suite in +[`toolkit/components/telemetry/tests/marionette/tests/client/`](https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/telemetry/tests/marionette/tests/client/). + +For more information on this suite, look to +[Firefox Telemetry's Test Documentation](https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/internals/tests.html#integration-tests-telemetry-tests-client-and-telemetry-integration-tests) +and +[Marionette's Documentation](/testing/marionette/Testing.md). + +To run these integration tests, run: +`./mach telemetry-tests-client toolkit/components/telemetry/tests/marionette/tests/client/` + +To capture the Firefox under test's logs, use the `--gecko-log` parameter. +For example, to echo to stdout: +`./mach telemetry-tests-client toolkit/components/telemetry/tests/marionette/tests/client/test_fog* --gecko-log "-"` + +**Note:** Running the `tt(c)` suite in this way ignored skip directives in the manifest. +This means that you might run tests that are not expected to succeed on your platform. +Check `toolkit/components/telemetry/tests/marionette/tests/client/manifest.ini` for details. diff --git a/toolkit/components/glean/docs/dev/updating_parser.md b/toolkit/components/glean/docs/dev/updating_parser.md new file mode 100644 index 0000000000..4609f76a80 --- /dev/null +++ b/toolkit/components/glean/docs/dev/updating_parser.md @@ -0,0 +1,52 @@ +# Updating glean_parser + +Project FOG uses the `glean_parser` to generate code from metric definitions. +It depends on [glean-parser] from pypi.org + +[glean-parser]: https://pypi.org/project/glean-parser/ + +To update the in-tree glean-parser change the version in `third_party/python/requirements.in`, +then run + +``` +./mach vendor python +``` + +```{note} +**Important**: the glean_parser and all of its dependencies must support Python 3.5, as discussed here. +This is the minimum version supported by mach and installed on the CI images for running tests. +This is enforced by the version ranges declared in the Python installation manifest. +``` + +## Version mismatch of the Python dependencies + +The logic for handling version mismatches is very similar to the one for the Rust crates. +See [Updating the Glean SDK](updating_sdk.md) for details. +However, updating Python packages also requires to think about Python 3.5 (and Python 2, still) compatibility. + +## Keeping versions in sync + +The Glean SDK and `glean_parser` are currently released as separate projects. +However each Glean SDK release requires a specific `glean_parser` version. +When updating one or the other ensure versions stay compatible. +You can find the currently used `glean_parser` version in the Glean SDK source tree, e.g. in [sdk_generator.sh]. + +[sdk_generator.sh]: https://github.com/mozilla/glean/blob/main/glean-core/ios/sdk_generator.sh#L28 + +## Using a local `glean_parser` development version + +To test out a new `glean_parser` in mozilla-central follow these steps: + +1. Remove `glean_parser` from the user-wide virtual environment. + This can be found in a path like `~/.mozbuild/srcdirs/gecko-f5e3b9c6ded5/_virtualenvs/mach/lib/python3.10/site-packages/glean_parser` + Note that the `gecko-f5e3b9c6ded5` part will be different depending on your local checkout. + Remove all directories and files mentioning `glean_parser` +2. Remove `glean_parser` from the build virtual enviromment. + This can be found in `$MOZ_OBJDIR/_virtualenvs/common/lib/python3.6/site-packages/glean_parser`. + Note that `$MOZ_OBJDIR` depends on your local mozconfig configuration. + Remove all directories and files mentioning `glean_parser` +3. Copy the local `glean_parser` checkout into `third_party/python/glean_parser`. + E.g. `cp ~/code/glean_parser $GECKO/third_party/python/glean_parser`. + +You should now be able to build `mozilla-central` and it will use the modified `glean_parser`. +You can make further edits in `$GECKO/third_party/python/glean_parser`. diff --git a/toolkit/components/glean/docs/dev/updating_sdk.md b/toolkit/components/glean/docs/dev/updating_sdk.md new file mode 100644 index 0000000000..fafec08d39 --- /dev/null +++ b/toolkit/components/glean/docs/dev/updating_sdk.md @@ -0,0 +1,48 @@ +# Updating the Glean SDK + +Project FOG uses the Glean SDK published as the [`glean`][glean-crate] +and [`glean-core`][glean-core] crates on crates.io. + +[glean-crate]: https://crates.io/crates/glean +[glean-core]: https://crates.io/crates/glean-core + +These two crates' versions are included in several places in mozilla-central. +To update them all, you should use the command +`mach update-glean <version, like "54.1.0">`. + +This is a semi-manual process. +Please pay attention to the output of `mach update-glean` for instructions, +and follow them closely. + +## Version mismatches of Rust dependencies + +Other crates that are already vendored might require a different version of the same dependencies that the Glean SDK requires. +The general strategy for Rust dependencies is to keep one single version of the dependency in-tree +(see [comment #8 in bug 1591555](https://bugzilla.mozilla.org/show_bug.cgi?id=1591555#c8)). +This might be hard to do in reality since some dependencies might require tweaks in order to work. +The following strategy can be followed to decide on version mismatches: + +* If the versions only **differ by the patch version**, Cargo will keep the vendored version, + unless some other dependency pinned specific patch versions; + assuming it doesn’t break the Glean SDK; + if it does, follow the next steps; +* If the version of the **vendored dependency is newer** (greater major or minor version) than the version required by the Glean SDK, + [file a bug in the Glean SDK component][glean-bug] to get Glean to require the same version; + * You will have to abandon updating the Glean SDK to this version. + You will have to wait for Glean SDK to update its dependency and for a new Glean SDK release. + Then you will have to update to that new Glean SDK version. +* If the version of the **vendored dependency is older** (lower major or minor version), consider updating the vendored version to the newer one; + seek review from the person who vendored that dependency in the first place; + if that is not possible or breaks mozilla-central build, then consider keeping both versions vendored in-tree; please note that this option will probably only be approved for small crates, + and will require updating the `TOLERATED_DUPES` list in `mach vendor` + (instructions are provided as you go). + +## Keeping versions in sync + +The Glean SDK and `glean_parser` are currently released as separate projects. +However each Glean SDK release requires a specific `glean_parser` version. +When updating one or the other ensure versions stay compatible. +You can find the currently used `glean_parser` version in the Glean SDK source tree, e.g. in [sdk_generator.sh]. + +[sdk_generator.sh]: https://github.com/mozilla/glean/blob/main/glean-core/ios/sdk_generator.sh#L28 +[glean-bug]: https://bugzilla.mozilla.org/enter_bug.cgi?product=Data+Platform+and+Tools&component=Glean%3A+SDK&priority=P3&status_whiteboard=%5Btelemetry%3Aglean-rs%3Am%3F%5D diff --git a/toolkit/components/glean/docs/index.md b/toolkit/components/glean/docs/index.md new file mode 100644 index 0000000000..c9d8f42eb4 --- /dev/null +++ b/toolkit/components/glean/docs/index.md @@ -0,0 +1,30 @@ +# Firefox on Glean (FOG) + +Firefox on Glean (FOG) is the name of the layer that integrates the +[Glean SDK][glean-sdk] into +[Firefox Desktop](https://www.firefox.com/). + +The [Glean SDK][glean-sdk] +is a data collection library built by Mozilla for use in its products. +Like [Telemetry][telemetry], it can be used to +(in accordance with our [Privacy Policy][privacy-policy]) +send anonymous usage statistics to Mozilla in order to make better decisions. + +If you have any questions, +please reach out to the team on +[#glean:mozilla.org][glean-matrix]. + +```{toctree} +:titlesonly: +:maxdepth: 2 +:glob: + +user/index +dev/index +``` + +[telemetry]: ../telemetry/index +[glean-sdk]: https://github.com/mozilla/glean/ +[book-of-glean]: https://mozilla.github.io/glean/book/index.html +[privacy-policy]: https://www.mozilla.org/privacy/ +[glean-matrix]: https://chat.mozilla.org/#/room/#glean:mozilla.org diff --git a/toolkit/components/glean/docs/user/geckoview_streaming_migration.md b/toolkit/components/glean/docs/user/geckoview_streaming_migration.md new file mode 100644 index 0000000000..6dede3e90e --- /dev/null +++ b/toolkit/components/glean/docs/user/geckoview_streaming_migration.md @@ -0,0 +1,262 @@ +# Migrating Telemetry Collected via Geckoview Streaming to Glean + +With Geckoview Streaming (GVST) having been deprecated, +this is a guide to migrating collections to [Glean][book-of-glean] +via [Firefox on Glean](../index.md). + +```{contents} +``` + +## Before we Begin + +You should familiarize yourself with the guide on +[Adding New Metrics to Firefox Desktop](./new_definitions_file.md). + +You should also read through the guide for +[Migrating Metrics from Legacy Telemetry to Glean](./migration.md). + +This guide assumes some basic familiarity with the above. +The [Glean book][book-of-glean] has a full API reference, as well. + +## Process + +There are 3 main steps: + +1. Move the metric definition and make necessary updates +2. Update the call to use the Glean API +3. Update the tests to use the Glean test API + +### Move and Update the Metric Definition + +Existing metrics that make use of the GVST will already have a fully specified YAML +entry that we will use as a starting point. +This is convenient, but we want to make some minor updates rather than take it fully as is. +At a minimum we need to move the definition out of the +[Geckoview metrics.yaml][gv-metrics-yaml] file and change from GVST to [GIFFT](./gifft.md). +It can go into whichever metrics.yaml file you feel is most appropriate. +If an appropriate one does not exist, create a new one [following this guide][new-yaml]. +Completely remove the metric definition from the Geckoview `metrics.yaml`. + +For all metric types other than `labeled counters` the first step is to change the key +of the `gecko_datapoint` entry to `telemetry_mirror`. +Next, update the value as per the rules outlined in the [GIFFT guide][telemetry-mirror-doc]. +This change is required to keep data flowing in the Legacy Telemetry version of the metric. +Doing so will ensure that downstream analyses do not break unintentionally. +It is not necessary to modify the [Histograms.json][histograms-json] or +[Scalars.yaml][scalars-yaml] file. + +To migrate `labeled counters` instead fully remove the `gecko_datapoint` entry. +Note that our overall treatment of this type is slightly different. + +Next add the bug that covers the migration to the `bugs` field. +Update the `description` field as well to indicate the metric used to be collected +via the Geckoview Streaming API. Other fields should be updated as makes sense. +For example, you may need to update the field for `notification_emails`. +Since you are not changing the collection a new data review is not necessary. +However, if you notice a metric is set to expire soon and it should continue to be collected, +complete a [data review renewal][dr-renewal] form. + +Do not change the name or metric type. +**If you need to change or one both you are creating a new collection.** + +### Update Calls to Use the Glean API + +The next step is to update the metric calls to the Glean API. +Fortunately, for the vast matjority of metricsthis is a 1:1 swapout, +or for `labeled counters` (which are `categorical histograms` in legacy) we add a second call. +We identify the Glean API, remove the old call, and put in its place the Glean call. +You can find a full API reference in the [Glean][book-of-glean], but we'll look at how to record +values for the types that have existing GVST metrics. + +One way to mentally organize the metrics is to break them into two groups, those that are set, +and those that are accumulated to. As when you use the Legacy Telemetry API for GVST, +they are invoked slightly differently. + +To record in C++, you need to include `#include "mozilla/glean/GleanMetrics.h"`. +In Javascript, it is extremely unlikely that you will not already have access to `Glean`. +If you do not, please reach out to a Data Collection Tools team member on +[the #glean:mozilla.org Matrix channel](https://chat.mozilla.org/#/room/#glean:mozilla.org). + +Let's try a few examples. + +#### Migrating a Set Value (string) in C++ + +Let's look at the case of the Graphics Adaptor Vendor ID. +This is a String, +and it's recorded via GVST in C++ + +GVST YAML entry (slightly truncated): + +```YAML +geckoview: + version: + description: > + The version of the Gecko engine, example: 74.0a1 + type: string + gecko_datapoint: gecko.version +``` + +And this is recorded: + +```CPP +Telemetry::ScalarSet(Telemetry::ScalarID::GECKO_VERSION, + NS_ConvertASCIItoUTF16(gAppData->version)); +``` + +To migrate this, let's update our YAML entry, again moving it out of the GVST +metrics.yaml into the most appropriate one: + +```YAML +geckoview: + version: + description: > + The version of the Gecko engine, example: 74.0a1 + (Migrated from geckoview.gfx.adapter.primary) + type: string + telemetry_mirror: GECKO_VERSION +``` + +Notice how we've checked all of our boxes: + +* Made sure our category makes sense +* Changed gecko_datapoint to telemetry_mirror +* Updated the description to note that it was migrated from another collection +* Kept the type identical. + +Now we can update our call: + +```CPP +mozilla::glean::geckoview::version.Set(nsDependentCString(gAppData->version)); +``` + +#### Migrating a Labeled Counter in C++ + +Let's look at probably the most complicated scenario, one where we need to accumulate +to a labeled collection. Because the glean `labeled counter` and legacy `categorical histogram` +type do not support GIFFT, we will add a second call. +Let's take a look at an elided version of how this would be done with GVST: + +```CPP +switch (aResult.as<NonDecoderResult>()) { + case NonDecoderResult::SizeOverflow: + AccumulateCategorical(LABELS_AVIF_DECODE_RESULT::size_overflow); + return; + case NonDecoderResult::OutOfMemory: + AccumulateCategorical(LABELS_AVIF_DECODE_RESULT::out_of_memory); + return; + case NonDecoderResult::PipeInitError: + AccumulateCategorical(LABELS_AVIF_DECODE_RESULT::pipe_init_error); + return; +} +``` + +And we update it by adding a call with the FOG API: + +```CPP +switch (aResult.as<NonDecoderResult>()) { + case NonDecoderResult::SizeOverflow: + AccumulateCategorical(LABELS_AVIF_DECODE_RESULT::size_overflow); + mozilla::glean::avif::decode_result.EnumGet(avif::DecodeResult::eSizeOverflow).Add(); + return; + case NonDecoderResult::OutOfMemory: + AccumulateCategorical(LABELS_AVIF_DECODE_RESULT::out_of_memory); + mozilla::glean::avif::decode_result.EnumGet(avif::DecodeResult::eOutOfMemory).Add(); + return; + case NonDecoderResult::PipeInitError: + AccumulateCategorical(LABELS_AVIF_DECODE_RESULT::pipe_init_error); + mozilla::glean::avif::decode_result.EnumGet(avif::DecodeResult::ePipeInitError).Add(); + return; +} +``` + +#### Migrating an Accumulated Value (Histogram) in Javascript + +Javascript follows the same pattern. Consider the case when want to record the number +of uniqiue site origins. Here's the original JS implementation: + +```Javascript +let originCount = this.computeSiteOriginCount(aWindows, aIsGeckoView); +let histogram = Services.telemetry.getHistogramById( + "FX_NUMBER_OF_UNIQUE_SITE_ORIGINS_ALL_TABS", +); + +if (!this._lastRecordSiteOrigin) { + this._lastRecordSiteOrigin = currentTime; +} else if (currentTime >= this._lastRecordSiteOrigin + this.min_interval) { + this._lastRecordSiteOrigin = currentTime; + + histogram.add(originCount); +} +``` + +And here is the direct Glean version + +```Javascript +let originCount = this.computeSiteOriginCount(aWindows, aIsGeckoView); + +if (!this._lastRecordSiteOrigin) { + this._lastRecordSiteOrigin = currentTime; +} else if (currentTime >= this._lastRecordSiteOrigin + this.min_interval) { + this._lastRecordSiteOrigin = currentTime; + + Glean.tabs.uniqueSiteOriginsAllTabs.accumulateSamples([originCount]); +} + +``` + +Note that we don't have to call into Services to get the histogram object. + +### Update the tests to use the Glean test API + +The last piece is updating tests. If tests don't exist +(which is often the case since testing metrics collected via GVST can be challenging), +we recommend that you write them as the +[the Glean test API is quite straightforward](./instrumentation_tests.md). + +The main test method is `testGetValue()`. Returning to our earlier example of +Number of Unique Site Origins, in a Javascript test we can invoke: + +```Javascript +let result = Glean.tabs.uniqueSiteOriginsAllTabs.testGetValue(); + +// This collection is a histogram, we can check the sum for this test +Assert.equal(result.sum, 144); +``` + +If your collection is in a child process, it can be helpful to invoke +`await Services.fog.testFlushAllChildren();` + +If you wish to write a C++ test, `testGetValue()` is also our main method: + +```CPP +#include "mozilla/glean/GleanMetrics.h" + +ASSERT_EQ(1, + mozilla::glean::avif::image_decode_result + .EnumGet(avif::DecodeResult::eSizeOverflow) + .TestGetValue() + .unwrap() + .ref()); + +ASSERT_EQ(3, + mozilla::glean::avif::image_decode_result + .EnumGet(avif::DecodeResult::eOutOfMemory) + .TestGetValue() + .unwrap() + .ref()); + +ASSERT_EQ(0, + mozilla::glean::avif::image_decode_result + .EnumGet(avif::DecodeResult::ePipeInitError) + .TestGetValue() + .unwrap() + .ref()); +``` + +[book-of-glean]: https://mozilla.github.io/glean/book/index.html +[gv-metrics-yaml]: https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/geckoview/streaming/metrics.yaml +[histograms-json]: https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/Histograms.json +[scalars-yaml]: https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/Scalars.yaml +[new-yaml]: ./new_definitions_file.md#where-do-i-define-new-metrics-and-pings +[dr-renewal]: https://github.com/mozilla/data-review/blob/main/renewal_request.md +[telemetry-mirror-doc]: https://firefox-source-docs.mozilla.org/toolkit/components/glean/user/gifft.html#the-telemetry-mirror-property-in-metrics-yaml diff --git a/toolkit/components/glean/docs/user/getting_started.md b/toolkit/components/glean/docs/user/getting_started.md new file mode 100644 index 0000000000..50b955bced --- /dev/null +++ b/toolkit/components/glean/docs/user/getting_started.md @@ -0,0 +1,97 @@ +# Getting Started with Firefox on Glean (FOG) + +This documentation is designed to be helpful to those who are +* New to data collection in Firefox Desktop, +* Experienced with data collection in Firefox Desktop, but not the Glean kind +* Those who are just interested in a refresher. + +## What is FOG? + +Firefox on Glean (FOG) is the library that brings +[the Glean SDK](https://mozilla.github.io/glean/book/index.html), +Mozilla's modern data collection system, +to Firefox Desktop. + +FOG's code is in `toolkit/components/glean` and is considered part of the +`Toolkit :: Telemetry` [module][modules]. +Bugs against FOG can be [filed][file-fog-bugs] +in Bugzilla in the `Toolkit` product and the `Telemetry` component. +(No bugs about adding new instrumentation, please. +You can file those in the components that you want instrumented.) +You can find folks who can help answer your questions about FOG in +* [#glean:mozilla.org](https://chat.mozilla.org/#/room/#glean:mozilla.org) +* [#telemetry:mozilla.org](https://chat.mozilla.org/#/room/#telemetry:mozilla.org) +* Slack#data-help + +On top of the usual things Glean embedders supply +(user engagement monitoring, network upload configuration, data upload preference watching, ...) +FOG supplies Firefox-Desktop-specific things: +* Privileged JS API +* C++ API +* IPC +* Test Preferences +* Support for `xpcshell`, browser-chrome mochitests, GTests, and rusttests +* `about:glean` +* ...and more. + +## What do I need to know about Glean? + +You use the APIs supplied by the Glean SDK to instrument Mozilla projects. + +The unit of instrumentation is the **metric**. +Recording the number of times a user opens a new tab? That's a metric. +Timing how long each JS garbage collector pass takes? Also a metric. + +Glean has documentation about +[how to add a new metric][add-a-metric] +that you should follow to learn how to add a metric to instrument Firefox Desktop. +There are some [peculiarities specific to Firefox Desktop](new_definitions_file) +that you'll wish to review as well. +Don't forget to get [Data Collection Review][data-review] +for any new or expanded data collections in mozilla projects. + +By adding a metric you've told the Glean SDK what shape of instrumentation you want. +And by using the metric's APIs to instrument your code, +you've put your interesting data into that metric. +But how does the data leave Firefox Desktop and make it to Mozilla's Data Pipeline? + +Batches of related metrics are collected into **pings** +which are submitted according to their specific schedules. +If you don't say otherwise, any non-`event`-metric will be sent in the +[built-in Glean "metrics" ping][metrics-ping] about once a day. +(`event` metrics are sent in [the "events" ping][events-ping] +more frequently than that). + +With data being sent to Mozilla's Data Pipeline, how do you analyse it? + +That's an impossible question to answer completely without knowing a _lot_ about what questions you want to answer. +However, in general, if you want to see what data is being collected by your instrumentation, +[go to its page in Glean Dictionary][glean-dictionary] +and you'll find links and information there about how to proceed. + +## Where do I learn more? + +Here in the [FOG User Documentation](./index) you will find FOG-specific details like +[how to write instrumentation tests](instrumentation_tests), or +[how to use Glean APIs to mirror data to Telemetry](gifft). + +Most of what you should have to concern yourself with, as an instrumentor, +is documented in [the Book of Glean](https://mozilla.github.io/glean/book/index.html). +Such as its [illuminating glossary][glean-glossary], +the [list of all metric types][metrics-types], +or the index of our long-running blog series [This Week in Glean][twig-index]. + +And for anything else you need help with, please find us in +[#glean:mozilla.org](https://chat.mozilla.org/#/room/#glean:mozilla.org). +We'll be happy to help you learn more about FOG and Glean. + +[add-a-metric]: https://mozilla.github.io/glean/book/user/metrics/adding-new-metrics.html +[metrics-ping]: https://mozilla.github.io/glean/book/user/pings/metrics.html +[events-ping]: https://mozilla.github.io/glean/book/user/pings/events.html +[modules]: https://wiki.mozilla.org/Modules/All +[data-review]: https://wiki.mozilla.org/Data_Collection +[glean-dictionary]: https://dictionary.telemetry.mozilla.org/ +[glean-glossary]: https://mozilla.github.io/glean/book/appendix/glossary.html +[twig-index]: https://mozilla.github.io/glean/book/appendix/twig.html +[metrics-types]: https://mozilla.github.io/glean/book/reference/metrics/index.html +[file-fog-bugs]: https://bugzilla.mozilla.org/enter_bug.cgi?product=Toolkit&component=Telemetry diff --git a/toolkit/components/glean/docs/user/gifft.md b/toolkit/components/glean/docs/user/gifft.md new file mode 100644 index 0000000000..4c173884ce --- /dev/null +++ b/toolkit/components/glean/docs/user/gifft.md @@ -0,0 +1,241 @@ +# Glean Interface For Firefox Telemetry (GIFFT) + +To make Migration from Firefox Telemetry to Glean easier, +the C++ and JS Glean API can be configured +(on a metric-by-metric basis) +to mirror data collection to both the Glean metric and a Telemetry probe. + +GIFFT should ideally be used only when the data you require for analysis still mostly lives in Telemetry, +and should be removed promptly when no longer needed. +Instrumentors are encouraged to have the Telemetry mirror probe expire within six versions. +(As always you can renew an expiring probe if you're still using it, +but this will help us get closer to the time when we eventually turn Telemetry off.) + +**Note:** GIFFT only works for data provided via C++ or JS. +Rust Glean metrics APIs will not mirror to Telemetry as Telemetry does not have a Rust API. + +**Note:** Using the Glean API replaces the Telemetry API. +Do not use any mix of the two APIs for the same probe. + +## How to Mirror a Glean Metric to a Firefox Telemetry Probe + +For the mirror to work, you need three things: +* A compatible Glean metric (defined in a `metrics.yaml`) +* A compatible Telemetry probe + (defined in `Histograms.json`, `Scalars.yaml`, or `Events.yaml`) +* A `telemetry_mirror` property on the Glean metric definition identifying the Telemetry probe + +### Compatibility + +This compatibility table explains which Telemetry probe types can be mirrors for which Glean metric types: + +| Glean Metric Type | Telementry Probe Type | +| ----------------- | --------------------- | +| [boolean](https://mozilla.github.io/glean/book/reference/metrics/boolean.html) | [Scalar of kind: boolean](/toolkit/components/telemetry/collection/scalars.html) | +| [labeled_boolean](https://mozilla.github.io/glean/book/reference/metrics/labeled_booleans.html) | [Keyed scalar of kind: boolean](/toolkit/components/telemetry/collection/scalars.html) | +| [counter](https://mozilla.github.io/glean/book/reference/metrics/counter.html) | [Scalar of kind: uint](/toolkit/components/telemetry/collection/scalars.html) | +| [labeled_counter](https://mozilla.github.io/glean/book/reference/metrics/labeled_counters.html) | [Keyed Scalar of kind: uint](/toolkit/components/telemetry/collection/scalars.html) | +| [string](https://mozilla.github.io/glean/book/reference/metrics/string.html) | [Scalar of kind: string](/toolkit/components/telemetry/collection/scalars.html) | +| [labeled_string](https://mozilla.github.io/glean/book/reference/metrics/labeled_strings.html) | *No Supported Telemetry Type* | +| [string_list](https://mozilla.github.io/glean/book/reference/metrics/string_list.html) | [Keyed Scalar of kind: boolean](/toolkit/components/telemetry/collection/scalars.html). The keys are the strings. The values are all `true`. Calling `Set` on the labeled_string is not mirrored (since there's no way to remove keys from a keyed scalar of kind boolean). Doing so will log a warning. | +| [timespan](https://mozilla.github.io/glean/book/reference/metrics/timespan.html) | [Scalar of kind: uint](/toolkit/components/telemetry/collection/scalars.html). The value is in units of milliseconds. | +| [timing_distribution](https://mozilla.github.io/glean/book/reference/metrics/timing_distribution.html) | [Histogram of kind "linear" or "exponential"](/toolkit/components/telemetry/collection/histograms.html#exponential). Samples will be in units of milliseconts. | +| [memory_distribution](https://mozilla.github.io/glean/book/reference/metrics/memory_distribution.html) | [Histogram of kind "linear" or "exponential"](/toolkit/components/telemetry/collection/histograms.html#exponential). Samples will be in `memory_unit` units. | +| [custom_distribution](https://mozilla.github.io/glean/book/reference/metrics/custom_distribution.html) | [Histogram of kind "linear" or "exponential"](/toolkit/components/telemetry/collection/histograms.html#exponential). Samples will be used as is. Ensure the bucket count and range match. | +| [uuid](https://mozilla.github.io/glean/book/reference/metrics/uuid.html) | [Scalar of kind: string](/toolkit/components/telemetry/collection/scalars.html). Value will be in canonical 8-4-4-4-12 format. Value is not guaranteed to be valid, and invalid values may be present in the mirrored scalar while the uuid metric remains empty. Calling `GenerateAndSet` on the uuid is not mirrored, and will log a warning. | +| [url](https://mozilla.github.io/glean/book/reference/metrics/url.html) | [Scalar of kind: string](/toolkit/components/telemetry/collection/scalars.html). The stringified Url will be cropped to the maximum length allowed by the legacy type. | +| [datetime](https://mozilla.github.io/glean/book/reference/metrics/datetime.html) | [Scalar of kind: string](/toolkit/components/telemetry/collection/scalars.html). Value will be in ISO8601 format. | +| [events](https://mozilla.github.io/glean/book/reference/metrics/event.html) | [Events](/toolkit/components/telemetry/collection/events.html). The `value` field will be left empty. | +| [quantity](https://mozilla.github.io/glean/book/reference/metrics/quantity.html) | [Scalar of kind: uint](/toolkit/components/telemetry/collection/scalars.html) | +| [rate](https://mozilla.github.io/glean/book/reference/metrics/rate.html) | [Keyed Scalar of kind: uint](/toolkit/components/telemetry/collection/scalars.html). The keys are "numerator" and "denominator". Does not work for `rate` metrics with external denominators. | +| [text](https://mozilla.github.io/glean/book/reference/metrics/text.html) | *No Supported Telemetry Type* | + +### The `telemetry_mirror` property in `metrics.yaml` + +You must use the C++ enum identifier of the Histogram, Scalar, or Event being mirrored to: +* For Histograms, the Telemetry C++ enum identifier is the histogram's name + * e.g. The C++ enum identifier for `WR_RENDERER_TIME` is + `WR_RENDERER_TIME` (see {searchfox}`gfx/metrics.yaml`) +* For Scalars, the Telemetry C++ enum identifier is the Scalar category and name in + `SCREAMING_SNAKE_CASE` with any `.` replaced with `_` + * e.g. The enum identifier for `extensions.startupCache.load_time` is + `EXTENSIONS_STARTUPCACHE_LOAD_TIME` (see {searchfox}`toolkit/components/extensions/metrics.yaml`) +* For Events, the Telemetry C++ enum identifier is the Event category, method, and object + rendered in `Snakey_CamelCase`. + * e.g. The enum identifier for `page_load.toplevel#content` is + `Page_load_Toplevel_Content` (see {searchfox}`dom/metrics.yaml`) + +If you use the wrong enum identifier, this will manifest as a build error. + +If you are having trouble finding the correct conjugation for the mirror Telemetry probe, +you can find the specific value in the list of all Telemetry C++ enum identifiers in +`<objdir>/toolkit/components/telemetry/Telemetry{Histogram|Scalar|Event}Enums.h`. +(Choose the file appropriate to the type of the Telemetry mirror.) + +## Artifact Build Support + +Sadly, GIFFT does not support Artifact builds. +You must build Firefox when you add the mirrored metric so the C++ enum value is present, +even if you only use the metric from Javascript. + +## Analysis Gotchas + +Firefox Telemetry and the Glean SDK are very different. +Though GIFFT bridges the differences as best it can, +there are many things it cannot account for. + +These are a few of the ways that differences between Firefox Telemetry and the Glean SDK might manifest as anomalies during analysis. + +### Processes, Products, and Channels + +Like Firefox on Glean itself, +GIFFT doesn't know what process, product, or channel it is recording in. +Telemetry does, and imposes restrictions on which probes can be recorded to and when. + +Ensure that the following fields in any Telemetry mirror's definition aren't too restrictive for your use: +* `record_in_processes` +* `products` +* `release_channel_collection`/`releaseChannelCollection` + +A mismatch won't result in an error. +If you, for example, +record to a Glean metric in a release channel that the Telemetry mirror probe doesn't permit, +then the Glean metric will have a value and the Telemetry mirror probe won't. + +Also recall that Telemetry probes split their values across processes. +[Glean metrics do not](../dev/ipc.md). +This may manifest as curious anomalies when comparing the Glean metric to its Telemetry mirror probe. +Ensure your analyses are aggregating Telemetry values from all processes, +or define and use process-specific Glean metrics and Telemetry mirror probes to keep things separate. + +### Pings + +Glean and Telemetry both send their built-in pings on their own schedules. +This means the values present in these pings may not agree since they reflect state at different time. + +For example, if you are measuring "Number of Monitors" with a +[`quantity`](https://mozilla.github.io/glean/book/reference/metrics/quantity.html) +sent by default in the Glean "metrics" ping mirrored to a +[Scalar of kind: uint](/toolkit/components/telemetry/collection/scalars.rst) +sent by default in the Telemetry "main" ping, +then if the user plugs in a second monitor between midnight +(when Telemetry "main" pings with reason "daily" are sent) and 4AM +(when Glean "metrics" pings with reason "today" are sent), +the value in the `quantity` will be `2` +while the value in the Scalar of kind: uint will be `1`. + +If the metric or mirrored probe are sent in Custom pings, +the schedules could line up exactly or be entirely unrelated. + +### Labels + +Labeled metrics supported by GIFFT +(`labeled_boolean` and `labeled_counter`) +adhere to the Glean SDK's +[label format](https://mozilla.github.io/glean/book/reference/metrics/index.html#label-format). + +Keyed Scalars, on the other hand, do not have a concept of an "Invalid key". +Firefox Telemetry will accept just about any sequence of bytes as a key. + +This means that a label deemed invalid by the Glean SDK may appear in the mirrored probe's data. +For example, using 72 "1" characters as a label that doesn't conform to the format +(it is longer than 71 printable ASCII characters). +See that the `labeled_boolean` metric +[correctly ascribes it to `__other__`](https://mozilla.github.io/glean/book/reference/metrics/index.html#labeled-metrics) +whereas the mirrored Keyed Scalar with kind boolean stores and retrieves it without change: +```js +Glean.testOnly.mirrorsForLabeledBools["1".repeat(72)].set(true); +Assert.equal(true, Glean.testOnly.mirrorsForLabeledBools.__other__.testGetValue()); +// The above actually throws NS_ERROR_LOSS_OF_SIGNIFICANT_DATA because it also records +// an invalid_label error. But you get the idea. +let snapshot = Services.telemetry.getSnapshotForKeyedScalars().parent; +Assert.equal(true, snapshot["telemetry.test.mirror_for_labeled_bool"]["1".repeat(72)]); +``` + +### Telemetry Events + +A Glean event can be mirrored to a Telemetry Event. +Telemetry Events must be enabled before they can be recorded to via the API +`Telemetry.setEventRecordingEnabled(category, enable);`. +If the Telemetry Event isn't enabled, +recording to the Glean event will still work, +and the event will be Summarized in Telemetry as all disabled events are. + +See +[the Telemetry Event docs](/toolkit/components/telemetry/collection/events.rst) +for details on how disabled Telemetry Events behave. + +### Numeric Values + +The arguments and storage formats for Glean's numeric types +(`counter`, `labeled_counter`, `quantity`, `rate`, and `timespan`) +are different from Telemetry's numeric type +(Scalar of kind `uint`). + +This results in a few notable differences. + +#### Saturation and Overflow + +`counter`, `labeled_counter`, and `rate` metrics are stored as 32-bit signed values. +`quantity` metrics are stored as 64-bit signed values. +`timing_distribution` samples can be 64-bit signed values. +All of these Glean numeric metric types saturate at their maximum representable value, +or according to the Limits section of the Glean metric type documentation. + +Scalars of kind `uint` are stored as 32-bit unsigned values. +They will overflow if they exceed the value $2^{32} - 1$. + +If a Glean numeric type saturates, it will record an error of type `invalid_overflow`. +In your analyses please check for these errors. + +#### Quantity Value Over-size + +Values greater than $2^{32} - 1$ passed to a `quantity` metric's +`set()` method will be clamped to $2^{32} - 1$ before being passed to the metric's Telemetry mirror. + +#### Negative Values + +Values less than 0 passed to any numeric metric type's API will not be passed on to the Telemetry mirror. +This avoids small negative numbers being cast into a stunningly large numbers, +and keeps the Telemetry mirror's value closer to that of the Glean metric. + +#### Long Time Spans + +If the number of milliseconds between calls to a +`timespan` metric's `start()` and `stop()` methods exceeds $2^{32} - 1$, +the value passed to the metric's Telemetry mirror will be clamped to $2^{32} - 1$. + +The same happens for samples in `timing_distribution` metrics: +values passed to the Telemetry mirror histogram will saturate at $2^{32} - 1$ +until they get past $2^{64}$ when they'll overflow. + +#### `timing_distribution` mirrors: Samples and Sums might be Different + +A specific value in a `timing_distribution` metric will not always agree with +the corresponding value in its mirrored-to histogram. +Though the calls to the clock are very close together in the code in Telemetry and Glean, +Telemetry's are not on the exact same instruction as Glean's _and_ +Telemetry uses a different clock source (`TimeStamp::Now()`) than Glean (`time::precise_time_ns()`). + +Also, if these slight drifts happen to cross the boundary of a bucket in either system, +samples might end up looking more different than you'd expect. + +This shouldn't affect analysis, but it can affect testing, so please +[bear this difference in mind](./instrumentation_tests.md#general-things-to-bear-in-mind) +in testing. + +### App Shutdown + +Telemetry only works up to +[`ShutdownPhase::AppShutdownTelemetry` aka `profile-before-change-telemetry`][app-shutdown]. +Telemetry data recorded after that phase just aren't persisted. + +FOG _presently_ shuts down Glean in a later phase, +and so is able to collect data deeper into shutdown. +(The particular phase is not presently something anyone's asked us to guarantee, +so that's why I'm not being precise.) + +What this means is that, for data recorded later in shutdown, +Glean will report more complete information than Telemetry will. + +[app-shutdown]: https://searchfox.org/mozilla-central/source/xpcom/base/AppShutdown.cpp#57 diff --git a/toolkit/components/glean/docs/user/index.md b/toolkit/components/glean/docs/user/index.md new file mode 100644 index 0000000000..f5ddf6d9e3 --- /dev/null +++ b/toolkit/components/glean/docs/user/index.md @@ -0,0 +1,17 @@ +# Using Firefox on Glean + +This section of docs is designed to be helpful to people instrumenting Firefox Desktop. +You may wish to begin with the [Getting Started](getting_started.md) docs. +Or, if you're already acquainted with Glean concepts and what FOG is, +you might want to know [how to migrate a piece of Firefox Telemetry to Glean](migration.md). + +```{toctree} +:titlesonly: +:maxdepth: 1 +:glob: + +getting_started +new_definitions_file +* +Glean SDK Documentation <https://mozilla.github.io/glean/book/index.html> +``` diff --git a/toolkit/components/glean/docs/user/instrumentation_tests.md b/toolkit/components/glean/docs/user/instrumentation_tests.md new file mode 100644 index 0000000000..e457e9fd39 --- /dev/null +++ b/toolkit/components/glean/docs/user/instrumentation_tests.md @@ -0,0 +1,278 @@ +# Writing Instrumentation Tests + +```{admonition} Old Glean Proverb +If it's important enough to be instrumented, it's important enough to be tested. +``` + +All metrics and pings in the Glean SDK have [well-documented APIs for testing][glean-metrics-apis]. +You'll want to familiarize yourself with `TestGetValue()` +(here's [an example JS (xpcshell) test of some metrics][metrics-xpcshell-test]) +for metrics and +[`TestBeforeNextSubmit()`][test-before-next-submit] +(here's [an example C++ (gtest) test of a custom ping][ping-gtest]) +for pings. + +All test APIs are available in all three of FOG's supported languages: +Rust, C++, and JavaScript. + +But how do you get into a position where you can even call these test APIs? +How do they fit in with Firefox Desktop's testing frameworks? + +## Manual Testing and Debugging + +The Glean SDK has [debugging capabilities][glean-debug] +for manually verifying that instrumentation makes it to Mozilla's Data Pipeline. +Firefox Desktop supports these via environment variables _and_ +via the interface on `about:glean`. + +This is all well and good for getting a good sense check that things are going well _now_, +but in order to check that everything stays good through the future, +you're going to want to write some automated tests. + +## General Things To Bear In Mind + +* You may see values from previous tests persist across tests because the profile directory was shared between test cases. + * You can reset Glean before your test by calling + `Services.fog.testResetFOG()` (in JS). + * If your instrumentation isn't on the parent process, + you should call `await Services.fog.testFlushAllChildren()` before `testResetFOG`. + That will ensure all pending data makes it to the parent process to be cleared. + * You shouldn't have to do this in C++ or Rust since there you should use the + `FOGFixture` test fixture. +* If your metric is based on timing (`timespan`, `timing_distribution`), + do not expect to be able to assert the correct timing value. + Glean does a lot of timing for you deep in the SDK, so unless you mock the system's monotonic clock, + do not expect the values to be predictable. + * Instead, check that a value is `> 0` or that the number of samples is expected. + * You might be able to assert that the value is at least as much as a known, timed value, + but beware of rounding. + * If your metric is a `timing_distribution` mirroring to a Telemetry probe via [GIFFT](./gifft.md), + there may be [small observed differences between systems](./gifft.md#timing-distribution-mirrors-samples-and-sums-might-be-different) + that can cause equality assertions to fail. +* Errors in instrumentation APIs do not panic, throw, or crash. + But Glean remembers that the errors happened. + * Test APIs, on the other hand, are permitted + (some may say "encouraged") + to panic, throw, or crash on bad behaviour. + * If you call a test API and it panics, throws, or crashes, + that means your instrumentation did something wrong. + Check your test logs for details about what went awry. + +### Tests and Artifact Builds + +Artifact build support is provided by [the JOG subsystem](../dev/jog). +It is able to register the latest versions of all metrics and pings at runtime. +However, the compiled code is still running against the +version of those metrics and pings that was current at the time the artifacts were compiled. + +This isn't a problem unless: +* You are changing a metric or ping that is used in instrumentation in the compiled code, or +* You are using `testBeforeNextSubmit` in JavaScript for a ping submitted in the compiled code. + +When in doubt, simply test your new test in artifact mode +(by e.g. passing `--enable-artifact-builds` to `mach try`) +before submitting it. +If it doesn't pass in artifact mode because of one of these two cases, +you may need to skip your test whenever FOG's artifact build support is enabled: +* xpcshell: +```js +add_task( + { skip_if: () => Services.prefs.getBoolPref("telemetry.fog.artifact_build", false) }, + function () { + // ... your test ... + } +); +``` +* mochitest: +```js +add_task(function () { + if (Services.prefs.getBoolPref("telemetry.fog.artifact_build", false)) { + Assert.ok(true, "Test skipped in artifact mode."); + return; + } + // ... your test ... +}); +``` + +## The Usual Test Format + +Instrumentation tests tend to follow the same three-part format: +1) Assert no value in the metric +2) Express behaviour +3) Assert correct value in the metric + +Your choice of test suite will depend on how the instrumented behaviour can be expressed. + + +## `xpcshell` Tests + +If the instrumented behaviour is on the main or content process and can be called from privileged JS, +`xpcshell` is an excellent choice. + +`xpcshell` is so minimal an environment, however, that +(pending [bug 1756055](https://bugzilla.mozilla.org/show_bug.cgi?id=1756055)) +you'll need to manually tell it you need two things: +1) A profile directory +2) An initialized FOG + +```js +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_setup(function test_setup() { + // FOG needs a profile directory to put its data in. + do_get_profile(); + + // FOG needs to be initialized in order for data to flow. + Services.fog.initializeFOG(); +}); +``` + +From there, just follow The Usual Test Format: + +```js +add_task(function test_instrumentation() { + // 1) Assert no value + Assert.equal(undefined, Glean.myMetricCategory.myMetricName.testGetValue()); + + // 2) Express behaviour + // ...<left as an exercise to the reader>... + + // 3) Assert correct value + Assert.equal(kValue, Glean.myMetricCategory.myMetricName.testGetValue()); +}); +``` + +If your new instrumentation includes a new custom ping, +there are two small additions to The Usual Test Format: + +* 1.1) Call `testBeforeNextSubmit` _before_ your ping is submitted. + The callback you register in `testBeforeNextSubmit` + is called synchronously with the call to the ping's `submit()`. +* 3.1) Check that the ping actually was submitted. + If all your Asserts are inside `testBeforeNextSubmit`'s closure, + another way this test could pass is by not running any of them. + +```js +add_task(function test_custom_ping() { + // 1) Assert no value + Assert.equal(undefined, Glean.myMetricCategory.myMetricName.testGetValue()); + + // 1.1) Set up Step 3. + let submitted = false; + GleanPings.myPing.testBeforeNextSubmit(reason => { + submitted = true; + // 3) Assert correct value + Assert.equal(kExpectedReason, reason, "Reason of submitted ping must match."); + Assert.equal(kExpectedMetricValue, Glean.myMetricCategory.myMetricName.testGetValue()); + }); + + // 2) Express behaviour that sends a ping with expected reason and contents + // ...<left as an exercise to the reader>... + + // 3.1) Check that the ping actually was submitted. + Assert.ok(submitted, "Ping was submitted, callback was called."); +}); +``` + +(( We acknowledge that this isn't the most ergonomic form. +Please follow +[bug 1756637](https://bugzilla.mozilla.org/show_bug.cgi?id=1756637) +for updates on a better design and implementation for ping tests. )) + +## mochitest + +`browser-chrome`-flavoured mochitests can be tested very similarly to `xpcshell`, +though you do not need to request a profile or initialize FOG. +`plain`-flavoured mochitests aren't yet supported (follow +[bug 1799977](https://bugzilla.mozilla.org/show_bug.cgi?id=1799977) +for updates and a workaround). + +If you're testing in `mochitest`, your instrumentation (or your test) +might not be running in the parent process. +This means you get to learn the IPC test APIs. + +### IPC + +All test APIs must be called on the main process +(they'll assert otherwise). +But your instrumentation might be on any process, so how do you test it? + +In this case there's a slight addition to the Usual Test Format: +1) Assert no value in the metric +2) Express behaviour +3) _Flush all pending FOG IPC operations with `await Services.fog.testFlushAllChildren()`_ +4) Assert correct value in the metric. + +**NOTE:** We learned in +[bug 1843178](https://bugzilla.mozilla.org/show_bug.cgi?id=1843178) +that the list of all content processes that `Services.fog.testFlushAllChildren()` +uses is very quickly updated after the end of a call to `BrowserUtils.withNewTab(...)`. +If you are using `withNewTab`, you should consider calling `testFlushAllChildren()` +_within_ the callback. + +## GTests/Google Tests + +Please make use of the `FOGFixture` fixture when writing your tests, like: + +```cpp +TEST_F(FOGFixture, MyTestCase) { + // 1) Assert no value + ASSERT_EQ(mozilla::Nothing(), + my_metric_category::my_metric_name.TestGetValue()); + + // 2) Express behaviour + // ...<left as an exercise to the reader>... + + // 3) Assert correct value + ASSERT_EQ(kValue, + my_metric_category::my_metric_name.TestGetValue().unwrap().ref()); +} +``` + +The fixture will take care of ensuring storage is reset between tests. + +## Rust `rusttests` + +The general-purpose +[Testing & Debugging Rust Code in Firefox](/testing-rust-code/index) +is a good thing to review first. + +Unfortunately, FOG requires gecko +(to tell it where the profile dir is, and other things), +which means we need to use the +[GTest + FFI approach](/testing-rust-code/index.md#gtests) +where GTest is the runner and Rust is just the language the test is written in. + +This means your test will look like a GTest like this: + +```cpp +extern "C" void Rust_MyRustTest(); +TEST_F(FOGFixture, MyRustTest) { Rust_MyRustTest(); } +``` + +Plus a Rust test like this: + +```rust +#[no_mangle] +pub extern "C" fn Rust_MyRustTest() { + // 1) Assert no value + assert_eq!(None, + fog::metrics::my_metric_category::my_metric_name.test_get_value(None)); + + // 2) Express behaviour + // ...<left as an exercise to the reader>... + + // 3) Assert correct value + assert_eq!(Some(value), + fog::metrics::my_metric_category::my_metric_name.test_get_value(None)); +} +``` + +[glean-metrics-apis]: https://mozilla.github.io/glean/book/reference/metrics/index.html +[metrics-xpcshell-test]: https://searchfox.org/mozilla-central/rev/66e59131c1c76fe486424dc37f0a8a399ca874d4/toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_glean.js#28 +[ping-gtest]: https://searchfox.org/mozilla-central/rev/66e59131c1c76fe486424dc37f0a8a399ca874d4/toolkit/components/glean/tests/gtest/TestFog.cpp#232 +[test-before-next-submit]: https://mozilla.github.io/glean/book/reference/pings/index.html#testbeforenextsubmit +[glean-debug]: https://mozilla.github.io/glean/book/reference/debug/index.html diff --git a/toolkit/components/glean/docs/user/migration.md b/toolkit/components/glean/docs/user/migration.md new file mode 100644 index 0000000000..f3c86a182b --- /dev/null +++ b/toolkit/components/glean/docs/user/migration.md @@ -0,0 +1,909 @@ +# Migrating Firefox Telemetry to Glean + +This guide aims to help you migrate individual data collections from +[Firefox Telemetry](/toolkit/components/telemetry/index.rst) +to +[Glean][book-of-glean] via [Firefox on Glean](../index.md). + +This is intended to be a reference to help you fill out your +[migration worksheet][migration-worksheet], +or for mentally translating Telemetry concepts to Glean ones. + +```{contents} +``` + +## General Things To Bear In Mind + +You should familiarize yourself with +[the guide on adding new metrics to Firefox Desktop](new_definitions_file.md). +Its advice stacks with the advice included in this guide as +(once you've figured out what kind) you will indeed be adding new metrics. + +There are some other broad topics specific to migrating Firefox Telemetry stuff to Glean stuff: + +### Process-Agnosticism: No more `record_in_processes` field + +Glean (and thus FOG) [doesn't know anything about processes][ipc-dev-doc] +except what it has to in order to ensure all the data makes it to the parent process. +Firefox Telemetry cared very much about which process was collecting which specific data, +keeping them separate. + +If you collect data in multiple processes and wish to keep data from each process type separate, +you will need to provide this separation yourself. + +Please see [this dev doc][ipc-dev-doc] for an example of how to do that. + +### Channel-Agnosticism: No more `release_channel_collection: opt-out` + +FOG doesn't make a differentiation between pre-release Firefox and release Firefox, +except inasmuch as is necessary to put the correct channel in `client_info.app_channel`. + +This means all data is collected in all build configurations. + +If you wish or are required to only collect your data in pre-release Firefox, +please avail yourself of the `EARLY_BETA_OR_EARLIER` `#define` or `AppConstant`. + +### File-level Product Inclusion/Exclusion: No more `products` field + +Glean determines which metrics are recorded in which products via +[a dependency tree][repositories-yaml]. +This means FOG doesn't distinguish between products at the per-product level. + +If some of your metrics are recorded in different sets of products +(e.g. some of your metrics are collected in both Firefox Desktop _and_ Firefox for Android, +but others are Firefox Desktop-specific) +you must separate them into separate [definitions files](new_definitions_file.md). + +### Many Definitions Files + +Each component is expected to own and care for its own +[metrics definitions files](new_definitions_file.md). +There is no centralized `Histograms.json` or `Scalars.yaml` or `Events.yaml`. + +Instead the component being instrumented will have its own `metrics.yaml` +(and `pings.yaml` for any [Custom Pings][custom-pings]) +in which you will define the data. + +See [this guide](new_definitions_file.md) for details. + +### Testing + +Firefox Telemetry had very uneven support for testing instrumentation code. +FOG has much better support. Anywhere you can instrument is someplace you can test. + +It's as simple as calling `testGetValue`. + +All migrated collections are expected to be tested. +If you can't test them, then you'd better have an exceptionally good reason why not. + +For more details, please peruse the +[instrumentation testing docs](instrumentation_tests). + +## Which Glean Metric Type Should I Use? + +Glean uses higher-level metric types than Firefox Telemetry does. +This complicates migration as something that is "just a number" +in Firefox Telemetry might map to any number of Glean metric types. + +Please choose the most specific metric type that solves your problem. +This'll make analysis easier as +1. Others will know more about how to analyse the metric from more specific types. +2. Tooling will be able to present only relevant operations for more specific types. + +Example: +> In Firefox Telemetry I record the number of monitors attached to the computer that Firefox Desktop is running on. +> I could record this number as a [`string`][string-metric], a [`counter`][counter-metric], +> or a [`quantity`][quantity-metric]. +> The `string` is an obvious trap. It doesn't even have the correct data type (string vs number). +> But is it a `counter` or `quantity`? +> If you pay attention to this guide you'll learn that `counter`s are used to accumulate sums of information, +> whereas `quantity` metrics are used to record specific values. +> The "sum" of monitors over time doesn't make sense, so `counter` is out. +> `quantity` is the correct choice. + +## Histograms + +[Histograms][telemetry-histograms] +are the oldest Firefox Telemetry data type, and as such they've accumulated +([ha!][histogram-accumulate]) the most ways of being used. + +### Scalar Values in Histograms: kind `flag` and `count` + +If you have a Histogram that records exactly one value, +please scroll down and look at the migration guide for the relevant Scalar: +* For Histograms of kind `flag` see "Scalars of kind `bool`" +* For Histograms of kind `count` see "Scalars of kind `uint`" + +### Continuous Distributions: kind `linear` and `exponential` + +If the Histogram you wish to migrate is formed of multiple buckets that together form a single continuous range +(like you have buckets 1-5, 6-10, 11-19, and 20-50 - they form the range 1-50), +then you will want a "distribution" metric type in Glean. +Which kind of "distribution" metric type depends on what the samples are. + +#### Timing samples - Use Glean's `timing_distribution` + +The most common type of continuous distribution in Firefox Telemetry is a histogram of timing samples like +[`GC_MS`][gc-ms]. + +In Glean this sort of data is recorded using a +[`timing-distribution`][timing-distribution-metric] metric type. + +You will no longer need to worry about the range of values or number or distribution of buckets +(represented by the `low`, `high`, `n_buckets`, or `kind` in your Histogram's definition). +Glean uses a [clever automatic bucketing algorithm][timing-distribution-metric] instead. + +So for a Histogram that records timing samples like this: + +``` + "GC_MS": { + "record_in_processes": ["main", "content"], + "products": ["firefox", "geckoview_streaming"], + "alert_emails": ["dev-telemetry-gc-alerts@mozilla.org", "jcoppeard@mozilla.com"], + "expires_in_version": "never", + "releaseChannelCollection": "opt-out", + "kind": "exponential", + "high": 10000, + "n_buckets": 50, + "bug_numbers": [1636419], + "description": "Time spent running JS GC (ms)" + }, +``` + +You will migrate to a `timing_distibution` metric type like this: + +```yaml +js: + gc: + type: timing_distribution + time_unit: millisecond + description: | + Time spent running the Javascript Garbage Collector. + Migrated from Firefox Telemetry's `GC_MS`. + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1636419 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1636419#c8 + data_sensitivity: + - technical + notification_emails: + - dev-telemetry-gc-alerts@mozilla.org + - jcoppeard@mozilla.com + expires: never +``` + +**GIFFT:** This type of collection is mirrorable back to Firefox Telemetry via the +[Glean Interface For Firefox Telemetry][gifft]. +See [the guide][gifft] for instructions. + +#### Memory Samples - Use Glean's `memory_distribution` + +Another common content of `linear` or `exponential` +Histograms in Firefox Telemetry is memory samples. +For example, [`MEMORY_TOTAL`][memory-total]'s samples are in kilobytes. + +In Glean this sort of data is recorded using a +[`memory-distribution`][memory-distribution-metric] metric type. + +You will no longer need to worry about the range of values or number or distribution of buckets +(represented by the `low`, `high`, `n_buckets`, or `kind` in your Histogram's definition). +Glean uses a [clever automatic bucketing algorithm][memory-distribution-metric] instead. + +So for a Histogram that records memory samples like this: + +``` + "MEMORY_TOTAL": { + "record_in_processes": ["main"], + "products": ["firefox", "thunderbird"], + "alert_emails": ["memshrink-telemetry-alerts@mozilla.com", "amccreight@mozilla.com"], + "bug_numbers": [1198209, 1511918], + "expires_in_version": "never", + "kind": "exponential", + "low": 32768, + "high": 16777216, + "n_buckets": 100, + "description": "Total Memory Across All Processes (KB)", + "releaseChannelCollection": "opt-out" + }, +``` + +You will migrate to a `memory_distribution` metric type like this: + +```yaml +memory: + total: + type: memory_distribution + memory_unit: kilobyte + description: | + The total memory allocated across all processes. + Migrated from Telemetry's `MEMORY_TOTAL`. + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1198209 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1511918 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1511918#c9 + data_sensitivity: + - technical + notification_emails: + - memshrink-telemetry-alerts@mozilla.com + - amccreight@mozilla.com + expires: never +``` + +**GIFFT:** This type of collection is mirrorable back to Firefox Telemetry via the +[Glean Interface For Firefox Telemetry][gifft]. +See [the guide][gifft] for instructions. + +#### Percentage Samples - Comment on bug 1657467 + +A very common Histogram in Firefox Desktop is a distribution of percentage samples. +[For example, `GC_SLICE_DURING_IDLE`][gc-idle]. + +Glean doesn't currently have a good metric type for this. +But we [intend to add one][new-metric-percent]. +If you are migrating a collection of this type, +please add a comment to the bug detailing which probe you are migrating, +and when you need it migrated by. +We'll prioritize adding this metric type accordingly. + +#### Other - Use Glean's `custom_distribution` + +Continuous Distribution Histograms have been around long enough to have gotten weird. +If you're migrating one of those histograms with units like +["square root of pixels times milliseconds"][checkerboard-severity], +we have a "catch all" metric type for you: [Custom Distribution][custom-distribution-metric]. + +Sadly, you'll have to care about the bucketing algorithm and bucket ranges for this one. +So for a Histogram with artisinal samples like: + +``` + "CHECKERBOARD_SEVERITY": { + "record_in_processes": ["main", "content", "gpu"], + "products": ["firefox", "fennec", "geckoview_streaming"], + "alert_emails": ["gfx-telemetry-alerts@mozilla.com", "botond@mozilla.com"], + "bug_numbers": [1238040, 1539309, 1584109], + "releaseChannelCollection": "opt-out", + "expires_in_version": "never", + "kind": "exponential", + "high": 1073741824, + "n_buckets": 50, + "description": "Opaque measure of the severity of a checkerboard event" + }, +``` + +You will migrate it to a `custom_distribution` like: + +```yaml +gfx.checkerboard: + severity: + type: custom_distribution + range_max: 1073741824 + bucket_count: 50 + histogram_type: exponential + unit: Opaque unit + description: > + An opaque measurement of the severity of a checkerboard event. + This doesn't have units, it's just useful for comparing two checkerboard + events to see which one is worse, for some implementation-specific + definition of "worse". The larger the value, the worse the + checkerboarding. + Migrated from Telemetry's `CHECKERBOARD_SEVERITY`. + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1238040 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1539309 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1584109 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1584109#c1 + notification_emails: + - gfx-telemetry-alerts@mozilla.com + - botond@mozilla.com + data_sensitivity: + - technical + expires: never +``` + +**TODO [Bug 1677447](https://bugzilla.mozilla.org/show_bug.cgi?id=1677447):** +Custom Distributions aren't yet implemented in FOG. We're working on it. +When they're done we'll see if they'll support GIFFT like the other distributions. + +#### Keyed Histograms with Continuous Sample Distributions - Ask on #glean:mozilla.org for assistance + +Glean doesn't currently have a good metric type for keyed continuous distributions +like video play time keyed by codec. +Please [reach out to us][glean-matrix] to explain your use-case. +We will help you either work within what Glean currently affords or +[design a new metric type for you][new-metric-type]. + +### Discrete Distributions: kind `categorical`, `enumerated`, or `boolean` - Use Glean's `labeled_counter` + +If the samples don't fall in a continuous range and instead fall into a known number of buckets, +Glean provides the [Labeled Counter][labeled-counter-metric] for these cases. + +Simply enumerate the discrete categories as `labels` in the `labeled_counter`. + +For example, for a Histogram of kind `categorical` like: + +``` + "AVIF_DECODE_RESULT": { + "record_in_processes": ["main", "content"], + "products": ["firefox", "geckoview_streaming"], + "alert_emails": ["cchang@mozilla.com", "jbauman@mozilla.com"], + "expires_in_version": "never", + "releaseChannelCollection": "opt-out", + "kind": "categorical", + "labels": [ + "success", + "parse_error", + "no_primary_item", + "decode_error", + "size_overflow", + "out_of_memory", + "pipe_init_error", + "write_buffer_error", + "alpha_y_sz_mismatch", + "alpha_y_bpc_mismatch" + ], + "description": "Decode result of AVIF image", + "bug_numbers": [1670827] + }, +``` + +You would migrate to a `labeled_counter` like: + +```yaml +avif: + decode_result: + type: labeled_counter, + description: | + Each AVIF image's decode result. + Migrated from Telemetry's `AVIF_DECODE_RESULT`. + labels: + - success + - parse_error + - no_primary_item + - decode_error + - size_overflow + - out_of_memory + - pipe_init_error + - write_buffer_error + - alpha_y_sz_mismatch + - alpha_y_bpc_mismatch + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1670827 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1670827#c9 + data_sensitivity: + - technical + notification_emails: + - cchang@mozilla.com + - jbauman@mozilla.com + expires: never +``` + +**N.B:** Glean Labels have a strict regex. +You may have to transform some categories to +`snake_case` so that they're safe for the data pipeline. + +**GIFFT:** This type of collection is mirrorable back to Firefox Telemetry via the +[Glean Interface For Firefox Telemetry][gifft]. +See [the guide][gifft] for instructions. +**N.B.:** This will mirror back as a Keyed Scalar of kind `uint`, +not as any kind of Histogram, +so your original un-migrated histogram cannot be used as the mirror. + +#### Keyed Histograms with Discrete Sample Distributions: `"keyed": true` and kind `categorical`, `enumerated`, or `boolean` - Comment on bug 1657470 + +Glean doesn't currently have a good metric type for this. +But we [intend to add one][new-metric-keyed-categorical]. +If you are migrating a collection of this type, +please add a comment to the bug detailing which probe you are migrating, +and when you need it migrated by. +We'll prioritize adding this metric type accordingly. + +## Scalars + +[Scalars][telemetry-scalars] are low-level individual data collections with a variety of uses. + +### Scalars of `kind: uint` that you call `scalarAdd` on - Use Glean's `counter` + +The most common kind of Scalar is of `kind: uint`. +The most common use of such a scalar is to repeatedly call `scalarAdd` +on it as countable things happen. + +The Glean metric type for countable things is [the `counter` metric type][counter-metric]. + +So for a Scalar like this: + +```yaml +script.preloader: + mainthread_recompile: + bug_numbers: + - 1364235 + description: + How many times we ended up recompiling a script from the script preloader + on the main thread. + expires: "100" + keyed: false + kind: uint + notification_emails: + - dothayer@mozilla.com + - plawless@mozilla.com + release_channel_collection: opt-out + products: + - 'firefox' + - 'fennec' + record_in_processes: + - 'main' + - 'content' +``` + +You will migrate to a `counter` metric type like this: + +```yaml +script.preloader: + mainthread_recompile: + type: counter + description: | + How many times we ended up recompiling a script from the script preloader + on the main thread. + Migrated from Telemetry's `script.preloader.mainthread_recompile`. + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1364235 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1364235#c25 + data_sensitivity: + - technical + notification_emails: + - dothayer@mozilla.com + - plawless@mozilla.com + expires: "100" +``` + +**GIFFT:** This type of collection is mirrorable back to Firefox Telemetry via the +[Glean Interface For Firefox Telemetry][gifft]. +See [the guide][gifft] for instructions. + +#### Keyed Scalars of `kind: uint` that you call `scalarAdd` on - Use Glean's `labeled_counter` + +Another very common use of Scalars is to have a Keyed Scalar of +`kind: uint`. This was often used to track UI usage. + +This is supported by the [Glean `labeled_counter` metric type][labeled-counter-metric]. + +So for a Keyed Scalar of `kind: uint` like this: + +```yaml +urlbar: + tips: + bug_numbers: + - 1608461 + description: > + A keyed uint recording how many times particular tips are shown in the + Urlbar and how often their confirm and help buttons are pressed. + expires: never + kind: uint + keyed: true + notification_emails: + - email@example.com + release_channel_collection: opt-out + products: + - 'firefox' + record_in_processes: + - main +``` + +You would migrate it to a `labeled_counter` like this: + +```yaml +urlbar: + tips: + type: labeled_counter + description: > + A keyed uint recording how many times particular tips are shown in the + Urlbar and how often their confirm and help buttons are pressed. + Migrated from Telemetry's `urlbar.tips`. + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1608461 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1608461#c42 + data_sensitivity: + - interaction + expires: never + notification_emails: + - email@example.com +``` + +Now, if your Keyed Scalar has a list of known keys, +you should provide it to the `labeled_counter` using the `labels` property like so: + +```yaml +urlbar: + tips: + type: labeled_counter + labels: + - tabtosearch_onboard_shown + - tabtosearch_shown + - searchtip_onboard_shown + ... +``` + +**N.B:** Glean Labels have a strict regex. +You may have to transform some categories to +`snake_case` so that they're safe for the data pipeline. + +**GIFFT:** This type of collection is mirrorable back to Firefox Telemetry via the +[Glean Interface For Firefox Telemetry][gifft]. +See [the guide][gifft] for instructions. + +### Scalars of `kind: uint` that you call `scalarSet` on - Use Glean's `quantity` + +Distinct from counts which are partial sums, +Scalars of `kind: uint` that you _set_ could contain just about anything. +The best metric type depends on the type of data you're setting +(See "Other Scalar-ish types" for some possibilities). + +If it's a numerical value you are setting, chances are you will be best served by +[Glean's `quantity` metric type][quantity-metric]. + +For a such a quantitative Scalar like: + +```yaml +gfx.display: + primary_height: + bug_numbers: + - 1594145 + description: > + Height of the primary display, takes device rotation into account. + expires: never + kind: uint + notification_emails: + - gfx-telemetry-alerts@mozilla.com + - ktaeleman@mozilla.com + products: + - 'geckoview_streaming' + record_in_processes: + - 'main' + release_channel_collection: opt-out +``` + +You would migrate it to a `quantity` like: + +```yaml +gfx.display: + primary_height: + type: quantity + unit: pixels + description: > + Height of the primary display, takes device rotation into account. + Migrated from Telemetry's `gfx.display.primary_height`. + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1594145 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1687219 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1594145#c4 + data_sensitivity: + - technical + notification_emails: + - gfx-telemetry-alerts@mozilla.com + expires: never +``` + +Note the required `unit` property. + +**GIFFT:** This type of collection is mirrorable back to Firefox Telemetry via the +[Glean Interface For Firefox Telemetry][gifft]. +See [the guide][gifft] for instructions. + +**IPC Note:** Due to `set` not being a [commutative operation][ipc-docs], using `quantity` +on non-parent processes is forbidden. +This is a restriction that favours correctness over friendliness, +which we may revisit if enough use cases require it. +Please [contact us][glean-matrix] if you'd like us to do so. + +#### Keyed Scalars of `kind: uint` that you call `scalarSet` on - Ask on #glean:mozilla.org for assistance + +Glean doesn't currently have a good metric type for keyed quantities. +Please [reach out to us][glean-matrix] to explain your use-case. +We will help you either work within what Glean currently affords or +[design a new metric type for you][new-metric-type]. + +### Scalars of `kind: uint` that you call `scalarSetMaximum` or some combination of operations on - Ask on #glean:mozilla.org for assistance + +Glean doesn't currently have a good metric type for dealing with maximums, +or for dealing with values you both count and set. +Please [reach out to us][glean-matrix] to explain your use-case. +We will help you either work within what Glean currently affords or +[design a new metric type for you][new-metric-type]. + +### Scalars of `kind: string` - Use Glean's `string` + +If your string value is a unique identifier, then consider +[Glean's `uuid` metric type][uuid-metric] first. + +If the string scalar value doesn't fit that or any other more specific metric type, +then [Glean's `string` metric type][string-metric] will do. + +For a Scalar of `kind: string` like: + +```yaml +widget: + gtk_version: + bug_numbers: + - 1670145 + description: > + The version of Gtk 3 in use. + kind: string + expires: never + notification_emails: + - layout-telemetry-alerts@mozilla.com + release_channel_collection: opt-out + products: + - 'firefox' + record_in_processes: + - 'main' +``` + +You will migrate it to a `string` metric like: + +```yaml +widget: + gtk_version: + type: string + description: > + The version of Gtk 3 in use. + Migrated from Telemetry's `widget.gtk_version`. + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1670145 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1670145#c7 + data_sensitivity: + - technical + notification_emails: + - layout-telemetry-alerts@mozilla.com + expires: never +``` + +**GIFFT:** This type of collection is mirrorable back to Firefox Telemetry via the +[Glean Interface For Firefox Telemetry][gifft]. +See [the guide][gifft] for instructions. + +**IPC Note:** Due to `set` not being a [commutative operation][ipc-docs], using `string` +on non-parent processes is forbidden. +This is a restriction that favours correctness over friendliness, +which we may revisit if enough use cases require it. +Please [contact us][glean-matrix] if you'd like us to do so. + +### Scalars of `kind: boolean` - Use Glean's `boolean` + +If you need to store a simple true/false, +[Glean's `boolean` metric type][boolean-metric] is likely best. + +If you have more that just `true` and `false` to store, +you may prefer a `labeled_counter`. + +For a Scalar of `kind: boolean` like: + +```yaml +widget: + dark_mode: + bug_numbers: + - 1601846 + description: > + Whether the OS theme is dark. + expires: never + kind: boolean + notification_emails: + - layout-telemetry-alerts@mozilla.com + - cmccormack@mozilla.com + release_channel_collection: opt-out + products: + - 'firefox' + - 'fennec' + record_in_processes: + - 'main' +``` + +You would migrate to a `boolean` metric type like: + +```yaml +widget: + dark_mode: + type: boolean + description: > + Whether the OS theme is dark. + Migrated from Telemetry's `widget.dark_mode`. + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1601846 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1601846#c5 + data_sensitivity: + - technical + notification_emails: + - layout-telemetry-alerts@mozilla.com + - cmccormack@mozilla.com + expires: never +``` + +**GIFFT:** This type of collection is mirrorable back to Firefox Telemetry via the +[Glean Interface For Firefox Telemetry][gifft]. +See [the guide][gifft] for instructions. + +**IPC Note:** Due to `set` not being a [commutative operation][ipc-docs], using `boolean` +on non-parent processes is forbidden. +This is a restriction that favours correctness over friendliness, +which we may revisit if enough use cases require it. +Please [contact us][glean-matrix] if you'd like us to do so. + +#### Keyed Scalars of `kind: boolean` - Use Glean's `labeled_boolean` + +If you have multiple related true/false values, you may have put them in a +Keyed Scalar of `kind: boolean`. + +The best match for this is +[Glean's `labeled_boolean` metric type][labeled-boolean-metric]. + +For a Keyed Scalar of `kind: boolean` like: + +```yaml +devtools.tool: + registered: + bug_numbers: + - 1447302 + - 1503568 + - 1587985 + description: > + Recorded on enable tool checkbox check/uncheck in Developer Tools options + panel. Boolean stating if the tool was enabled or disabled by the user. + Keyed by tool id. Current default tools with their id's are defined in + https://searchfox.org/mozilla-central/source/devtools/client/definitions.js + expires: never + kind: boolean + keyed: true + notification_emails: + - dev-developer-tools@lists.mozilla.org + - accessibility@mozilla.com + release_channel_collection: opt-out + products: + - 'firefox' + - 'fennec' + record_in_processes: + - 'main' +``` + +You would migrate to a `labeled_boolean` like: + +```yaml +devtools.tool: + registered: + type: labeled_boolean + description: > + Recorded on enable tool checkbox check/uncheck in Developer Tools options + panel. Boolean stating if the tool was enabled or disabled by the user. + Migrated from Telemetry's `devtools.tool`. + labels: + - options + - inspector + - webconsole + - jsdebugger + - styleeditor + - performance + - memory + - netmonitor + - storage + - dom + - accessibility + - application + - dark + - light + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1447302 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1503568 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1587985 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1447302#c17 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1503568#c3 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1587985#c5 + data_sensitivity: + - interaction + notification_emails: + - dev-developer-tools@lists.mozilla.org + - accessibility@mozilla.com + expires: never +``` + +**N.B:** Glean Labels have a strict regex. +You may have to transform some categories to +`snake_case` so that they're safe for the data pipeline. + +**GIFFT:** This type of collection is mirrorable back to Firefox Telemetry via the +[Glean Interface For Firefox Telemetry][gifft]. +See [the guide][gifft] for instructions. + +**IPC Note:** Due to `set` not being a [commutative operation][ipc-docs], using `labeled_boolean` +on non-parent processes is forbidden. +This is a restriction that favours correctness over friendliness, +which we may revisit if enough use cases require it. +Please [contact us][glean-matrix] if you'd like us to do so. + +### Other Scalar-ish types: `rate`, `timespan`, `datetime`, `uuid` + +The Glean SDK provides some very handy higher-level metric types for specific data. +If your data +* Is two or more numbers that are related (like failure count vs total count), + then consider the [Glean `rate` metric type][rate-metric]. +* Is a single duration or span of time (like how long Firefox takes to start), + then consider the [Glean `timespan` metric type][timespan-metric]. +* Is a single point in time (like the most recent sync time), + then consider the [Glean `datetime` metric type][datetime-metric]. +* Is a unique identifier (like a session id), + then consider the [Glean `uuid` metric type][uuid-metric]. + +**GIFFT:** These types of collection are mirrorable back to Firefox Telemetry via the +[Glean Interface For Firefox Telemetry][gifft]. +See [the guide][gifft] for instructions. + +## Events - Use Glean's `event` + +[Telemetry Events][telemetry-events] +are a lesser-used form of data collection in Firefox Desktop. +Glean aimed to remove some of the stumbling blocks facing instrumentors when using events +in the [Glean `event` metric type][event-metric]: + +* Don't worry about enabling event categories. + In Glean all `events` are always on. +* No more event `name`. + Events in Glean follow the same `category.name.metric_name` + naming structure that other metrics do. +* No more `method`/`object`/`value`. + Events in Glean are just their identifier and an `extras` key/value dictionary. + +Since the two Event types aren't that analogous you will need to decide if your event +* Prefers to put its `method`/`object`/`value` in the `extras` dictionary +* Prefers to fold its `method`/`object`/`value` into its identifier + +**GIFFT:** Events are mirrorable back to Firefox Telemetry via the +[Glean Interface For Firefox Telemetry][gifft]. +See [the guide][gifft] for instructions. + +## Other: Environment, Crash Annotations, Use Counters, Etc - Ask on #glean:mozilla.org for assistance + +Telemetry has a lot of collection subsystems build adjacent to those already mentioned. +We have solutions for the common ones, +but they are entirely dependent on the specific use case. +Please [reach out to us][glean-matrix] to explain it to us so we can help you either +work within what Glean currently affords or +[design a new metric type for you][new-metric-type]. + +[book-of-glean]: https://mozilla.github.io/glean/book/index.html +[gc-ms]: https://glam.telemetry.mozilla.org/firefox/probe/gc_ms/explore +[histogram-accumulate]: https://searchfox.org/mozilla-central/rev/d59bdea4956040e16113b05296c56867f761735b/toolkit/components/telemetry/core/Telemetry.h#61 +[ipc-docs]: ../dev/ipc.md +[gifft]: gifft.md +[memory-total]: https://glam.telemetry.mozilla.org/firefox/probe/memory_total/explore +[migration-worksheet]: https://docs.google.com/spreadsheets/d/1uEK7zSIJDcGGmof9NywP5AwaovVQCv_Bm3iNqibtESI/edit#gid=0 +[boolean-metric]: https://mozilla.github.io/glean/book/reference/metrics/boolean.html +[labeled-boolean-metric]: https://mozilla.github.io/glean/book/reference/metrics/labeled_booleans.html +[counter-metric]: https://mozilla.github.io/glean/book/reference/metrics/counter.html +[labeled-counter-metric]: https://mozilla.github.io/glean/book/reference/metrics/labeled_counters.html +[string-metric]: https://mozilla.github.io/glean/book/reference/metrics/string.html +[labeled-string-metric]: https://mozilla.github.io/glean/book/reference/metrics/labeled_strings.html +[timespan-metric]: https://mozilla.github.io/glean/book/reference/metrics/timespan.html +[timing-distribution-metric]: https://mozilla.github.io/glean/book/reference/metrics/timing_distribution.html +[memory-distribution-metric]: https://mozilla.github.io/glean/book/reference/metrics/memory_distribution.html +[uuid-metric]: https://mozilla.github.io/glean/book/reference/metrics/uuid.html +[datetime-metric]: https://mozilla.github.io/glean/book/reference/metrics/datetime.html +[event-metric]: https://mozilla.github.io/glean/book/reference/metrics/event.html +[custom-distribution-metric]: https://mozilla.github.io/glean/book/reference/metrics/custom_distribution.html +[quantity-metric]: https://mozilla.github.io/glean/book/reference/metrics/quantity.html +[rate-metric]: https://mozilla.github.io/glean/book/reference/metrics/rate.html +[ipc-dev-doc]: ../dev/ipc.md +[gc-idle]: https://glam.telemetry.mozilla.org/firefox/probe/gc_slice_during_idle/explore +[new-metric-keyed-categorical]: https://bugzilla.mozilla.org/show_bug.cgi?id=1657470 +[new-metric-percent]: https://bugzilla.mozilla.org/show_bug.cgi?id=1657467 +[new-metric-type]: https://wiki.mozilla.org/Glean/Adding_or_changing_Glean_metric_types +[glean-matrix]: https://chat.mozilla.org/#/room/#glean:mozilla.org +[checkerboard-severity]: https://searchfox.org/mozilla-central/rev/d59bdea4956040e16113b05296c56867f761735b/gfx/layers/apz/src/CheckerboardEvent.cpp#44 +[telemetry-events]: /toolkit/components/telemetry/collection/events.rst +[telemetry-scalars]: /toolkit/components/telemetry/collection/scalars.rst +[telemetry-histograms]: /toolkit/components/telemetry/collection/histograms.rst +[repositories-yaml]: https://github.com/mozilla/probe-scraper/blob/main/repositories.yaml diff --git a/toolkit/components/glean/docs/user/new_definitions_file.md b/toolkit/components/glean/docs/user/new_definitions_file.md new file mode 100644 index 0000000000..b9d1ada8f3 --- /dev/null +++ b/toolkit/components/glean/docs/user/new_definitions_file.md @@ -0,0 +1,116 @@ +# New Metrics and Pings + +To add a new metric or ping to Firefox Desktop you should follow the +[Glean SDK documentation on the subject](https://mozilla.github.io/glean/book/user/adding-new-metrics.html), +with some few twists we detail herein: + +## Testing + +Instrumentation, being code, should be tested. +Firefox on Glean [supports a wide variety of Firefox Desktop test suites][instrumentation-tests] +in addition to [Glean's own debugging mechanisms][glean-debug]. + +## IPC + +Firefox Desktop is made of multiple processes. +You can record data from any process in Firefox Desktop +[subject to certain conditions](../dev/ipc.md). + +If you will be recording data to this metric in multiple processes, +you should make yourself aware of those conditions. + +## Where do I Define new Metrics and Pings? + +Metrics and pings are defined in their definitions files +(`metrics.yaml` or `pings.yaml`, respectively). +But where can you find `metrics.yaml` or `pings.yaml`? + +If you're not the first person in your component to ask that question, +the answer is likely "in the root of your component". +Look for the definitions files near to where you are instrumenting your code. +Or you can look in +`toolkit/components/glean/metrics_index.py` +to see the list of all currently-known definitions files. + +If you _are_ the first person in your component to ask that question, +you get to choose where to start them! +We recommend adding them in the root of your component, next to a `moz.build`. +Be sure to link to this document at the top of the file! +It contains many useful tidbits of information that anyone adding new metrics should know. +Preferably, use this blank template to get started, +substituting your component's `product :: component` tag from +[the list](https://searchfox.org/mozilla-central/source/toolkit/components/glean/tags.yaml): + +```yaml +# 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/. + +# Adding a new metric? We have docs for that! +# https://firefox-source-docs.mozilla.org/toolkit/components/glean/user/new_definitions_file.html + +--- +$schema: moz://mozilla.org/schemas/glean/metrics/2-0-0 +$tags: + - 'Your Product :: Your Component' + +``` + +If you add a new definitions file, be sure to edit +`toolkit/components/glean/metrics_index.py`, +adding your definitions files to the Python lists therein. +If you don't, no API will be generated for your metrics and your build will fail. +You will have to decide which products your metrics will be used in. +For code that's also used in other Gecko-based products (Firefox Desktop, Firefox for Android, Focus for Android), use `gecko_metrics`. +For Desktop-only instrumentation use `firefox_desktop_metrics`. +For other products use their respective lists. + +Changes to `metrics_index.py` are automatically reflected in the data pipeline once a day +using the [fog-updater automation in probe-scraper](https://github.com/mozilla/probe-scraper/tree/main/fog-updater). +Data will not show up in datasets and tools until this happens. +If something is unclear or data is not showing up in time you will need to file a bug in +`Data Platform and Tools :: General`. + +If you have any questions, be sure to ask on +[the #glean channel](https://chat.mozilla.org/#/room/#glean:mozilla.org). + +**Note:** Do _not_ use `toolkit/components/glean/metrics.yaml` +or `toolkit/components/glean/pings.yaml`. +These are for metrics instrumenting the code under `toolkit/components/glean` +and are not general-purpose locations for adding metrics and pings. + +## How does Expiry Work? + +In FOG, +unlike in other Glean-SDK-using projects, +metrics expire based on Firefox application version. +This is to allow metrics to be valid over the entire life of an application version, +whether that is the 4-6 weeks of usual releases or the 13 months of ESR releases. + +There are three values accepted in the `expires` field of `metrics.yaml`s for FOG: +* `"X"` (where `X` is the major portion of a Firefox Desktop version) - + The metric will be expired when the `MOZ_APP_VERSION` reaches or exceeds `X`. + (For example, when the Firefox Version is `88.0a1`, + all metrics marked with `expires: "88"` or lower will be expired.) + This is the recommended form for all new metrics to ensure they stop recording when they stop being relevant. +* `expired` - For marking a metric as manually expired. + Not usually used, but sometimes helpful for internal tests. +* `never` - For marking a metric as part of a permanent data collection. + Metrics marked with `never` must have + [instrumentation tests](instrumentation_tests). + +For more information on what expiry means and the +`metrics.yaml` format, see +[the Glean SDK docs](https://mozilla.github.io/glean/book/user/metric-parameters.html) +on this subject. Some quick facts: + +* Data collected to expired metrics is not recorded or sent. +* Recording to expired metrics is not an error at runtime. +* Expired metrics being in a `metrics.yaml` is a linting error in `glean_parser`. +* Expired (and non-expired) metrics that are no longer useful should be promptly removed from your `metrics.yaml`. + This reduces the size and improves the performance of Firefox + (and speeds up the Firefox build process) + by decreasing the amount of code that needs to be generated. + +[instrumentation-tests]: ./instrumentation_tests +[glean-debug]: https://mozilla.github.io/glean/book/reference/debug/index.html |