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,讓每個元件都能公開檢查,並提供給 Archivist。朝向通訊協定發展時,我們必須確保所有元件都能繼續公開檢查資料,這對開發人員來說非常重要,有助於在執行階段偵錯元件的行為。

這不符合人體工學,且容易出錯,因為我們需要更新所有 CML,才能手動將這個通訊協定路由至目前正在編寫 Inspect 的所有元件。LogSink 也有同樣的問題,尤其是在測試中,很容易忘記將 LogSink 路由至受測元件,導致記錄遺失,浪費開發人員的時間。

元件管理服務會利用元件的 LogSink,列印歸因於該元件的路由錯誤。這項功能可讓開發人員快速發現路由錯誤,進而提升 DX。不過,如果 LogSink 未正確路由,這些錯誤最終會歸因於元件管理服務的全域系統記錄,開發人員查看自己的元件記錄時,更容易忽略這些錯誤。

本文嘗試在 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.LogSinkfuchsia.diagnostics.InspectSink 傳遞至這些選項。

如要完全停用這項檢查,無論如何為資訊清單呼叫 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 從 Archivist 轉送至所有同層級項目。由於 bootstrap 是公開這項能力的項目,我們會將 void 中的優惠新增至 bootstrapInspect/LogSink

我們希望藉此減少 Fuchsia 開發人員錯過記錄或檢查資料的機率。

zarvox@ 為這個部分建構了原型 (和關係鏈)。

允許向 CML 中的所有孩子和集合提供能力

為改善所有子項的路由傳送 DX,我們將在 CML 中導入語法糖,允許將路由傳送能力「傳送至所有子項和集合」。

這個語法糖可依下列方式使用:

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

編譯含有該語法的 CML 檔案時,系統會產生 N 個 OfferDecl,其中 N 是元件擁有的集合和子項總數。

系統會在 cmc 中設下閘道,確保 OfferDecl 僅以目標 all 使用,且僅限於前一節所述新選用引數中定義的通訊協定。

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 (因為使用通訊協定),則由於這是語法糖,只會展開為 OfferDecl,因此分片中的 offer to all 陳述式會是無運算。

為方便起見,我們會提供包含這兩個 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 採用的方法不一致,但 RealmBuilder API 已在某些領域有所不同,可提供更便利的工作流程,更適合用於測試。由於我們預期 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 會更新,但直到 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,使其具有 diagnostics_capabilities,就像 debug_capabilities 一樣,或是將 debug_capabilities 變成 diagnostics_capabilities,或僅將 debug_capabilities 用於診斷通訊協定,讓樹狀結構中的任何元件 from: diagnosticsfrom: debug 都能使用。

這項功能會在元件管理服務安全性政策中受到限制,確保只有根 Archivist 和測試中嵌入的 Archivist 才能使用。

優點

  • 樹狀結構中的任何元件都可以使用 InspectSinkLogSink
  • 與世界現況一致,每個元件都可以公開檢查。
  • 開發人員不必花時間找出元件未記錄的原因,也不必在測試中尋找缺少的供應項目,因此 DX 獲得提升。
  • 可靜態檢查能力點對點使用情形。
  • 除非明確使用能力,否則所有元件的命名空間都會以「nothing」開頭。
  • 涵蓋透過 fuchsia.component.Realm/CreateChild 建立的動態元件。

缺點

  • 不再提供明確的父項/子項服務,也就是說,這與階層式隔離的安全原則不一致。
  • 如要在拓撲中取代或模擬 LogSink/InspectSink,必須調整環境,這需要變更安全政策。
  • 我們不是在「吃自己的狗食」嗎?第三方開發人員無法將環境用於通訊協定的任意用途,我們為什麼可以?

LogSinkInspectSink 設為架構功能

允許使用這些通訊協定 from: framework。封存管理員可以向架構公開這些功能,也可以與元件管理服務簽訂合約,提供這些功能。

優點

  • 與上一個替代方案的優點相同,但即使不是由元件管理服務提供服務,診斷通訊協定 (InspectSinkLogSink) 也會成為架構通訊協定。
  • 由於每個元件都有自己的一組專屬架構功能,因此架構會直接進行歸因,不需要能力歸因。

缺點

  • 缺點與上一個替代方案相同。
  • 架構中使用的通訊協定第一個執行個體,並非由元件管理服務 直接提供。
  • 不清楚如何在測試中提供獨立記錄,而不需額外建構供 Test Manager 使用的機制。
  • 為所有元件 (包括裝置) 建立單一記錄目的地。

自動向所有孩子提供 cmc 優惠 LogSink

系統不會要求使用者在 CML 中新增 OfferDecl,而是會為每個子項和集合自動執行這項操作。cmc

優點

  • 明確的父項/子項產品,有助於模擬、取代拓撲中的通訊協定等。
  • CML 沒有變更。

缺點

  • CMC 中能力的特殊處理方式。
  • .cml 中宣告的元件與透過 Realm/CreateChild 建構的元件行為不一致。

cmc 中提供選項,並在 CML 中提供語法糖,可讓這項功能更具彈性,並提供其他機制可供利用,不只用於診斷。

不採取任何行動,照常轉接

開發人員必須手動為所有子項提供 LogSinkInspectSink

優點

  • 明確的父項/子項產品,有助於模擬、取代拓撲中的通訊協定等。
  • API 邊界仍是父項和子項之間的本地問題,不會涉及其他當事人。

缺點

  • 目前的問題:很容易錯過路由 LogSink,導致偵錯測試時浪費時間。
  • 其他問題:很容易會錯過將路由 InspectSink 傳送至某些元件 (因為現在每個人都能公開),導致缺少現場診斷資訊。這與 LogSink 的問題相同,因此現在我們有兩個通訊協定,而非只有一個。

由於這些通訊協定廣為使用,我們認為在 cmcCML 中新增其他選項,有助於降低遺漏路徑的機率。

其他建議

其他討論的想法包括使用能力套件來傳送包含兩種通訊協定的套件,或以網域或能力來源的形式改善環境。diagnostics由於我們打算審查路由 API,因此捨棄了這些提案,改用現有機制和 API 提供的短期解決方案。

既有技術和參考資料

不適用