RFC-0171:改进了诊断路由

RFC-0171:改进了诊断路由
状态已接受
领域
  • 诊断
  • 组件框架
说明

引入 CML 和 CMC 实用程序,以改进诊断路由

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2022-05-19
审核日期(年-月-日)2022-06-23

摘要

提议在 cmc 和 CML 中提供实用程序以简化诊断协议的路由 (fuchsia.logger.LogSinkfuchsia.diagnostics.InspectSink)位于树中的任何位置,并减少 DX 的痛点是缺少日志或检查数据。本文档重点介绍检查和 还可以提高其他协议的可用性,而大多数组件可能 想要拥有的,例如 fuchsia.tracing.provider.Registry

设计初衷

使用日志的 DX 痛点是组件需要在所有位置路由 fuchsia.logger.LogSink: 在生产组件、测试、RealmBuilder 路由等中。日志是大多数 Fuchsia 的核心部分 我们期望的几乎每个组件和测试都会用到的体验。

RFC-0168 提议使用 fuchsia.inspect.InspectSink 协议, 允许组件发布检查,从而进行一些改进并减少技术债务。只是 例如 fuchsia.logger.LogSink,我们希望所有(或至少大部分)组件都使用 Inspect 插桩。现在,每个组件都可以 expose /diagnostics to framework,这样每个 组件公开“检查”并使其可供档案管理员使用。改用协议后 我们必须确保所有组件都能继续公开检查数据, 有助于开发者调试其组件在运行时的运行情况。

这不符合人体工程学,并且容易出错,因为我们需要更新所有 CML 以手动路由此协议 所有正在写入 Inspect 的组件。LogSink也有同样的问题 特别是在测试中,很容易忘记将 LogSink 路由到被测组件 会导致缺少日志并浪费开发者时间。

组件管理器利用组件的 LogSink 来输出归因于该组件的路由错误 组件。这改进了 DX,因为开发者可以快速发现路由错误。但是,如果 LogSink 这些错误最终会出现在归因于组件管理器的全局 syslog 中, 更易错过。

本文档尝试在 cmc 和 CML 中引入实用程序来改善这种情况, 简化将这两种协议路由到每个组件的过程。

组件框架计划审查路由 API,并概念化实现 使模型更一致且更易用。这将需要几个季度的时间,因此 最好使用现有基元并对其进行扩展。

利益相关方

教员:leannogasawara@google.com

审核者

  • crjohns@google.com
  • geb@google.com
  • hjfreyer@google.com
  • shayba@google.com
  • zarvox@google.com

已咨询

  • bryanhenry@google.com
  • cgonyeo@google.com
  • jmatt@google.com
  • thatguy@google.com

社交化:这项设计以 Google 文档文档的形式进行了社交化, 记录了频繁讨论的备选方案,以及各个 利益相关者。

设计

为了让开发者更轻松地避免错过日志,并在当前组件下进行检查 功能路由系统,遵循最小权限和分层隔离原则, 并继续公开 Inspect,因此我们将开发以下内容:

  • cmc 项必需的优惠检查工具。
  • 能够在 CML 中为所有子级和集合提供功能。
  • 用于诊断的新 CML 分片。
  • RealmBuilder 会自动为所有组件提供诊断功能。

cmc 个必需的优惠和用途

cmc 将获取命令行选项 --must-offer-protocol,其中包含 用于验证以下语句是否属实的协议名称:

对于在清单中声明的每个子项和集合,都存在来自某OfferDecl 针对所需协议列表中定义的每个协议向该来源发送来源。

此外,cmc 将获得一个等效的命令行选项 --must-use-protocol,该选项将检查 等效,但适用于 UseDecl

GN 和 Bazel 工具将进行更新,以通过 fuchsia.logger.LogSinkfuchsia.diagnostics.InspectSinkcmc

希望完全停用此检查的开发者(无论如何针对其调用 cmc) 清单可以将以下内容添加到其 CML 文件中(这是 CML 中引入的新语法):

{
    disable: {
        must_use_protocol: [ "fuchsia.logger.LogSink", "fuchsia.diagnostics.InspectSink" ],
        must_offer_protocol: [ "fuchsia.logger.LogSink", "fuchsia.diagnostics.InspectSink" ],
    }
}

如果开发者不希望将 LogSinkInspectSink 转送给自己的部分子级,可以自由 您可以:

  • 使用可选功能路由:将协议 from: "void" 路由到 子/集合。
  • 从所需的来源手动路由协议。

