Codelab:使用分类

此 Codelab 介绍了分类实用程序:

  • 用途。
  • 如何运行它,包括命令行选项。
  • 如何添加和测试配置规则,以检测 Fuchsia 快照中的问题。

本文档中提及的源文件和示例可从以下位置获取:

什么是分类?

借助分类功能,您可以扫描 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 的其余部分介绍了如何在分类中配置新行为。

概览

分类会通过以下步骤将大量诊断数据浓缩为有用的信息:

  1. 在配置文件的 select 部分中,使用选择器字符串从 inspect.json 文件中选择值。
  2. 执行计算和比较以生成新值,如配置文件的 eval 部分中所指定。
  3. 根据配置文件的 act 部分中的条目执行操作。
    1. 如果错误条件(布尔表达式)为 true,则发出警告。
    2. 向用户显示一个值。
  4. 支持通过 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 部分中的键应为 evalselect 条目的名称。所提供的值将替换条目原本要选择或计算的值。

您还可以测试不应触发操作的条件:

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 文件中可以省略空白部分。此文件不包含 selectacttest 条目。
  • 虽然 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 规则中组合计算和比较。
  • 您可以使用括号。
  • 您可以将 evalselect 条目的键名称用作变量。
  • 空格在任何位置都是可选的,并且除了 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 - 分类功能将不断改进!