| RFC-0171:改进了诊断路由 | |
|---|---|
| 状态 | 已接受 |
| 区域 |
|
| 说明 | 引入了 CML 和 CMC 实用程序,以改进诊断路由 |
| 问题 | |
| Gerrit 更改 | |
| 作者 | |
| 审核人 | |
| 提交日期(年-月-日) | 2022-05-19 |
| 审核日期(年-月-日) | 2022-06-23 |
摘要
一项在 cmc 和 CML 中提供实用程序的提案,旨在简化树中各处的诊断协议(fuchsia.logger.LogSink 和 fuchsia.diagnostics.InspectSink)的路由,并减少缺少日志或检查数据带来的 DX 痛点。虽然本文档侧重于检查和日志记录,但它也可用于提高大多数组件可能希望可用的其他协议(例如 fuchsia.tracing.provider.Registry)的可用性。
设计初衷
使用日志的 DX 痛点在于,组件需要将 fuchsia.logger.LogSink 路由到各个位置:生产组件、测试、RealmBuilder 路由等。日志是大多数 Fuchsia 体验的核心部分,我们希望几乎每个组件和测试都能使用日志。
RFC-0168 提议使用协议 fuchsia.inspect.InspectSink,该协议将允许组件发布 Inspect,从而带来一些改进并减少技术债务。与 fuchsia.logger.LogSink 类似,我们希望所有(或至少大多数)组件都使用 Inspect 检测。现在,每个组件都可以进行 expose /diagnostics to framework,这使得每个组件都可以公开检查并将其提供给 Archivist。在转向协议的过程中,我们必须确保所有组件都能继续公开检查数据,这对于开发者在运行时调试组件的行为非常有价值。
这不符合人体工程学,而且容易出错,因为我们需要更新所有 CML,以手动将此协议路由到当前正在写入 Inspect 的所有组件。LogSink 也存在同样的问题,尤其是在测试中,很容易忘记将 LogSink 路由到被测组件,从而导致日志丢失并浪费开发者时间。
组件管理器利用组件的 LogSink 来打印归因于该组件的路由错误。这有助于改善开发者体验,因为开发者可以快速发现路由错误。不过,如果 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 文档的形式进行了社会化,该文档是一份决策文档,其中详细讨论了列出的替代方案,并召开了利益相关者会议和对话。
设计
为了让开发者在当前组件功能路由系统下更轻松地查看日志和检查,并遵循最小权限和分层隔离原则,同时继续能够公开检查,我们将开发以下内容:
cmc必需的优惠检查器。- 能够为 CML 中的所有儿童和集合提供功能。
- 用于诊断的新 CML 分片。
RealmBuilder会自动为所有组件提供诊断功能。
cmc 个必需的优惠和使用次数
cmc 将获得一个命令行选项 --must-offer-protocol,其中包含一个协议名称列表,它将验证以下语句是否为真:
对于清单中声明的每个子级和集合,对于必需协议列表中的每种协议,都存在从某个来源到该子级/集合的
OfferDecl。
此外,cmc 将获得一个等效的命令行选项 --must-use-protocol,该选项将检查等效性,但针对的是 UseDecl。
GN 和 Bazel 工具将更新为在调用 cmc 时,在这些选项中传递 fuchsia.logger.LogSink 和 fuchsia.diagnostics.InspectSink。
如果开发者希望完全停用此检查,无论其清单如何调用 cmc,都可以向其 CML 文件添加以下内容(这是 CML 中引入的新语法):
{
disable: {
must_use_protocol: [ "fuchsia.logger.LogSink", "fuchsia.diagnostics.InspectSink" ],
must_offer_protocol: [ "fuchsia.logger.LogSink", "fuchsia.diagnostics.InspectSink" ],
}
}
如果开发者不希望将 LogSink 或 InspectSink 路由到部分子账号,可以自由选择以下任一做法:
- 使用可选功能路由:将协议
from: "void"路由到要关闭单个优惠的子级/集合。 - 手动从所需来源路由协议。
这些功能所源自的 bootstrap 和 root 领域需要进行一些特殊处理:
bootstrap:将启用此选项,以确保LogSink路由到引导加载程序中的所有组件。此外,它还会将来自void的Inspect/LogSink优惠添加到 Archivist。root:将启用此选项,以确保我们将来自 Archivist 的LogSink路由到其所有同级。由于bootstrap是公开此功能的实体,因此我们将从void向bootstrap添加Inspect/LogSink优惠。
我们希望通过这种方式,让 Fuchsia 上的每位开发者都不太可能因疏忽而错过日志或检查数据。
zarvox@ 为此部分构建了原型(和关系链)。
允许向 CML 中的所有儿童和合集提供功能
为了改进路由到所有子项的开发者体验,我们将在 CML 中引入语法糖,以允许将功能路由到“所有子项和集合”。
此语法糖可按如下方式使用:
offer: [
{
protocol: "fuchsia.logger.LogSink",
from: "parent",
to: "all",
}
]
当包含该语法的 CML 文件被编译时,系统将生成 N 个 OfferDecl,其中 N 是相应组件拥有的集合和子项的总数。
具有目标 all 的 OfferDecl 将在 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.cml和syslog/offer.shard.cml。inspect/client.shard.cml:包括inspect/use.shard.cml和inspect/offer.shard.cml。
仅执行路由而不执行任何程序的逻辑组件可以使用 offer.shard.cml。需要使用这些协议但需要配置要路由到其子级的组件可以使用 use.shard.cml。其余用户可以使用标准且便捷的 client.shard.cml。
如果某个组件没有子级或集合,但仍使用 client.shard.cml(因为它使用的是协议),那么由于 offer to all 语句只是扩展为 OfferDecl 的语法糖,因此该语句在分片中将不会执行任何操作。
为方便起见,我们将提供一个包含这两个 client.shard.cml 文件的 diagnostics/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 会自动将这些协议路由到所有组件。这可能与
cmc和 CML 中采用的方法不太一致,但RealmBuilderAPI 在某些方面已经有所不同,以提供更便捷的工作流程,更好地适应测试。鉴于我们预计 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;
实现
- 更新了
cmc,以支持 CML 中的新标志和offer to all。 - 添加包含
offer LogSink to all的syslog/offer.shard.cml。 - 更新了树中的
cmc用法,以使用新标志并更新可能缺少路由的现有 CML。GN 和 Bazel SDK 将会更新,但在 OOT CML 迁移为具有完整的一组产品之前,默认会使用[]作为一组必需的协议。 - 更新了树外的
cmc用法,以使用新标志并更新可能缺少路由的现有 CML(利用了优惠分片)。 - 更新了 GN 和 Bazel SDK,以要求使用诊断协议。
- 包含
syslog/client.shard.cml中的syslog/offer.shard.cml。 - 推出后,重构使用 offer 分片但不再需要它的 OOT 清单,因为该分片已通过客户端分片包含在内。
性能
cmc 将执行一些额外的工作,但预计不会对编译时间产生任何重大影响。
安全注意事项
此更改符合组件框架安全属性,尤其是最小权限原则和分层隔离原则。
隐私注意事项
无隐私保护方面的影响。
测试
新的 cmc 功能将进行单元测试。
文档
cmc 将更新为包含新选项,CML 将更新为描述新的 offer to all 功能。
缺点、替代方案和未知因素
在 Environment 中使用 debug_capabilities
这是考虑的主要替代方案。在这种替代方案下,我们会扩展 fuchsia.sys2.Environment,使其具有 diagnostics_capabilities(就像 debug_capabilities 一样),或者将 debug_capabilities 转换为 diagnostics_capabilities,或者仅将 debug_capabilities 用于诊断协议,从而使树 from: diagnostics 或 from: debug 中的任何组件都可以使用它们。
此功能将在组件管理器安全政策中受到限制,以确保它仅由根 Archivist 和嵌入在测试中的 Archivist 使用。
优点:
- 每个组件都可以使用树中任何位置的
InspectSink和LogSink。 - 与当前世界状态保持一致,其中每个组件都可以公开检查。
- 改进了开发者体验,因为开发者无需花费时间来弄清楚为什么其组件未记录日志,从而发现他们在测试中缺少了优惠。
- 可以静态检查功能的使用情况。
- 除非组件明确使用该功能,否则其命名空间中最初没有任何内容。
- 涵盖通过
fuchsia.component.Realm/CreateChild创建的动态组件。
缺点:
- 不再提供明确的父级/子级产品,这意味着这不符合分层隔离的安全原则。
- 替换或模拟拓扑中的
LogSink/InspectSink需要调整环境,这需要更改安全政策。 - 没有采用自食其狗粮的做法 - 第三方开发者无法出于任意目的使用环境来开发协议,为什么我们却可以?
将 LogSink 和 InspectSink 设为框架功能
允许使用这些协议 from: framework。归档器可以将这些功能公开给框架,也可以通过归档器与组件管理器之间的合约来提供这些功能。
优点:
- 与上一个替代方案的优点相同,但不同之处在于,即使诊断协议(
InspectSink和LogSink)不是由组件管理器提供服务的,也会成为框架协议。 - 无需进行功能归因,因为归因会直接在框架中进行,每个组件都有自己的一组独特的框架功能。
缺点:
- 缺点与上一个替代方案相同。
- 从框架(而非 Component Manager 本身)使用的协议的第一个实例。
- 不清楚如何在测试中提供隔离的日志,而无需构建供 Test Manager 使用的额外机制。
- 为所有组件建立一个设备范围内的单一日志目的地。
自动向所有儿童提供 cmc 优惠 LogSink
cmc 不会使用一个标志来请求用户向其 CML 添加 OfferDecl,而是会自动为每个子项和集合执行此操作。
优点:
- 显式的父子产品,可帮助进行模拟、替换拓扑中的协议等。
- CML 中没有变化。
缺点:
- CMC 中对功能进行的特殊处理。
- 在
.cml中声明的组件与通过Realm/CreateChild构建的组件的行为不一致。
在 cmc 中提供选项并在 CML 中提供语法糖,可使此功能更加灵活,并提供一种可供他人利用的机制,不仅可用于诊断。
不执行任何操作,照常进行路由
让开发者手动向所有子女提供 LogSink 和 InspectSink。
优点:
- 显式的父子产品,可帮助进行模拟、替换拓扑中的协议等。
- API 边界仍然是父级和子级之间的本地问题,而不是涉及其他方的边界。
缺点:
- 当前存在的问题:很容易错过路由 LogSink,导致在调试测试时浪费时间。
- 其他问题:很容易错过将路由
InspectSink传递给某个组件(鉴于现在每个人都可以公开它),从而导致现场缺少诊断信息。这与 LogSink 存在的问题相同,因此现在我们有两个协议存在此问题,而不是只有一个。
鉴于这些协议的广泛使用,我们认为在 cmc 和 CML 中添加其他选项有助于降低错过路线的可能性。
其他想法
我们还讨论了其他想法,例如使用功能包来路由包含这两种协议的 diagnostics 包,或者以网域或功能源的形式改进环境。鉴于有计划审核路由 API,因此我们舍弃了这些方案,转而采用使用现有机制和 API 的短期解决方案。
在先技术和参考资料
不适用