用于 Firefox 遥测的 Glean 接口 (GIFFT)

为了使从 Firefox 遥测到 Glean 的迁移更容易,C++ 和 JS Glean API 可以配置(按指标进行)以将数据收集镜像到 Glean 指标和遥测探测器。

理想情况下,GIFFT 仅在您需要分析的数据主要仍存在于遥测中时使用,并在不再需要时立即将其移除。 建议检测人员在六个版本内使遥测镜像探测器过期。(与往常一样,如果您仍在使用它,您可以续订即将过期的探测器,但这将帮助我们更接近最终关闭遥测的时间。)

注意:GIFFT 仅适用于通过 C++ 或 JS 提供的数据。Rust Glean 指标 API 不会镜像到遥测,因为遥测没有 Rust API。

注意:使用 Glean API 会替换遥测 API。不要对同一个探测器使用这两种 API 的任何混合。

如何将 Glean 指标镜像到 Firefox 遥测探测器

要使镜像正常工作,您需要三件事

  • 兼容的 Glean 指标(在 metrics.yaml 中定义)

  • 兼容的遥测探测器(在 Histograms.jsonScalars.yamlEvents.yaml 中定义)

  • Glean 指标定义上的 telemetry_mirror 属性,用于识别遥测探测器

兼容性

此兼容性表说明了哪些遥测探测器类型可以作为哪些 Glean 指标类型的镜像

Glean 指标类型 遥测探测器类型
布尔值 类型为布尔值的标量
带标签的布尔值 类型为布尔值的键控标量
计数器 类型为无符号整数的标量
带标签的计数器 类型为无符号整数的键控标量
字符串 类型为字符串的标量
带标签的字符串 不支持的遥测类型
字符串列表 类型为布尔值的键控标量。键是字符串。值均为 true。不会镜像对带标签字符串调用 Set 的操作(因为无法从类型为布尔值的键控标量中移除键)。这样做会记录警告。
时间跨度 类型为无符号整数的标量。值为毫秒。
计时分布 类型为“线性”或“指数”的直方图。样本将以毫秒为单位。
带标签的计时分布 类型为“线性”或“指数”的键控直方图。样本将以毫秒为单位。
内存分布 类型为“线性”或“指数”的直方图。样本将以 memory_unit 为单位。
带标签的内存分布 类型为“线性”或“指数”的键控直方图。样本将以 memory_unit 为单位。
自定义分布 类型为“线性”或“指数”的直方图。样本将按原样使用。确保桶数和范围匹配。
带标签的自定义分布 类型为“线性”或“指数”的键控直方图。样本将按原样使用。确保桶数和范围匹配。
UUID 类型为字符串的标量。值为规范的 8-4-4-4-12 格式。无法保证值有效,并且镜像标量中可能存在无效值,而 UUID 指标仍然为空。不会镜像对 UUID 调用 GenerateAndSet 的操作,并且会记录警告。
URL 类型为字符串的标量。字符串化的 URL 将被裁剪到传统类型允许的最大长度。
日期时间 类型为字符串的标量。值为 ISO8601 格式。
事件 事件。如果定义并存在,则 value 字段将由名为 value 的 Glean 附加信息填充。
数量 类型为无符号整数的标量
速率 类型为无符号整数的键控标量。键为“分子”和“分母”。不适用于具有外部分母的 rate 指标。
文本 不支持的遥测类型

metrics.yaml 中的 telemetry_mirror 属性

