Ubuntu 22.04 安装 Apache Flagon 指南
在 Ubuntu 22.04 从零安装 Apache Flagon(UserALE.js 2.4.0 + 收集服务器 + Distill 0.1.0)的源码构建与 npm 包双方案实测指南,含 systemd 托管与端到端数据收集验证。
Ubuntu 22.04 安装 Apache Flagon 指南
目标:在 Ubuntu 22.04 服务器上从零安装 Apache Flagon 的可跑通组件组合——UserALE.js 2.4.0(npm
flagon-userale)+ 官方 Example Collector(Node.js 收集服务器)+ Distill 0.1.0(Python 分析端),并以 systemd 托管、用 curl 与 Distill 验证行为日志端到端收集。全部命令与回显均在 Ubuntu 22.04.5 LTS(x86_64)实测通过(2026-10-16 实测)。
一、环境信息
本文实测环境与目录约定如下,所有命令默认在 /root 下执行:
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- Node.js:v20.20.2(npm 10.8.2)、pnpm:9.15.9
- Python:3.10.12(pip 22.0.2,系统自带)、Git:2.34.1
- 源码目录:
/root/flagon(monorepo 主线);npm 方案目录:/root/uale-npm - 收集服务器端口:8000(HTTP + WebSocket)
- 日志落盘目录:
/root/flagon/products/userale/example/logs/ - 实测版本:UserALE.js 2.4.0(npm dist-tags latest)、Distill 0.1.0(PyPI)、monorepo master(2026-10-11 提交)
先确认系统版本(实测回显):
cat /etc/os-release | head -3
uname -m
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
x86_64
💡 说明:Apache Flagon 当前主线是 monorepo(github.com/apache/flagon),历史上独立存在的 distillery 数据收集服务与 stout 仓库已在 GitHub 上消失(实测返回 404),因此本指南的收集端采用官方
example/server参考实现,前端采集端采用 UserALE.js——这是官方仓库现状下唯一可跑通的最小闭环组合。
二、前置条件
Flagon 最小闭环由「前端采集(UserALE.js)+ 收集端(Node.js)+ 分析端(Python)」组成,安装前需要准备:基础编译与下载工具(curl、ca-certificates、git)、Node.js ≥ 20、pnpm、Python 3.10+ 与 pip、可用的出网通道。逐项安装基础依赖(实测回显,输出节选):
apt-get update
apt-get install -y curl ca-certificates gnupg git python3 python3-pip
Get:18 http://archive.ubuntu.com/ubuntu jammy-backports/universe amd64 Packages [35.6 kB]
Fetched 49.0 MB in 21s (2299 kB/s)
Setting up ca-certificates (20260601~22.04.1) ...
0 added, 0 removed; done.
💡 技术拓展:Node.js 的安装方式不止 NodeSource 仓库一种——Ubuntu 官方仓库版本旧(jammy 为 12.x,无法满足构建要求);nvm 适合开发机多版本并存;官方 tar.xz 二进制包适合内网离线。生产服务器推荐 NodeSource apt 仓库(20/22/24 大版本可选、apt 统一管理、
/usr/bin/node路径固定便于 systemd 引用),本文即采用该方式(见 4.2 节)。
三、版本选型说明
安装前先核实各组件的当前版本,避免用过时资料里的旧组件(如已消失的 distillery)。实测核实 npm 侧 UserALE.js:
npm view flagon-userale dist-tags version
dist-tags = { latest: '2.4.0' }
version = '2.4.0'
pip3 index versions flagon-distill
WARNING: pip index is currently an experimental command. It may be removed/changed in a future release without prior warning.
flagon-distill (0.1.0)
Available versions: 0.1.0
INSTALLED: 0.1.0
LATEST: 0.1.0
版本选型对照表:
| 组件 | 实测最新版 | 获取渠道 | 说明 |
|---|---|---|---|
| UserALE.js | 2.4.0 | npm flagon-userale | 前端采集库,版本序列 1.0.0→2.4.0 共 8 版 |
| Example Collector | master(随 monorepo) | git clone | Node.js Express + WebSocket 收集参考实现 |
| Distill | 0.1.0 | PyPI flagon-distill | 分析端仅一个已发布版本,建议源码安装 monorepo 版 |
| monorepo | master 61677c7(2026-10-11) | github.com/apache/flagon | 主线开发仓库 |
选型结论:生产采集端用 npm 固定 2.4.0 版本;需要最新修复/参与开发则走 monorepo 源码构建;分析端直接源码安装 monorepo 的 products/distill(其依赖比 PyPI 0.1.0 新,实测功能更全)。
四、方案 A:源码构建安装(官方主线,推荐)
4.1 方案说明
从官方 monorepo 克隆源码,用 pnpm 构建 UserALE workspace(同时产出前端 IIFE 包与浏览器扩展),直接以仓库自带 Example Collector 起收集服务。适合需要完整能力(扩展、示例、最新修复)的部署,也是官方 Quick Start 路径。
4.2 安装 Node.js 20 与 pnpm
NodeSource 脚本方式接入 Node.js 20 仓库并安装(实测回显):
curl -fsSL https://deb.nodesource.com/setup_20.x -o /tmp/nodesource_setup.sh
bash /tmp/nodesource_setup.sh
apt-get install -y nodejs
npm install -g pnpm@9
2026-10-16 04:00:47 - You can use N|solid Runtime as a node.js alternative
2026-10-16 04:00:48 - To install N|solid Runtime, run: apt install nsolid -y
Setting up nodejs (20.20.2-1nodesource1) ...
npm notice To update run: npm install -g npm@12.2.0
验证版本(四条命令逐条执行,实测回显合并展示):
node -v
npm -v
pnpm -v
git --version
v20.20.2
10.8.2
9.15.9
git version 2.34.1
💡 技术拓展:JavaScript 包管理器主流三种——npm(Node 自带,扁平 node_modules,适合简单单包项目)、yarn(经典/berry 两代,锁文件成熟)、pnpm(内容寻址全局存储 + 硬链接,磁盘占用小、严格依赖隔离)。Flagon monorepo 是 pnpm workspace(根
package.json定义多个 package),因此本文采用 pnpm,pnpm -r run build可一次构建全部子包。
4.3 获取源码
cd /root
git clone --depth 5 https://github.com/apache/flagon.git flagon
cd /root/flagon
git log -1 --format='%H %ad %s' --date=iso
Cloning into 'flagon'...
61677c77727a5f9158923c42034a59b6d576f476 2026-10-11 21:26:58 -0700 fix(site): improve homepage hero formatting, add deployment stack pills, and replace raw backticks in HTML (#201)
实测说明:--depth 5 浅克隆仅取最近提交,节省时间;git log 确认拿到的 master 最新提交为 2026-10-11,主线活跃。
4.4 构建 UserALE workspace
cd /root/flagon/products/userale
pnpm install
pnpm build
Done in 2m 8.1s using pnpm v9.15.9
packages/flagon-userale build: [USERALE] ESM ⚡️ Build success in 21ms
packages/flagon-userale build: Done
packages/flagon-userale-ext build: 🟣 Plasmo v0.90.3
packages/flagon-userale-ext build: 🟢 DONE | Finished in 981ms!
packages/flagon-userale-ext build: Done
验证要点:构建同时产出浏览器端 IIFE 包 packages/flagon-userale/build/main.global.js(实测 71872 字节)与浏览器扩展的 chrome-mv3-prod 目录(packages/flagon-userale-ext/build/ 下 manifest.json 存在)。
4.5 启动收集服务器
Example Collector 位于 example/server/server.js,依赖已在 pnpm install 时随 workspace 装好。生产用 nohup 后台启动并记录 PID(本指南第八、九章的端到端验证即基于该方式,实测回显):
cd /root/flagon/products/userale
nohup node example/server/server.js > /root/server.log 2>&1 &
echo "server pid: $!"
sleep 3
cat /root/server.log
server pid: 5314
UserAle HTTP + WebSocket server running on port 8000
4.6 验证
页面与构建产物可达性验证(实测回显):
curl -s -o /tmp/index_out.html -w 'HTTP %{http_code} bytes=%{size_download}\n' http://localhost:8000/
curl -s -o /dev/null -w 'HTTP %{http_code} bytes=%{size_download}\n' http://localhost:8000/build/main.global.js
HTTP 200 bytes=3447
HTTP 200 bytes=71872
再核对示例页面中 UserALE 的埋点配置已正确内嵌(实测回显):
grep -oE 'data-(url|user|version|tool|threshold|interval)="[^"]*"' /tmp/index_out.html
data-url="http://localhost:8000/"
data-user="example-user"
data-version="2.3.0"
data-tool="Apache UserALE Example"
data-threshold="1"
data-interval="1000"
验证要点:示例页面默认把日志发到 data-url 指向的收集端,data-threshold="1" 表示每 1 条日志即触发一次发送、data-interval="1000" 表示每 1 秒检查一次发送——用真实浏览器打开 http://<服务器IP>:8000/ 交互后,日志会持续写入 example/logs/ 目录。
五、方案 B:npm 包安装(轻量集成)
5.1 方案说明
不克隆 monorepo,直接用 npm 安装发布的 flagon-userale 包,把包内 IIFE 产物部署到任意静态页面。适合只需要「给现有站点加埋点」的场景:不需要 pnpm 与源码构建,部署物只有几十 KB。
5.2 npm 安装 flagon-userale
mkdir -p /root/uale-npm && cd /root/uale-npm
npm init -y
npm install flagon-userale@2.4.0
Wrote to /root/uale-npm/package.json:
added 1 package, and audited 2 packages in 1s
found 0 vulnerabilities
💡 说明:
npm init -y会生成默认package.json(name 取目录名uale-npm,license 为 ISC 等,实测内容为标准模板)。
核对包内构建产物与版本(实测回显,输出节选):
ls -la node_modules/flagon-userale/build/ | grep -vE '\.map|\.d\.ts'
total 72
drwxr-xr-x 3 root root 4096 Oct 16 04:13 .
drwxr-xr-x 8 root root 4096 Oct 16 04:13 ..
drwxr-xr-x 3 root root 4096 Oct 16 04:13 UserALEWebExtension
-rw-r--r-- 1 root root 44729 Oct 16 04:13 userale-2.4.0.js
-rw-r--r-- 1 root root 15276 Oct 16 04:13 userale-2.4.0.min.js
5.3 部署埋点页面
把包内 IIFE 产物复制到站点目录,并在页面 <script> 标签中传入配置(data-url 指向收集端,参数逐项含义见《Apache Flagon 配置参数详解》):
mkdir -p /var/www/uale-site && cp node_modules/flagon-userale/build/userale-2.4.0.js /var/www/uale-site/
cat > /var/www/uale-site/index.html <<'EOF'
<!DOCTYPE html>
<html>
<head>
<title>Flagon npm Deploy Demo</title>
<script src="userale-2.4.0.js"
data-url="http://localhost:8000/"
data-user="demo-user"
data-version="2.4.0"
data-tool="npm-demo-app"
data-threshold="1"
data-interval="1000"></script>
</head>
<body>
<button id="test_button">Click Me!</button>
</body>
</html>
EOF
ls -la /var/www/uale-site/
total 56
drwxr-xr-x 2 root root 4096 Oct 16 05:12 .
drwxr-xr-x 3 root root 4096 Oct 16 05:12 ..
-rw-r--r-- 1 root root 392 Oct 16 05:12 index.html
-rw-r--r-- 1 root root 44729 Oct 16 05:12 userale-2.4.0.js
💡 说明:方案 B 的收集端复用方案 A 的 Example Collector(Node.js 服务常驻方式见第七章 systemd 托管)。页面文件可由任意静态服务器(Nginx 等)托管,本文为聚焦 Flagon 本身不再展开。部署后用真实浏览器打开页面任意点击,日志即按
http-json格式 POST 到收集端(与方案 A 相同的数据流)。
六、方案对比与选择建议
| 维度 | 方案 A:源码构建 | 方案 B:npm 包 |
|---|---|---|
| 产物版本 | master 最新(61677c7,2026-10-11) | 发布版 2.4.0 |
| 前置依赖 | Node 20 + pnpm 9 + git + 全 workspace 依赖 | 仅 npm(Node 自带) |
| 构建耗时 | pnpm install 2m8s + build 秒级 | npm install 1s |
| 附带能力 | 浏览器扩展构建、示例页、OTel demo、Distill 源码 | 仅 IIFE 产物 + 扩展随包文件 |
| 适用场景 | 评估全量能力、参与开发、需要最新修复 | 现有站点快速埋点、版本固定 |
选择建议:生产埋点优先方案 B(版本固定、体积小、依赖面窄);需要浏览器扩展、Distill 源码或跟随主线修复时用方案 A。两方案的收集端与分析端完全一致,可并行共存(方案 A 目录提供收集器,方案 B 目录提供页面产物)。
七、systemd 服务托管
收集服务器需要开机自启与崩溃自动拉起,用 systemd 托管(⚠️ 本章命令需要带 systemd 的 Linux 真机环境执行;单元文件与验证回显均为 systemd 环境实测)。写入单元文件:
cat > /etc/systemd/system/flagon-collector.service <<'EOF'
[Unit]
Description=Apache Flagon UserALE Example Collector
After=network.target
[Service]
Type=simple
WorkingDirectory=/root/flagon/products/userale
ExecStart=/usr/bin/node example/server/server.js
Environment=NODE_ENV=production
Environment=PORT=8000
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target
EOF
逐行加载、设自启、启动(daemon-reload 全局执行一次,enable/start 针对同一单元逐条操作;实测回显合并展示):
systemctl daemon-reload
systemctl enable flagon-collector
systemctl start flagon-collector
sleep 3
systemctl is-active flagon-collector
Created symlink /etc/systemd/system/multi-user.target.wants/flagon-collector.service → /etc/systemd/system/flagon-collector.service.
active
服务状态核查(实测回显,输出节选):
systemctl status flagon-collector --no-pager -l | head -8
journalctl -u flagon-collector --no-pager -n 2
● flagon-collector.service - Apache Flagon UserALE Example Collector
Loaded: loaded (/etc/systemd/system/flagon-collector.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2026-10-16 04:18:45 UTC; 3s ago
Main PID: 3947 (node)
Memory: 15.5M
Oct 16 04:18:45 aa6f16b2a761 node[3947]: UserAle HTTP + WebSocket server running on port 8000
重启与停止行为验证(实测回显,命令逐条执行):
systemctl restart flagon-collector
sleep 3
systemctl is-active flagon-collector
active
systemctl stop flagon-collector
sleep 2
systemctl is-active flagon-collector
journalctl -u flagon-collector --no-pager -n 3
inactive
Oct 16 04:19:24 aa6f16b2a761 node[3993]: HTTP server closed.
Oct 16 04:19:24 aa6f16b2a761 node[3993]: WebSocket server closed.
Oct 16 04:19:24 aa6f16b2a761 systemd[1]: flagon-collector.service: Deactivated successfully.
配置逐项说明:WorkingDirectory 必须是 products/userale(server.js 以相对路径引用 workspace 依赖与静态目录);ExecStart 用绝对路径 /usr/bin/node(NodeSource 安装的固定位置);PORT=8000 覆盖默认监听端口;Restart=on-failure + RestartSec=3 表示异常退出 3 秒后拉起。实测要点:systemd stop 发送 SIGTERM,收集服务器会在退出前把日志文件补写完整(第九章 FAQ 的「缺右括号」问题在 SIGTERM 收尾下未复现)。
八、端到端数据收集验证
本节把「采集 → 收集 → 分析」整条链路用可重复的命令验证一遍:先装分析端,再模拟日志上报,最后用 Distill 检出 rage click。
8.1 安装 Distill 分析端
先尝试 PyPI 发布版(实测回显):
pip3 install flagon-distill
Successfully installed flagon-distill-0.1.0 networkx-2.8.8 numpy-2.2.6 packaging-26.3 pandas-1.5.3 plotly-5.24.1 python-dateutil-2.9.0.post0 pytz-2026.5 six-1.17.0 tenacity-9.2.1
⚠️ 实测发现 PyPI 0.1.0 依赖 pandas 1.5.3 与 numpy 2.2.6 存在二进制不兼容(import distill 报 ValueError: numpy.dtype size changed,处理见第九章 FAQ)。为保证分析函数可用,实测采用 monorepo 源码安装(会重装新版依赖集):
pip3 uninstall -y flagon-distill
cd /root/flagon/products/distill
pip3 install .
pip3 install 'numpy<2'
Uninstalling flagon-distill-0.1.0:
Successfully uninstalled flagon-distill-0.1.0
Successfully built flagon-distill
Successfully installed annotated-types-0.8.0 contourpy-1.3.2 cycler-0.12.1 dateparser-1.4.3 flagon-distill-0.1.0 fonttools-4.65.0 kiwisolver-1.5.1 matplotlib-3.10.9 pillow-12.3.0 pksuid-1.1.2 pybase62-0.4.3 pydantic-2.14.1 pydantic-core-2.50.1 pyparsing-3.3.3 regex-2026.9.29 scipy-1.15.3 typing-extensions-4.16.0 typing-inspection-0.4.4 tzlocal-5.4.4
Successfully installed numpy-1.26.4
💡 说明:pip 全局安装会输出 root 用户告警(
WARNING: Running pip as the 'root' user...),属预期行为;生产建议在 venv 中执行,本指南为演示简洁直接全局安装。
验证导入(实测回显):
python3 -c "import distill; print('distill import OK')"
pip3 show flagon-distill | head -3
distill import OK
Name: flagon-distill
Version: 0.1.0
Summary: An analytics framework for front-end UserALE data, enabling modeling, sequence analysis, and customization in Python.
8.2 模拟行为日志上报
收集服务器运行中(第七章已托管或 4.5 已启动)时,用 curl 按标准 UserALE 平铺 JSON 协议逐条 POST。先上报一条正常点击(实测回显):
curl -s -o /dev/null -w 'HTTP %{http_code}\n' -X POST http://localhost:8000/v1/logs \
-H 'Content-Type: application/json' \
-d '[{"logType":"raw","clientTime":1760030001000,"microTime":1760030001000.35,"userAction":true,"type":"click","action":"click","target":"BUTTON#submit","path":[{"position":0,"tag":"BODY","id":null,"classes":[]}],"user":"demo-user","sessionId":"sess-run-3","tool":"Demo App","version":"2.4.0","pageUrl":"http://localhost:8000/","pageTitle":"Demo Page","location":{"x":512,"y":300},"scrnRes":"1920x1080","details":{}}]'
HTTP 200
再上报同一目标 4 次快速点击(制造 rage click 行为模式;下为其中两条,其余两条仅 clientTime 依次为 1760030006150/1760030006300,实测逐条返回 200):
curl -s -o /dev/null -w 'HTTP %{http_code}\n' -X POST http://localhost:8000/v1/logs -H 'Content-Type: application/json' -d '[{"logType":"raw","clientTime":1760030006000,"microTime":1760030006000.35,"userAction":true,"type":"click","action":"click","target":"BUTTON#broken","user":"demo-user","sessionId":"sess-run-3","tool":"Demo App","version":"2.4.0","pageUrl":"http://localhost:8000/","pageTitle":"Demo Page","location":{"x":320,"y":420},"scrnRes":"1920x1080","details":{}}]'
curl -s -o /dev/null -w 'HTTP %{http_code}\n' -X POST http://localhost:8000/v1/logs -H 'Content-Type: application/json' -d '[{"logType":"raw","clientTime":1760030006450,"microTime":1760030006450.35,"userAction":true,"type":"click","action":"click","target":"BUTTON#broken","user":"demo-user","sessionId":"sess-run-3","tool":"Demo App","version":"2.4.0","pageUrl":"http://localhost:8000/","pageTitle":"Demo Page","location":{"x":321,"y":420},"scrnRes":"1920x1080","details":{}}]'
HTTP 200
HTTP 200
收集服务器控制台同步打印了收到的日志(实测回显,输出节选):
tail -22 /root/server.log
UserAle HTTP + WebSocket server running on port 8000
HTTP POST: [
{
logType: 'raw',
clientTime: 1760030006450,
microTime: 1760030006450.35,
userAction: true,
type: 'click',
action: 'click',
target: 'BUTTON#broken',
path: [ [Object] ],
user: 'demo-user',
sessionId: 'sess-run-3',
tool: 'Demo App',
version: '2.4.0',
location: { x: 321, y: 420 },
details: {}
}
]
8.3 日志落盘验证
收集服务器把日志追加写入启动时间戳命名的 JSON 文件(实测回显):
LOG=$(ls -t /root/flagon/products/userale/example/logs/logs_*.json | head -1)
echo "$LOG"
ls -la "$LOG"
/root/flagon/products/userale/example/logs/logs_1792123964892.json
-rw-r--r-- 1 root root 3295 Oct 16 04:12 /root/flagon/products/userale/example/logs/logs_1792123964892.json
优雅停机后再解析(SIGINT/SIGTERM 会触发收集器补写结尾括号,实测回显):
kill -INT 5314
sleep 6
tail -3 /root/server.log
python3 -c "import json; d=json.load(open('$LOG')); print('records:', len(d))"
Shutting down...
HTTP server closed.
WebSocket server closed.
records: 8
验证要点:文件为合法 JSON 数组且包含全部上报日志;sleep 6 是给写流收尾留出的时间(过短可能读到未补全文件,见第九章 FAQ)。
8.4 Distill 行为分析验证
把生成的日志交给 Distill 做「解析 → 会话摘要 → 挫败感检测 → 图谱」全流程分析(脚本实测回显):
cat > /root/analyze.py <<'EOF'
import json, glob
import distill
from distill.schemas.userale import extract_logs
f = sorted(glob.glob('/root/flagon/products/userale/example/logs/logs_*.json'))[-1]
payload = json.load(open(f))
print('== source file:', f.split('/')[-1], '| raw records:', len(payload))
docs = [d.model_dump(by_alias=True) if hasattr(d, 'model_dump') else d for d in extract_logs(payload)]
print('== extract_logs ->', len(docs), 'logs; keys:', sorted(docs[0].keys()))
summary = distill.session_summary(docs)
print('== session_summary:', json.dumps(summary, default=str))
fric = distill.frustration_score(docs)
short = dict(fric); short['deadClicks'] = f"<{len(fric['deadClicks'])} items>"
print('== frustration_score:', json.dumps(short, default=str))
rage = distill.detect_rage_clicks(docs)
print('== detect_rage_clicks:', json.dumps(rage, default=str))
tm = distill.transition_matrix(docs, drop_recursions=True)
print('== transition_matrix:')
print(tm)
EOF
python3 /root/analyze.py
== source file: logs_1792123964892.json | raw records: 8
== extract_logs -> 8 logs; keys: ['action', 'clientTime', 'details', 'location', 'logType', 'microTime', 'pageTitle', 'pageUrl', 'path', 'scrnRes', 'sessionId', 'target', 'tool', 'type', 'user', 'userAction', 'version']
== session_summary: {"total_logs": 8, "raw_logs": 8, "interval_logs": 0, "custom_logs": 0, "mutation_logs": 0, "replay_logs": 0, "click_count": 8, "rage_click_count": 0, "duration_seconds": 8.0, "click_rate": 1.0, "unique_targets": 5, "unique_pages": 1, "page_load_time_ms": null, "trace_ids": []}
== frustration_score: {"frustrationScore": 65.0, "severity": "high", "rageClickCount": 1, "deadClickCount": 8, "domThrashBurstCount": 0, "errorCount": 0, "rageClicks": [{"target": "BUTTON#broken", "pageUrl": "http://localhost:8000/", "sessionId": "sess-run-3", "timestamp": 1760030006300, "clickCount": 3, "targetRect": null, "traceId": null, "source": "inferred"}], "deadClicks": "<8 items>"}
== detect_rage_clicks: [{"target": "BUTTON#broken", "pageUrl": "http://localhost:8000/", "sessionId": "sess-run-3", "timestamp": 1760030006300, "clickCount": 3, "targetRect": null, "traceId": null, "source": "inferred"}]
== transition_matrix:
BODY BUTTON#broken BUTTON#submit DIV#hero INPUT#search
BODY 0.0 0.0 0.0 0.0 0.0
BUTTON#broken 1.0 0.0 0.0 0.0 0.0
BUTTON#submit 0.0 0.0 0.0 0.0 1.0
DIV#hero 0.0 1.0 0.0 0.0 0.0
INPUT#search 0.0 0.0 0.0 1.0 0.0
验证要点解读:
extract_logs把 8 条原始日志全部校验归一化,17 个标准字段齐全;session_summary正确统计出 8 次点击、8 秒会话时长、5 个唯一目标、1 个页面;frustration_score给出 65.0 分(severity=high),detect_rage_clicks精确检出BUTTON#broken上 1 秒内 3 次连续点击(默认阈值 threshold=3、窗口 window_ms=1000),source: inferred表示由原始点击流推断而非前端显式上报;transition_matrix输出目标间一阶转移概率矩阵,可直接喂给漏斗/桑基图可视化。
至此端到端链路全部验证通过。日常使用中,把 8.2 节的 curl 替换为真实浏览器流量(页面埋点自动上报)即可持续收集。
九、常见问题(FAQ)
Q1:node example/server/server.js 报 EADDRINUSE: address already in use :::8000?
端口已被占用(实测多为上一个实例未退干净)。实测错误现象:
Uncaught exception: Error: listen EADDRINUSE: address already in use :::8000
at Server.setupListenHandle [as _listen2] (node:net:1908:16)
at listenInCluster (node:net:1965:12)
定位与解决:先精确找出占用进程再终止(实测输出):
pgrep -af 'server\.js'
pkill -f 'server\.js'
sleep 2
ps -ef | grep [n]ode
5527 node example/server/server.js
no node process left
注意:pkill -f 'node server.js' 匹配不到以长路径启动的进程(node example/server/server.js 不含该子串),要么用 pgrep -af 先核对再按 PID kill,要么用匹配性更强的模式如 server\.js。
Q2:停机后 json.load 日志文件报 Expecting ',' delimiter?
收集器运行期间日志文件始终处于打开状态、缺少结尾 ],只有优雅停机(SIGINT/SIGTERM)才会补写。若停机等待过短,进程可能在写流 flush 完成前退出。实测现象与处理:
python3 -c "import json; json.load(open('$LOG'))"
echo "]" >> "$LOG"
python3 -c "import json; print('records:', len(json.load(open('$LOG'))))"
json.decoder.JSONDecodeError: Expecting ',' delimiter: line 9 column 148 (char 1365)
records: 8
根治办法:停机后等待足够时间再解析(实测 sleep 6 后文件必然完整),或对文件做结尾括号检查后再消费。
Q3:import distill 报 ValueError: numpy.dtype size changed, may indicate binary incompatibility?
PyPI 的 flagon-distill 0.1.0 锁定 pandas<2.0(实测装出 1.5.3),与最新 numpy 2.x 二进制不兼容。实测修复(任选其一):
pip3 install 'numpy<2'
Successfully installed numpy-1.26.4
降级 numpy 后实测导入恢复正常(pandas 1.5.3 与 numpy 1.26.4 兼容);或按 8.1 节改用 monorepo 源码安装(新版依赖集已避开该组合)。若源码安装后 plot_click_heatmap 渲染报 pandas 相关 ImportError,同样先 pip3 install 'numpy<2' 统一版本即可。
Q4:本机 curl 访问收集服务器返回 502?
服务器设置了 http_proxy 环境变量时,curl 会把 localhost 请求也发给代理。实测现象与解决:
curl -s -o /dev/null -w 'GET / -> HTTP %{http_code}\n' http://localhost:8000/
curl -s --noproxy '*' -o /dev/null -w 'GET / -> HTTP %{http_code}\n' http://localhost:8000/
GET / -> HTTP 502
GET / -> HTTP 200
或对当前会话取消代理变量:unset http_proxy https_proxy。
Q5:pnpm install 缓慢或超时?
国内网络访问 npm registry 慢时,走 HTTP 代理或换 registry 镜像(实测走代理约 2 分钟完成):
export http_proxy=http://192.168.1.62:7897 https_proxy=http://192.168.1.62:7897
pnpm install
Done in 2m 8.1s using pnpm v9.15.9
十、卸载与清理
逐项清理(按部署方式选择执行,实测回显合并展示):
systemctl stop flagon-collector
systemctl disable flagon-collector
rm -f /etc/systemd/system/flagon-collector.service
systemctl daemon-reload
Removed /etc/systemd/system/multi-user.target.wants/flagon-collector.service.
删除源码与数据目录(实测路径):
rm -rf /root/flagon /root/flagon-repo /root/uale-npm /var/www/uale-site
rm -f /root/server.log /root/analyze.py
卸载 Python 分析端与全局工具:
pip3 uninstall -y flagon-distill
npm uninstall -g pnpm
apt-get purge -y nodejs && apt-get autoremove -y
Successfully uninstalled flagon-distill-0.1.0
removed 1 package in 161ms
After this operation, 196 MB disk space will be freed.
(Reading database ... 22663 files and directories currently installed.)
Removing nodejs (20.20.2-1nodesource1) ...
0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded.
清理验证:
node -v
bash: node: command not found
十一、参考链接
- 官方仓库(monorepo 主线):https://github.com/apache/flagon
- 官方 Releases 页:https://flagon.apache.org/releases/
- UserALE.js npm 包:https://www.npmjs.com/package/flagon-userale
- Distill PyPI 包:https://pypi.org/project/flagon-distill/
- 本文组件背景与选型对照见《Apache Flagon 介绍与选型指南》;收集器与前端埋点参数逐项说明见《Apache Flagon 配置参数详解》;日常命令与排障见《Apache Flagon 常用 CLI 命令与工具详解》。