10. 事件流监听器
活动频道(波特 10020) 连接后,输出根据级别、名称模式和排除条件进行选择性筛选的系统事件。由于是只读模式,因此不会发送会话配置文件,也不会传输任何命令。
学习内容:
- 作为一名旁观者 事件 WebSocket(波特
10020) 订阅 - 活动 JSON 解析 —
level,name,category,data,message - 按最低严重程度级别进行筛选
- 应用通配符名称匹配和排除规则
- 将本教程与其他教程结合使用,对控制回路进行性能测试
工作流程
- CLI 标志(
--level,--name,--exclude,--no-hide-rate,--port)进行解析。 ws://localhost:10020(活动频道) 进行连接。由于是只读观察者,因此不会传输会话配置文件。- 对于收到的每条消息,都会解析其事件 JSON 对象,并应用以下过滤器:
level如果低于此最低严重程度,则予以丢弃。--name如果指定了模式,则其中一个模式(name单独或category/name) 不匹配时,则将其丢弃。--exclude只要有一个模式匹配,就将其丢弃。
- 经过过滤的事件,包括级别、完整名称、可选消息、可选
data与有效载荷一起输出。
参数
| 标志 | 默认值 | 用途 |
|---|---|---|
--port | 10020 | 事件通道端口 |
-l, --level | info | 最低严重程度 — info, notice, warning, error, critical, panic 其中之一 |
-n, --name | (无) | 仅显示与模式(通配符,可重复指定)匹配的事件 |
-x, --exclude | (无) | 隐藏与模式(通配符,可指定重复次数)匹配的事件 |
--no-hide-rate | false | system-rate-report 包含事件(默认隐藏——输出量非常大) |
在一个终端中运行任意一个教程(04-hello-floor、05-position-control、06-combined...),在另一个终端中 --no-hide-rate 请指定选项以触发事件监听器。 system-rate-report 该事件包含实际设备的时钟频率。如果比较同一教程中 Python/C++、nlohmann/C++ 和 Glaze 版本之间的该值,可以观察到在约 4 kHz 的控制回路中存在的序列化开销。
# Terminal 1 — pick a variant
./04-haply-inverse-hello-floor # C++ nlohmann
./04-haply-inverse-hello-floor-glz # C++ Glaze
python 04-haply-inverse-hello-floor.py # Python
# Terminal 2 — watch the rate
./10-haply-inverse-events --no-hide-rate
“正在阅读”字段
每条接收到的消息都算作一个事件:
level— 字符串严重程度(info……panic)name— 活动名称(例如:device-connected,system-rate-report)category— 类别(例如:device,session,system)message—可选的、可供人阅读的字符串data— 可选的嵌套 JSON 有效载荷(结构因事件而异)
有关完整事件列表,请参阅“事件与监控”。
发送 / 接收
由于是手动订阅,因此 recv()仅进行读取操作,不会返回任何内容。这三种变体都实现了相同的过滤器管道,而在针对 Inverse API 的专用部分中,值得注意的是事件结构体的形式。
- Python
- C++ (nlohmann)
- C++ (Glaze)
async for msg in websocket这是只读循环的最简洁形式。
async with websockets.connect(uri) as websocket:
async for msg in websocket:
try:
event = json.loads(msg)
except json.JSONDecodeError:
continue
if accept_event(event, min_level_index, name_patterns, exclude_patterns):
print(format_event(event))
这是 libhv 的回调模型 — onmessage在 I/O 线程中运行,主线程则处于阻塞状态,等待 ENTER 键的输入。事件被视为无类型的 JSON 格式,每个字段都带有默认值, .value(...)读作。
ws.onmessage = [&](const std::string &msg) {
json event;
try { event = json::parse(msg); } catch (...) { return; }
if (accept_event(event, opts.min_level, opts.name_patterns, opts.exclude_patterns))
print_event(event);
};
ws.open("ws://localhost:10020");
while (std::cin.get() != '\n') {} // block main thread
已知的事件字段是指定了类型的 event_data 映射到结构体上。 data 字段是 glz::raw_json_view由于保持不变,因此无需定义整个模式,即可直接传递根据事件而变化的任意嵌套有效载荷。
// Struct model — known fields typed, nested `data` kept as raw JSON
struct event_data {
std::string level;
std::string name;
std::string category;
std::string message;
glz::raw_json_view data{};
};
// Send / receive
ws.onmessage = [&](const std::string &msg) {
event_data event{};
if (glz::read<glz_settings>(event, msg)) return; // drop malformed
if (accept_event(event, opts.min_level, opts.name_patterns, opts.exclude_patterns))
print_event(event);
};
ws.open("ws://localhost:10020");
while (std::cin.get() != '\n') {} // block main thread
教程 10 也随 SDK 一起安装在本地。位于服务安装目录下的 tutorials/10-haply-inverse-events/请在……处查看。
相关文档: 事件与监控·WebSocket 协议