本快速入門導覽課程將引導您熟悉
元件檢查。您會瞭解如何將檢查功能整合至
使用專屬於您的元件,並使用
ffx inspect
。
如需「檢查」概念的詳細逐步操作說明,請參閱 檢查程式碼研究室。
專案設定
請參閱下方您所選擇語言的快速入門指南:
C++
本節假設您要編寫非同步元件,而且
元件的某些部分 (通常是 main.cc
) 如下所示:
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
auto context_ = sys::ComponentContext::CreateAndServeOutgoingDirectory();
// ...
loop.Run();
這會設定非同步迴圈,建立 ComponentContext
包裝控點
然後從其他部分執行
初始化工作
在 BUILD.gn
檔案中加入檢查程式庫依附元件:
"//sdk/lib/inspect/component/cpp",
"//sdk/lib/sys/cpp",
新增下列項目:
#include <lib/inspect/component/cpp/component.h>
加入下列程式碼來初始化檢查作業:
inspector_ = std::make_unique<inspect::ComponentInspector>(async_get_default_dispatcher(),
inspect::PublishOptions{});
您現在正在使用檢查功能!在「檢查」樹狀結構中建立屬性,方法是附加以下副本: 寫入根節點:
// Attach properties to the root node of the tree
inspect::Node& root_node = inspector_->root();
// Important: Hold references to properties and don't let them go out of scope.
auto total_requests = root_node.CreateUint("total_requests", 0);
auto bytes_processed = root_node.CreateUint("bytes_processed", 0);
如需完整的資料清單,請參閱支援的資料類型 。
健康狀態檢查
健康狀態檢查子系統提供的標準化檢查指標 元件健康狀態您可以使用健康狀態節點 元件:
inspector_->Health().StartingUp();
// ...
inspector_->Health().Ok();
測試
如要測試檢查程式碼,您可以使用 //sdklib/inspect/testing/cpp/inspect.h:
#include <lib/inspect/cpp/inspect.h>
#include <lib/inspect/testing/cpp/inspect.h>
#include <gtest/gtest.h>
using namespace inspect::testing;
這個程式庫包含一組完整的比對器,可用來驗證 檢查樹狀結構。
// Validate the contents of the tree match
auto hierarchy_result = inspect::ReadFromVmo(inspector_.DuplicateVmo());
ASSERT_TRUE(hierarchy_result.is_ok());
EXPECT_THAT(hierarchy_result.take_value(),
NodeMatches(AllOf(PropertyList(::testing::UnorderedElementsAre(
UintIs("bytes_processed", 24), UintIs("total_requests", 2))))));
荒漠油廠
本節假設您要編寫非同步元件,而且
部分元件 (通常是 main.rs
) 看起來與以下內容類似:
async fn main() -> Result<(), Error> {
// ...
let mut service_fs = ServiceFs::new();
// ...
service_fs.take_and_serve_directory_handle().unwrap();
service_fs.collect::<()>().await;
Ok(())
}
在 BUILD.gn
檔案中加入檢查程式庫依附元件:
"//src/lib/diagnostics/inspect/runtime/rust",
"//src/lib/diagnostics/inspect/rust",
加入下列程式碼來初始化檢查作業:
// This creates the root of an Inspect tree
// The Inspector is a singleton that you can access from any scope
let inspector = fuchsia_inspect::component::inspector();
// This serves the Inspect tree, converting failures into fatal errors
let _inspect_server_task =
inspect_runtime::publish(inspector, inspect_runtime::PublishOptions::default());
您現在正在使用檢查功能!在「檢查」樹狀結構中建立屬性,方法是附加以下副本: 寫入根節點:
// Attach properties to the root node of the tree
let root_node = inspector.root();
let total_requests = root_node.create_uint("total_requests", 0);
let bytes_processed = root_node.create_uint("bytes_processed", 0);
如需完整的資料清單,請參閱支援的資料類型 。
健康狀態檢查
健康狀態檢查子系統提供的標準化檢查指標 元件健康狀態您可以使用健康狀態節點 元件:
fuchsia_inspect::component::health().set_starting_up();
// ...
fuchsia_inspect::component::health().set_ok();
測試
如要測試檢查程式碼,可以使用 assert_data_tree
來驗證
「檢查項目」樹狀結構中的內容:
// Get a reference to the root node of the Inspect tree
let inspector = fuchsia_inspect::component::inspector();
// ...
// Validate the contents of the tree match
diagnostics_assertions::assert_data_tree!(inspector, root: {
total_requests: 2u64,
bytes_processed: 24u64,
});
檢查程式庫
現在您已擁有 root_node
,可以開始建構
階層本節說明一些重要的概念和模式
,協助你開始使用 Google Cloud。
- 節點可包含任意數量的鍵/值組合 (稱為「屬性」)。
- 值的鍵一律為 UTF-8 字串,值可以是 支援的類型。
節點可能包含任意數量的子項,也就是「節點」。
C++
上述程式碼可讓您存取名為
「root」。hello_world_property
是包含字串值的屬性
(改編為 StringProperty)。
- 值和節點是在父項節點下建立。
Node
類別有適合各種類型的創作者方法
支援的值。「hello_world_property
」是使用以下用途建立:
CreateStringProperty
。您可以在根節點下建立子項
呼叫 root_node.CreateChild("child name")
。請注意,名稱必須
一律為 UTF-8 字串。
- 值和節點具有嚴格的擁有權語意。
hello_world_property
擁有屬性。刪除後會刪除
範圍外) 基礎資源遭到刪除且不再顯示
位於元件的「檢查」輸出內容中子項節點也是如此。
如果您建立的值不需要修改,請使用
ValueList
敬上
保持應用程式存留狀態
直到不再需要時
- 檢查時,會盡可能盡全力進行檢查。
由於空間有限,檢查程式庫可能無法滿足
Create
要求。您的程式碼不會出現這個錯誤:您會
接收節點/資源物件,取得方法為免人工管理。
- 模式:將子項節點傳遞至子項物件。
在建構函式中加入 inspect::Node
引數會很實用
打造專屬於自己的課程父項物件,應有自己的
inspect::Node
,之後可能會傳入 CreateChild(...)
的結果
套用至子項:
class Child {
public:
Child(inspect::Node my_node) : my_node_(std::move(my_node)) {
// Create a string that doesn't change, and emplace it in the ValueList
my_node_.CreateString("version", "1.0", &values_);
// Create metrics and properties on my_node_.
}
private:
inspect::Node my_node_;
inspect::StringProperty some_property_;
inspect::ValueList values_;
// ... more properties and metrics
};
class Parent {
public:
// ...
void AddChild() {
// Note: inspect::UniqueName returns a globally unique name with the specified prefix.
children_.emplace_back(my_node_.CreateChild(inspect::UniqueName("child-")));
}
private:
std::vector<Child> children_;
inspect::Node my_node_;
};
荒漠油廠
Rust 程式庫提供兩種管理節點和屬性的方式:建立 以及錄製文字
使用 create_*
方法時,屬性或節點物件的擁有權屬於
。捨棄傳回的物件時,該屬性會遭到移除。
例如:
{
let property = root.create_int("name", 1);
}
本例中的 property
超出範圍,因此資源減少
物件。讀者不會看到這項資源。
使用 record_*
方法時,屬性的生命週期會與父項相關聯
節點。刪除節點時,記錄的屬性也會一併刪除。
{
let node = root.create_child("name");
{
node.record_uint(2); // no return
}
// The uint property will still be visible to readers.
}
在這個範例中,讀者可以看到與 name
相關聯的 uint 屬性
直到父項 node
超出範圍
動態價值
本節說明在符合下列條件的節點檢查程式庫中: 在讀取時延遲加載。這些方法接受回呼函式,而不是 值。系統讀取屬性值時,會叫用回呼函式。
C++
C++ 程式庫有兩個用於動態值的屬性建立者:
《CreateLazyNode
》和《CreateLazyValues
》。
這兩種方法都會採用回呼,針對
inspect::Inspector
,唯一的差別在於動態值是
儲存在樹狀結構中。
root->CreateLazyNode(name, callback)
會建立子節點
帶有指定的 name
的 root
。callback
會針對
將根節點分割為父項階層的 inspect::Inspector
因此,系統會在您閱讀時提供快訊以下範例顯示名為「lazy」的子項存在的
字串屬性 "version"而且有一個額外呼叫了
「延遲」。
root->CreateLazyValues(name, callback)
的運作方式與 root->CreateLazyNode(name,
callback)
類似,但承諾根節點上的所有屬性和子節點
直接新增為值
轉換為原始 root
。在這個例子的第二個輸出內容中
系統不會顯示延遲節點,而且這些值會平併成
root
。
root->CreateLazy{Node,Values}("lazy", [] {
Inspector a;
a.GetRoot().CreateString("version", "1.0", &a);
a.GetRoot().CreateLazy{Node,Values}("lazy", [] {
Inspector b;
b.GetRoot().RecordInt("value", 10);
return fpromise::make_ok_promise(std::move(b));
}, &a);
return fpromise::make_ok_promise(std::move(a));
});
輸出 (CreateLazyNode):
root:
lazy:
version = "1.0"
lazy:
value = 10
輸出 (CreateLazyValues):
root:
value = 10
version = "1.0"
CreateLazy{Node,Values}
傳回的值是擁有的 LazyNode
傳遞的回呼。LazyNode
呼叫後,系統一律不會呼叫回呼
已刪除。刪除 LazyNode
與執行
回呼,刪除作業會遭到封鎖,直到回呼傳回為止
我們的承諾
如果您想以動態方式公開 this
上的屬性,只需
寫入以下內容:
class Employee {
public:
Employee(inspect::Node node) : node_(std::move(node)) {
calls_ = node_.CreateInt("calls", 0);
// Create a lazy node that populates values on its parent
// dynamically.
// Note: The callback will never be called after the LazyNode is
// destroyed, so it is safe to capture "this."
lazy_ = node_.CreateLazyValues("lazy", [this] {
// Create a new Inspector and put any data in it you want.
inspect::Inspector inspector;
// Keep track of the number of times this callback is executed.
// This is safe because the callback is executed without locking
// any state in the parent node.
calls_.Add(1);
// ERROR: You cannot modify the LazyNode from the callback. Doing
// so may deadlock!
// lazy_ = ...
// The value is set to the result of calling a method on "this".
inspector.GetRoot().RecordInt("performance_score",
this->CalculatePerformance());
// Callbacks return a fpromise::promise<Inspector>, so return a result
// promise containing the value we created.
// You can alternatively return a promise that is completed by
// some asynchronous task.
return fpromise::make_ok_promise(std::move(inspector));
});
}
private:
inspect::Node node_;
inspect::IntProperty calls_;
inspect::LazyNode lazy_;
};
荒漠油廠
請參閱 C++ 動態值支援,瞭解 Rust 中的類似概念。
範例:
root.create_lazy_{child,values}("lazy", [] {
async move {
let inspector = Inspector::default();
inspector.root().record_string("version", "1.0");
inspector.root().record_lazy_{node,values}("lazy", || {
let inspector = Inspector::default();
inspector.root().record_int("value", 10);
// `_value`'s drop is called when the function returns, so it will be removed.
// For these situations `record_` is provided.
let _value = inspector.root().create_int("gone", 2);
Ok(inspector)
});
Ok(inspector)
}
.boxed()
});
Output (create_lazy_node):
root:
lazy:
version = "1.0"
lazy:
value = 10
Output (create_lazy_values):
root:
value = 10
version = "1.0"
字串參照
C++
您可以使用 inspect::StringReference
來減少記憶體用量
包含大量重複資料的檢查階層舉例來說:
using inspect::Inspector;
Inspector inspector;
for (int i = 0; i < 100; i++) {
inspector.GetRoot().CreateChild("child", &inspector);
}
檢查中會包含 100 則 "child"
字串的副本
輸出內容
或者,
using inspect::Inspector;
using inspect::StringReference;
namespace {
const StringReference kChild("child");
}
Inspector inspector;
for (int i = 0; i < 100; i++) {
inspector.GetRoot().CreateChild(kChild, &inspector)
}
只會產生一個 "child"
的副本,且該副本已參照 100 次。
這樣為每個子節點節省 16 個位元組,費用為 32 個位元組 共用資料並省下了 1,568 個位元組。
建議您在任何會使用全域常數鍵的地方使用這個模式。
荒漠油廠
Rust Inspect 會自動刪除重複的字串名稱。例如:
use fuchsia_inspect::Inspector;
let inspector = Inspector::default();
for _ in 0..100 {
inspector.root().record_child("child");
}
只會產生 1 份 "child"
的副本,且已參照 100 次。
這樣為每個子節點節省 16 個位元組,費用為 32 個位元組 共用資料並省下了 1,568 個位元組。
查看檢查資料
您可以使用 ffx inspect
指令查看「檢查」資料
您從元件匯出的文字
本節假設您對執行中的 Fuchsia 系統具有 SSH 存取權
開始執行元件我們將使用
my_component.cm
做為元件資訊清單名稱的預留位置。
讀取檢查資料
下列指令會顯示所有元件的檢查階層 系統中執行的映像檔:
ffx inspect show
使用 ffx inspect list
的輸出內容就能指定
單一元件 (例如 my_component.cm
) 做為輸入內容
ffx inspect show
:
ffx inspect show --manifest my_component.cm
在上方指定 --manifest
會傳回所有執行個體的資料
系統所執行元件的程序如果您知道
元件 (例如 core/my_component
)
可能會傳遞該值:
ffx inspect show core/my_component
您可以指定多個元件 (例如 core/font_provider
和 core/my_component
):
ffx inspect show core/font_provider core/my_component
您也可以指定節點和屬性值。為了瞭解
所有可能的選取器清單,請使用 ffx inspect selectors
:
ffx inspect selectors core/my_component
接著,您可以指定選取器 (例如 core/my_component:root
)
做為 ffx inspect show
的輸入內容:
ffx inspect show core/my_component:root
如果不知道元件使用的路徑名稱,可以使用
--manifest
具有套用至所有相符元件的選取器
monikers (使用 *
):
ffx inspect show --manifest my_component.cm *:root
如果您遵循建議的操作,系統就會輸出以下內容 上述步驟:
root:
hello = world
在測試環境中列印檢查項目
使用 JSON 美化印表機取得完整清單。例如:
use diagnostics_assertions::JsonGetter;
...
#[fuchsia::test]
fn my_test() {
let inspect = fuchsia_inspect::component::inspector();
...
print!("{}", inspect.get_pretty_json());
}
支援的資料類型
類型 | 說明 | 附註 |
---|---|---|
IntProperty | 包含帶正負號 64 位元整數的指標。 | 所有語言 |
UIntProperty | 包含無正負號 64 位元整數的指標。 | Dart 不支援 |
DoubleProperty | 包含雙浮點數的指標。 | 所有語言 |
BoolProperty | 包含雙浮點數的指標。 | 所有語言 |
{Int,Double,Uint}陣列 | 指標類型的陣列,包括各種直方圖的型別包裝函式。 | 支援的語言與基本指標類型相同 |
StringArray | 字串陣列。以 StringReference 表示。 | 不適用於 Dart。 |
StringProperty | 包含 UTF-8 字串值的屬性。 | 所有語言 |
ByteVectorProperty | 具有任意位元組值的屬性。 | 所有語言 |
節點 | 指標、屬性等節點下可能包含巢狀結構的節點。 | 所有語言 |
LazyNode | 動態例項化節點的完整樹狀結構。 | C++、Rust |