这些功能源自的 bootstraproot 领域将需要一些特殊的 处理:

  • bootstrap:会启用此选项,以确保 LogSink 会路由到 组件。此外,还会添加从 void到 的优惠 Inspect/LogSink 档案管理员。
  • root:将启用此选项,以确保我们将 LogSink 从归档管理员转到所有 同级。由于 bootstrap 是公开此功能的 activity,因此我们将添加一个优惠 Inspect/LogSink,从 voidbootstrap

这样,我们希望 Fuchsia 上的每个开发者都不太可能错误地遗漏日志或 检查数据。

zarvox@ 为本部分构建了一个原型(和关系链)。

允许向 CML 中的所有子项和集合提供某项功能

为了改进路由到所有子级的 DX,我们将在 CML 中引入语法糖,以允许路由 一项“所有子项和合集”功能

此语法糖可按如下方式使用:

offer: [
    {
        protocol: "fuchsia.logger.LogSink",
        from: "parent",
        to: "all",
    }
]

编译包含该语法的 CML 文件时,系统会生成 N 个 OfferDecl,其中 N 是 该组件包含的集合和子项的总数。

目标为 allOfferDecl 将在 cmc 中设有限制,仅供之前使用的协议使用 定义新的可选参数。

CML 分片

将创建以下分片:

// syslog/use.shard.cml
{
    use: [
        { protocol: "fuchsia.logger.LogSink" },
    ],
}

// syslog/offer.shard.cml
offer: [
    {
        protocol: "fuchsia.logger.LogSink",
        from: "parent",
        to: "all"
    }
]

// inspect/use.shard.cml
{
    use: [
        { protocol: "fuchsia.diagnostics.InspectSink" },
    ],
}

// inspect/offer.shard.cml
offer: [
    {
        protocol: "fuchsia.diagnostics.InspectSink",
        from: "parent",
        to: "all"
    }
]

以下现有分片将更新:

  • syslog/client.shard.cml:包括 syslog/use.shard.cmlsyslog/offer.shard.cml
  • inspect/client.shard.cml:包括 inspect/use.shard.cmlinspect/offer.shard.cml

仅执行路由而不执行任何程序的逻辑组件可以使用 offer.shard.cml。需要使用这些协议但需要配置要路由内容的组件 子女可以使用 use.shard.cml。其余客户可以使用 client.shard.cml

如果某个组件没有子级或集合,但仍使用 client.shard.cml(因为它 使用协议),那么分片中的 offer to all 语句将是一个空操作,因为它是 如前所述,扩展为 OfferDecl 的语法糖。

为方便起见,我们将提供一个同时包含这两项的 diagnostics/client.shard.cml client.shard.cml 个文件。

RealmBuilder 项更新以支持 offer to all

为方便将诊断协议路由至所有被测组件,RealmBuilder 将 接收几项更新,以允许将协议路由至所有子项和集合:

  • 自动向所有子级和集合提供 LogSink 和 InspectSink。在 Rust 中 如下所示:

    builder
        .add_route(
            Route::new()
                .capability(Capability::protocol_by_name("fuchsia.diagnostics.InspectSink"))
                .from(Ref::parent())
                .to(Ref::all()),
        )
        .await?;
    
  • 由于我们希望所有测试都执行此操作,除了一些小众场景外,RealmBuilder 将 并自动将这些协议路由到所有组件这似乎与 但 RealmBuilder API 在某些方面已偏离,以提供更多cmc 便捷的工作流,更适合测试。考虑到我们预计 99% 的时间 我们会将这些协议路由到测试组件,然后教 RealmBuilder 执行 并提供一种关闭方式:

    let builder = RealmBuilder::new().await?;
    
    let instance = builder
        .route_logs_to_all(false)     // defaults to true
        .route_inspect_to_all(false)
        .build()
        .await;
    

实现

  1. 更新了 cmc 以支持 CML 中的新标志和 offer to all
  2. 添加一个包含 offer LogSink to allsyslog/offer.shard.cml
  3. 更新树中的 cmc 用法以使用新的标志,并更新可能缺失的现有 CML 路由。系统将更新 GN 和 Bazel SDK,但对于所需的一组 SDK,系统将默认为 [] 直到 OOT CML 完成迁移,以获得完整的优惠集。
  4. 更新树外的 cmc 用法,以使用新的标志并更新可能缺失的现有 CML 路由(利用优惠分片)。
  5. 更新 GN 和 Bazel SDK,以要求使用诊断协议。
  6. 包含 syslog/client.shard.cml 中的 syslog/offer.shard.cml
  7. 滚动后,重构正在使用优惠分片但不再需要它的 OOT 清单, 因为这是通过客户端分片纳入的

