10. イベントストリームリスナー
イベントチャンネル(ポート 10020)に接続し、レベル、名前パターン、除外条件に基づいて選択的にフィルタリングしたシステムイベントを出力します。読み取り専用であるため、セッションプロファイルは送信されず、コマンドも送信されません。
学習内容:
- 受動的な観察者として イベント WebSocket(ポート
10020) 購読する - イベントのJSON 構文解析 —
level,name,category,data,message - 深刻度レベルが「最低」のものに絞り込む
- ワイルドカードによる名前の一致および除外を適用する
- このチュートリアルを他のチュートリアルと組み合わせて、制御ループのベンチマークを行う
ワークフロー
- CLIフラグ(
--level,--name,--exclude,--no-hide-rate,--port)を解析します。 ws://localhost:10020(イベントチャンネル)に接続します。読み取り専用のオブザーバーであるため、セッションプロファイルは送信されません。- 受信する各メッセージについて、イベントのJSONオブジェクトを解析し、以下のフィルターを適用します:
levelこの最小深刻度よりも低い場合は破棄します。--nameパターンが指定されている場合、そのパターンのうちの1つ(name単独またはcategory/name)と一致しない場合は破棄します。--excludeパターンが1つでも一致すれば、破棄します。
- フィルターを通過したイベントのレベル、完全な名前、オプションのメッセージ、オプションの
dataペイロードとともに出力します。
パラメータ
| フラグ | デフォルト値 | 用途 |
|---|---|---|
--port | 10020 | イベントチャネルポート |
-l, --level | info | 最小深刻度 — info, notice, warning, error, critical, panic その一つ |
-n, --name | (なし) | パターン(glob、繰り返し指定可能)に一致するイベントのみを表示 |
-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
読み取り状態フィールド
受信される各メッセージは、1つのイベントです:
level— 文字列の深刻度(info...panic)name— イベント名(例:device-connected,system-rate-report)category— カテゴリ(例:device,session,system)message—オプション:人が読める文字列data—オプションのネストされたJSONペイロード(構造はイベントによって異なります)
イベントの一覧については、「イベントとモニタリング」を参照してください。
送信 / 受信
手動での購読であるため、 recv()のみを使用し、何も返しません。3つのバリエーションはすべて同じフィルターパイプラインを実装しており、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プロトコル