clickstack-otel-collector
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSet up an OpenTelemetry collector for Managed ClickStack
为托管ClickStack服务配置OpenTelemetry收集器
This skill wires an OpenTelemetry collector into a Managed ClickStack service running on
ClickHouse Cloud, sends rich synthetic telemetry through it, and confirms the data is actually
visible in ClickStack. It uses
for all cloud and SQL operations.
clickhousectlScope. This skill supports two paths, chosen in Step 0:
- Deploy a new collector locally. You can do this two ways: individual commands, or a
dockerfile (recommended, fewer commands and one file to start/stop). Make the user aware of both up front and let them pick in Step 0; do not assume plaindocker compose. Either way runs the ClickStack distribution of the collector, preconfigured for Managed ClickStack.docker - Configure your own existing collector by adding the ClickHouse exporter configuration. We give you the exact config to drop in; you reload your collector. Use this if you already run a collector in a gateway role.
A full Kubernetes deployment (Helm, secrets in K8s Secrets) is out of scope here; the config
we generate in path 2 can be applied to a collector running anywhere.
The end state is:
- A dedicated SQL user on the target service, with exactly the grants the collector needs (it creates the
hyperdx_ingestschema on first write).otel.* - A collector forwarding logs, traces, and metrics into the database on the service, either the new local ClickStack collector or your existing one.
otel - Rich synthetic telemetry across several services, severities, span statuses, and metric types, so ClickStack's Search, Service Map, and dashboards have something real to show.
- The service confirmed awake, and the user walked through the ClickStack onboarding in the Cloud console so they can actually see their data.
Secrets (the OTLP auth token and the SQL password) are generated locally, written once to a
env file, and passed to Docker via . They are never pasted into the chat,
never passed with , and never echoed back after creation.
0600--env-filedocker run -eFollow these steps in order. Each step depends on state established by the previous one.
本技能将OpenTelemetry收集器接入ClickHouse Cloud上运行的托管ClickStack服务,通过收集器发送丰富的合成遥测数据,并确认数据已成功显示在ClickStack中。所有云操作和SQL操作均通过完成。
clickhousectl适用范围:本技能支持两种部署路径,需在步骤0中选择:
- 部署新的本地收集器:提供两种方式——单独的命令,或
docker文件(推荐,命令更少,仅需一个文件即可启停)。需提前告知用户两种方式并让其在步骤0中选择,不要默认使用纯docker compose命令。无论哪种方式,均运行ClickStack分发版的收集器,已预先配置为适配托管ClickStack服务。docker - 配置现有收集器:通过添加ClickHouse导出器配置来完成。我们会提供可直接复用的配置代码,您只需重新加载收集器即可。此路径适用于已在网关角色下运行收集器的场景。
Kubernetes完整部署(Helm、存储在K8s Secrets中的密钥)不在本技能的覆盖范围内;路径2中生成的配置可应用于任何环境下运行的收集器。
最终实现效果:
- 目标服务上创建专用的SQL用户,仅拥有收集器所需的权限(首次写入时会自动创建
hyperdx_ingest模式)。otel.* - 收集器将日志、链路追踪和指标转发至服务的数据库,可为新部署的本地ClickStack收集器或您的现有收集器。
otel - 生成跨多个服务、不同严重级别、链路状态和指标类型的丰富合成遥测数据,使ClickStack的搜索功能、服务地图和仪表盘拥有真实的数据展示内容。
- 确认服务处于活跃状态,并引导用户完成ClickHouse Cloud控制台中的ClickStack入门流程,确保用户能够实际查看数据。
密钥(OTLP认证令牌和SQL密码)在本地生成,仅写入一次到权限为的环境文件中,并通过传递给Docker。密钥不会粘贴到对话中,不会通过传递,也不会在创建后回显。
0600--env-filedocker run -e请按顺序执行以下步骤,每一步都依赖于上一步建立的状态。
Step 0: Choose your path
步骤0:选择部署路径
Ask the user two short questions before doing anything else, because they determine which later
steps run.
Question 1: Do you already have an OpenTelemetry collector running in a gateway role?
- No, set one up for me. -> the new-collector path. Continue to Question 2.
- Yes, I have one. -> the existing-collector path. Skip Question 2 (it does not apply), and in Step 6 you will configure their collector rather than deploy a new one.
Question 2 (new-collector path only): Run the collector with individual Docker commands, or a
Docker Compose file?
- Docker Compose (recommended). Fewer commands, one file to start and stop, easiest to
re-run. Best if is available.
docker compose - Individual Docker commands. Use if Compose is not installed or you prefer explicit commands.
Record the answers as ( or ) and, for the new path,
( or ). Refer back to them in Step 6 and Step 7.
COLLECTOR_PATHnewexistingDEPLOY_MODEcomposerun在执行任何操作前,先向用户提出两个简短问题,答案将决定后续执行的步骤。
问题1:您是否已在网关角色下运行了OpenTelemetry收集器?
- 否,帮我部署一个。 → 进入新收集器路径,继续回答问题2。
- 是,我已有收集器。 → 进入现有收集器路径,跳过问题2(不适用),在步骤6中配置现有收集器而非部署新收集器。
问题2(仅新收集器路径适用):使用单独的Docker命令还是Docker Compose文件运行收集器?
- Docker Compose(推荐):命令更少,仅需一个文件即可启停,便于重新运行。适用于已安装的环境。
docker compose - 单独的Docker命令:适用于未安装Compose或偏好显式命令的场景。
将答案记录为(或),对于新收集器路径,还需记录(或)。后续步骤6和步骤7会参考这些值。
COLLECTOR_PATHnewexistingDEPLOY_MODEcomposerunStep 1: Batch the permissions up front
步骤1:提前批量申请权限
Coding agents prompt for approval the first time they see each shell command. To avoid
interrupting the user every few steps, ask them once, up front, to allowlist the command
prefixes below (the "always allow for this project / session" option in their agent). There are
no destructive operations and nothing targets anything outside this project or their ClickHouse
Cloud service.
| Command prefix | Used for | Needed when |
|---|---|---|
| generate the OTLP token and SQL password | always |
| auth, resolve the service, run SQL via the Query API | always |
| parse JSON from | always |
| run/inspect the collector and the telemetry generator | new-collector path, and the optional telemetry check |
| local health check against | new-collector path |
Tell the user, in your own words: "If your agent supports it, choose 'always allow' for each
of these the first time it asks. The whole run is read-only against your machine except for the
collector container, and write operations against ClickHouse are limited to creating the ingest
user and the schema."
otelIf the user is on the existing-collector path and does not want to run the optional telemetry
check, you can drop and from the list.
dockercurlTwo approvals are semantic, not prefix-based, so allowlisting won't pre-clear them. Warn the
user to expect these and approve them explicitly when they appear:
- The install in Step 3 uses
clickhousectl, which many agent sandboxes flag as "downloading and running untrusted code" regardless of anycurl … | shallowlist rule.curl - The /
CREATE USERin Step 5 may be flagged as "modifying shared production infrastructure," again independent of theGRANTprefix rule.clickhousectl
Neither is solved by the table above; they are one-time, intentional, and safe to approve.
Then continue.
代码代理在首次执行每个shell命令时会提示用户批准。为避免在每一步都打断用户,需提前一次性请求用户将以下命令前缀加入白名单(代理中的“针对本项目/会话始终允许”选项)。所有操作均无破坏性,且不会针对本项目或ClickHouse Cloud服务以外的资源执行。
| 命令前缀 | 用途 | 适用场景 |
|---|---|---|
| 生成OTLP令牌和SQL密码 | 所有场景 |
| 认证、解析服务、通过Query API执行SQL | 所有场景 |
| 解析 | 所有场景 |
| 运行/检查收集器和遥测数据生成器 | 新收集器路径,以及可选的遥测数据检查步骤 |
| 对 | 新收集器路径 |
用您自己的语言告知用户:“如果您的代理支持该功能,首次提示时请为每个命令前缀选择‘始终允许’。除收集器容器外,整个流程对您的机器仅执行只读操作;针对ClickHouse的写入操作仅限于创建采集用户和模式。”
otel若用户选择现有收集器路径且不想执行可选的遥测数据检查步骤,可从列表中移除和。
dockercurl有两个操作需语义批准,而非基于前缀,因此白名单无法预先通过。需提醒用户注意这两个操作,并在出现时明确批准:
- 步骤3中安装使用
clickhousectl,许多代理沙箱会将其标记为“下载并运行不受信任的代码”,无论是否添加了curl … | sh白名单规则。curl - 步骤5中的/
CREATE USER操作可能被标记为“修改共享生产基础设施”,同样不受GRANT前缀规则的影响。clickhousectl
这两个操作均无法通过上述表格解决,它们是一次性的、有意设计的安全操作,用户可放心批准。
之后继续执行后续步骤。
Step 2: Confirm the target service and lay down the secrets file
步骤2:确认目标服务并创建密钥文件
The user's prompt contains a service identifier, either a service ID (UUID) or a service name.
Treat that value as .
SERVICE_REFCreate a working directory and a env file that will hold all configuration and
secrets for this run. The key names match exactly what the collector image reads, so this same
file is passed straight to (or referenced by Compose) in Step 6. Write
it under a tight so the secret is never briefly world-readable:
0600docker run --env-fileumaskbash
WORKDIR="${WORKDIR:-$HOME/clickstack-otel-collector}"
mkdir -p "$WORKDIR" && chmod 700 "$WORKDIR"
ENV_FILE="$WORKDIR/collector.env"用户的提示中包含服务标识符,可为服务ID(UUID)或服务名称。将该值视为。
SERVICE_REF创建工作目录和一个权限为**的环境文件**,用于存储本次运行的所有配置和密钥。密钥名称与收集器镜像读取的名称完全一致,因此该文件可直接在步骤6中通过传递(或被Compose引用)。通过严格的设置写入文件,确保密钥不会短暂地被全局可读:
0600docker run --env-fileumaskbash
WORKDIR="${WORKDIR:-$HOME/clickstack-otel-collector}"
mkdir -p "$WORKDIR" && chmod 700 "$WORKDIR"
ENV_FILE="$WORKDIR/collector.env"Generate secrets WITHOUT printing them; write straight into a private file.
生成密钥但不打印;直接写入私有文件。
( umask 177
{
echo "SERVICE_REF=$SERVICE_REF"
echo "OTLP_AUTH_TOKEN=$(openssl rand -hex 32)"
echo "CLICKHOUSE_USER=hyperdx_ingest"
echo "CLICKHOUSE_PASSWORD=$(openssl rand -hex 24)Aa1-"
echo "HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE=otel"
} > "$ENV_FILE"
)
chmod 600 "$ENV_FILE"
ls -l "$ENV_FILE"
Two things about these values matter and are easy to get wrong:
- **Key names are exact.** The collector reads `CLICKHOUSE_USER`, `CLICKHOUSE_PASSWORD`,
`CLICKHOUSE_ENDPOINT`, and `HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE`. Store the SQL password
under `CLICKHOUSE_PASSWORD` (not a custom name); if it is missing, the collector starts with an
**empty** password and dies with `code: 516, Authentication failed`.
- **The password charset is constrained from three directions at once.** ClickHouse Cloud rejects
passwords without at least one uppercase character and one special character, so a plain hex
string fails at `CREATE USER`. At the same time, the collector's migration tool embeds the
password in a connection URL, so `@`, `:`, `/`, `?`, `#`, and `%` corrupt it (symptom:
`code: 516` at startup even though the password is "correct"). The recipe above is random hex
(lowercase + digits) plus the suffix `Aa1-`, which adds the required uppercase, a digit, and a
**URL-unreserved** special character (`-`). The OTLP token has no such rules (it is just a
bearer token), so plain hex is fine for it.
The env file uses **bare `KEY=VALUE` lines with no quotes**: Docker's `--env-file` does not do
shell parsing, so any quotes you add become part of the value.
On the **existing-collector path** the `OTLP_AUTH_TOKEN` is not used by your collector (auth on
your receiver is your own setup); it is generated only so the same file works if you later switch
to the local collector. The `CLICKHOUSE_*` values are still used: they go into the exporter
config you add to your collector in Step 6.
**Every later step runs in a fresh shell, so `WORKDIR`, `ENV_FILE`, and any exported credentials do
not persist, and `WORKDIR`/`ENV_FILE` are not stored inside the env file, so sourcing it can't
recover them.** Begin each subsequent step's shell with this **standard preamble**, which
re-derives the paths from the deterministic default, loads the saved credentials (Step 3), and
loads the config:
```bash
WORKDIR="${WORKDIR:-$HOME/clickstack-otel-collector}"; ENV_FILE="$WORKDIR/collector.env"
[ -f "$WORKDIR/creds.env" ] && . "$WORKDIR/creds.env"; set -a; . "$ENV_FILE"; set +aIf you chose a non-default , set it explicitly at the top of every step (the
default only covers the standard location). Later steps refer to this as "the standard preamble".
WORKDIR${WORKDIR:-…}Confirm with the user that is correct. Tell them the working directory and that
(mode ) now holds the OTLP token and the SQL password. Do not print
either secret. If they want to see a value, point them at the file
().
SERVICE_REFcollector.env0600grep OTLP_AUTH_TOKEN "$ENV_FILE"If the user supplied their own token or password, write those into the file instead of the
generated ones, but keep the same discipline and make sure any custom password still meets
the charset rules above.
0600( umask 177
{
echo "SERVICE_REF=$SERVICE_REF"
echo "OTLP_AUTH_TOKEN=$(openssl rand -hex 32)"
echo "CLICKHOUSE_USER=hyperdx_ingest"
echo "CLICKHOUSE_PASSWORD=$(openssl rand -hex 24)Aa1-"
echo "HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE=otel"
} > "$ENV_FILE"
)
chmod 600 "$ENV_FILE"
ls -l "$ENV_FILE"
这些值有两个关键点,容易出错:
- **密钥名称必须完全匹配**:收集器读取`CLICKHOUSE_USER`、`CLICKHOUSE_PASSWORD`、`CLICKHOUSE_ENDPOINT`和`HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE`。SQL密码必须存储在`CLICKHOUSE_PASSWORD`下(不能使用自定义名称);若缺少该密钥,收集器将使用**空密码**启动,并因`code: 516, Authentication failed`错误终止。
- **密码字符集受三重限制**:ClickHouse Cloud会拒绝未包含至少一个大写字母和一个特殊字符的密码,因此纯十六进制字符串会在`CREATE USER`时失败。同时,收集器的迁移工具会将密码嵌入连接URL,因此`@`、`:`、`/`、`?`、`#`和`%`会破坏URL(症状:即使密码“正确”,启动时仍会出现`code: 516`错误)。上述生成规则使用随机十六进制(小写+数字)加上后缀`Aa1-`,添加了所需的大写字母、数字和**URL安全**的特殊字符(`-`)。OTLP令牌无此类规则(仅作为Bearer令牌),因此纯十六进制即可。
环境文件使用**无引号的`KEY=VALUE`格式**:Docker的`--env-file`不执行shell解析,因此添加的任何引号都会成为值的一部分。
在**现有收集器路径**中,`OTLP_AUTH_TOKEN`不会被您的收集器使用(接收器的认证由您自行配置);生成该值仅为了让同一文件在您后续切换到本地收集器时仍能使用。`CLICKHOUSE_*`值仍会被使用:它们将被添加到步骤6中您收集器的导出器配置中。
**后续每个步骤都在新的shell中运行,因此`WORKDIR`、`ENV_FILE`和任何导出的凭证不会持久化,且`WORKDIR`/`ENV_FILE`不会存储在环境文件中,因此无法通过source命令恢复**。每个后续步骤的shell都需以以下**标准前置代码**开头,从确定性默认值重新推导路径,加载保存的凭证(步骤3)和配置:
```bash
WORKDIR="${WORKDIR:-$HOME/clickstack-otel-collector}"; ENV_FILE="$WORKDIR/collector.env"
[ -f "$WORKDIR/creds.env" ] && . "$WORKDIR/creds.env"; set -a; . "$ENV_FILE"; set +a若您选择了非默认的,需在每个步骤的顶部显式设置(默认仅覆盖标准位置)。后续步骤将此称为“标准前置代码”。
WORKDIR${WORKDIR:-…}与用户确认是否正确。告知用户工作目录位置,以及(权限)已存储OTLP令牌和SQL密码。不要打印任何密钥。若用户想要查看某个值,可指引他们查看文件(例如)。
SERVICE_REFcollector.env0600grep OTLP_AUTH_TOKEN "$ENV_FILE"若用户提供了自己的令牌或密码,需将其写入文件而非生成的值,但需保持相同的权限,并确保自定义密码仍符合上述字符集规则。
0600Step 3: Authenticate clickhousectl
(separate terminal by default)
clickhousectl步骤3:认证clickhousectl
(默认使用独立终端)
clickhousectlCheck is on . Run this presence check on its own, not chained to the
installer: the form drags a harmless check into a compound command that sandboxes
deny wholesale as an untrusted-code download.
clickhousectlPATH|| curl … | shbash
which clickhousectlOnly if that prints nothing, install it (the user may need to approve this explicitly, see Step 1):
bash
curl -fsSL https://clickhouse.com/cli | shCheck authentication:
bash
clickhousectl cloud auth statusThis skill needs API key authentication: OAuth is read-only and cannot create users or run
write queries. If the row is not , the user must authenticate.
API keyActiveDo not ask the user to paste their API key and secret into the chat. Anything pasted into the
conversation lives in the transcript and has to be rotated afterward. Instead, ask them to
authenticate in a separate terminal, then tell you when they are done:
I need a ClickHouse Cloud Admin API key to create the ingest user and verify the data. Please don't paste it here. Instead:
In the Cloud console, open Organization → API keys → New API key, and give it the Admin role. (Developer-scoped keys can't provision the per-service Query API endpoint thatuses.)cloud service query In a separate terminal, run:bashclickhousectl cloud auth login --api-key <key-id> --api-secret <key-secret> Tell me when that's done and I'll re-check the auth status.
Poll until the API key row reports , then confirm with a real privileged call rather than
trusting the status table alone. Use a ref-agnostic call here: may be a name, and
only accepts a UUID, so confirming with would fail on a name for reasons
unrelated to auth. needs no ref and proves the API key works:
ActiveSERVICE_REFcloud service getgetcloud service listbash
clickhousectl cloud auth status
clickhousectl cloud service list --json | jq -r '.[].name'If the list returns your services, you are authenticated; continue. The actual name-or-UUID
resolution of happens in Step 4.
SERVICE_REFExpect to need the env-var credentials (common, not an edge case). Many builds
save the credentials file but a freshly spawned shell (such as the one your tool calls run in)
doesn't read it, so shows yet the very next call reports
. Rather than treat this as a rare fallback, write a small sourceable
creds file once, then load it in every later shell. This keeps each subsequent shell to a single
line instead of two re-derivations, and keeps the secret out of the chat:
clickhousectlauth statusActiveclickhousectlNo credentials found.jqbash
undefined检查是否在中。单独运行此存在性检查不要与安装命令链式执行:形式会将无害的检查拖入复合命令,沙箱会将其整体拒绝为不受信任的代码下载。
clickhousectlPATH|| curl … | shbash
which clickhousectl仅当命令无输出时,才进行安装(用户可能需要明确批准此操作,见步骤1):
bash
curl -fsSL https://clickhouse.com/cli | sh检查认证状态:
bash
clickhousectl cloud auth status本技能需要API密钥认证:OAuth为只读权限,无法创建用户或执行写入查询。若行未显示,用户必须进行认证。
API keyActive不要要求用户将API密钥和密钥粘贴到对话中。粘贴到对话中的任何内容都会保留在记录中,后续必须轮换。相反,要求用户在独立终端中进行认证,完成后告知您:
我需要ClickHouse Cloud的Admin API密钥来创建采集用户并验证数据。 请不要在此处粘贴密钥。请按以下步骤操作:
在Cloud控制台中,打开Organization → API keys → New API key,并为其分配Admin角色。(Developer范围的密钥无法提供使用的每个服务的Query API端点。)cloud service query 在独立终端中运行:bashclickhousectl cloud auth login --api-key <key-id> --api-secret <key-secret> 完成后告知我,我将重新检查认证状态。
轮询直到API密钥行显示,然后通过实际的特权调用确认,而非仅信任状态表。此处使用与引用无关的调用:可能是名称,而仅接受UUID,因此使用确认会因名称问题失败,与认证无关。无需引用,可证明API密钥有效:
ActiveSERVICE_REFcloud service getgetcloud service listbash
clickhousectl cloud auth status
clickhousectl cloud service list --json | jq -r '.[].name'若列表返回您的服务,则认证成功;继续执行。的名称或UUID解析将在步骤4中进行。
SERVICE_REF预期需要环境变量凭证(常见情况,非边缘案例):许多构建会保存凭证文件,但新生成的shell(例如您的工具调用的shell)不会读取该文件,因此显示,但下一个调用会报告。与其将此视为罕见的回退方案,不如一次性编写一个小型可source的凭证文件,然后在后续每个shell中加载。这样后续每个shell只需一行命令,而非两次重新推导,且可避免密钥出现在对话中:
clickhousectlauth statusActiveclickhousectlNo credentials found.jqbash
undefinedWrite a private, sourceable creds file next to collector.env.
在collector.env旁边写入私有、可source的凭证文件。
( umask 177
{ echo "export CLICKHOUSE_CLOUD_API_KEY=$(jq -r .api_key "$HOME/.clickhouse/credentials.json")"
echo "export CLICKHOUSE_CLOUD_API_SECRET=$(jq -r .api_secret "$HOME/.clickhouse/credentials.json")"
} > "$WORKDIR/creds.env"
)
chmod 600 "$WORKDIR/creds.env"
**From now on, open every shell that calls `clickhousectl` with both loads**, because env vars do
not persist across shells:
```bash
. "$WORKDIR/creds.env"; set -a; . "$ENV_FILE"; set +aRe-run the check above with the creds loaded; it should now succeed. Do not continue
until a real call works. (If already shows and calls
succeed without , you can skip this; but most agent shells need it.)
service listclickhousectl auth statusAPI key … Activecreds.env( umask 177
{ echo "export CLICKHOUSE_CLOUD_API_KEY=$(jq -r .api_key "$HOME/.clickhouse/credentials.json")"
echo "export CLICKHOUSE_CLOUD_API_SECRET=$(jq -r .api_secret "$HOME/.clickhouse/credentials.json")"
} > "$WORKDIR/creds.env"
)
chmod 600 "$WORKDIR/creds.env"
**从现在开始,每个调用`clickhousectl`的shell都需同时加载这两个文件**,因为环境变量不会在shell之间持久化:
```bash
. "$WORKDIR/creds.env"; set -a; . "$ENV_FILE"; set +a加载凭证后重新运行上述检查;应成功执行。在实际调用成功前不要继续。(若已显示且调用无需即可成功,可跳过此步骤;但大多数代理shell需要此步骤。)
service listclickhousectl auth statusAPI key … Activecreds.envStep 4: Resolve the service and capture the HTTPS endpoint
步骤4:解析服务并捕获HTTPS端点
Run the standard preamble (Step 2) so the paths, credentials, and config are all loaded in this
shell, then resolve the service. If is a UUID, use it directly; otherwise look it up
by name:
SERVICE_REFbash
WORKDIR="${WORKDIR:-$HOME/clickstack-otel-collector}"; ENV_FILE="$WORKDIR/collector.env"
[ -f "$WORKDIR/creds.env" ] && . "$WORKDIR/creds.env"; set -a; . "$ENV_FILE"; set +abash
undefined运行标准前置代码(步骤2),使路径、凭证和配置均加载到当前shell中,然后解析服务。若是UUID,直接使用;否则按名称查找:
SERVICE_REFbash
WORKDIR="${WORKDIR:-$HOME/clickstack-otel-collector}"; ENV_FILE="$WORKDIR/collector.env"
[ -f "$WORKDIR/creds.env" ] && . "$WORKDIR/creds.env"; set -a; . "$ENV_FILE"; set +abash
undefinedUUID form
UUID格式
clickhousectl cloud service get "$SERVICE_REF" --json > "$WORKDIR/svc.json"
clickhousectl cloud service get "$SERVICE_REF" --json > "$WORKDIR/svc.json"
Name form (note the double quotes: service names can contain spaces or apostrophes,
名称格式(注意双引号:服务名称可能包含空格或撇号,例如"Alex's test")
e.g. "Alex's test")
—
clickhousectl cloud service list --json
| jq --arg n "$SERVICE_REF" '.[] | select(.name==$n)' > "$WORKDIR/svc.json"
| jq --arg n "$SERVICE_REF" '.[] | select(.name==$n)' > "$WORKDIR/svc.json"
Extract the values you need, coercing the port to an integer. The port serializes as a float
(`8443.0`); if `:8443.0` leaks into the endpoint the collector's ClickHouse exporter cannot dial
it:
```bash
SERVICE_ID=$(jq -r '.id' "$WORKDIR/svc.json")
SERVICE_NAME=$(jq -r '.name' "$WORKDIR/svc.json")
STATE=$(jq -r '.state' "$WORKDIR/svc.json")
CLICKHOUSE_ENDPOINT=$(jq -r '.endpoints[] | select(.protocol=="https")
| "https://\(.host):\(.port | tonumber | floor)"' "$WORKDIR/svc.json")clickhousectl cloud service list --json
| jq --arg n "$SERVICE_REF" '.[] | select(.name==$n)' > "$WORKDIR/svc.json"
| jq --arg n "$SERVICE_REF" '.[] | select(.name==$n)' > "$WORKDIR/svc.json"
提取所需的值,将端口转换为整数。端口会序列化为浮点数(`8443.0`);若`:8443.0`泄漏到端点中,收集器的ClickHouse导出器将无法连接:
```bash
SERVICE_ID=$(jq -r '.id' "$WORKDIR/svc.json")
SERVICE_NAME=$(jq -r '.name' "$WORKDIR/svc.json")
STATE=$(jq -r '.state' "$WORKDIR/svc.json")
CLICKHOUSE_ENDPOINT=$(jq -r '.endpoints[] | select(.protocol=="https")
| "https://\(.host):\(.port | tonumber | floor)"' "$WORKDIR/svc.json")Persist the resolved values back into the env file for later steps and docker --env-file.
将解析后的值持久化回环境文件,供后续步骤和docker --env-file使用。
Append only if the key is not already present, so a second run does not duplicate lines.
仅当密钥不存在时才追加,避免重复行。
grep -q '^SERVICE_ID=' "$ENV_FILE" || echo "SERVICE_ID=$SERVICE_ID" >> "$ENV_FILE"
grep -q '^CLICKHOUSE_ENDPOINT=' "$ENV_FILE" || echo "CLICKHOUSE_ENDPOINT=$CLICKHOUSE_ENDPOINT" >> "$ENV_FILE"
printf 'service=%q state=%s endpoint=%s\n' "$SERVICE_NAME" "$STATE" "$CLICKHOUSE_ENDPOINT"
`STATE` must be `running`. If it is `stopped` or `starting`, ask the user to start the service (or
wait), and do not proceed. ClickHouse Cloud services **idle-suspend**, so even a "running" service
can be asleep; the next query both checks reachability and wakes it:
```bash
clickhousectl cloud service query --id "$SERVICE_ID" --query "SELECT version()"A successful response confirms the service is awake and that the per-service Query API key is
provisioned. On the first call prints , which is expected.
clickhousectlProvisioning Query API endpoint + key for service '<name>'...grep -q '^SERVICE_ID=' "$ENV_FILE" || echo "SERVICE_ID=$SERVICE_ID" >> "$ENV_FILE"
grep -q '^CLICKHOUSE_ENDPOINT=' "$ENV_FILE" || echo "CLICKHOUSE_ENDPOINT=$CLICKHOUSE_ENDPOINT" >> "$ENV_FILE"
printf 'service=%q state=%s endpoint=%s\n' "$SERVICE_NAME" "$STATE" "$CLICKHOUSE_ENDPOINT"
`STATE`必须为`running`。若为`stopped`或`starting`,需要求用户启动服务(或等待),不要继续执行。ClickHouse Cloud服务会**空闲暂停**,因此即使是“running”状态的服务也可能处于休眠状态;下一个查询将同时检查可达性并唤醒服务:
```bash
clickhousectl cloud service query --id "$SERVICE_ID" --query "SELECT version()"成功响应确认服务已唤醒,且每个服务的Query API密钥已配置。首次调用时会打印,这是预期行为。
clickhousectlProvisioning Query API endpoint + key for service '<name>'...Step 5: Create the hyperdx_ingest
SQL user and grant it otel.*
hyperdx_ingestotel.*步骤5:创建hyperdx_ingest
SQL用户并授予otel.*
权限
hyperdx_ingestotel.*This step is the same on both paths: the collector (new or existing) authenticates to ClickHouse
as . Open the shell with the combined load so (and
credentials) are set.
hyperdx_ingest$CLICKHOUSE_PASSWORDExpect an approval prompt here. The/CREATE USERstatements below are DDL against a Cloud service, so some agent sandboxes flag them as "modifying shared production infrastructure" even whenGRANTis allowlisted. This is expected; the operations are scoped to a single dedicated ingest user and theclickhousectlschema, and the user should approve them explicitly when prompted.otel
Never put the plaintext password in the SQL. Hash it locally and use . Two
problems rule out : the secret would
land in the process arg list (visible in ) and shell history, and, critically, the Query API
echoes the failing statement verbatim in its error JSON, so any error (a transient failure, a
charset slip) leaks the password into output an agent may surface. Passing it over stdin does not
help, the error echo still contains it. Instead compute the SHA-256 hash of the password locally
( stores exactly what would, so the collector still logs in with the
plaintext from the env file) and put only the hash in the statement. A hash is non-reversible,
so even an echoed error cannot leak the password:
sha256_hashIDENTIFIED WITH sha256_password BY '$CLICKHOUSE_PASSWORD'pssha256_hashsha256_passwordbash
WORKDIR="${WORKDIR:-$HOME/clickstack-otel-collector}"; ENV_FILE="$WORKDIR/collector.env"
[ -f "$WORKDIR/creds.env" ] && . "$WORKDIR/creds.env"; set -a; . "$ENV_FILE"; set +a此步骤对两种路径均相同:收集器(新收集器或现有收集器)以身份认证到ClickHouse。打开shell并同时加载凭证,确保(和其他凭证)已设置。
hyperdx_ingest$CLICKHOUSE_PASSWORD预期会出现批准提示:以下/CREATE USER语句是针对Cloud服务的DDL操作,因此即使GRANT已加入白名单,某些代理沙箱仍会将其标记为“修改共享生产基础设施”。这是预期行为;操作仅针对单个专用采集用户和clickhousectl模式,用户在提示时应明确批准。otel
切勿在SQL中使用明文密码。在本地哈希密码并使用。有两个问题排除了使用的可能:密钥会出现在进程参数列表中(可通过查看)和shell历史记录中,更关键的是,Query API会在错误JSON中逐字回显失败的语句,因此任何错误(临时故障、字符集错误)都会将密码泄漏到代理可能显示的输出中。通过stdin传递也无济于事,错误回显仍会包含密码。相反,在本地计算密码的SHA-256哈希(存储的内容与完全相同,因此收集器仍可使用环境文件中的明文登录),并仅将哈希值放入语句中。哈希值不可逆转,因此即使错误回显也不会泄漏密码:
sha256_hashIDENTIFIED WITH sha256_password BY '$CLICKHOUSE_PASSWORD'pssha256_hashsha256_passwordbash
WORKDIR="${WORKDIR:-$HOME/clickstack-otel-collector}"; ENV_FILE="$WORKDIR/collector.env"
[ -f "$WORKDIR/creds.env" ] && . "$WORKDIR/creds.env"; set -a; . "$ENV_FILE"; set +aSHA-256 of the password. openssl is already a dependency; this is portable (macOS + Linux).
密码的SHA-256哈希值。openssl已是依赖项;此命令可跨平台(macOS + Linux)运行。
Only this hash ever reaches SQL, output, or ps
; the plaintext stays in the env file.
ps只有哈希值会进入SQL、输出或ps
;明文密码始终保存在环境文件中。
psPW_HASH=$(printf %s "$CLICKHOUSE_PASSWORD" | openssl dgst -sha256 | awk '{print $NF}')
PW_HASH=$(printf %s "$CLICKHOUSE_PASSWORD" | openssl dgst -sha256 | awk '{print $NF}')
Send statements ONE AT A TIME: the Query API runs over HTTP and rejects multi-statement input
逐个发送语句:Query API通过HTTP运行,拒绝多语句输入("Multi-statements are not allowed"),因此单个分号分隔的批处理会失败。
("Multi-statements are not allowed"), so a single ; -separated batch fails.
—
clickhousectl cloud service query --id "$SERVICE_ID" --query
"CREATE USER IF NOT EXISTS hyperdx_ingest IDENTIFIED WITH sha256_hash BY '$PW_HASH'"
"CREATE USER IF NOT EXISTS hyperdx_ingest IDENTIFIED WITH sha256_hash BY '$PW_HASH'"
clickhousectl cloud service query --id "$SERVICE_ID" --query
"CREATE USER IF NOT EXISTS hyperdx_ingest IDENTIFIED WITH sha256_hash BY '$PW_HASH'"
"CREATE USER IF NOT EXISTS hyperdx_ingest IDENTIFIED WITH sha256_hash BY '$PW_HASH'"
Re-run safe: force the password to this run's value if the user already existed.
可安全重新运行:若用户已存在,强制将密码设置为本次运行的值。
clickhousectl cloud service query --id "$SERVICE_ID" --query
"ALTER USER hyperdx_ingest IDENTIFIED WITH sha256_hash BY '$PW_HASH'"
"ALTER USER hyperdx_ingest IDENTIFIED WITH sha256_hash BY '$PW_HASH'"
Grant the least privilege the collector needs to create and write the `otel.*` schema. On the
current image the schema migrations and their version table also live in `otel`, so `otel.*` is
sufficient (this statement carries no secret):
```bash
clickhousectl cloud service query --id "$SERVICE_ID" --query \
"GRANT SELECT, INSERT, CREATE DATABASE, CREATE TABLE, CREATE VIEW ON otel.* TO hyperdx_ingest"Older image builds: some earlier collector versions ran their goose migrations against a version table in thedatabase, so startup looped ondefaultuntilACCESS_DENIEDwas also granted. If you seedefault.*referencingACCESS_DENIEDin the collector logs (Step 6), add this and restart the container:defaultbashclickhousectl cloud service query --id "$SERVICE_ID" --query \ "GRANT SELECT, INSERT, CREATE TABLE ON default.* TO hyperdx_ingest"
Verify:
bash
clickhousectl cloud service query --id "$SERVICE_ID" --query "SHOW GRANTS FOR hyperdx_ingest"You should see .
GRANT SELECT, INSERT, CREATE DATABASE, CREATE TABLE, CREATE VIEW ON otel.* TO hyperdx_ingestclickhousectl cloud service query --id "$SERVICE_ID" --query
"ALTER USER hyperdx_ingest IDENTIFIED WITH sha256_hash BY '$PW_HASH'"
"ALTER USER hyperdx_ingest IDENTIFIED WITH sha256_hash BY '$PW_HASH'"
授予收集器创建和写入`otel.*`模式所需的最小权限。在当前镜像中,模式迁移及其版本表也位于`otel`中,因此`otel.*`权限已足够(此语句不包含密钥):
```bash
clickhousectl cloud service query --id "$SERVICE_ID" --query \
"GRANT SELECT, INSERT, CREATE DATABASE, CREATE TABLE, CREATE VIEW ON otel.* TO hyperdx_ingest"旧版镜像构建:某些早期收集器版本会在数据库中的版本表上运行goose迁移,因此启动时会因default错误循环,直到授予ACCESS_DENIED权限。若在收集器日志(步骤6)中看到引用default.*的default错误,添加以下权限并重启容器:ACCESS_DENIEDbashclickhousectl cloud service query --id "$SERVICE_ID" --query \ "GRANT SELECT, INSERT, CREATE TABLE ON default.* TO hyperdx_ingest"
验证权限:
bash
clickhousectl cloud service query --id "$SERVICE_ID" --query "SHOW GRANTS FOR hyperdx_ingest"您应看到。
GRANT SELECT, INSERT, CREATE DATABASE, CREATE TABLE, CREATE VIEW ON otel.* TO hyperdx_ingestStep 6: Set up the collector
步骤6:配置收集器
Follow the sub-section that matches the path and mode you chose in Step 0. All three converge on
the same end state: a collector accepting OTLP and writing into the database on the service.
Every code block in this step assumes you have run the standard preamble (Step 2) first, so
, , , and the secrets are set in the shell.
otel$WORKDIR$ENV_FILE$SERVICE_IDMake sure Docker is running (new-collector path only):
bash
WORKDIR="${WORKDIR:-$HOME/clickstack-otel-collector}"; ENV_FILE="$WORKDIR/collector.env"
[ -f "$WORKDIR/creds.env" ] && . "$WORKDIR/creds.env"; set -a; . "$ENV_FILE"; set +a
docker info > /dev/null按照步骤0中选择的路径和模式执行相应的子步骤。所有三种方式最终都会实现相同的状态:收集器接收OTLP数据并写入服务的数据库。此步骤中的所有代码块均假设您已先运行标准前置代码(步骤2),因此、、和密钥已在shell中设置。
otel$WORKDIR$ENV_FILE$SERVICE_ID确保Docker正在运行(仅新收集器路径适用):
bash
WORKDIR="${WORKDIR:-$HOME/clickstack-otel-collector}"; ENV_FILE="$WORKDIR/collector.env"
[ -f "$WORKDIR/creds.env" ] && . "$WORKDIR/creds.env"; set -a; . "$ENV_FILE"; set +a
docker info > /dev/nullStep 6a: New collector with Docker Compose (DEPLOY_MODE=compose
)
DEPLOY_MODE=compose步骤6a:使用Docker Compose部署新收集器(DEPLOY_MODE=compose
)
DEPLOY_MODE=composeWrite a Compose file in the working directory. It reads the same for secrets,
publishes the OTLP and health ports, and pins a named network so the telemetry generator in Step 7
can reach the collector by container name:
collector.envbash
cat > "$WORKDIR/docker-compose.yaml" <<'EOF'
name: clickstack
services:
otel-collector:
image: clickhouse/clickstack-otel-collector:latest
container_name: clickstack-otel-collector
env_file: ./collector.env
ports:
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
- "13133:13133" # health
restart: unless-stopped
networks: [clickstack-net]
networks:
clickstack-net:
name: clickstack-net
EOF在工作目录中编写Compose文件。文件读取相同的获取密钥,发布OTLP和健康检查端口,并固定命名网络,以便步骤7中的遥测数据生成器可通过容器名称访问收集器:
collector.envbash
cat > "$WORKDIR/docker-compose.yaml" <<'EOF'
name: clickstack
services:
otel-collector:
image: clickhouse/clickstack-otel-collector:latest
container_name: clickstack-otel-collector
env_file: ./collector.env
ports:
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
- "13133:13133" # health
restart: unless-stopped
networks: [clickstack-net]
networks:
clickstack-net:
name: clickstack-net
EOFCompose refuses to adopt a clickstack-net it did not create (a leftover from the docker run
Compose不会采用非自身创建的clickstack-net(例如来自docker run路径、之前失败的Compose运行或DEPLOY_MODE切换的遗留网络),会失败并提示"network clickstack-net was found but has incorrect label"。若存在无容器连接的孤立网络,需将其删除,以便Compose使用自己的标签重新创建。
path, a prior failed Compose run, or a DEPLOY_MODE switch), failing with "network clickstack-net
—
was found but has incorrect label". If an orphan exists with no containers attached, remove it so
—
Compose can recreate it with its own labels.
—
if docker network inspect clickstack-net >/dev/null 2>&1
&& [ -z "$(docker network inspect clickstack-net -f '{{range .Containers}}{{.Name}} {{end}}')" ]; then docker network rm clickstack-net fi
&& [ -z "$(docker network inspect clickstack-net -f '{{range .Containers}}{{.Name}} {{end}}')" ]; then docker network rm clickstack-net fi
( cd "$WORKDIR" && docker compose up -d )
Compose creates the `clickstack-net` network for you (the guard above clears an orphaned one from a
prior run first). Skip to **Step 6d** to confirm health.if docker network inspect clickstack-net >/dev/null 2>&1
&& [ -z "$(docker network inspect clickstack-net -f '{{range .Containers}}{{.Name}} {{end}}')" ]; then docker network rm clickstack-net fi
&& [ -z "$(docker network inspect clickstack-net -f '{{range .Containers}}{{.Name}} {{end}}')" ]; then docker network rm clickstack-net fi
( cd "$WORKDIR" && docker compose up -d )
Compose会为您创建`clickstack-net`网络(上述防护代码会先清除之前运行遗留的孤立网络)。跳至**步骤6d**确认健康状态。Step 6b: New collector with individual Docker commands (DEPLOY_MODE=run
)
DEPLOY_MODE=run步骤6b:使用单独的Docker命令部署新收集器(DEPLOY_MODE=run
)
DEPLOY_MODE=runCreate a user-defined network so the telemetry generator in Step 7 can reach the collector by
container name:
bash
docker network create clickstack-net 2>/dev/null || trueStart the collector, passing all secrets via (never , which would put the
secret on the command line, in shell history, and in ). The first makes the step
safe to re-run:
--env-file-epsdocker rm -fbash
docker rm -f clickstack-otel-collector 2>/dev/null || true
docker run -d \
--name clickstack-otel-collector \
--network clickstack-net \
--env-file "$ENV_FILE" \
-p 4317:4317 \
-p 4318:4318 \
-p 13133:13133 \
clickhouse/clickstack-otel-collector:latestThe image reads , , , ,
and from the env file. It enables bearer-token auth on
the OTLP receiver with an empty scheme, so callers send the raw token as the header
(no prefix). Continue to Step 6d.
OTLP_AUTH_TOKENCLICKHOUSE_ENDPOINTCLICKHOUSE_USERCLICKHOUSE_PASSWORDHYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASEauthorizationBearer 创建用户定义的网络,以便步骤7中的遥测数据生成器可通过容器名称访问收集器:
bash
docker network create clickstack-net 2>/dev/null || true启动收集器,通过传递所有密钥(切勿使用,否则密钥会出现在命令行、shell历史记录和中)。先执行确保步骤可安全重新运行:
--env-file-epsdocker rm -fbash
docker rm -f clickstack-otel-collector 2>/dev/null || true
docker run -d \
--name clickstack-otel-collector \
--network clickstack-net \
--env-file "$ENV_FILE" \
-p 4317:4317 \
-p 4318:4318 \
-p 13133:13133 \
clickhouse/clickstack-otel-collector:latest镜像从环境文件中读取、、、和。它在OTLP接收器上启用Bearer令牌认证,无前缀,因此调用者需将原始令牌作为头发送(无需前缀)。继续执行步骤6d。
OTLP_AUTH_TOKENCLICKHOUSE_ENDPOINTCLICKHOUSE_USERCLICKHOUSE_PASSWORDHYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASEauthorizationBearer Step 6c: Configure your existing collector (COLLECTOR_PATH=existing
)
COLLECTOR_PATH=existing步骤6c:配置现有收集器(COLLECTOR_PATH=existing
)
COLLECTOR_PATH=existingAdd the ClickHouse exporter to your existing collector configuration. The config below matches the
behavior of the ClickStack distribution, including the Session Replay () routing path, and
writes into the database the ClickStack UI expects.
rrwebotelReference the endpoint and password as environment variables (), do not hardcode them
into the config file. The contrib collector expands at load time, so keeping the
plaintext password out of the config file is both safer and consistent with the rest of this skill.
Start your collector with the env vars available, the simplest way is the same the
local collector uses:
${env:…}${env:VAR}--env-filebash
undefined将ClickHouse导出器添加到现有收集器的配置中。以下配置与ClickStack分发版的行为一致,包括会话重放()路由路径,并写入ClickStack UI期望的数据库。
rrwebotel将端点和密码引用为环境变量(),不要硬编码到配置文件中。contrib收集器会在加载时展开,因此将明文密码保留在配置文件外既更安全,也与本技能的其余部分保持一致。启动收集器时需确保环境变量可用,最简单的方式是使用本地收集器使用的相同:
${env:…}${env:VAR}--env-filebash
undefinedWhen running the contrib collector in Docker, pass collector.env so ${env:CLICKHOUSE_*} resolve:
在Docker中运行contrib收集器时,传递collector.env以便${env:CLICKHOUSE_*}解析:
docker run -d --env-file "$ENV_FILE" -p 4317:4317 -p 4318:4318 \
docker run -d --env-file "$ENV_FILE" -p 4317:4317 -p 4318:4318 \
-v "$WORKDIR/your-config.yaml:/etc/otelcol-contrib/config.yaml:ro" \
-v "$WORKDIR/your-config.yaml:/etc/otelcol-contrib/config.yaml:ro" \
otel/opentelemetry-collector-contrib:latest
otel/opentelemetry-collector-contrib:latest
For a non-Docker collector, export CLICKHOUSE_ENDPOINT and CLICKHOUSE_PASSWORD into its
对于非Docker收集器,在启动前将CLICKHOUSE_ENDPOINT和CLICKHOUSE_PASSWORD导出到其环境中(例如systemd单元中的EnvironmentFile=)。
environment (e.g. an EnvironmentFile= in the systemd unit) before it starts.
—
Add this to your collector config and reload it:
```yaml
receivers:
otlp/hyperdx:
protocols:
grpc:
include_metadata: true
endpoint: "0.0.0.0:4317"
http:
cors:
allowed_origins: ["*"]
allowed_headers: ["*"]
include_metadata: true
endpoint: "0.0.0.0:4318"
processors:
batch:
memory_limiter:
limit_mib: 1500
spike_limit_mib: 512
check_interval: 5s
connectors:
routing/logs:
default_pipelines: [logs/out-default]
error_mode: ignore
table:
- context: log
statement: route() where IsMatch(attributes["rr-web.event"], ".*")
pipelines: [logs/out-rrweb]
exporters:
clickhouse:
database: otel
endpoint: ${env:CLICKHOUSE_ENDPOINT}
username: hyperdx_ingest
password: ${env:CLICKHOUSE_PASSWORD}
ttl: 720h
timeout: 5s
retry_on_failure:
enabled: true
initial_interval: 5s
max_interval: 30s
max_elapsed_time: 300s
clickhouse/rrweb:
database: otel
endpoint: ${env:CLICKHOUSE_ENDPOINT}
username: hyperdx_ingest
password: ${env:CLICKHOUSE_PASSWORD}
ttl: 720h
logs_table_name: hyperdx_sessions
timeout: 5s
retry_on_failure:
enabled: true
initial_interval: 5s
max_interval: 30s
max_elapsed_time: 300s
service:
pipelines:
traces:
receivers: [otlp/hyperdx]
processors: [memory_limiter, batch]
exporters: [clickhouse]
metrics:
receivers: [otlp/hyperdx]
processors: [memory_limiter, batch]
exporters: [clickhouse]
logs/in:
receivers: [otlp/hyperdx]
exporters: [routing/logs]
logs/out-default:
receivers: [routing/logs]
processors: [memory_limiter, batch]
exporters: [clickhouse]
logs/out-rrweb:
receivers: [routing/logs]
processors: [memory_limiter, batch]
exporters: [clickhouse/rrweb]Notes for this path:
- If you use your own distribution, ensure it includes the ClickHouse exporter. The upstream contrib image already does.
- Authentication on the OTLP receivers is your existing setup. The generated in Step 2 is not used here unless you wire it into your own auth (for example
OTLP_AUTH_TOKEN).bearertokenauth - After reloading, skip the health check below (that is specific to the local container) and go straight to Step 7 to send a verification burst (point the generator at your own collector's OTLP endpoint).
将以下内容添加到收集器配置中并重新加载:
```yaml
receivers:
otlp/hyperdx:
protocols:
grpc:
include_metadata: true
endpoint: "0.0.0.0:4317"
http:
cors:
allowed_origins: ["*"]
allowed_headers: ["*"]
include_metadata: true
endpoint: "0.0.0.0:4318"
processors:
batch:
memory_limiter:
limit_mib: 1500
spike_limit_mib: 512
check_interval: 5s
connectors:
routing/logs:
default_pipelines: [logs/out-default]
error_mode: ignore
table:
- context: log
statement: route() where IsMatch(attributes["rr-web.event"], ".*")
pipelines: [logs/out-rrweb]
exporters:
clickhouse:
database: otel
endpoint: ${env:CLICKHOUSE_ENDPOINT}
username: hyperdx_ingest
password: ${env:CLICKHOUSE_PASSWORD}
ttl: 720h
timeout: 5s
retry_on_failure:
enabled: true
initial_interval: 5s
max_interval: 30s
max_elapsed_time: 300s
clickhouse/rrweb:
database: otel
endpoint: ${env:CLICKHOUSE_ENDPOINT}
username: hyperdx_ingest
password: ${env:CLICKHOUSE_PASSWORD}
ttl: 720h
logs_table_name: hyperdx_sessions
timeout: 5s
retry_on_failure:
enabled: true
initial_interval: 5s
max_interval: 30s
max_elapsed_time: 300s
service:
pipelines:
traces:
receivers: [otlp/hyperdx]
processors: [memory_limiter, batch]
exporters: [clickhouse]
metrics:
receivers: [otlp/hyperdx]
processors: [memory_limiter, batch]
exporters: [clickhouse]
logs/in:
receivers: [otlp/hyperdx]
exporters: [routing/logs]
logs/out-default:
receivers: [routing/logs]
processors: [memory_limiter, batch]
exporters: [clickhouse]
logs/out-rrweb:
receivers: [routing/logs]
processors: [memory_limiter, batch]
exporters: [clickhouse/rrweb]此路径的注意事项:
- 若使用自定义分发版,需确保包含ClickHouse导出器。上游contrib镜像已包含该导出器。
- OTLP接收器的认证由您的现有配置决定。步骤2中生成的仅在您将其接入自己的认证(例如
OTLP_AUTH_TOKEN)时才会使用。bearertokenauth - 重新加载后,跳过以下健康检查(仅适用于本地容器),直接进入步骤7发送验证数据(将生成器指向您自己收集器的OTLP端点)。
Step 6d: Confirm the local collector is healthy (new-collector path)
步骤6d:确认本地收集器健康(仅新收集器路径适用)
bash
docker ps --filter name=clickstack-otel-collector --format '{{.Status}}'
curl -fsS http://localhost:13133/ && echo
docker logs --tail 40 clickstack-otel-collector 2>&1 | tail -40A healthy start shows the seed migrations running to completion ( lines ending in
), then (or equivalent), reporting , and the health check returning
HTTP 200. A seed line like on an older server version is expected and harmless, not an error; do not pause on it.
If instead the container exits, the cause is almost always in the seed step:
[seed] OK ...goose: up to current file version: NEverything is ready. Begin running and processing data.docker psUp ... (healthy)ClickHouse 25.12 < 26.2, falling back to compatibility logs and traces schemas- ->
code: 516, Authentication failed: password is incorrectis empty or wrong in the env file. The most common slip is storing the password under a different key name (it must beCLICKHOUSE_PASSWORD), or using a password containingCLICKHOUSE_PASSWORD, which corrupts the migration tool's connection URL.@ : / ? # % - /
[HTTP 403]at "server hello" -> same root cause: an empty/wrong password against the HTTPS endpoint.data size should be 0 < <huge number> - TLS / dial errors -> is malformed (it must be
CLICKHOUSE_ENDPOINT, with nohttps://<host>:8443on the port)..0 - referencing
ACCESS_DENIED-> only on older image builds; apply thedefaultgrant from the Step 5 note and restart.default.*
bash
docker ps --filter name=clickstack-otel-collector --format '{{.Status}}'
curl -fsS http://localhost:13133/ && echo
docker logs --tail 40 clickstack-otel-collector 2>&1 | tail -40健康启动会显示种子迁移运行完成(以开头的行,结尾为),然后显示(或类似内容),报告,健康检查返回HTTP 200。在旧版服务器上,若出现类似的种子行,属于预期且无害的情况,并非错误;无需在此暂停。若容器退出,原因几乎总是在种子步骤中:
[seed] OK ...goose: up to current file version: NEverything is ready. Begin running and processing data.docker psUp ... (healthy)ClickHouse 25.12 < 26.2, falling back to compatibility logs and traces schemas- → 环境文件中的
code: 516, Authentication failed: password is incorrect为空或错误。最常见的错误是将密码存储在其他密钥名称下(必须为CLICKHOUSE_PASSWORD),或使用包含CLICKHOUSE_PASSWORD的密码,这会破坏迁移工具的连接URL。@ : / ? # % - /
[HTTP 403]在“server hello”时出现 → 根本原因相同:HTTPS端点使用的密码为空或错误。data size should be 0 < <huge number> - TLS / 连接错误 → 格式错误(必须为
CLICKHOUSE_ENDPOINT,端口后不能有https://<host>:8443)。.0 - 引用
ACCESS_DENIED→ 仅旧版镜像构建会出现;应用步骤5备注中的default权限并重启容器。default.*
Step 7: Send rich synthetic telemetry and verify ingestion
步骤7:发送丰富的合成遥测数据并验证采集
Use (the OpenTelemetry Collector Contrib generator) from its Docker image, so
nothing is installed on the host. Instead of one flat burst, send telemetry across several
services, severities, span statuses, and metric types, so ClickStack's Search,
Service Map, and dashboards have realistic, varied data rather than a single uniform stream.
telemetrygenLoad the env file so the token is available, then reference . The helper
below redirects all generator output to a log file and prints only an exit code, because
echoes its full config, including the header (your OTLP token),
to stdout. Never surface that raw output in the chat. 's header syntax requires the
value to be a quoted string: .
$OTLP_AUTH_TOKENtgtelemetrygenauthorizationtelemetrygenkey="value"bash
WORKDIR="${WORKDIR:-$HOME/clickstack-otel-collector}"; ENV_FILE="$WORKDIR/collector.env"
[ -f "$WORKDIR/creds.env" ] && . "$WORKDIR/creds.env"; set -a; . "$ENV_FILE"; set +a
TG_IMAGE=ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:latest
NET=clickstack-net
ENDPOINT=clickstack-otel-collector:4317
TG_LOG="$WORKDIR/telemetrygen.log"; : > "$TG_LOG"
tg() {
# usage: tg <logs|traces|metrics> [extra telemetrygen flags...]
# Output (which contains the token in the echoed config) goes to $TG_LOG, never the terminal.
local signal="$1"; shift
docker run --rm --network "$NET" "$TG_IMAGE" "$signal" \
--otlp-endpoint "$ENDPOINT" \
--otlp-insecure \
--otlp-header "authorization=\"$OTLP_AUTH_TOKEN\"" \
--rate 10 --duration 15s "$@" >>"$TG_LOG" 2>&1
echo "$signal exit=$?"
}Existing-collector path: setandNETto reach your collector instead. If it runs on this host, useENDPOINTstyle access or point--network hostat its published address, and set theENDPOINTheader (or other auth) to whatever your receiver expects. Everything below is otherwise identical.authorization
Judge success by exit code and row counts, never by the generator's logs. Two reasons. First,
the log contains your OTLP token (see above), so do not print it. Second, it is noisy and every run
ends with once
elapses, which is expected shutdown, not a failure. The helper already prints
on success. If you must inspect a failure, grep the log for the real signal
without dumping it, for example (a non-zero count plus a
non-zero exit means the header did not match). Confirm overall success with the row
counts in the verification queries below.
rpc error: code = Canceled desc = grpc: the client connection is closing--durationtg<signal> exit=0grep -c Unauthenticated "$TG_LOG"authorizationQuote attribute values so the inner double quotes survive the shell. requires
each attribute as (with literal double quotes), and rejects a bare with
. If you write , bash strips the quotes and the container receives
, which hard-fails. Wrap the whole argument in single quotes
so the inner double quotes reach the container, exactly as the helper already does for the
auth header.
telemetrygenkey="value"key=valuevalue should be a string wrapped in double quotes--otlp-attributes deployment.environment="production"deployment.environment=productiontgLogs across two services with different severities and bodies, including an error line:
bash
tg logs --service checkout --severity-text Info --severity-number 9 \
--body "checkout completed" \
--otlp-attributes 'deployment.environment="production"' \
--telemetry-attributes 'http.method="POST"'
tg logs --service payment --severity-text Error --severity-number 17 \
--body "payment gateway timeout" \
--otlp-attributes 'deployment.environment="production"' \
--telemetry-attributes 'http.status_code="500"'Traces with child spans, a healthy service and an erroring one (this is what populates the Service
Map and the error views):
bash
tg traces --service checkout --child-spans 4 --span-duration 120ms --status-code Ok \
--otlp-attributes 'deployment.environment="production"' \
--telemetry-attributes 'http.route="/cart"'
tg traces --service payment --child-spans 3 --span-duration 400ms --status-code Error \
--otlp-attributes 'deployment.environment="production"' \
--telemetry-attributes 'http.route="/charge"'Metrics across the three common types, so dashboards have gauges, counters, and a distribution:
bash
tg metrics --service checkout --metric-type Sum
tg metrics --service checkout --metric-type Gauge
tg metrics --service payment --metric-type Histogram( accepts , , , or . Add
with to exercise the HTTP path instead of gRPC.)
--metric-typeGaugeSumHistogramExponentialHistogram--otlp-http--otlp-endpoint clickstack-otel-collector:4318Wait ~15 seconds for the collector to flush its batch, then confirm the tables exist:
bash
clickhousectl cloud service query --id "$SERVICE_ID" --query \
"SELECT name FROM system.tables WHERE database='otel' ORDER BY name"Then confirm rows are landing. Count by , which is signal-agnostic and avoids
hard-coding per-signal column names:
parts.rowsbash
clickhousectl cloud service query --id "$SERVICE_ID" --query \
"SELECT table, sum(rows) AS rows
FROM system.parts
WHERE database='otel' AND active
AND table IN ('otel_logs','otel_traces',
'otel_metrics_sum','otel_metrics_gauge',
'otel_metrics_histogram','otel_metrics_exponential_histogram',
'otel_metrics_summary')
GROUP BY table ORDER BY table"You should see non-zero for , , ,
, and . If a signal is missing:
rowsotel_logsotel_tracesotel_metrics_sumotel_metrics_gaugeotel_metrics_histogram- Tail the collector logs () for export errors.
docker logs --tail 50 clickstack-otel-collector - Confirm the header matches
authorization:$OTLP_AUTH_TOKEN(a non-zero count means a mismatch, the full message isgrep -c Unauthenticated "$TG_LOG"). Grep rather than print the log, since it contains the token.code = Unauthenticated desc = provided authorization does not match expected scheme or token - Re-check has the
CLICKHOUSE_ENDPOINTscheme andhttps://port.:8443 - Some metric kinds flush slowly. Re-run the count after another 30 seconds before declaring failure.
Do not proceed until every expected signal has non-zero rows.
使用(OpenTelemetry Collector Contrib生成器)的Docker镜像,无需在主机上安装任何内容。不要发送单一的扁平数据,而是发送跨多个服务、严重级别、链路状态和指标类型的遥测数据,使ClickStack的搜索功能、服务地图和仪表盘拥有真实多样的数据,而非单一统一的数据流。
telemetrygen加载环境文件以获取令牌,然后引用。以下助手会将所有生成器输出重定向到日志文件,仅打印退出代码,因为会回显其完整配置,**包括头(您的OTLP令牌)**到标准输出。切勿在对话中显示原始输出。的头语法要求值为带引号的字符串:。
$OTLP_AUTH_TOKENtgtelemetrygenauthorizationtelemetrygenkey="value"bash
WORKDIR="${WORKDIR:-$HOME/clickstack-otel-collector}"; ENV_FILE="$WORKDIR/collector.env"
[ -f "$WORKDIR/creds.env" ] && . "$WORKDIR/creds.env"; set -a; . "$ENV_FILE"; set +a
TG_IMAGE=ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:latest
NET=clickstack-net
ENDPOINT=clickstack-otel-collector:4317
TG_LOG="$WORKDIR/telemetrygen.log"; : > "$TG_LOG"
tg() {
# 使用方法:tg <logs|traces|metrics> [额外的telemetrygen参数...]
# 输出(包含回显配置中的令牌)会写入$TG_LOG,不会显示在终端。
local signal="$1"; shift
docker run --rm --network "$NET" "$TG_IMAGE" "$signal" \
--otlp-endpoint "$ENDPOINT" \
--otlp-insecure \
--otlp-header "authorization=\"$OTLP_AUTH_TOKEN\"" \
--rate 10 --duration 15s "$@" >>"$TG_LOG" 2>&1
echo "$signal exit=$?"
}现有收集器路径:设置和NET以指向您的收集器。若收集器在本机运行,使用ENDPOINT方式访问或将--network host指向其发布地址,并设置ENDPOINT头(或其他认证方式)以匹配接收器的要求。其余操作完全相同。authorization
通过退出代码和行数判断成功,而非生成器的日志。原因有二:首先,日志包含您的OTLP令牌(如上所述),因此不要打印;其次,日志内容繁杂,每次运行结束时都会出现,这是结束后的预期关闭,并非故障。助手会在成功时打印。若必须检查故障,可在日志中搜索真实信号而非完整打印,例如(非零计数加非零退出码表示头不匹配)。通过以下验证查询中的行数确认整体成功。
rpc error: code = Canceled desc = grpc: the client connection is closing--durationtg<signal> exit=0grep -c Unauthenticated "$TG_LOG"authorization为属性值添加引号,确保内部双引号在shell中保留。要求每个属性为(包含字面双引号),并拒绝裸格式,提示。若您编写,bash会移除引号,容器将收到,这会导致失败。需将整个参数用单引号包裹,使内部双引号传递到容器中,就像助手对认证头的处理一样。
telemetrygenkey="value"key=valuevalue should be a string wrapped in double quotes--otlp-attributes deployment.environment="production"deployment.environment=productiontg发送跨两个服务、不同严重级别和内容的日志,包括一条错误日志:
bash
tg logs --service checkout --severity-text Info --severity-number 9 \
--body "checkout completed" \
--otlp-attributes 'deployment.environment="production"' \
--telemetry-attributes 'http.method="POST"'
tg logs --service payment --severity-text Error --severity-number 17 \
--body "payment gateway timeout" \
--otlp-attributes 'deployment.environment="production"' \
--telemetry-attributes 'http.status_code="500"'发送包含子链路、健康服务和错误服务的链路追踪数据(这会填充服务地图和错误视图):
bash
tg traces --service checkout --child-spans 4 --span-duration 120ms --status-code Ok \
--otlp-attributes 'deployment.environment="production"' \
--telemetry-attributes 'http.route="/cart"'
tg traces --service payment --child-spans 3 --span-duration 400ms --status-code Error \
--otlp-attributes 'deployment.environment="production"' \
--telemetry-attributes 'http.route="/charge"'发送三种常见类型的指标,使仪表盘拥有仪表图、计数器和分布数据:
bash
tg metrics --service checkout --metric-type Sum
tg metrics --service checkout --metric-type Gauge
tg metrics --service payment --metric-type Histogram(接受、、或。添加并设置可使用HTTP路径而非gRPC。)
--metric-typeGaugeSumHistogramExponentialHistogram--otlp-http--otlp-endpoint clickstack-otel-collector:4318等待约15秒让收集器刷新批处理,然后确认表已存在:
bash
clickhousectl cloud service query --id "$SERVICE_ID" --query \
"SELECT name FROM system.tables WHERE database='otel' ORDER BY name"然后确认数据已写入。通过计数,该方式与信号类型无关,无需硬编码每个信号的列名:
parts.rowsbash
clickhousectl cloud service query --id "$SERVICE_ID" --query \
"SELECT table, sum(rows) AS rows
FROM system.parts
WHERE database='otel' AND active
AND table IN ('otel_logs','otel_traces',
'otel_metrics_sum','otel_metrics_gauge',
'otel_metrics_histogram','otel_metrics_exponential_histogram',
'otel_metrics_summary')
GROUP BY table ORDER BY table"您应看到、、、和的值非零。若某个信号缺失:
otel_logsotel_tracesotel_metrics_sumotel_metrics_gaugeotel_metrics_histogramrows- 查看收集器日志尾部()寻找导出错误。
docker logs --tail 50 clickstack-otel-collector - 确认头与
authorization匹配:$OTLP_AUTH_TOKEN(非零计数加非零退出码表示不匹配,完整消息为grep -c Unauthenticated "$TG_LOG")。仅搜索日志而非打印,因为日志包含令牌。code = Unauthenticated desc = provided authorization does not match expected scheme or token - 重新检查是否包含
CLICKHOUSE_ENDPOINT协议和https://端口。:8443 - 某些指标类型刷新较慢。在判定失败前,等待30秒后重新运行计数。
在所有预期信号的行数均非零前不要继续。
Step 8: Confirm the service is awake, then complete onboarding in ClickStack
步骤8:确认服务活跃,完成ClickStack入门流程
Rows in ClickHouse are not the same as the user seeing telemetry in ClickStack. The ClickStack
UI requires a one-time onboarding step that auto-detects the data sources, and that step fails if
the ClickHouse service has idle-suspended in the meantime.
First, confirm the service is awake. Do not skip this; it is the most common reason onboarding
shows no sources. Run a real query and require it to succeed:
bash
clickhousectl cloud service query --id "$SERVICE_ID" --query "SELECT 1"If this returns , the service is awake; continue immediately to the console steps below while it
stays warm. If it errors or times out, the service was asleep and this call is waking it: wait a
few seconds and re-run until it returns . Only proceed once it succeeds.
11Then walk the user through onboarding explicitly. Do not just say "done"; spell out each click,
because the sources only appear after this flow is completed:
- Go to the ClickHouse Cloud console and open the target service.
- In the left-hand menu, select ClickStack.
- Click through to Getting Started and follow the onboarding flow.
- Ignore any prompt that asks you to set up or configure a collector / start ingestion. You have already done that in the steps above. Skip straight past those screens (click through / "Next") to source detection. Re-running the console's collector setup is unnecessary and only causes confusion.
- The data sources are auto-detected: logs, traces, and metrics for the database are picked up automatically, and your data appears in the Search and dashboard views.
otel
The direct link is (substitute
).
https://console.clickhouse.cloud/services/<SERVICE_ID>/clickstack$SERVICE_IDIf source detection shows nothing, the service almost certainly idle-suspended between the data
send and the console step. Re-run the wake query above for the user, then have them
re-run the detection, rather than leaving them to debug an opaque failure.
SELECT 1ClickHouse中的数据不等于用户在ClickStack中看到遥测数据。ClickStack UI需要一次性入门步骤来自动检测数据源,若ClickHouse服务在此期间空闲暂停,该步骤会失败。
首先,确认服务活跃。不要跳过此步骤;这是入门流程未显示数据源的最常见原因。运行真实查询并确保成功:
bash
clickhousectl cloud service query --id "$SERVICE_ID" --query "SELECT 1"若返回,则服务活跃;请立即继续以下控制台步骤,保持服务处于活跃状态。若出现错误或超时,说明服务处于休眠状态,此调用正在唤醒服务:等待几秒后重新运行,直到返回。仅在成功后继续。
11然后明确引导用户完成入门流程。不要只说“完成”;需详细说明每一步,因为只有完成此流程后数据源才会显示:
- 前往ClickHouse Cloud控制台并打开目标服务。
- 在左侧菜单中选择ClickStack。
- 进入Getting Started并跟随入门流程操作。
- 忽略任何要求您设置或配置收集器/开始采集的提示。您已在上述步骤中完成了这些操作。直接跳过这些屏幕(点击“Next”)进入数据源检测。重新运行控制台的收集器设置毫无必要,只会造成混淆。
- 数据源会自动检测:数据库的日志、链路追踪和指标会被自动识别,您的数据会显示在搜索和仪表盘视图中。
otel
直接链接为(替换)。
https://console.clickhouse.cloud/services/<SERVICE_ID>/clickstack$SERVICE_ID若数据源检测未显示任何内容,几乎可以肯定是在发送数据和控制台步骤之间服务空闲暂停了。为用户重新运行唤醒查询,然后让他们重新运行检测,而非让他们调试模糊的故障。
SELECT 1Step 9: Summarize and hand off (without echoing secrets)
步骤9:总结并交接(不回显密钥)
Print a summary in roughly this format. Note the token is referenced, not printed, the SQL
password is not shown at all, and the collector keeps running until the user stops it. Adjust the
"how to stop" line to the deploy mode they chose.
✅ ClickStack is set up and ingesting telemetry for service <SERVICE_NAME> (<SERVICE_ID>).
Complete onboarding in the console (Step 8) to auto-detect the sources and see your data.
Collector
▸ New local collector via <Docker Compose | docker run> (or: configured your existing collector)
▸ Send OTLP gRPC to: localhost:4317
▸ Send OTLP HTTP to: localhost:4318
▸ Health check: http://localhost:13133/ (local collector only)
▸ Required header: authorization: <OTLP token>
(retrieve with: grep OTLP_AUTH_TOKEN <WORKDIR>/collector.env)
ClickHouse target
▸ Endpoint: <CLICKHOUSE_ENDPOINT>
▸ SQL user: hyperdx_ingest (password in <WORKDIR>/collector.env, mode 0600)
▸ Database: otel
Finish in the ClickHouse Cloud console:
▸ Open the service, select ClickStack in the left menu, then Getting Started,
and complete onboarding to auto-detect sources.
▸ https://console.clickhouse.cloud/services/<SERVICE_ID>/clickstackThen tell the user, in your own words, that:
- All secrets live in (mode
<WORKDIR>/collector.env). Nothing sensitive was pasted into this chat or passed on a0600command line.docker run - The collector keeps running until they stop it. For Compose:
stops it,
cd <WORKDIR> && docker compose downbrings it back. For individual Docker:docker compose up -danddocker stop clickstack-otel-collector.docker start clickstack-otel-collector - Any application, SDK, or agent on this host can now send OTLP to (gRPC) or
localhost:4317(HTTP) with thelocalhost:4318header from the env file.authorization - The ClickHouse Cloud service idle-suspends. If ClickStack later shows no recent data, the service may simply be asleep; sending new telemetry or running any query wakes it.
打印大致如下格式的总结。注意令牌仅被引用,不打印,SQL密码完全不显示,收集器会持续运行直到用户停止。根据用户选择的部署模式调整“如何停止”的内容。
✅ 已为服务<SERVICE_NAME>(<SERVICE_ID>)完成ClickStack设置并开始采集遥测数据。
完成控制台中的入门流程(步骤8)以自动检测数据源并查看您的数据。
收集器信息
▸ 通过<Docker Compose | docker run>部署的新本地收集器 (或:已配置您的现有收集器)
▸ OTLP gRPC发送地址:localhost:4317
▸ OTLP HTTP发送地址:localhost:4318
▸ 健康检查地址: http://localhost:13133/ (仅本地收集器)
▸ 必填请求头: authorization: <OTLP令牌>
(获取方式: grep OTLP_AUTH_TOKEN <WORKDIR>/collector.env)
ClickHouse目标信息
▸ 端点:<CLICKHOUSE_ENDPOINT>
▸ SQL用户:hyperdx_ingest (密码存储在<WORKDIR>/collector.env,权限0600)
▸ 数据库:otel
在ClickHouse Cloud控制台完成后续操作:
▸ 打开服务,在左侧菜单中选择ClickStack,然后进入Getting Started,
完成入门流程以自动检测数据源。
▸ https://console.clickhouse.cloud/services/<SERVICE_ID>/clickstack然后用您自己的语言告知用户:
- 所有密钥存储在中(权限0600)。任何敏感内容均未粘贴到此对话中,也未在
<WORKDIR>/collector.env命令行中传递。docker run - 收集器会持续运行直到用户停止。对于Compose部署:停止服务,
cd <WORKDIR> && docker compose down重新启动。对于单独的Docker部署:docker compose up -d停止,docker stop clickstack-otel-collector启动。docker start clickstack-otel-collector - 本机上的任何应用、SDK或代理现在均可将OTLP数据发送到(gRPC)或
localhost:4317(HTTP),并附带环境文件中的localhost:4318头。authorization - ClickHouse Cloud服务会空闲暂停。若ClickStack后续未显示最新数据,可能是服务处于休眠状态;发送新的遥测数据或运行任何查询即可唤醒服务。
Cleanup (only if the user explicitly asks)
清理(仅当用户明确要求时执行)
bash
undefinedbash
undefinedDocker Compose deployment:
Docker Compose部署:
( cd "$WORKDIR" && docker compose down )
( cd "$WORKDIR" && docker compose down )
Individual Docker deployment:
单独的Docker部署:
docker rm -f clickstack-otel-collector
docker network rm clickstack-net 2>/dev/null || true
docker rm -f clickstack-otel-collector
docker network rm clickstack-net 2>/dev/null || true
Either deployment, remove the ingest user:
任何部署方式,移除采集用户:
clickhousectl cloud service query --id "$SERVICE_ID" --query "DROP USER IF EXISTS hyperdx_ingest"
clickhousectl cloud service query --id "$SERVICE_ID" --query "DROP USER IF EXISTS hyperdx_ingest"
Optionally remove the local files once they are no longer needed:
可选:不再需要时删除本地文件:
rm -f "$WORKDIR/collector.env" "$WORKDIR/svc.json" "$WORKDIR/docker-compose.yaml"
rm -f "$WORKDIR/collector.env" "$WORKDIR/svc.json" "$WORKDIR/docker-compose.yaml"
Do **not** drop the `otel` database: it contains telemetry the user may want to retain.
请勿删除`otel`数据库:它包含用户可能需要保留的遥测数据。