4.9 KiB
name, description
| name | description |
|---|---|
| logstore | Wavelet 项目专用:当新增或修改日志/分析用途表(访问日志、审计流水、可观测时序)、接入 internal/repository/logstore、切换日志主库、实现 PG/SQLite 回落,或判断一张表该走业务主库还是日志库时必须使用。 |
日志用途表开发
开始前阅读根目录 AGENTS.md。DDL 用 database-migration;高频写入队列用 clickhouse-batchwriter;切换任务用 new-async-task。本技能只回答:这张表是不是日志表,以及如何接入可切换的日志主库。
分层与切换协议见 日志用途表。
先判定
日志表同时满足:
- 追加写入、几乎不更新单行
- 按时间查询/聚合,允许按保留天数删除
- 关闭 ClickHouse 后仍要能写、能查
- 不参与用户/配置/任务等事务一致性
不要做成日志表:用户、配置、任务执行、上传元数据、需要事务或强一致的业务实体。这些走主库 repository,不要进 logstore。
当前框架已接入的日志表:w_user_access_logs(管理端 API 访问审计)。
分层
| 层级 | 路径 | 职责 |
|---|---|---|
| 抽象 | internal/repository/logstore |
接口 + Active/BuildForMigration;apps 只面向这里 |
| CH 实现 | logstore 委托 internal/repository/analytics |
原生 PrepareBatch / ChDB 查询 |
| 主库实现 | logstore GORM |
PG(按月分区)与 SQLite(普通表) |
| Model | internal/model/analytics |
实体、TableName、InsertColumns、BatchInsertSQL,无 IO |
| 入队 | internal/apps/<domain> + batchwriter |
FlushFunc 调 logstore.Active().….BatchInsert |
| 切换 | internal/apps/admin/logs 的 logs:db_switch |
冻结写入 → 排空 → 复制 → 翻转 log_database |
| 清理 | logstore.CleanupExpired,由 system:cleanup 调用 |
按库读取保留天数后 DeleteBefore |
log_database ∈ {postgres,sqlite,clickhouse},且只能是「随主库」或 ClickHouse:主库为 PG 时日志不能是 SQLite,反之亦然。log_database / log_db_migration 受保护,禁止管理端手动改。
新增一张日志表
按顺序做,列名三库必须一致。
-
Model
在internal/model/analytics/定义 struct;实现TableName();批量写再提供InsertColumns()/BatchInsertSQL()。 -
三套 DDL(
database-migration)- ClickHouse:
goose/clickhouse/,MergeTree,PARTITION BY toYYYYMM(时间列)。 - PostgreSQL:
goose/postgres/,高频表用PARTITION BY RANGE (时间列),复合主键必须包含分区键。 - SQLite:
goose/sqlite/,普通表 + 时间/过滤列索引。
不要在 PG/SQLite 上复制 CH 物化视图;聚合在查询时实时算。
- ClickHouse:
-
logstore 接口
在对应 Store(现有UserAccessLogStore,或新域自建接口并挂到Store)补齐至少:- 写入:
BatchInsert(flush 目标;内调ensureWritable) - 查询:业务需要的 List/Count/聚合
- 迁移:
ListForMigration(afterID, limit)、MigrationRange、DeleteAll、EnsurePartitions(PG 按月预建,CH/SQLite no-op) - 清理:
DeleteBefore(cutoff)
- 写入:
-
双实现
- CH:委托
analyticsrepo,零额外查询路径。 - GORM:PG/SQLite 共用一套;方言 SQL 只放小函数(如按日
to_char/strftime)。零值id落库前用idgen.NextUint64ID()。
- CH:委托
-
buildStore
在provider.go的 CH / GORM 分支同时挂上新域。 -
写入
apps 用独立batchwriter实例;FlushFunc→logstore.Active(ctx)→BatchInsert。禁止analyticsrepo.BatchInsert、禁止db.ChConn。迁移任务调用域的Drain(等队列空一个 flush 周期,不要Stopwriter)。 -
切换任务
在copy*流程增加该表:DeleteAll目标 →MigrationRange+EnsurePartitions→ 按 id 分页复制。不要改切换协议(仍冻结写入、源数据不删、成功才翻转)。 -
清理
CleanupExpired对该表DeleteBefore;保留天数用已有log_retention_days_*,不要为单表再发明一套 key,除非产品明确要求独立 TTL。
禁止
- apps 直接
importinternal/repository/analytics或db.ChConn/db.ChDB做日志读写 - 只建 CH 表、不建 PG/SQLite 回落
- 在 Handler 里逐条
PrepareBatch+Send - 把业务表「顺便」放进 logstore 以便关 CH
- 管理端 API 改
log_database/log_db_migration
验证
go test ./internal/repository/logstore ./internal/repository/analytics
go test ./internal/apps/admin/logs ./internal/apps/risk_control ./internal/platform/bootstrap
make swagger # 若改了状态/查询 API
make code-check
对照:w_user_access_logs 的 model、三库 goose、logstore GORM/CH、risk_control.InitLogWriter、logs.LogDBSwitchHandler、system:cleanup。