性能

cmc”将执行一些额外的工作,但预计不会在 编译时间。

安全注意事项

这一变更与组件框架安全属性一致,特别是 最小权限和分层隔离原则

隐私注意事项

对隐私权没有影响。

测试

新的 cmc 功能将进行单元测试。

文档

cmc将会更新以包含这个新选项,而CML将会是 进行了更新,以说明新的 offer to all 功能。

缺点、替代方案和未知问题

Environment 中使用 debug_capabilities

这是考虑的主要备选方案。在这个替代方案下, fuchsia.sys2.Environment,以便具有与 debug_capabilities 一样的 diagnostics_capabilities,或者 将debug_capabilities转换为diagnostics_capabilities,或者仅使用debug_capabilities 以便供树中的任何组件使用, from: diagnosticsfrom: debug

该功能受到组件管理器安全政策的限制,以确保只有 root Archivist 以及嵌入测试中的 Archiveist 者。

优点

  • 每个组件都可以从树中的任何位置使用 InspectSinkLogSink
  • 与每个组件都可以公开 Inspect 的世界的当前状态保持一致。
  • 改进了 DX,因为开发者无需花时间来了解组件未记录的原因 发现他们在测试中错过了优惠。
  • 可以静态地检查功能的点对点使用情况。
  • 除非明确使用该功能,否则所有组件在其命名空间中都以“nothing”开头。
  • 涵盖通过 fuchsia.component.Realm/CreateChild 创建的动态组件。

缺点

  • 不再明确提供父级-子级优惠,也就是说,这与安全原则不符 采用分层隔离机制
  • 替换或模拟拓扑中的 LogSink/InspectSink 需要调整环境 这需要更改安全政策
  • 不吃我们自己的 dogfood - 第三方开发者不会使用环境任意自如 我们为什么要这样做?

Make LogSinkInspectSink 框架功能

允许使用这些协议:from: framework。档案管理员可以公开这些内容 或者在 Archivist 和 Component Manager 之间可以签订合同来 提供这些功能。

优点

  • 与上一个替代方案相同,但详细了诊断协议 即使不是由组件管理器提供,(InspectSinkLogSink)也会成为框架协议。
  • 无需进行功能归因,因为归因将直接在 框架,因为每个组件都有自己独特的框架功能集。

缺点

  • 与上一个替代方案相同的缺点。
  • 框架使用的协议(不是由组件管理器直接提供的)的第一个实例 :自身。
  • 不清楚如何在测试中提供隔离日志,而不构建 测试管理器使用的代码。
  • 为整个设备的所有组件建立一个日志目标位置。

cmc自动向所有子级提供 LogSink

cmc 不会使用一个标志来要求用户将 OfferDecl 添加到其 CML 中,而是会 并自动为每个子集合和合集创建这种资源

优点

  • 明确的父级-子级服务,有助于进行模拟,取代了 拓扑等
  • CML 中没有更改。

缺点

  • 在 CMC 中对功能进行特殊处理。
  • .cml 中声明的组件和通过 Realm/CreateChild

cmc 中提供选项并在 CML 中提供语法糖可使其更加灵活,并提供 其他人可以利用的机制,不仅仅是诊断。

不进行任何操作,照常规划路线

让开发者手动为其所有子级提供 LogSinkInspectSink

优点

  • 明确的父级-子级服务,有助于进行模拟,取代了 拓扑等
  • API 边界仍然是父级和子级之间的局部问题,而不是涉及到 其他方。

缺点

  • 当前问题:很容易错过路由 LogSink,导致在调试测试时损失时间。
  • 其他问题:很容易错过将 InspectSink 路由到某个组件(考虑到目前的情况) 都可能泄露,从而导致现场无法进行诊断。 所以现在我们有两种协议,而不仅仅是一个。

鉴于这些协议的广泛使用,我们认为在 cmcCML 有助于降低错过路线的可能性。

其他建议

还讨论了其他想法,例如使用功能包来路由 diagnostics bundle 以域或功能源的形式包含协议或改进环境。 这些被舍弃,取而代之的是使用现有机制和 API 的短期解决方案,因为 计划审核路由 API

先验技术和参考资料

不适用