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 | (无) | 仅显示符合模式的事件(glob,可指定多个) |
-x, --exclude | (无) | 隐藏符合该模式的事件(glob,可指定多个) |
--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 协议