您必须使用要镜像到的直方图、标量或事件的 C++ 枚举标识符

  • 对于直方图,遥测 C++ 枚举标识符是直方图的名称

    • 例如,WR_RENDERER_TIME 的 C++ 枚举标识符是 WR_RENDERER_TIME(请参阅 gfx/metrics.yaml

  • 对于标量,遥测 C++ 枚举标识符是标量类别和名称,使用 SCREAMING_SNAKE_CASE,并将任何 . 替换为 _

  • 对于事件,遥测 C++ 枚举标识符是事件类别、方法和对象,以 Snakey_CamelCase 呈现。

    • 例如,page_load.toplevel#content 的枚举标识符是 Page_load_Toplevel_Content(请参阅 dom/metrics.yaml

如果您使用错误的枚举标识符,则会出现构建错误。

如果您难以找到遥测镜像探测器的正确连接,可以在 <objdir>/toolkit/components/telemetry/Telemetry{Histogram|Scalar|Event}Enums.h 中的所有遥测 C++ 枚举标识符列表中找到特定值。(选择与遥测镜像类型相符的文件。)

工件构建支持

遗憾的是,GIFFT 不支持工件构建。您必须在添加镜像指标时构建 Firefox,以便 C++ 枚举值存在,即使您仅从 Javascript 使用指标也是如此。

分析注意事项

Firefox 遥测和 Glean SDK 差别很大。尽管 GIFFT 尽最大努力弥合了这些差异,但它无法解决许多问题。

以下是一些 Firefox 遥测和 Glean SDK 之间的差异在分析过程中可能表现为异常的方式。

进程、产品和渠道

与 Firefox on Glean 本身一样,GIFFT 不知道它在哪个进程、产品或渠道中进行记录。遥测知道,并对可以记录到哪些探测器以及何时记录施加限制。

确保任何遥测镜像定义中的以下字段限制不要太严格

  • record_in_processes

  • products

  • release_channel_collection/releaseChannelCollection

不匹配不会导致错误。例如,如果您在遥测镜像探测器不允许的发布渠道中记录到 Glean 指标,则 Glean 指标将有一个值,而遥测镜像探测器将没有。

还要记住,遥测探测器将其值拆分到各个进程中。Glean 指标不会这样做。在将 Glean 指标与其遥测镜像探测器进行比较时,这可能会表现为奇怪的异常现象。确保您的分析正在聚合来自所有进程的遥测值,或者定义并使用特定于进程的 Glean 指标和遥测镜像探测器以保持分离。

Ping

Glean 和遥测都根据自己的时间表发送其内置 Ping。这意味着这些 Ping 中存在的值可能不一致,因为它们反映了不同时间的状态。

例如,如果您使用 quantity(默认情况下在 Glean“metrics”Ping 中发送)测量“显示器数量”,并将该指标镜像到 类型为无符号整数的标量(默认情况下在遥测“main”Ping 中发送),那么如果用户在午夜(遥测“main”Ping 由于“daily”原因发送)和凌晨 4 点(Glean“metrics”Ping 由于“today”原因发送)之间插入第二个显示器,则 quantity 中的值将为 2,而类型为无符号整数的标量中的值将为 1

如果指标或镜像探测器在自定义 Ping 中发送,则时间表可能完全一致或完全无关。

标签

GIFFT 支持的带标签的指标遵循 Glean SDK 的 标签格式

另一方面,键控标量和键控直方图没有“无效键”的概念。Firefox 遥测几乎可以接受任何字节序列作为键。

这意味着 Glean SDK 认为无效的标签可能会出现在镜像探测器的数据中。例如,使用 72 个“1”字符作为不符合格式的标签(它超过了 71 个可打印的 ASCII 字符)。请注意,labeled_boolean 指标 正确地将其归因于 __other__,而类型为布尔值的镜像键控标量则会对其进行存储和检索而不会更改

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)]);

遥测事件

Glean 事件可以镜像到遥测事件。

为了利用遥测事件中的 value 字段,您必须首先在 metrics.yaml 文件中定义一个事件附加信息,其名称为“value”。在使用填充了“value”的 Glean 附加信息键记录事件时,GIFFT 会将其映射到遥测事件 value 属性,并将其从附加信息列表中移除,以避免重复。

数值

Glean 数值类型(counterlabeled_counterquantityratetimespan)的参数和存储格式与遥测数值类型(类型为 uint 的标量)不同。

这导致了一些显着的差异。

饱和和溢出

counterlabeled_counterrate 指标存储为 32 位有符号值。 quantity 指标存储为 64 位有符号值。 timing_distribution 样本可以是 64 位有符号值。所有这些 Glean 数值指标类型都将在其最大可表示值处饱和,或者根据 Glean 指标类型文档的“限制”部分进行饱和。

