HyperDX 2.41.0 常用 CLI 命令详解
HyperDX 2.41.0 常用 CLI 命令详解:以实测四服务栈为基准,覆盖 hdx CLI 0.7.0(认证、数据源发现、SQL 查询、终端图表、TUI)、Docker Compose 编排运维、otelcontribcol 配置校验三场景、外部 API v2 的 curl 调用(team/connections/sources/search/charts/series)与三路日志排查,全部命令与回显均为 2026-10-23 实测。
HyperDX 2.41.0 常用 CLI 命令详解
目标:把 HyperDX 2.41.0(ClickStack 开源版)日常运维会用到的五类命令工具——
hdx终端 CLI、Docker Compose 栈编排、collector 配置校验、外部 REST API(curl)、日志排查与底层体检——逐条实测并沉淀参数与回显,读者照抄即可在自己的栈上复现同样的结果。本文全部命令与回显均在 2026-10-23 于 Linux 服务器实测执行,栈的部署过程见 《HyperDX 2.41.0 Docker Compose 部署指南》。
一、环境信息
实测环境(2026-10-23,真实服务器视角):
- 栈:B2 篇部署的 HyperDX 2.41.0 四服务栈(app / otel-collector / ClickHouse 26.1.12.23 / MongoDB 5.0.32),项目名
hyperdx-2410-stack,四服务全部运行中 - 服务端口(与本栈编排一致):UI
8130、API8136、OTLP gRPC8137、OTLP HTTP8138、collector 健康检查8139、fluentd receiver8152 - 示例账号:
root@quzuo.net/Q1w2e3r4t5y6!(首用户,注册过程见 B2 篇第 4.4 节) - 团队 ingest key(OTLP 摄入用):
cca923a9-201f-4aa6-9d2d-98d016261d61 - 用户 accessKey(外部 API 用):
b758ccd0-1eb5-4179-a365-82fdffe3e95d - CLI 运行环境:Node.js
v24.21.0、npm11.19.0(registryhttps://registry.npmmirror.com)、@hyperdx/cli安装版本0.7.0 - 容器运行时:Docker
29.8.1、Docker Composev5.5.1
$ hdx --version
0.7.0
$ docker --version
Docker version 29.8.1, build 4a63305
$ docker compose version
Docker Compose version v5.5.1
二、工具概览
ClickStack 没有单一的"万能 CLI",日常命令分散在五个入口,各自负责一层:
| 工具 | 形态 | 负责什么 | 典型命令 |
|---|---|---|---|
hdx(@hyperdx/cli) | 终端 CLI / TUI | 以用户身份检索日志与追踪、跑 SQL、画终端图表、切团队 | hdx auth login、hdx query、hdx chart |
| Docker Compose | 栈编排 | 四服务栈的启停、状态、日志、配置校验 | docker compose ps、docker compose logs |
otelcontribcol validate | collector 内置校验器 | 校验 OTel Collector 配置文件语法与组件装配 | validate --config=… |
| 外部 API v2 | REST(curl) | 程序化检索与资源管理(搜索、图表序列、告警、仪表盘等) | POST /api/v2/search |
docker compose exec + 客户端 | 底层体检 | 直入 ClickHouse / MongoDB 查内部状态 | clickhouse-client、mongosh |
关键差异与分工:hdx 走的是「用户会话 + HyperDX 查询代理」,与网页端看到的结果严格一致;curl + /api/v2 走「accessKey + REST」,用于脚本与外部系统集成;clickhouse-client / mongosh 则绕开应用层直查存储,排障时定位「数据到底落没落库」用。三层在本文都有实测。
三、前置条件
- 已按 B2 篇完成四服务栈部署且四服务全部运行(
docker compose ps确认); - 已注册首用户并登录过一次(本文示例
root@quzuo.net); - 宿主机已装 Node.js ≥ 22.16(
hdxCLI 的硬性要求,本文实测 24.21.0); - 已取得两个密钥(获取命令见第七章 7.1):团队 ingest key 与用户 accessKey;
hdxCLI 的--app-url指向 UI 端口(本文 8130),而 curl 直调 API 用 API 端口(本文 8136)——两者别混,原因见第十章常见问题 1。
四、hdx CLI:终端检索与查询
hdx 是 HyperDX 官方终端客户端(npm 包 @hyperdx/cli),与网页端跑同一条查询管线,适合在 SSH 会话里直接检索事件、跑 SQL、看趋势。本章全部命令在实测栈上执行。
4.1 安装与认证(auth)
全局安装得到 hdx 可执行文件;认证用 auth login,支持交互与非交互两种方式:
$ npm install -g @hyperdx/cli
changed 1 package in 315ms
$ hdx --version
0.7.0
非交互登录(CI 友好),-a 指 UI 端口:
$ hdx auth login -a http://localhost:8130 -e root@quzuo.net -p 'Q1w2e3r4t5y6!'
Logged in as root@quzuo.net (http://localhost:8130)
认证状态与会话存储:
$ hdx auth status
Logged in as root@quzuo.net (http://localhost:8130)
Team: root@quzuo.net's Team [6adaae2ed640de28d174c2ad]
$ ls -la ~/.config/hyperdx/cli/
total 12
drwx------ 2 root root 4096 10月 23 08:47 .
drwx------ 3 root root 4096 10月 23 14:36 ..
-rw------- 1 root root 160 10月 23 14:36 session.json
会话文件权限 0600,所有子命令复用它直到过期;登出用 hdx auth logout(无额外参数)。
4.2 数据源与连接发现(sources / connections / dashboards / team)
写 SQL 或画图之前先弄清「有什么源、哪个连接、哪些仪表盘」。四个发现类命令都支持 --json:
$ hdx connections --json
[
{
"id": "6adaae2ed640de28d174c2b2",
"name": "Local ClickHouse",
"host": "http://ch-server:8123"
}
]
$ hdx dashboards
No dashboards found.
hdx sources 列出全部数据源及其 ClickHouse 建表语句(可用作字段字典)。完整输出很长,以下为实测节选(首尾):
$ hdx sources
Logs log default.otel_logs
CREATE TABLE default.otel_logs
(
`Timestamp` DateTime64(9) CODEC(Delta(8), ZSTD(1)),
`TraceId` String CODEC(ZSTD(1)),
`SpanId` String CODEC(ZSTD(1)),
`SeverityText` LowCardinality(String) CODEC(ZSTD(1)),
`ServiceName` LowCardinality(String) CODEC(ZSTD(1)),
`Body` String CODEC(ZSTD(1)),
`ResourceAttributes` Map(LowCardinality(String), String) CODEC(ZSTD(1)),
(中段为 Scope/LogAttributes 等列与 6 个 __hdx_materialized_k8s_* 物化列、8 个索引定义,此处略)
INDEX idx_lower_body lower(Body) TYPE tokenbf_v1(32768, 3, 0) GRANULARITY 8
)
ENGINE = MergeTree
PARTITION BY toDate(Timestamp)
ORDER BY (toStartOfFiveMinutes(Timestamp), ServiceName, Timestamp)
TTL toDateTime(Timestamp) + toIntervalDay(30)
SETTINGS index_granularity = 8192, ttl_only_drop_parts = 1, enable_block_number_column = 1, enable_block_offset_column = 1
Traces trace default.otel_traces
(otel_traces 建表语句,含 SpanAttributes/Duration/StatusCode 与 Links 三列数组等)
Metrics metric default.
Sessions session default.hyperdx_sessions
CREATE TABLE default.hyperdx_sessions
(
`Timestamp` DateTime64(9) CODEC(Delta(8), ZSTD(1)),
`TimestampTime` DateTime DEFAULT toDateTime(Timestamp),
(中段列与 otel_logs 同构,此处略)
)
ENGINE = MergeTree
PARTITION BY toDate(TimestampTime)
PRIMARY KEY (ServiceName, TimestampTime)
ORDER BY (ServiceName, TimestampTime, Timestamp)
TTL TimestampTime + toIntervalDay(30)
SETTINGS index_granularity = 8192, ttl_only_drop_parts = 1
💡 注意两点实测细节:①
Logs/Traces源的时间列是Timestamp,只有Sessions源额外有TimestampTime派生列(与 C1 篇 5.4 节的列名分布实测一致);②Metrics源没有单一表名,按指标类型分散在otel_metrics_gauge/histogram/sum等表,所以 sources 输出里 Metrics 行的表名显示为default.。
团队命令(单团队部署下基本是只读确认):
$ hdx team list
▸ root@quzuo.net's Team [6adaae2ed640de28d174c2ad]
You belong to a single team. hdx team use is a no-op here.
$ hdx team current
root@quzuo.net's Team [6adaae2ed640de28d174c2ad]
4.3 原始 SQL 查询(query)
hdx query 把 ClickHouse SQL 经 HyperDX 代理下推执行,输出默认 JSONEachRow(每行一个 JSON 对象),可直接进 jq:
$ hdx query --connection-id 6adaae2ed640de28d174c2b2 --sql "SELECT count() AS c FROM default.otel_logs"
{"c":"3"}
$ hdx query --connection-id 6adaae2ed640de28d174c2b2 --sql "SELECT ServiceName, count() AS c, max(Timestamp) AS latest FROM default.otel_logs GROUP BY ServiceName ORDER BY c DESC LIMIT 5"
{"ServiceName":"hyperdx-docs-test","c":"1","latest":"2026-10-23T00:46:03.531476487Z"}
{"ServiceName":"recreate-check","c":"1","latest":"2026-10-23T01:10:35.000000000Z"}
{"ServiceName":"compose-final-check","c":"1","latest":"2026-10-23T01:08:19.000000000Z"}
--connection-id 的取值来自 4.2 的 hdx connections --json。完整参数如下(hdx query --help 实测回显):
Usage: hdx query [options]
Run raw SQL against a ClickHouse connection (add --patterns to cluster result
into Drain log patterns)
Options:
--connection-id <id> Connection ID (from 'hdx connections --json')
--sql <query> SQL query to execute
-a, --app-url <url> HyperDX app URL
--format <format> ClickHouse output format (default: "JSONEachRow")
--patterns Mine Drain log patterns from the query result instead
of emitting rows
--body-column <name> Column whose string value is clustered when --patterns
is set (default: whole row JSON)
-h, --help display help for command
💡 技术拓展:
--format接受任意 ClickHouse 输出格式,常用格式对比——
格式 形态 适用场景 JSONEachRow(默认)每行一个 JSON 对象(NDJSON) 管道进 jq、脚本逐行处理JSON单个 JSON 文档(含 meta/statistics) 人读、看列类型 TabSeparated制表符分隔 进 awk/剪贴板、与 TSV 文件互换 CSV逗号分隔 进表格软件 本文默认用
JSONEachRow;要看列类型元信息时用JSON。
实测陷阱:SQL 内联 FORMAT 子句会失败。 把 FORMAT TabSeparated 直接写进 SQL 末尾,代理报语法错并退出码 1;改用 --format 旗标则正常:
$ hdx query --connection-id 6adaae2ed640de28d174c2b2 --sql "SELECT Timestamp, ServiceName, Body FROM default.otel_logs LIMIT 1 FORMAT TabSeparated"
Query failed: Syntax error: failed at position 127
(退出码 1,无 stdout)
$ hdx query --connection-id 6adaae2ed640de28d174c2b2 --format TabSeparated --sql "SELECT Timestamp, ServiceName, SeverityText, Body FROM default.otel_logs ORDER BY Timestamp DESC LIMIT 3"
2026-10-23T01:10:35.000000000Z recreate-check info collector recreate check
2026-10-23T01:08:19.000000000Z compose-final-check info B2 部署闭环验证 1792717699000000000
2026-10-23T00:46:03.531476487Z hyperdx-docs-test error HyperDX 2.41.0 ingest smoke test from quzuo docs
退出码契约(实测验证):成功 0(结果为空时 stdout 为空也是成功);失败 1,且两类错误在 stderr 可区分——连接不存在会附上可用连接清单,SQL 错误直接给 ClickHouse 报错:
$ hdx query --connection-id deadbeef-0000 --sql "SELECT 1"
Connection "deadbeef-0000" not found.
Available connections:
- Local ClickHouse [6adaae2ed640de28d174c2b2]
(退出码 1)
$ hdx query --connection-id 6adaae2ed640de28d174c2b2 --sql "SELECT nonexistent_col FROM default.otel_logs LIMIT 1"
Query failed: Unknown expression identifier `nonexistent_col` in scope SELECT nonexistent_col FROM default.otel_logs LIMIT 1.
(退出码 1)
日志模式聚类(--patterns):用 Drain 算法把大量行聚成模板,按出现次数排序输出。实测栈日志量小(3 条),每条各成一 pattern:
$ hdx query --connection-id 6adaae2ed640de28d174c2b2 --patterns --body-column Body --sql "SELECT Body FROM default.otel_logs LIMIT 1000"
{"pattern":"HyperDX 2.41.0 ingest smoke test from quzuo docs","count":1,"sample":"HyperDX 2.41.0 ingest smoke test from quzuo docs"}
{"pattern":"B2 部署闭环验证 1792717699000000000","count":1,"sample":"B2 部署闭环验证 1792717699000000000"}
{"pattern":"collector recreate check","count":1,"sample":"collector recreate check"}
生产日志量大时该命令的价值是把上万行原始日志压成几十个模板,sample 字段给出每类的代表样本。
4.4 终端图表(chart)
hdx chart 在终端直接渲染图表,三种模式:仪表盘 tile(-d)、即席聚合(-s 源名)、原始 SQL(--sql)。实测栈没建过仪表盘,重点验证即席模式。
按严重级别过滤计数、按服务分组:
$ hdx chart -s Logs --where 'SeverityText:error' --since 24h --display table
count() where SeverityText:error (table)
count()
1
$ hdx chart -s Logs --group-by ServiceName --since 24h --display table
count() by ServiceName (table)
count() ServiceName
1 compose-final-check
1 hyperdx-docs-test
1 recreate-check
默认 line 显示在终端画出 ANSI 字符图(实测节选):
$ hdx chart -s Logs --since 24h
count() (line)
2 ┼ ╭╮
┤ ││
┤ ││
1.5 ┤ ╭╯│
┤ │ │
1 ┤ ╭╯ ╰╮
┤ │ │
0.5 ┤ ╭╯ │
┤ │ │
--json 不画图,返回原始行与列元信息(供脚本消费):
$ hdx chart -s Logs --group-by ServiceName --since 24h --json
[
{
"id": null,
"name": "count() by ServiceName",
"displayType": "line",
"status": "ok",
"data": [
{
"count()": "1",
"ServiceName": "hyperdx-docs-test",
"__hdx_time_bucket": "2026-10-23T00:30:00Z"
},
{
"count()": "1",
"ServiceName": "recreate-check",
"__hdx_time_bucket": "2026-10-23T01:00:00Z"
},
{
"count()": "1",
"ServiceName": "compose-final-check",
"__hdx_time_bucket": "2026-10-23T01:00:00Z"
}
],
"meta": [
{
"name": "count()",
"type": "UInt64"
},
参数要点(实测确认):--display 可选 line(默认)/stacked_bar/number/table/bar/pie;时间范围用 --since 15m|1h|7d 或 --from/--to(ISO 8601、日期或 now-24h 相对值);追踪源的延迟分位用 --agg quantile --level 0.95 --value Duration;输出重定向时 ANSI 颜色自动剥离。
4.5 交互式 TUI 与 source maps 上传
hdx tui 是全功能终端界面(搜索、实时 tail、行详情、追踪瀑布、告警与仪表盘浏览)。交互界面无法以回显呈现,此处给出实测的参数表(hdx tui --help):
Usage: hdx tui [options]
Interactive TUI for event search and tail
Options:
-a, --app-url <url> HyperDX app URL
-q, --query <query> Initial Lucene search query
--source <name> Source name (skips picker)
-f, --follow Start in follow/live tail mode
-h, --help display help for command
常用启动形态:hdx tui --source Logs(跳过源选择)、hdx tui -q 'SeverityText:error' -f(带过滤条件进入实时 tail 模式)。界面内按 ? 显示键位帮助,q 退出。
hdx upload-sourcemaps 用于构建流水线里上传 JS source maps(堆栈反混淆),参数实测回显:
Usage: hdx upload-sourcemaps [options]
Upload JavaScript source maps to HyperDX for stack trace de-obfuscation
Options:
-k, --serviceKey <string> The HyperDX service account API key
-u, --apiUrl [string] An optional api url for self-hosted deployments
-rid, --releaseId [string] An optional release id to associate the
sourcemaps with
-p, --path [string] Sets the directory of where the sourcemaps are
(default: ".")
-bp, --basePath [string] An optional base path for the uploaded sourcemaps
--apiVersion [string] The API version to use (v1 for HyperDX V1 Cloud,
v2 for latest) (default: "v1")
-h, --help display help for command
自托管部署调用时 -u 填 HyperDX 的对外地址,-k 填服务账号 API key;该命令面向前端构建流水线,本文栈无前端构建产物,参数以 --help 回显为准。
五、Docker Compose 栈编排命令
四服务栈的日常启停、状态与日志全部经 docker compose 操作,须在编排文件所在目录执行(本文即 B2 篇的部署目录)。本节命令逐条实测。
5.1 配置校验与状态查看
改完 docker-compose.yml 先做无副作用校验(语法与引用错误,--quiet 无输出即通过):
$ docker compose config --quiet && echo 'config OK'
config OK
状态查看的两种常用形态:
$ docker compose ps --format 'table {{.Name}}\t{{.Status}}'
NAME STATUS
hyperdx-2410-stack-app-1 Up 6 hours (healthy)
hyperdx-2410-stack-ch-server-1 Up 6 hours
hyperdx-2410-stack-db-1 Up 6 hours
hyperdx-2410-stack-otel-collector-1 Up 6 hours (healthy)
$ docker compose ps --format 'table {{.Name}}\t{{.Image}}\t{{.Status}}'
NAME IMAGE STATUS
hyperdx-2410-stack-app-1 hyperdx/hyperdx:2.41.0 Up 6 hours (healthy)
hyperdx-2410-stack-ch-server-1 clickhouse/clickhouse-server:26.1-alpine Up 6 hours
hyperdx-2410-stack-db-1 mongo:5.0.32-focal Up 6 hours
hyperdx-2410-stack-otel-collector-1 clickhouse/clickstack-otel-collector:2.41.0 Up 6 hours (healthy)
健康判据:app 与 otel-collector 带 (healthy) 即栈可用;ch-server 与 db 的编排未配 healthcheck,Up 即正常。端口到服务的映射用 port 查(对照编排里的映射关系,排查「端口被谁占了」时用):
$ docker compose port app 8130
0.0.0.0:8130
$ docker compose port otel-collector 4318
0.0.0.0:8138
5.2 镜像与进程拓扑(images / top)
images 核对四个镜像的 tag 与体积(升级前后的对照基线):
$ docker compose images
CONTAINER REPOSITORY TAG PLATFORM IMAGE ID SIZE CREATED
hyperdx-2410-stack-app-1 hyperdx/hyperdx 2.41.0 linux/amd64 00c6d5b7f3d4 979MB 10 days ago
hyperdx-2410-stack-ch-server-1 clickhouse/clickhouse-server 26.1-alpine linux/amd64 369bd6894256 988MB 5 months ago
hyperdx-2410-stack-db-1 mongo 5.0.32-focal linux/amd64 3b6c281e1c08 1.08GB 9 months ago
hyperdx-2410-stack-otel-collector-1 clickhouse/clickstack-otel-collector 2.41.0 linux/amd64 04725e89ed30 497MB 10 days ago
top 看 app 内部进程树——它不是单进程服务,而是 concurrently 托管的三个进程(API、APP、ALERT-TASK),排障时先分清日志来自哪一路(实测节选):
$ docker compose top app
SERVICE # UID PID PPID C STIME TTY TIME CMD
app 1 yahui 2580377 2580348 0 09:06 ? 00:00:00 sh /etc/local/entry.sh
app 1 yahui 2580465 2580377 0 09:06 ? 00:00:00 node ./node_modules/.bin/concurrently --kill-others-on-fail --names=API,APP,ALERT-TASK PORT=8136 HYPERDX_APP_PORT=8130 ./packages/api/bin/hyperdx api cd ./packages/app/packages/app && HOSTNAME='0.0.0.0' HYPERDX_API_PORT=8136 PORT=8130 node server.js ./packages/api/bin/hyperdx task check-alerts
app 1 yahui 2580523 2580465 0 09:06 ? 00:00:12 node -r @hyperdx/node-opentelemetry/build/src/tracing /app/packages/api/bin/../build/index.js
app 1 yahui 2580526 2580465 0 09:06 ? 00:00:01 next-server (v
app 1 yahui 2580527 2580465 0 09:06 ? 00:00:08 node -r @hyperdx/node-opentelemetry/build/src/tracing /app/packages/api/bin/../build/tasks/index.js check-alerts
5.3 生命周期与日志
常用生命周期命令(均在编排目录执行):
# 修改编排后增量生效(只重建受影响服务,数据卷不动)
docker compose up -d
# 重启单个服务(collector 重启后会自动重新向 app 领取 OpAMP 配置)
docker compose restart otel-collector
# 停止与销毁(-v 连同匿名卷;本编排数据在 bind mount,需另行清理 volumes/ 目录)
docker compose down
docker compose down -v
日志排查用 logs,--tail 控制行数、-f 跟随(第八章有日志形态详解):
$ docker compose logs --tail=3 app
app-1 | [ALERT-TASK] {"level":30,"time":1792737600038,"pid":25,"hostname":"b607c48a34ab","msg":"Lost connection to MongoDB server"}
app-1 | [ALERT-TASK] {"level":30,"time":1792737600038,"pid":25,"hostname":"b607c48a34ab","msg":"check-alerts finished in 10.09 ms"}
app-1 | [API] {"level":30,"time":1792737618182,"pid":21,"hostname":"b607c48a34ab","req":{"id":779,"method":"GET","url":"/health","query":{},"params":
六、Collector 配置校验(otelcontribcol validate)
collector 容器内有两个二进制:/opampsupervisor(PID 1,管理配置下发)与 /otelcontribcol(真正的 OTel Collector,运行参数 --config /etc/otel/supervisor-data/effective.yaml --feature-gates service.AllowNoPipelines,实测 ps 输出)。supervisor 把 app 经 OpAMP 下发的动态配置渲染成 effective.yaml,collector 实际加载的就是它——校验也应针对这个文件。
改配置(如自定义 receiver、排障怀疑配置损坏)后,用内置 validate 子命令做无副作用校验。场景一:正常配置——容器内环境变量齐全,${env:...} 占位符都能解析,校验通过无任何输出:
$ docker exec hyperdx-2410-stack-otel-collector-1 /otelcontribcol validate --config=/etc/otel/supervisor-data/effective.yaml
(退出码 0,无输出)
场景二:配置文件语法损坏——把 YAML 值写坏(数组括号不闭合)后校验,报解析错误并退出码 1:
$ docker exec hyperdx-2410-stack-otel-collector-1 sh -c 'printf "receivers:\n otlp:\n protocols:\n grpc:\n endpoint: [broken\n" > /etc/otel/supervisor-data/bad.yaml && /otelcontribcol validate --config=/etc/otel/supervisor-data/bad.yaml'
Error: failed to get config: cannot resolve the configuration: retrieved value (type=string) cannot be used as a Conf: assuming string type since contents are not valid YAML: yaml: line 4: did not find expected ',' or ']'
(退出码 1)
场景三:环境变量缺失——effective.yaml 大量引用 ${env:CLICKHOUSE_ENDPOINT} 这类占位符,清空环境变量后校验,ClickHouse 导出器因拿不到 endpoint 报错(退出码 1):
$ docker exec hyperdx-2410-stack-otel-collector-1 env -i /otelcontribcol validate --config=/etc/otel/supervisor-data/effective.yaml
Error: exporters::clickhouse/rrweb: endpoint must be specified
parse dsn address failed
exporters::clickhouse: endpoint must be specified
parse dsn address failed
(退出码 1)
三个场景合起来的结论:validate 只校验「YAML 语法 + 组件装配 + ${env:} 可解析」,不校验 ClickHouse/Mongo 是否真的可达(endpoint 写错但占位符有值时,validate 依然通过)。连通性问题要看 collector 运行日志(第八章 8.1)。
💡 技术拓展:ClickStack collector 的配置生效方式有两条路线——
路线 机制 适用场景 OpAMP 动态下发(默认) app 把 receiver/导出器配置经 OpAMP 推给 supervisor,渲染为 effective.yaml 并热加载 标准部署;配置随 UI/环境变量变化自动同步 静态文件挂载 环境变量 CUSTOM_OTELCOL_CONFIG_FILE指向自定义配置需要预置 app 未覆盖的 collector 组件时 本栈采用默认动态下发;两条路线的参数细节见 《HyperDX 2.41.0 配置参数详解》第三章。
七、外部 API v2 调用(curl 实测)
HyperDX 提供版本化的外部 REST API(OpenAPI 标题 HyperDX External API 2.0.0),挂在 API 端口(本文 8136)的 /api/v2 前缀下,Bearer 方式认证,覆盖搜索、图表序列、告警、仪表盘、Saved Search、Webhook、团队等资源。本节全部请求用 curl 实测。
7.1 双密钥体系与认证
ClickStack 有两套独立密钥,用途与传递方式都不同:
💡 技术拓展:两套密钥对比——
密钥 归属 传递方式 用途 团队 ingest key 团队(teams 集合) OTLP 请求头 authorization: <key>(裸值,不加 Bearer)遥测摄入(4317/4318) 用户 accessKey 用户(users 集合) REST 请求头 Authorization: Bearer <key>外部 API v2 的程序化调用 本文外部 API 调用一律用 accessKey;ingest key 的摄入用法见 B2 篇第 4.5 节。
两个密钥都可直接从 MongoDB 取(UI 的 Team Settings 页同样可见):
$ docker exec hyperdx-2410-stack-db-1 mongosh --quiet hyperdx --eval 'JSON.stringify(db.users.find({},{email:1,accessKey:1}).toArray())'
[{"_id":"6adaae2ed640de28d174c2a9","email":"root@quzuo.net","accessKey":"b758ccd0-1eb5-4179-a365-82fdffe3e95d"}]
$ docker exec hyperdx-2410-stack-db-1 mongosh --quiet hyperdx --eval 'JSON.stringify(db.teams.find({},{apiKey:1}).toArray())'
[{"_id":"6adaae2ed640de28d174c2ad","apiKey":"cca923a9-201f-4aa6-9d2d-98d016261d61"}]
7.2 元数据端点(team / connections / sources)
先验证认证并拿到资源 ID(后续搜索需要 sourceId,SQL 代理需要 connectionId):
$ curl -s -w '\nHTTP=%{http_code}\n' --max-time 10 http://localhost:8136/api/v2/team \
-H "Authorization: Bearer b758ccd0-1eb5-4179-a365-82fdffe3e95d"
{"data":{"id":"6adaae2ed640de28d174c2ad","name":"root@quzuo.net's Team"}}
HTTP=200
$ curl -s --max-time 10 http://localhost:8136/api/v2/connections \
-H "Authorization: Bearer b758ccd0-1eb5-4179-a365-82fdffe3e95d"
{"data":[{"id":"6adaae2ed640de28d174c2b2","name":"Local ClickHouse","host":"http://ch-server:8123","username":"default","createdAt":"2026-10-23T00:45:34.864Z","updatedAt":"2026-10-23T00:45:34.864Z"}]}
/api/v2/sources 返回四类源(截取关键字段):
$ curl -s --max-time 10 http://localhost:8136/api/v2/sources \
-H "Authorization: Bearer b758ccd0-1eb5-4179-a365-82fdffe3e95d"
(实测返回四个对象,关键映射如下)
6adaae2ed640de28d174c2b6 | log | Logs | otel_logs
6adaae2ed640de28d174c2b8 | trace | Traces | otel_traces
6adaae2ed640de28d174c2ba | metric | Metrics | (无单一表,按指标类型分表)
6adaae2ed640de28d174c2bc | session | Sessions | hyperdx_sessions
7.3 搜索与图表序列(search / charts/series)
POST /api/v2/search 对应网页端 Search 面板:给源 ID、时间窗、Lucene 过滤式与 SELECT 列,返回按时间倒序的原始行。实测检索近 24 小时的 error 日志:
$ curl -s -w '\nHTTP=%{http_code}\n' --max-time 15 -X POST http://localhost:8136/api/v2/search \
-H "Authorization: Bearer b758ccd0-1eb5-4179-a365-82fdffe3e95d" \
-H 'Content-Type: application/json' \
-d '{"sourceId":"6adaae2ed640de28d174c2b6","startTime":"2026-10-22T07:00:00Z","endTime":"2026-10-23T07:00:00Z","where":"SeverityText:error","select":"Timestamp,SeverityText,Body,ServiceName","maxResults":10}'
{"data":[{"Timestamp":"2026-10-23T00:46:03.531476487Z","SeverityText":"error","Body":"HyperDX 2.41.0 ingest smoke test from quzuo docs","ServiceName":"hyperdx-docs-test"}],"rows":1}
HTTP=200
POST /api/v2/charts/series 对应图表时间序列:毫秒时间戳 + 粒度 + 聚合定义数组。实测按 1 小时粒度统计日志行数:
$ curl -s -w '\nHTTP=%{http_code}\n' --max-time 15 -X POST http://localhost:8136/api/v2/charts/series \
-H "Authorization: Bearer b758ccd0-1eb5-4179-a365-82fdffe3e95d" \
-H 'Content-Type: application/json' \
-d '{"startTime":1792651200000,"endTime":1792737600000,"granularity":"1h","series":[{"sourceId":"6adaae2ed640de28d174c2b6","aggFn":"count","where":"","groupBy":[]}]}'
{"data":[{"ts_bucket":1792713600000,"group":[],"series_0.data":"1"},{"ts_bucket":1792717200000,"group":[],"series_0.data":"2"}]}
HTTP=200
两个端点的参数约定(实测确认):search 的 startTime/endTime 用 ISO 8601 字符串,charts/series 用毫秒 epoch;where 用 Lucene 风格(SeverityText:error、ServiceName:api AND Duration:>1000000000);分页由 maxResults 与响应游标控制。
7.4 错误响应与端点总表
三类错误的实测回显,脚本里按状态码分支处理:
$ curl -s -w '\nHTTP=%{http_code}\n' --max-time 10 http://localhost:8136/api/v2/team -H "Authorization: Bearer 00000000-0000-0000-0000-000000000000"
Unauthorized
HTTP=401
$ curl -s -w '\nHTTP=%{http_code}\n' --max-time 10 http://localhost:8136/api/v2/team
Unauthorized
HTTP=401
$ curl -s -w '\nHTTP=%{http_code}\n' --max-time 10 -X POST http://localhost:8136/api/v2/search \
-H "Authorization: Bearer b758ccd0-1eb5-4179-a365-82fdffe3e95d" -H 'Content-Type: application/json' \
-d '{"startTime":"2026-10-23T00:00:00Z","endTime":"2026-10-23T23:59:59Z"}'
{"message":"Body validation failed: sourceId: Required"}
HTTP=400
外部 API v2 的完整端面(OpenAPI 规范 packages/api/openapi.json,查询日期 2026-10-23):
| 资源 | 方法与路径 |
|---|---|
| 团队 | GET /api/v2/team、GET /api/v2/team/members、POST /api/v2/team/invitation 等 |
| 连接 | `GET |
| 数据源 | `GET |
| 搜索与图表 | POST /api/v2/search、POST /api/v2/charts/series |
| 告警 | `GET |
| 仪表盘 | `GET |
| Saved Search | `GET |
| Webhook | `GET |
实测结论:UI 内部端点不对外。 试图用会话 Cookie 调内部搜索路径(GET|POST /api/search)返回 Cannot GET/POST /api/search(404),带 Cookie 调 /api/v2/search 也因无 Bearer 得 401——程序化集成一律走「API 端口 + /api/v2 + Bearer accessKey」,不要试图复用网页会话。
八、日志排查与底层体检
三层日志各自负责一段:app 日志看应用行为,collector 日志看摄入与配置下发,ClickHouse/Mongo 直查看数据落没落。本节给出实测的排查入口与关键日志形态。
8.1 app 三路日志与 collector OpAMP 心跳
app 容器一路容器日志里混着三路进程日志,前缀 [API] / [APP] / [ALERT-TASK]。首启阶段的 API 关键行实测(判断配置问题先看这几条):
$ docker compose logs app 2>/dev/null | grep -E '^\S+\s+\| \[(API|ALERT-TASK)\]' | head -7
app-1 | [API] {"level":40,"time":1792716321456,"pid":21,"hostname":"33482c20926e","msg":"Token encryption is disabled: third-party tokens will be stored in plain text (set TOKEN_ENCRYPTION_KEY to enable)"}
app-1 | [API] {"level":30,"time":1792716321457,"pid":21,"hostname":"33482c20926e","msg":"API Server listening on port 8136, NODE_ENV=production"}
app-1 | [API] {"level":30,"time":1792716321457,"pid":21,"hostname":"33482c20926e","msg":"OpAMP Server listening on port 4320, NODE_ENV=production"}
app-1 | [API] {"level":50,"time":1792716321457,"pid":21,"hostname":"33482c20926e","msg":"EXPRESS_SESSION_SECRET is missing or uses the public legacy value: generated a random secret for this process. Users are signed out whenever it restarts, and replicas do not share sessions. Configure a random secret shared by all replicas to keep sessions."}
app-1 | [API] {"level":30,"time":1792716321477,"pid":21,"hostname":"33482c20926e","msg":"Connection established to MongoDB"}
app-1 | [ALERT-TASK] {"level":30,"time":1792716360054,"pid":25,"hostname":"33482c20926e","msg":"Connection established to MongoDB"}
app-1 | [ALERT-TASK] {"level":30,"time":1792716480034,"pid":25,"hostname":"33482c20926e","msg":"Connection established to MongoDB"}
逐条解读:API Server listening(API 端口就绪)、OpAMP Server listening(4320 就绪,collector 才能领到配置)、EXPRESS_SESSION_SECRET 为 level 50(error 级)的告警——未设该变量则每次重启全员登出(生产要设,见 C1 篇 5.5 节);ALERT-TASK 的 Connection established to MongoDB 约每 120 秒重复一次,是告警检查任务的周期心跳,属正常而非故障。
collector 侧的排查入口是 supervisor 心跳与 agent 日志。Connected to the OpAMP server. 约每 30 秒重复一次(心跳,正常),agent 自身日志在容器内 /etc/otel/supervisor-data/agent.log:
$ docker compose logs --tail=400 otel-collector 2>/dev/null | grep 'Connected to the OpAMP' | head -3
otel-collector-1 | {"level":"info","ts":1792725646.8463557,"logger":"supervisor","caller":"supervisor/supervisor.go:1051","msg":"Connected to the OpAMP server."}
otel-collector-1 | {"level":"info","ts":1792725676.85377,"logger":"supervisor","caller":"supervisor/supervisor.go:1051","msg":"Connected to the OpAMP server."}
otel-collector-1 | {"level":"info","ts":1792725706.8613946,"logger":"supervisor","caller":"supervisor/supervisor.go:1051","msg":"Connected to the OpAMP server."}
OTLP 端口不监听的排查链(B2 篇常见问题 3 的命令级展开):① docker compose top otel-collector 确认 /otelcontribcol 进程在跑且带 service.AllowNoPipelines gate;② grep 上表心跳确认 OpAMP 通路;③ 读 agent.log 找 receiver 绑定报错;④ 仍无端口则重启 collector 强制重领配置(docker compose restart otel-collector)。
8.2 ClickHouse 与 Mongo 快速体检
绕开应用层直查存储,确认「数据到底落没落库」。经 docker compose exec 执行(与 B2 篇的 docker exec 形态等价,前缀换成 compose 可少写容器名):
$ docker compose exec ch-server clickhouse-client --query "SELECT version()"
26.1.12.23
$ docker compose exec ch-server clickhouse-client --query "SELECT ServiceName, count() AS c FROM default.otel_logs GROUP BY ServiceName ORDER BY c DESC"
hyperdx-docs-test 1
recreate-check 1
compose-final-check 1
$ docker compose exec db mongosh --quiet hyperdx --eval 'JSON.stringify(db.teams.find({},{apiKey:1}).toArray())'
[{"_id":"6adaae2ed640de28d174c2ad","apiKey":"cca923a9-201f-4aa6-9d2d-98d016261d61"}]
表清单体检(新 schema 的 14 张表/视图,全量实测):
$ docker compose exec ch-server clickhouse-client --query "SELECT name, engine FROM system.tables WHERE database='default' ORDER BY name FORMAT TSV"
hyperdx_sessions MergeTree
otel_logs MergeTree
otel_logs_attr_kv_rollup_15m_mv MaterializedView
otel_logs_kv_rollup_15m SummingMergeTree
otel_metrics_exponential_histogram MergeTree
otel_metrics_gauge MergeTree
otel_metrics_histogram MergeTree
otel_metrics_sum MergeTree
otel_metrics_summary MergeTree
otel_traces MergeTree
otel_traces_kv_rollup_15m SummingMergeTree
otel_traces_kv_rollup_15m_mv MaterializedView
otel_traces_trace_id_ts MergeTree
otel_traces_trace_id_ts_mv MaterializedView
三方交叉验证的用法:一条日志「摄入了但搜不到」时,先 curl 打 OTLP HTTP 看 200(B2 篇 4.5 节),再 clickhouse-client 直查 otel_logs(本节),最后 hdx query 走代理查(4.3 节)——三处结果差异能把故障定位到摄入、落库或查询代理三者之一。
九、注意事项
- 端口分工:
hdx的--app-url与hdx auth login -a指 UI 端口(8130);curl 的/api/v2、/health、/register、/login指 API 端口(8136)。混用是新手第一坑(见第十章问题 1)。 - 退出码契约:
hdx query成功 0 / 失败 1,脚本里判断$?即可;docker compose config --quiet以「无输出」为通过,不能只看退出码之外的提示。 - validate 的边界:
otelcontribcol validate过了不代表连通性 OK——它不探测 ClickHouse/Mongo 可达性(第六章场景三实测)。 - 时间参数类型不一致:
search用 ISO 8601 字符串、charts/series用毫秒 epoch(7.3 实测),脚本封装时别统一成一种。 - 密钥最小化:accessKey 等同账号凭据,脚本是放进环境变量或凭据管理,不要落进版本库;ingest key 泄露的后果是任何人都能往栈里写遥测。
- 日志前缀即进程:app 容器日志先按
[API]/[APP]/[ALERT-TASK]前缀分路再看内容,能省一半排查时间(8.1 实测)。
十、常见问题
1. hdx auth login 报连接失败或超时,但网页能打开。
-a 传成了 API 端口(8136)。CLI 的 --app-url 依赖 Next.js 侧的代理路径,必须指 UI 端口(8130)。curl 直调 API 时才用 8136。两个端口各自服务,见 B2 篇常见问题 5 的实测。
2. hdx query 报 Syntax error: failed at position N。
SQL 末尾带了内联 FORMAT <format> 子句——HyperDX 代理不接受(4.3 实测)。把格式改到 --format 旗标上。
3. curl 调 /api/v2 下任意端点全部 401。
检查三点:用的是 accessKey(不是 ingest key)、头格式为 Authorization: Bearer <key>(ingest key 的 OTLP 头才是裸值)、请求打在 API 端口。三者任一错都得到 Unauthorized(7.4 实测回显)。
4. POST /api/v2/search 返回 400 Body validation failed: sourceId: Required。
请求体缺 sourceId。先 GET /api/v2/sources 拿源 ID(7.2 实测),或 hdx sources --json 获取同一份映射。
5. docker compose port 报 error: no such service 或空输出。
port 的第二个参数是容器内端口而非宿主端口,且服务必须带对应映射。查 4318 映射要写 docker compose port otel-collector 4318(5.1 实测得 0.0.0.0:8138)。
6. validate 场景三报 endpoint must be specified,但我的配置明明有 endpoint。
那是 env -i 清空环境变量后的预期现象——配置里写的是 ${env:CLICKHOUSE_ENDPOINT} 占位符(第六章场景三实测)。真实运行时占位符由容器环境变量解析,勿据此误判配置损坏。
十一、参考链接
- hdx CLI 官方说明:https://github.com/hyperdxio/hyperdx/tree/main/packages/cli
- 外部 API OpenAPI 规范:https://raw.githubusercontent.com/hyperdxio/hyperdx/refs/heads/main/packages/api/openapi.json(查询日期 2026-10-23)
- ClickStack API 参考文档:https://clickhouse.com/docs/clickstack/api-reference
- OTel Collector 配置校验:https://opentelemetry.io/docs/collector/configuration/#validate-the-configuration
- 官方配置选项总表:https://clickhouse.com/docs/clickstack/managing/config
- 站内系列:《HyperDX 2.41.0 介绍与选型指南》、《HyperDX 2.41.0 Docker Compose 部署指南》、《HyperDX 2.41.0 配置参数详解》
- 站内同类:《SigNoz v0.146.0 Docker Compose 部署指南》