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 probe expire no later than Firefox 98 (scheduled for 2021-12-02).
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
, orEvents.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 | Scalar of kind: boolean |
labeled_boolean | Keyed scalar of kind: boolean |
counter | Scalar of kind: uint |
labeled_counter | Keyed Scalar of kind: uint |
string | Scalar of kind: string |
labeled_string | No Supported Telemetry Type |
string_list | Keyed Scalar of kind: boolean. 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 | Scalar of kind: uint. The value is in units of milliseconds. |
timing_distribution | Histogram of kind "linear" or "exponential". Samples will be in units of milliseconts. |
memory_distribution | Histogram of kind "linear" or "exponential". Samples will be in memory_unit units. |
custom_distribution | Histogram of kind "linear" or "exponential". Samples will be used as is. Ensure the bucket count and range match. |
uuid | Scalar of kind: string. 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 which the uuid metric remains empty. Calling GenerateAndSet on the uuid is not mirrored, and will log a warning. |
datetime | Scalar of kind: string. Value will be in ISO8601 format. |
events | Events. The value field will be left empty. |
quantity | Scalar of kind: uint |
rate | Keyed Scalar of kind: uint. The keys are "numerator" and "denominator". Does not work for rate metrics with external denominators. |
The telemetry_mirror
property in metrics.yaml
¶
You must use the C++ enum value of the Histogram, Scalar, or Event being mirrored to.
For example, for this Scalar of kind boolean
:
category.name:
probe_name:
kind: boolean
...
You must provide the following telemetry_mirror
name for its source
boolean
metric’s definition:
telemetry_mirror: CATEGORY_NAME_PROBE_NAME
If you get this wrong it will manifest as a build error.
Artifact Build Support¶
Sadly, GIFFT will have no support for Artifact builds even when support is added to FOG. 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. 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
sent by default in the Glean “metrics” ping mirrored to a
Scalar of kind: uint
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.
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 InvalidLabel
as a label that doesn’t conform to the format
(it has upper-case letters)
see that the labeled_boolean
metric
correctly ascribes it to __other__
whereas the mirrored Keyed Scalar with kind boolean stores and retrieves it without change:
Glean.testOnly.mirrorsForLabeledBools.InvalidLabel.set(true);
Assert.equal(true, Glean.testOnly.mirrorsForLabeledBools.__other__.testGetValue());
let snapshot = Services.telemetry.getSnapshotForKeyedScalars().parent;
Assert.equal(true, snapshot["telemetry.test.mirror_for_labeled_bool"]["InvalidLabel"]);
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 for details on how disabled Telemetry Events behave.