类型为 uint 的标量存储为 32 位无符号值。如果它们超过 $2^{32} - 1$ 的值,它们将溢出。

如果 Glean 数值类型饱和,它将记录类型为 invalid_overflow 的错误。在您的分析中,请检查这些错误。

数量值过大

传递给 quantity 指标的 set() 方法的值大于 $2^{32} - 1$ 将被钳位到 $2^{32} - 1$,然后再传递到指标的遥测镜像。

负值

传递给任何数值指标类型 API 的小于 0 的值将不会传递到遥测镜像。这避免了小负数被转换为极大的数字,并使遥测镜像的值更接近 Glean 指标的值。

长时间跨度

如果传递给 timespan 指标的 start()stop() 方法的毫秒数超过 $2^{32} - 1$,则传递到指标的遥测镜像的值将被钳位到 $2^{32} - 1$。

timing_distribution 指标中的样本也是如此:传递到遥测镜像直方图的值将饱和到 $2^{32} - 1$,直到它们超过 $2^{64}$ 时才会溢出。

timing_distribution 镜像:样本和总和可能不同

timing_distribution 指标中的特定值并不总是与其镜像到的直方图中的相应值一致。尽管在遥测和 Glean 的代码中对时钟的调用非常接近,但遥测的调用不在与 Glean 完全相同的指令上,并且遥测使用与 Glean (time::precise_time_ns()) 不同的时钟源 (TimeStamp::Now())。

此外,如果这些轻微的漂移恰好跨越了任一系统中存储桶的边界,样本看起来可能比您预期的差异更大。

这不会影响分析,但可能会影响测试,因此请在测试中牢记这种差异

timing_distribution 镜像:基于样本的 API 未记录

使用 accumulate_samplesaccumulate_single_sample 存储的值不会使用 GIFFT 传递到遥测镜像直方图。

应用关闭

遥测仅在ShutdownPhase::AppShutdownTelemetry,即 profile-before-change-telemetry 之前有效。在此阶段之后记录的遥测数据不会持久化。

FOG *目前* 在稍后的阶段关闭 Glean,因此能够在关闭过程中收集更深入的数据。(特定阶段目前并不是任何人要求我们保证的事情,所以这就是为什么我不精确的原因。)

这意味着,对于在关闭过程中稍后记录的数据,Glean 将报告比遥测更完整的信息。

每会话一次的标量

传统遥测标量保证至少在每个会话的遥测“主” ping 中提交一次。Glean 中的默认指标传输,“metrics” ping,至少每天提交一次。

这意味着,如果您的检测代码每会话运行一次,在您的 Glean 指标中,后续会话的值将覆盖之前的会话的值,直到提交 Glean “metrics” ping。

Glean 时间跨度指标略有不同

如果您的 Glean 指标是 timespan,后续会话的值不会覆盖之前的会话的值。相反,最早的值将保留,并将记录 invalid_state 错误。如果您希望它改为静默覆盖,请使用 quantity 而不是 timespan

要保留所有会话的值,您可以使用不同的 metric 类型

  • 对于 quantity 指标

    • 如果与时间相关,请使用 timing_distribution

    • 如果与内存相关,请使用 memory_distribution

    • 否则,请使用 custom_distribution

  • 对于 stringuuidurldatetime 指标,您可以使用 string_list

  • 对于 boolean 指标,请使用带有“true”和“false”标签的 labeled_counter

要仅在会话处于活动状态时保留会话的值,请使用 lifetime: application 并应用 no_lint: [GIFFT_NON_PING_LIFETIME],以便 Glean在每个会话的“metrics” ping 中发送该值,并在会话完成后清除它

传统遥测没有指标生命周期的概念

在将 lifetime: application 与 GIFFT 结合使用时要小心。传统遥测没有指标生命周期的概念。您最好仔细考虑正在进行的检测操作以及何时进行。

如果您有任何疑问,请联系我们寻求帮助