OpenHarmony子系统开发 - DFX(五)
HiSysEvent开发指导(一)
一、HiSysEvent概述
简介
HiSysEvent是面向OpenHarmony系统开发者提供的系统打点功能,通过在关键路径埋点来记录系统在运行过程中的重要信息,辅助开发者定位问题,此外还支持开发者将打点数据上传到云进行大数据质量度量。
HiSysEvent包括HiSysEvent打点配置、HiSysEvent打点、HiSysEvent订阅、HiSysEvent查询以及HiSysEvent工具模块,各模块能力介绍如下:
-
HiSysEvent打点配置:提供了事件打点配置的相关能力,支持在yaml文件中对打点事件进行定义。
-
HiSysEvent打点:提供了事件打点的相关接口能力,支持对打点事件进行落盘。
-
HiSysEvent订阅:提供了事件订阅的相关接口能力,支持根据事件领域和事件名称来对打点事件进行订阅。
-
HiSysEvent查询:提供了事件查询的相关接口能力,支持根据事件领域和事件名称来对打点事件进行查询。
-
HiSysEvent工具:提供了HiSysEvent工具,支持通过该工具来实时订阅打点事件及查询历史打点事件。
参考
如果您想了解更多关于HiSysEvent特性的源码及使用信息,请参考HiSysEvent代码仓。
二、HiSysEvent打点配置
概述
功能简介
组件若有HiSysEvent事件的打点需求,则需要先定义yaml文件并在bundle.json文件中配置yaml文件的路径。OpenHarmony编译框架在编译过程中则会通过python编译脚本解析校验bundle.json文件指定的所有yaml文件。在解析校验之后,编译框架会将这些yaml文件中配置的信息汇总转换成名为hisysevent.zip文件。最后,将此zip文件打包到系统指定路径下,用作HiSysEvent事件落盘的判断依据。
基本概念
在配置HiSysEvent打点之前,开发者应了解以下基本概念:
-
事件领域 用于标识事件所属的领域,在yaml文件中以domain为键值指定,可参考yaml文件样例中的domain。
-
事件名称 用于指定事件领域包含的所有事件,可参考yaml文件样例中的EVENT_NAMEA/EVENT_NAMEB。
-
参数 用于定义某个事件名称包含的所有键值,可参考yaml文件样例中的__BASE/NAME1/NAME2。
约束与限制
定义事件领域、事件名称及参数的约束与限制:
-
每个yaml文件只能有一个事件领域,且不能与其他yaml文件中定义的事件领域重名。
-
每个事件领域可定义零个或多个事件名称,同一个事件领域内部的事件名称不能重名。
-
每个事件名称可定义多个参数,同一个事件名称内部的参数不能重名,每个事件名称有且只有一个名称为__BASE的参数,此参数字段组成如表1,其它自定义参数,具体字段组成如表2。 表1 __BASE参数字段说明
字段名称 描述 type 字段说明:必选字段,用来标识该事件名称的类型。
取值范围:
- FAULT:故障类型。
- STATISTIC:统计类型。
- SECURITY:安全类型。
- BEHAVIOR:行为类型。level 字段说明:必选字段,用来标识该事件名称的级别。
取值范围:
- CRITICAL:严重。
- MINOR:一般。tag 字段说明:可选字段,用来标识该事件名称的标签。
定义规则:
- 最多可同时定义5个标签,标签之间使用空格来分隔。
- 单个标签最多包含16个字符,字符范围[a-zA-Z0-9]。desc 字段说明:必选字段,用来对该事件名称进行描述。
定义规则:
- 至少包含3个字符,最多包含128个字符。preserve 字段说明:可选字段,用来标识事件是否需要落盘,默认值为true。
取值范围:
- true:事件需要落盘。
- false:事件不需要落盘。表2 自定义参数字段说明
字段名称 描述 type 字段说明:必选字段,用来标识该参数的类型。
取值范围:
- BOOL
- INT8
- UINT8
- INT16
- UINT16
- INT32
- UINT32
- INT64
- UINT64
- FLOAT
- DOUBLE
- STRINGarrsize 字段作用:可选字段,用来标识数组类型参数的长度。
取值范围:
- 1~100desc 字段作用:必选字段,用来对该参数进行描述。
定义规则:
- 至少包含3个字符,最多包含128个字符。
开发步骤
编写yaml文件
编写规则
-
事件领域命名规则:
- 字母开头,且只能由大写字母/数字/下划线组成;
- 字符串长度取值范围为1~16。
-
事件名称命名规则:
- 字母开头,且只能由大写字母/数字/下划线组成;
- 字符串长度取值范围1~32;
- 单个事件领域内部事件名称的不能超过4096个。
-
参数命名规则:
- 字母开头,且只能由大写字母/数字/下划线组成;
- 字符串长度取值范围1~48;
- 单个事件名称内包含的参数的个数不能超过128个。
编写样例
-
yaml文件样例指定的事件领域名称为MODULEA,该事件领域包含两个事件,名称分别是EVENT_NAMEA和EVENT_NAMEB。
-
EVENT_NAMEA被定义成错误类型的严重事件,该事件包含类型为字符串类型的NAME1参数、字符串类型的NAME2参数及无符号短整型类型的NAME3参数,可以通过事件领域MODULEA和事件名称EVENT_NAMEA对其进行实时订阅。
-
EVENT_NAMEB被定义成统计类型的一般事件,EVENT_NAMEB包含类型为无符号短整型类型的NAME1参数及整型类型的NAME2参数。因为EVENT_NAMEB在__BASE参数中定义了名称为tag1和tag2的两个事件标签,所以不仅可以通过事件领域MODULEA和事件名称EVENT_NAMEB对其进行实时订阅,所以还可以通过事件标签对该事件进行实时订阅。
########################################## # the hisysevent definition for module a # ########################################## domain: MODULEA EVENT_NAMEA: __BASE: {type: FAULT, level: CRITICAL, desc: event name a} NAME1: {type: STRING, desc: name1} NAME2: {type: STRING, desc: name2} NAME3: {type: UINT16, desc: name3} EVENT_NAMEB: __BASE: {type: STATISTIC, level: MINOR, tag: tag1 tag2, desc: event name b} NAME1: {type: UINT16, desc: name1} NAME2: {type: INT32, desc: name2}
验证yaml文件
配置yaml文件路径
在bundle.json文件中通过hisysevent_config属性完成yaml文件的路径指定:
{
"name": "@ohos/moduel_a",
"description": "module a",
"version": "3.1",
"license": "Apache License 2.0",
"publishAs": "code-segment",
"segment": {
"destPath": "moduel_a_path"
},
"dirs": {},
"scripts": {},
"component": {
"name": "hisysevent_native",
"subsystem": "hiviewdfx",
"adapted_system_type": [
"standard"
],
"rom": "",
"ram": "",
"hisysevent_config": [
"//moduel_a_path/yaml_file1.yaml",
"//moduel_a_path/yaml_file2.yaml"
],
"deps": {
"components": [
"hilog_native",
"hitrace_native",
"ipc",
"safwk",
"samgr",
"utils_base"
],
"third_party": []
},
"build": {
}
}
}
说明: yaml文件可根据实际需求置于组件工程的任意目录下,只要在bundle.json文件指定即可。
编译yaml文件
-
全量编译:
-
全量编译整个系统,会将所有组件配置的yaml文件中的配置进行汇总,正常完成系统编译后,指定目录下就会生成hisysevent.zip文件。
cd 工程根目录的绝对路径 ./build --product-name <product name>
-
全量编译生成的hisysevent.zip文件可以通过以下命令获取:
cd 工程根目录的绝对路径 find out -name hisysevent.zip -type f
-
-
单文件编译: 也可以只编译单个组件的yaml文件,命令如下:
cd 工程根目录的绝对路径 ./build/ohos/hisysevent/gen_def_from_all_yaml.py --yaml-list <yaml file list> --def-path <file store directory>
表3 单文件编译参数说明
选项名称 描述 --yaml-list 指定需要编译的yaml文件路径列表,多个yaml文件路径之间用空格分隔。 --def-path 指定编译生成的hisysevent.zip文件的生成路径。
打点及查询定义的事件
-
通过hdc_std工具将从hisysevent.zip解压的hisysevent.def文件推送至设备的/data/system/hiview/unzip_configs/sys_event_def/目录下。
-
触发yaml文件自定义的HiSysEvent事件完成打点,通过“hisysevent -l”命令查询历史HiSysEvent事件,确认触发的自定义HiSysEvent事件是否打点成功。
三、HiSysEvent打点
概述
功能简介
HiSysEvent打点提供了事件打点功能,开发者可以通过在关键路径打点来记录系统在运行过程中的重要信息。同时,HiSysEvent打点也提供了以事件领域为单位的HiSysEvent打点屏蔽机制,方便开发者评估及调试HiSysEvent打点操作的影响。
运作机制
在进行HiSysEvent事件打点之前,需要先完成HiSysEvent打点配置,具体配置方法请参考HiSysEvent打点配置指导。
开发指导
场景介绍
事件打点的主要工作是将打点数据进行落盘。
接口说明
C++接口说明
C++事件打点开发能力如下:HiSysEvent类,具体API详见接口目录(/base/hiviewdfx/hisysevent/interfaces/native/innerkits/hisysevent/include/)。
说明:
从OpenHarmony-3.2-Beta3版本开始,为避免打点风暴事件引发性能问题,对HiSysEvent打点进行了管控。表1中的HiSysEvent::Write打点接口被表2中的HiSysEventWrite宏接口取代。HiSysEvent::Write接口已废弃,请使用HiSysEventWrite宏接口完成HiSysEvent事件打点。
表1 事件打点接口(已废弃)
接口名 | 描述 |
---|---|
template<typename... Types> static int Write(const std::string &domain, const std::string &eventName, EventType type, Types... keyValues) | 将打点事件数据进行落盘。 |
表2 事件打点宏接口
接口名 | 描述 |
---|---|
HiSysEventWrite(domain, eventName, type, ...) | 将打点事件数据进行落盘。 |
表3 EventType事件类型枚举
事件类型 | 描述 |
---|---|
FAULT | 故障类型事件。 |
STATISTIC | 统计类型事件。 |
SECURITY | 安全类型事件。 |
BEHAVIOR | 行为类型事件。 |
C接口说明
C事件打点开发能力如下:具体API详见接口目录(/base/hiviewdfx/hisysevent/interfaces/native/innerkits/hisysevent/include/)。
表4 事件打点接口
接口名 | 描述 |
---|---|
int OH_HiSysEvent_Write(const char* domain, const char* name, HiSysEventEventType type, HiSysEventParam params[], size_t size); | 将打点事件数据进行落盘。 |
表5 HiSysEventEventType事件类型枚举
事件类型 | 描述 |
---|---|
HISYSEVENT_FAULT | 故障类型事件。 |
HISYSEVENT_STATISTIC | 统计类型事件。 |
HISYSEVENT_SECURITY | 安全类型事件。 |
HISYSEVENT_BEHAVIOR | 行为类型事件。 |
表6 HiSysEventParam事件参数结构体
属性名称 | 属性类型 | 描述 |
---|---|---|
name | char name[] | 事件参数名称。 |
t | HiSysEventParamType | 事件参数类型。 |
v | HiSysEventParamValue | 事件参数值。 |
arraySize | size_t | 事件参数值为数组类型时的数组长度。 |
表7 HiSysEventParamType事件参数类型枚举
参数类型 | 描述 |
---|---|
HISYSEVENT_INVALID | 无效类型事件参数。 |
HISYSEVENT_BOOL | bool类型事件参数。 |
HISYSEVENT_INT8 | int8_t类型事件参数。 |
HISYSEVENT_UINT8 | uint8_t类型事件参数。 |
HISYSEVENT_INT16 | int16_t类型事件参数。 |
HISYSEVENT_UINT16 | uint16_t类型事件参数。 |
HISYSEVENT_INT32 | int32_t类型事件参数。 |
HISYSEVENT_UINT32 | uint32_t类型事件参数。 |
HISYSEVENT_INT64 | int64_t类型事件参数。 |
HISYSEVENT_UINT64 | uint64_t类型事件参数。 |
HISYSEVENT_FLOAT | float类型事件参数。 |
HISYSEVENT_DOUBLE | double类型事件参数。 |
HISYSEVENT_STRING | char*类型事件参数。 |
HISYSEVENT_BOOL_ARRAY | bool数组类型事件参数。 |
HISYSEVENT_INT8_ARRAY | int8_t数组类型事件参数。 |
HISYSEVENT_UINT8_ARRAY | uint8_t数组类型事件参数。 |
HISYSEVENT_INT16_ARRAY | int16_t数组类型事件参数。 |
HISYSEVENT_UINT16_ARRAY | uint16_t数组类型事件参数。 |
HISYSEVENT_INT32_ARRAY | int32_t数组类型事件参数。 |
HISYSEVENT_UINT32_ARRAY | uint32_t数组类型事件参数。 |
HISYSEVENT_INT64_ARRAY | int64_t数组类型事件参数。 |
HISYSEVENT_UINT64_ARRAY | uint64_t数组类型事件参数。 |
HISYSEVENT_FLOAT_ARRAY | float数组类型事件参数。 |
HISYSEVENT_DOUBLE_ARRAY | double数组类型事件参数。 |
HISYSEVENT_STRING_ARRAY | char*数组类型事件参数。 |
表8 HiSysEventParamValue事件参数值联合体
属性名称 | 属性类型 | 描述 |
---|---|---|
b | bool | bool类型事件参数值。 |
i8 | int8_t | int8_t类型事件参数值。 |
ui8 | uint8_t | uint8_t类型事件参数值。 |
i16 | int16_t | int16_t类型事件参数值。 |
ui16 | uint16_t | uint16_t类型事件参数值。 |
i32 | int32_t | int32_t类型事件参数值。 |
ui32 | uint32_t | uint32_t类型事件参数值。 |
i64 | int64_t | int64_t类型事件参数值。 |
ui64 | uint64_t | uint64_t类型事件参数值。 |
f | float | float类型事件参数值。 |
d | double | double类型事件参数值。 |
s | char* | char*类型事件参数值。 |
array | void* | 数组类型事件参数值。 |
kernel接口说明
kernel事件打点开发能力如下:具体API详见接口文件(/kernel/linux/linux-5.10/include/dfx/hiview_hisysevent.h)。
表9 事件打点接口
接口名 | 描述 |
---|---|
struct hiview_hisysevent *hisysevent_create(const char *domain, const char *name, enum hisysevent_type type); | 创建一个事件对象。 |
void hisysevent_destroy(struct hiview_hisysevent *event); | 销毁一个事件对象。 |
int hisysevent_put_integer(struct hiview_hisysevent *event, const char *key, long long value); | 将整数类型的事件参数添加到事件对象。 |
int hisysevent_put_string(struct hiview_hisysevent *event, const char *key, const char *value); | 将字符串类型的事件参数添加到事件对象。 |
int hisysevent_write(struct hiview_hisysevent *event); | 将事件对象数据进行落盘。 |
表10 hisysevent_type事件类型枚举
事件类型 | 描述 |
---|---|
FAULT | 故障类型事件。 |
STATISTIC | 统计类型事件。 |
SECURITY | 安全类型事件。 |
BEHAVIOR | 行为类型事件。 |
开发步骤
C++打点开发步骤
在需要打点的地方直接调用打点接口,并传入相应事件参数。
HiSysEventWrite(HiSysEvent::Domain::AAFWK, "START_APP", HiSysEvent::EventType::BEHAVIOR, "APP_NAME", "com.ohos.demo");
C打点开发步骤
-
如果需要在打点时传入自定义事件参数,先要根据事件参数类型创建对应的事件参数对象,再将其放入到事件参数数组中。
// 创建一个int32_t类型的事件参数 HiSysEventParam param1 = { .name = "KEY_INT32", .t = HISYSEVENT_INT32, .v = { .i32 = 1 }, .arraySize = 0, }; // 创建一个int32_t数组类型的事件参数 int32_t int32Arr[] = { 1, 2, 3 }; HiSysEventParam param2 = { .name = "KEY_INT32_ARR", .t = HISYSEVENT_INT32_ARRAY, .v = { .array = int32Arr }, .arraySize = sizeof(int32Arr) / sizeof(int32Arr[0]), }; // 将事件参数对象放入创建的事件参数数组中 HiSysEventParam params[] = { param1, param2 };
-
在需要打点的地方调用打点接口,并传入相应事件参数。
OH_HiSysEvent_Write("TEST_DOMAIN", "TEST_NAME", HISYSEVENT_BEHAVIOR, params, sizeof(params) / sizeof(params[0]));
kernel打点开发步骤
-
根据事件领域、事件名称、事件类型参数,创建一个基础的事件对象。
struct hiview_hisysevent *event = hisysevent_create("KERNEL", "BOOT", BEHAVIOR);
-
将自定义的事件参数,传入到事件对象里。
// 添加整数类型参数 hisysevent_put_integer(event, "BOOT_TIME", 100); // 添加字符串类型参数 hisysevent_put_string(event, "MSG", "This is a test message");
-
在事件对象构建完成后,将事件进行上报。
hisysevent_write(event);
-
事件上报完成后,需要手动将对象销毁。
hisysevent_destroy(&event);
事件领域屏蔽的步骤
- 在相应的文件中定义名称为“DOMAIN_MASKS”,内容形如“DOMAIN_NAME_1|DOMAIN_NAME_2|...|DOMAIN_NAME_n”。共有三种屏蔽场景:
-
只屏蔽当前源码文件中的相应事件领域的HiSysEvent打点,在该cpp文件引入hisysevent.h头文件之前定义宏DOMAIN_MASKS即可。
#define DOMAIN_MASKS "DOMAIN_NAME_1|DOMAIN_NAME_2|...|DOMAIN_NAME_n" #include "hisysevent.h"
-
屏蔽整个模块相应事件领域的HiSysEvent打点,在模块的BUILD.gn文件中定义宏DOMAIN_MASKS即可。
config("module_a"){ cflags_cc += ["-DDOMAIN_MASKS=\"DOMAIN_NAME_1|DOMAIN_NAME_2|...|DOMAIN_NAME_n\""] }
-
全局屏蔽相应事件领域的HiSysEvent打点,则在/build/config/compiler/BUILD.gn中定义宏DOMAIN_MASKS即可。
cflags_cc += ["-DDOMAIN_MASKS=\"DOMAIN_NAME_1|DOMAIN_NAME_2|...|DOMAIN_NAME_n\""]
- 通过HiSysEventWrite宏完成HiSysEvent打点操作:
constexpr char DOMAIN[] = "DOMAIN_NAME_1"; const std::string eventName = "EVENT_NAME1"; OHOS:HiviewDFX::HiSysEvent::EventType eventType = OHOS:HiviewDFX::HiSysEvent::EventType::FAULT; HiSysEventWrite(domain, eventName, eventType); //因为DOMAIN_NAME_1事件领域已经在DOMAIN_MASKS中定义,所以该HiSysEvent打点不会执行。
开发实例
C++打点开发实例
假设业务模块需要在应用启动时进行打点来记录应用启动事件,且需要记录应用的包名信息,完整使用示例如下所示:
-
首先,需要在业务模块的在BUILD.gn里增加HiSysEvent部件依赖。
external_deps = [ "hisysevent:libhisysevent" ]
-
在业务模块的应用启动函数StartAbility()中,调用打点接口并传入对应事件参数。
#include "hisysevent.h" int StartAbility() { ... // 其他业务逻辑 int ret = HiSysEventWrite(HiSysEvent::Domain::AAFWK, "START_APP", HiSysEvent::EventType::BEHAVIOR, "APP_NAME", "com.ohos.demo"); ... // 其他业务逻辑 }
C打点开发实例
假设业务模块需要在应用启动时进行打点来记录应用启动事件,且需要记录应用的包名信息,完整使用示例如下所示:
-
首先,需要在业务模块的在BUILD.gn里增加HiSysEvent部件依赖。
external_deps = [ "hisysevent:libhisysevent" ]
-
在业务模块的应用启动函数StartAbility()中,调用打点接口并传入对应事件参数。
#include "hisysevent_c.h" int StartAbility() { ... // 其他业务逻辑 char packageName[] = "com.ohos.demo"; HiSysEventParam param = { .name = "APP_NAME", .t = HISYSEVENT_STRING, .v = { .s = packageName }, .arraySize = 0, }; HiSysEventParam params[] = { param }; int ret = OH_HiSysEvent_Write("AAFWK", "START_APP", HISYSEVENT_BEHAVIOR, params, sizeof(params) / sizeof(params[0])); ... // 其他业务逻辑 }
kernel打点开发实例
假设内核业务模块需要在设备启动时进行打点来记录设备启动事件,完整使用示例如下所示:
-
在设备启动函数device_boot()中,构建一个启动事件对象,然后将事件进行上报,最后销毁事件对象。
#include <dfx/hiview_hisysevent.h> #include <linux/errno.h> #include <linux/printk.h> int device_boot() { ... // 其他业务逻辑 struct hiview_hisysevent *event = NULL; int ret = 0; event = hisysevent_create("KERNEL", "BOOT", BEHAVIOR); if (!event) { pr_err("failed to create event"); return -EINVAL; } ret = hisysevent_put_string(event, "MSG", "This is a test message"); if (ret != 0) { pr_err("failed to put sting to event, ret=%d", ret); goto hisysevent_end; } ret = hisysevent_write(event); hisysevent_end: hisysevent_destroy(&event); ... // 其他业务逻辑 }
事件领域屏蔽的开发实例
-
假设业务模块中,需要在某个cpp文件中屏蔽名称分别为AAFWK和POWER的事件领域的打点,在该cpp文件引入hisysevent.h头文件之前,定义名称为DOMAIN_MASKS的宏:
#define DOMAIN_MASKS "AAFWK|POWER" #include "hisysevent.h" ... // 其他业务逻辑 HiSysEventWrite(OHOS:HiviewDFX::HiSysEvent::Domain::AAFWK, "JS_ERROR", OHOS:HiviewDFX::HiSysEvent::EventType::FAULT, "MODULE", "com.ohos.module"); // 该HiSysEvent打点操作不会执行 ... // 其他业务逻辑 HiSysEventWrite(OHOS:HiviewDFX::HiSysEvent::Domain::POWER, "POWER_RUNNINGLOCK", OHOS:HiviewDFX::HiSysEvent::EventType::FAULT, "NAME", "com.ohos.module"); // 该HiSysEvent打点操作不会执行
-
假设需要在整个业务模块中屏蔽名称分别为AAFWK和POWER的事件领域的打点,在模块的BUILG.gn文件中定义名称为DOMAIN_MASKS的宏:
config("module_a") { ... // 其他配置项 cflags_cc += ["-DDOMAIN_MASKS=\"AAFWK|POWER\""] }
-
假设需要在整个系统中屏蔽名称分别为AAFWK和POWER的事件领域的打点,则直接在/build/config/compiler/BUILD.gn文件中定义名称为DOMAIN_MASKS的宏:
... // 其他配置项 cflags_cc += ["-DDOMAIN_MASKS=\"AAFWK|POWER\""]
参考
HiSysEvent模块会将打点数据写入到节点文件中,而打点数据的解析处理会在Hiview模块中统一进行,详细处理过程可参考Hiview开发指导。