此 Codelab 介绍了分类实用程序:
- 用途。
- 如何运行它,包括命令行选项。
- 如何添加和测试配置规则,以检测 Fuchsia 快照中的问题。
本文档中提及的源文件和示例可从以下位置获取:
- //examples/diagnostics/triage/snapshot/inspect.json.
- //examples/diagnostics/triage/rules.triage.
- //examples/diagnostics/triage/solution.
什么是分类?
借助分类功能,您可以扫描 Fuchsia 快照(snapshot.zip 文件),以查看是否存在预定义的条件。
分类系统可让您轻松配置新条件,从而提高分类功能对所有用户的实用性。
前提条件
在开始此 Codelab 之前,请确保您已完成以下操作:
- 开始使用。
- 使用
fx build
构建了 Fuchsia 版本。
从命令行运行分类
- 如需运行分类,请执行以下操作:
fx triage
此命令使用 fx snapshot
命令下载新的 snapshot.zip
文件。此命令会运行位于源代码树中的默认规则:
//src/diagnostics/config/triage/*.triage
如需分析特定的 snapshot.zip 文件,请使用 --data
。
- 您最多只能指定一个
--data
参数。 --data
的参数还可以是包含已解压缩快照的目录的路径。- 如果您在运行
fx triage
时未指定--data
选项,则该命令会运行一个新的fx snapshot
并分析其文件。
fx triage --data my/foo/snapshot.zip
如需使用特定目录中的特定配置文件或所有 *.triage
文件,请使用 --config
。
- 您可以使用多个
--config
参数。 - 如果使用
--config
参数,系统将不会自动加载默认规则。
fx triage --config my/directory --config my/file.triage
添加分类规则
本 Codelab 的其余部分介绍了如何在分类中配置新行为。
概览
分类会通过以下步骤将大量诊断数据浓缩为有用的信息:
- 在配置文件的
select
部分中,使用选择器字符串从inspect.json
文件中选择值。 - 执行计算和比较以生成新值,如配置文件的
eval
部分中所指定。 - 根据配置文件的
act
部分中的条目执行操作。- 如果错误条件(布尔表达式)为 true,则发出警告。
- 向用户显示一个值。
- 支持通过
test
部分中的条目对操作和计算进行单元测试。
查找 Codelab 的示例文件
前往源代码树中的 examples/diagnostics/triage
目录。以下命令应从该目录运行:
fx triage --config . --data snapshot
在包含未修改 Codelab 文件的示例目录中运行此命令,系统会输出预先提供的操作中的一行:
Warning: 'always_triggered' in 'rules' detected 'Triage is running': 'always_true' was true
inspect.json
此 Codelab 包含一个包含 Inspect 数据的 inspect.json
文件,以便您可预测练习的运行情况。此文件位于 snapshot/inspect.json
下的示例目录中。
rules.triage
分类程序使用从一个或多个 .triage 文件加载的配置。此 Codelab 使用位于示例目录中的 rules.triage
文件。
.triage 文件使用 JSON5,这种格式比 JSON 更易于读写:
- 在最后一个列表项后面添加一个英文逗号是一种良好的样式。
- 大多数键(包括所有有效的分类名称)不需要用引号括起来。
- 可以使用 /* 多行 */ 和 // 单行注释。
为“检查”值添加选择器
示例目录中的 inspect.json
文件表明系统存在一些问题。您将配置分类系统来检测这些问题。
此步骤用于配置 Triage,以便从 inspect.json
文件中的数据中提取值。
rules.triage
文件包含一个名为 select
的键值对部分。每个键(名称)都可以在其他配置条目的正文中使用。每个值都是一个选择器字符串。实际上,select
部分(以及下文介绍的 eval
部分)中的每个条目都定义了一个变量。
选择器字符串是一个以英文冒号分隔的字符串,用于指明在“检查”数据中的哪个位置可以找到所需的值。
select: {
disk_total: "INSPECT:bootstrap/fshost:root/data_stats/stats:total_bytes",
// "data_stat" is an intentional typo to fix later in the codelab.
disk_used: "INSPECT:bootstrap/fshost:root/data_stat/stats:used_bytes",
}
组件发布的检查数据的组织方式为节点树,叶节点包含值(属性)。inspect.json
文件是这些树的数组,每个树都有一个标识源组件的标记。
选择器字符串中 INSPECT:
和第二个英文冒号之间的部分应与 inspect.json
文件中的某个标识符字符串匹配。
第二个冒号和第三个冒号之间的部分是使用 /
分隔的节点名称列表。
最后一个英文冒号后面的部分是属性名称。
上述选择器字符串表示 moniker
与字符串 bootstrap/fshost
匹配且检查树包含路径 root/data_stat/stats
的组件。它还会指示该组件的“Inspect Tree”的 root
节点的 stats
子节点中的 used_bytes
属性。
将上述选择器放入 rules.triage 文件的“select”部分。
生成选择器
手动输入选择器容易出错,因此可以使用 fx triage --select
输出有效的选择器。
fx triage --data snapshot --select total_bytes
INSPECT:bootstrap/fshost:root/data_stats/stats:total_bytes
可以使用多个 --select
参数。该程序将为快照的诊断数据生成所有可能的选择器,然后过滤(grep)所有 --select
参数。
添加计算
从 inspect.json
文件中选择值后,您需要执行一些逻辑运算(可能还需要进行一些算术运算),以确定这些值是否表明存在值得标记的条件。
将以下代码行复制并添加到 rules.triage
文件的 eval
部分,以计算磁盘的占用率:
eval: {
....
disk_percentage: "disk_used / disk_total",
}
eval
条目使用普通的算术中缀表达式。如需了解详情,请参阅详细信息部分。
添加操作
在配置文件的“act”部分中,添加一个操作,以便在磁盘已满 98% 时输出警告。使用以下代码行:
act: {
...
disk_full: {
type: "Warning",
trigger: "disk_percentage > 0.98",
print: "Disk reached 98% full",
},
}
请注意以下几点:
添加仪表板
act: {
...
disk_display: {
type: "Gauge",
value: "disk_percentage",
format: "percentage",
}
}
仪表盘始终显示所提供的值。
format
字段为可选字段。值为“percentage”时,表示输出格式设置程序应预期值介于 0 到 1 之间,并将其显示为百分比。
试试看
以下命令将对本地配置文件运行分类。
fx triage --config . --data snapshot
您会收到如下所示的错误消息:
[ERROR] In config 'rules': No value found matching selector
bootstrap/fshost:root/data_stat/stats:used_bytes
选择器规则中存在拼写错误。分类功能找不到评估规则所需的值。事实上,正确的选择器是“data_stats”,而不是“data_stat”。请在选择器规则中修正此问题,然后重试。
fx triage --config . --data snapshot
现在发生了什么情况?没什么,对吧?那么,您如何知道 inspect.json
文件中没有问题,还是规则中存在 bug?
测试您的规则
您可以(并且应该)为操作添加测试。对于每项测试,请指定值以及这些值是否应触发规则。
如需测试您添加的规则,请将以下内容添加到 rules.triage
文件的 test
部分:
test: {
....
is_full: {
yes: ["disk_full"],
values: {
disk_used: 98,
disk_total: 100,
}
}
}
values
部分中的键应为 eval
或 select
条目的名称。所提供的值将替换条目原本要选择或计算的值。
您还可以测试不应触发操作的条件:
test: {
....
not_full: {
no: ["disk_full"],
values: {
disk_used: 97,
disk_total: 100,
}
}
}
如需运行测试,只需运行分类即可。它会在每次运行时自动进行自测。
fx triage --config . --data snapshot
糟糕!这应该会发出错误信号:
Test is_full failed: trigger 'disk_percentage > 0.98' of action disk_full
returned Bool(false), expected true
修正规则
您希望在磁盘满载 98% 或以上时触发操作,但您编写的代码并非如此,而您的测试发现了这个问题。将操作中的 >
修改为 >=
:
trigger: "disk_percentage >= 0.98",
再次运行分类。该错误应该会消失,取而代之的是一条警告,指出您的 inspect.json
文件确实表明磁盘已满。
Warning: 'disk_full' in 'rules' detected 'Disk is 98% full': 'disk98' was true
日志文件扫描
您可以编写表达式来测试日志文件(syslog.txt、klog.txt、bootlog.txt)中的某行是否与正则表达式匹配。如下所示:
eval: {
syslog_has_not_found: "SyslogHas('ERROR.*not found')",
...
}
act: {
something_not_found: {
trigger: "SyslogHas('ERROR.*not found')",
...
}
}
这些函数分别是 SyslogHas()、KlogHas() 和 BootlogHas()。如果缺少日志文件(例如,某些快照不包含 bootlog.txt),则系统会将其视为空文件。
如需进行测试,您可以在测试中添加条目,如下所示:
test: {
test_error: {
yes: [error_scan],
syslog: "ERROR: file Foo not found\nSecond line OK",
}
}
annotations.json
快照包含一个 annotations.json
文件,其中包含 build、开发板、正常运行时间等信息。
您可以使用函数 Annotation()
和单个字符串参数(即文件中 JSON 对象的键)从此文件中提取值。例如,
eval: {
using_chromebook: "Annotation('build.board') == 'chromebook-x64'",
}
使用多个配置文件
您可以添加任意数量的分类配置文件,甚至可以在一个文件中使用另一个文件中定义的变量。这有很多应用场景:
- 一个文件用于存储与磁盘相关的变量和操作,另一个文件用于存储与网络相关的变量和操作。
- 用于定义产品专用编号的文件。
- 为特定工程师或团队创建单独的文件。
添加一个名为“product.triage”的文件,其中包含以下内容:
{
eval: {
max_components: "4",
},
}
请注意以下几点:
- .triage 文件中可以省略空白部分。此文件不包含
select
、act
或test
条目。 - 虽然 JSON 中的数值不需要加引号,但
4
是数学表达式字符串,因此需要加引号。
将以下条目添加到 rules.triage 文件中:
select: {
...
actual_components: "INSPECT:bootstrap/archivist:root/event_stats:components_started",
}
这将提取设备中活跃的组件数量。
eval: {
...
too_many_components: "actual_components > product::max_components",
这会将产品的实际组件与理论上限进行比较。
最后,添加操作:
act: {
...
component_overflow: {
type: "Warning",
trigger: "too_many_components",
print: "Too many components!",
},
}
很遗憾,此设备尝试使用了太多组件,因此在运行“fx triage”时应会触发此警告。
在生产环境中,您可以在不同的目录中维护多个“product.triage”文件,并可以使用“--config”命令行参数指示 Triage 使用其中的任何一个文件。
测试和命名空间
测试仅使用测试发生的文件中的指标,以及测试提供的值。如果表达式(eval 或测试触发器)使用命名空间型值(例如“a::b”),则必须由测试值中的“a::b”条目提供这些值。
test: {
component_max_ok: {
no: [
"component_overflow",
],
values: {
actual_components: 17,
"product::max_components": 17,
},
},
},
详细信息
姓名
名称(选择器、表达式、操作和测试的名称,以及配置文件的 basename)可以是任何字母或下划线,后跟任意数量的字母、数字或下划线。
在未来的 Triage 版本中,以下划线开头的名称可能具有特殊含义。我们并未禁止使用这些字符,但最好还是避免使用。
每个 .triage 文件的名称都会建立其命名空间。不允许从不同目录加载两个同名的 .triage 文件。
数学表达式
- 变量可以是 64 位浮点数、有符号 64 位整数或布尔值。
- 算术表达式使用
+ - * / //
运算符,并采用常规的运算顺序和运算优先级。 - 除法运算符
/
会生成浮点值。 - 除法运算符
//
会生成 int 值,并将结果舍入 0,即使使用浮点参数也是如此。(请注意,这与 Python 3 不同,在 Python 3 中,// 会向下截断。) + - *
保留运算数的类型(混合类型会提升为浮点数)。- 比较运算符为
> >= < <= == !=
- 比较运算的结果类型为布尔值,可用于触发操作。
- 您可以在单个
eval
规则中组合计算和比较。 - 您可以使用括号。
- 您可以将
eval
和select
条目的键名称用作变量。 - 空格在任何位置都是可选的,并且除了
filename::variable
命名空间型变量之外,在任何位置都可以使用。
预定义函数
Triage 提供了可在 eval
表达式中使用的预定义函数:
Max(value1, value2, value3...)
会返回最大值,并将类型提升为浮点值。Min(value1, value2, value3...)
会返回最小值,并将类型提升为浮点值。And(value1, value2, value3...)
接受布尔参数,并返回值的逻辑 AND 运算结果。Or(value1, value2, value3...)
接受布尔值参数,并返回值的逻辑 OR 运算结果。Not(value)
接受一个布尔值参数,并返回其逻辑 NOT。- 如果相应的日志文件包含行匹配匹配器(即包含正则表达式的字符串),
SyslogHas(matcher)
、KlogHas(matcher)
和BootlogHas(matcher)
会返回 true。 Annotation(key)
会从 annotations.json 文件返回相应的值。Option(value1, value2, value3...)
会返回第一个有用值,以支持选择器迁移和默认值:第一个非空列表、非缺失值(如果有);或空列表(如果已指定);或缺失。- 如果值是错误指示,
Missing(value)
会返回 true。 Days()
、Hours()
、Minutes()
、Seconds()
、Millis()
、Micros()
和Nanos()
会计算值,以便与单调时间戳进行比较。Now()
会返回诊断数据的创建时间大致时间戳。StringMatches(value, regex)
会将给定的正则表达式应用于给定值,如果存在匹配项,则返回 true。正则表达式语法是 Rust regex crate 支持的语法。
函数式编程
分类功能可以将函数应用于值的矢量。矢量的格式为 "[expr, expr, expr...]"
。某些选择器会返回多元素矢量。
Triage 提供了 Map()
、Fold()
、Filter()
和 Count()
函数来处理矢量,Fn()
用于定义要应用的 Map、Fold 和 Filter 的函数或 lambda,Apply()
用于对参数应用 Fn()。
如需了解详情,请参阅配置 fx 分类。
延伸阅读
如需了解最新功能和选项,请参阅 fx triage
- 分类功能将不断改进!