- LogController: 新增 /issues/{id}/events, /issues/{id}/trend, 管理接口
(resolve/ignore/assign/bulk),queryIssues 改用 level/status/q 参数
- LogService: 全面重写,eventId 幂等、breadcrumbs 存储、affectedUsers 计数、
Issue status 管理、getIssueEvents/getIssueTrend 独立接口
- Entity: LogIssueEventEntity 增加 eventId/exceptionType/exceptionValue/breadcrumbs;
LogIssueEntity 增加 status/affectedUsers/assignee;LogEventEntity 增加 eventId
- Repository: LogIssueEventRepository/LogIssueRepository/LogEventRepository 新增
idempotency/filter/trend/bulk 查询方法
- DTO: IssueActionRequest/IssueTrendResponse 新增;IssueResponse/IssueEventResponse 扩展
- V3 migration: log_issue_events/log_issues/log_events 结构升级
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
40 KiB
BugCollect API v1 规范
版本:1.1.0
日期:2026-06-17
状态:Draft
设计参考:Sentry Event Payloads
服务端模块:xuqm-bugcollect-service
基础路径:/bugcollect/v1
目录
- 概述
- 术语表
- 认证与安全
- 数据上报端点
- 4.1 Issue 批量上报
- 4.2 Event 批量上报
- 4.3 SourceMap / 符号文件上传
- 4.4 Session 上报
- 数据模型
- 5.1 批量信封 Envelope
- 5.2 IssueEvent
- 5.3 LogEvent
- 5.4 Breadcrumb
- 5.5 枚举定义
- 查询端点
- Issue 管理端点
- Webhook
- 错误码
- Fingerprint 去重机制
- SDK 集成指南
- 数据库 Schema
- 变更日志
1. 概述
BugCollect 是一个轻量级错误收集与分析服务,设计目标对齐 Sentry 核心能力,为 XuqmGroup 全平台 SDK(Android、iOS、HarmonyOS、React Native、Web)提供统一的错误上报、聚合、查询和告警能力。
核心能力
| 能力 | 说明 |
|---|---|
| Issue 聚合 | 按 fingerprint 自动去重,将同类错误聚合为 Issue |
| Event 追踪 | 每次错误发生记录独立 Event,保留完整上下文和面包屑 |
| Analytics 事件 | 自定义业务事件上报,支持漏斗分析 |
| Session 追踪 | 会话生命周期上报,支持 crash-free session rate 计算 |
| 符号化 | 上传 SourceMap / ProGuard mapping / dSYM,支持多平台堆栈还原 |
| Webhook 告警 | 新 Issue、fatal 级别、阈值超限等事件触发 Webhook 通知 |
| Issue 管理 | 解决、忽略、分配、批量操作 |
| 多平台 | 统一 API,平台差异由 platform 字段区分 |
设计原则
- Sentry 对齐:字段命名和结构参考 Sentry,降低学习成本
- 批量优先:上报端点均为批量接口,减少网络请求
- 信封封装:请求体使用信封(Envelope)结构,支持携带 SDK 元信息
- 幂等安全:每条 Event 携带
eventId,服务端按此去重 - 向前兼容:未知字段忽略不报错,新字段可选添加
2. 术语表
| 术语 | 说明 |
|---|---|
| Issue | 一类错误的聚合,由 fingerprint 唯一标识。一个 Issue 对应多次 Event |
| Event | 一次具体的错误发生记录,包含完整的堆栈、面包屑、设备、用户等上下文 |
| Analytics Event | 自定义业务事件(如页面访问、按钮点击),用于漏斗分析 |
| Session | 一次应用使用过程,从前台打开到退出/崩溃,用于计算 crash-free rate |
| Breadcrumb | 崩溃前的操作轨迹,如导航、网络请求、用户操作,自动附带在 Event 中 |
| Fingerprint | 错误指纹,SHA-256 哈希值,用于 Issue 去重分组 |
| Level | 错误严重级别:fatal > error > warning > info > debug |
| Status | Issue 状态:open(未处理)/ resolved(已解决)/ ignored(已忽略) |
| Release | 应用版本号,对应 appVersion |
| Environment | 运行环境:production / staging / development / integration |
| Envelope | 批量请求的信封结构,包含 sentAt、sdk、events |
| AppKey | 应用唯一标识,由平台分配 |
3. 认证与安全
上报端点(SDK → 服务端)
SDK 通过 config.xuqm 完成初始化认证,appKey 由 SDK 自动从配置文件读取并附带在请求体中,开发者无需手动处理认证逻辑。
appKey 来源:assets/xuqm/config.xuqm(加密文件,由租户平台下发)
认证链路:
- 开发者从租户平台下载
config.xuqm,内含appKey和可选的serverUrl config.xuqm已加密存储,且绑定包名(SDK 启动时校验包名与文件中记录的一致性)- SDK 初始化时从平台拉取配置,验证 BugCollect 服务已开通(
t_feature_service.enabled = true);未开通时captureError为空操作,不发送任何请求 - 服务端收到上报后,验证
appKey有效且对应 BugCollect 服务已激活,否则拒绝写入
服务激活即权限边界:BugCollect 服务开通状态由租户在平台管理,未开通的
appKey的上报请求会被服务端拒绝,无需额外 Token。
建议 SDK 端通过 HTTPS 传输,防止 appKey 被中间人截获。
查询端点 / 管理端点(Web → 服务端)
- 通过 API 网关统一鉴权(租户 Token)
- 查询参数中的
appKey必须与鉴权租户匹配
速率限制
| 端点类型 | 限制 | 超限行为 |
|---|---|---|
| Issue / Event 上报 | 1000 次/分钟/appKey | HTTP 429,SDK 将事件重新入队,下次重试 |
| Session 上报 | 5000 次/分钟/appKey | HTTP 429,SDK 丢弃(会话数据可接受损失) |
| SourceMap 上传 | 20 次/小时/appKey | HTTP 429 |
| 查询端点 | 100 次/分钟/租户 | HTTP 429 |
4. 数据上报端点
4.1 Issue 批量上报
捕获的错误、未捕获的崩溃统一通过此端点上报。
POST /bugcollect/v1/issues/batch
Content-Type: application/json
请求体
{
"sentAt": "2026-06-17T10:30:00Z",
"sdk": {
"name": "bugcollect.android",
"version": "1.0.0"
},
"events": [
{
"eventId": "550e8400-e29b-41d4-a716-446655440000",
"appKey": "2000111111110002",
"level": "error",
"platform": "android",
"release": "7.2.13",
"environment": "production",
"timestamp": 1718620200000,
"fingerprint": "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456",
"exception": {
"type": "IllegalStateException",
"value": "更新服务未开通 (code=40404)",
"stacktrace": "java.lang.IllegalStateException: 更新服务未开通\n\tat com.szyx.app.MainActivity.onCreate(MainActivity.kt:178)\n\tat android.app.Activity.performCreate(Activity.java:8000)"
},
"breadcrumbs": [
{
"timestamp": 1718620195000,
"category": "navigation",
"message": "进入首页",
"level": "info"
},
{
"timestamp": 1718620199000,
"category": "network",
"message": "GET /api/update → 404",
"level": "warning",
"data": { "url": "https://update.dev.xuqinmin.com/", "statusCode": 404 }
}
],
"user": {
"id": "user-123"
},
"device": {
"name": "Pixel 7",
"model": "Pixel 7",
"manufacturer": "Google",
"osName": "Android",
"osVersion": "14",
"locale": "zh_CN",
"timezone": "Asia/Shanghai",
"network": "wifi",
"isEmulator": false,
"freeMemoryMb": 512,
"buildType": "release"
},
"tags": {
"context": "checkAppUpdate"
}
}
]
}
响应
{
"code": 200,
"message": "success",
"data": null
}
幂等说明:服务端按
eventId去重。相同appKey+eventId的二次提交直接返回 200,不重复写入。
cURL 示例
curl -X POST https://bugcollect.xuqinmin.com/bugcollect/v1/issues/batch \
-H "Content-Type: application/json" \
-d '{
"sentAt": "2026-06-17T10:30:00Z",
"sdk": { "name": "bugcollect.android", "version": "1.0.0" },
"events": [{
"eventId": "550e8400-e29b-41d4-a716-446655440000",
"appKey": "2000111111110002",
"level": "error",
"platform": "android",
"release": "7.2.13",
"environment": "production",
"timestamp": 1718620200000,
"fingerprint": "abc123...",
"exception": {
"type": "NullPointerException",
"value": "Attempt to invoke virtual method on a null reference",
"stacktrace": "java.lang.NullPointerException: ...\n\tat ..."
}
}]
}'
4.2 Event 批量上报
自定义业务事件(页面访问、功能使用、漏斗步骤等)通过此端点上报。
POST /bugcollect/v1/events/batch
Content-Type: application/json
请求体
{
"sentAt": "2026-06-17T10:30:00Z",
"sdk": {
"name": "bugcollect.android",
"version": "1.0.0"
},
"events": [
{
"eventId": "660e8400-e29b-41d4-a716-446655440001",
"appKey": "2000111111110002",
"name": "page_view",
"properties": {
"page": "/home",
"referrer": "/login"
},
"platform": "android",
"release": "7.2.13",
"environment": "production",
"timestamp": 1718620200000,
"user": {
"id": "user-123"
},
"device": {
"osName": "Android",
"osVersion": "14",
"isEmulator": false
}
}
]
}
响应
{
"code": 200,
"message": "success",
"data": null
}
4.3 SourceMap / 符号文件上传
上传符号文件,用于堆栈还原。各平台文件格式不同:
| 平台 | 文件类型 | 说明 |
|---|---|---|
web / react-native |
.map |
JavaScript SourceMap |
android |
.txt |
ProGuard / R8 mapping 文件 |
ios |
.zip |
dSYM 压缩包(含 DWARF 调试信息) |
harmonyos |
.map |
类 SourceMap 格式 |
POST /bugcollect/v1/sourcemaps/upload
Content-Type: multipart/form-data
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
appKey |
string | ✅ | 应用标识 |
platform |
string | ✅ | 平台:web / react-native / android / ios / harmonyos |
appVersion |
string | ✅ | 应用版本,对应 release 字段 |
bundleName |
string | JS Bundle 名称,默认 index(web/rn 专用) |
|
file |
file | ✅ | 符号文件 |
cURL 示例
# React Native SourceMap
curl -X POST https://bugcollect.xuqinmin.com/bugcollect/v1/sourcemaps/upload \
-F "appKey=2000111111110002" \
-F "platform=react-native" \
-F "appVersion=7.2.13" \
-F "bundleName=index" \
-F "file=@./index.bundle.map"
# Android ProGuard mapping
curl -X POST https://bugcollect.xuqinmin.com/bugcollect/v1/sourcemaps/upload \
-F "appKey=2000111111110002" \
-F "platform=android" \
-F "appVersion=7.2.13" \
-F "file=@./mapping.txt"
# iOS dSYM
curl -X POST https://bugcollect.xuqinmin.com/bugcollect/v1/sourcemaps/upload \
-F "appKey=2000111111110002" \
-F "platform=ios" \
-F "appVersion=7.2.13" \
-F "file=@./YwxApp.app.dSYM.zip"
响应
{
"code": 200,
"message": "success",
"data": {
"id": 1,
"appKey": "2000111111110002",
"platform": "android",
"appVersion": "7.2.13",
"uploadedAt": "2026-06-17T10:30:00"
}
}
4.4 Session 上报
上报会话生命周期,用于计算 crash-free session rate。
POST /bugcollect/v1/sessions/batch
Content-Type: application/json
请求体
{
"sentAt": "2026-06-17T10:30:00Z",
"sdk": { "name": "bugcollect.android", "version": "1.0.0" },
"sessions": [
{
"sessionId": "sess-abc-123",
"appKey": "2000111111110002",
"status": "exited",
"platform": "android",
"release": "7.2.13",
"environment": "production",
"startedAt": 1718620100000,
"duration": 95000,
"user": { "id": "user-123" },
"errors": 0
}
]
}
Session 状态
status |
说明 |
|---|---|
ok |
进行中(心跳上报) |
exited |
正常退出(用户主动离开或 App 进入后台超时) |
crashed |
因未捕获异常终止 |
abnormal |
进程被系统杀死(ANR、OOM、后台清理) |
字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
sessionId |
string | ✅ | 会话唯一 ID(UUID) |
appKey |
string | ✅ | 应用标识 |
status |
string | ✅ | 会话状态,见上表 |
platform |
string | ✅ | 平台 |
release |
string | 应用版本 | |
environment |
string | 运行环境 | |
startedAt |
long | ✅ | 会话开始时间戳(毫秒) |
duration |
long | 会话时长(毫秒) | |
user.id |
string | 用户 ID | |
errors |
int | 会话内捕获的 error 数量 |
5. 数据模型
5.1 批量信封 Envelope
所有批量上报端点共享统一的信封结构。信封层的 sdk 字段作为默认值,事件层不再重复携带。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
sentAt |
string (ISO 8601) | 客户端发送时间,用于时钟偏差校正 | |
sdk |
object | SDK 信息 | |
sdk.name |
string | SDK 标识,如 bugcollect.android、bugcollect.ios、bugcollect.harmonyos、bugcollect.rn、bugcollect.web |
|
sdk.version |
string | SDK 版本号 | |
events |
array | ✅ | 事件数组,不能为空 |
5.2 IssueEvent
错误事件数据模型,用于 captureError() 和 captureCrash()。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
eventId |
string (UUID) | ✅ | 客户端生成的唯一事件 ID,服务端按此去重 |
appKey |
string | ✅ | 应用标识 |
level |
string | ✅ | 严重级别,见 Level 枚举 |
platform |
string | ✅ | 平台,见 Platform 枚举 |
fingerprint |
string | ✅ | 错误指纹,64 字符 SHA-256 哈希 |
timestamp |
long | ✅ | 事件时间戳(毫秒) |
exception |
object | 异常信息 | |
exception.type |
string | 异常类名,如 NullPointerException |
|
exception.value |
string | 异常消息 | |
exception.stacktrace |
string | 完整堆栈文本 | |
breadcrumbs |
array | 崩溃前操作轨迹,见 Breadcrumb,最多 50 条 | |
release |
string | 应用版本号 | |
environment |
string | 运行环境,默认 production |
|
user |
object | 用户信息 | |
user.id |
string | 用户 ID | |
device |
object | 设备信息,见下表 | |
tags |
object | 自定义标签,key-value 均为 string |
device 字段
| 字段 | 类型 | 说明 |
|---|---|---|
name |
string | 设备名称,如 Pixel 7 |
model |
string | 设备型号 |
manufacturer |
string | 制造商 |
osName |
string | 操作系统名称 |
osVersion |
string | 操作系统版本 |
locale |
string | 语言区域,如 zh_CN |
timezone |
string | 时区,如 Asia/Shanghai |
network |
string | 网络类型:wifi / cellular / none / unknown |
isEmulator |
boolean | 是否模拟器(过滤开发噪声) |
freeMemoryMb |
int | 可用内存(MB) |
buildType |
string | 构建类型:debug / release |
最小上报示例
{
"eventId": "550e8400-e29b-41d4-a716-446655440000",
"appKey": "2000111111110002",
"level": "error",
"platform": "android",
"fingerprint": "abc123...",
"timestamp": 1718620200000,
"exception": {
"type": "Exception",
"value": "something went wrong",
"stacktrace": "..."
}
}
5.3 LogEvent
自定义业务事件数据模型,用于 event() 方法。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
eventId |
string (UUID) | ✅ | 客户端生成的唯一事件 ID,服务端按此去重 |
appKey |
string | ✅ | 应用标识 |
name |
string | ✅ | 事件名称,如 page_view、button_click |
timestamp |
long | ✅ | 事件时间戳(毫秒) |
properties |
object | 事件属性,任意 key-value | |
platform |
string | 平台 | |
release |
string | 应用版本号 | |
environment |
string | 运行环境 | |
user |
object | 用户信息 | |
user.id |
string | 用户 ID | |
device |
object | 设备信息(同 IssueEvent.device) |
5.4 Breadcrumb
崩溃前的操作轨迹条目,自动附带在 IssueEvent 的 breadcrumbs 数组中,最多保留最近 50 条。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
timestamp |
long | ✅ | 轨迹时间戳(毫秒) |
category |
string | ✅ | 分类,见下表 |
message |
string | ✅ | 描述文本 |
level |
string | info / warning / error,默认 info |
|
data |
object | 额外键值对,如 url、statusCode、method |
标准 Category
| category | 说明 | 典型 data 字段 |
|---|---|---|
navigation |
页面/路由切换 | from, to |
network |
HTTP 请求 | url, method, statusCode, durationMs |
ui |
用户交互 | action(tap/swipe),target |
lifecycle |
App / Activity 生命周期 | event(foreground/background) |
console |
手动打点日志 | — |
error |
SDK 内部捕获的非致命错误 | — |
5.5 枚举定义
5.5.1 Level
错误严重级别,从高到低排列。
| 值 | 含义 | 对应 SDK 方法 | Web 展示颜色 |
|---|---|---|---|
fatal |
未捕获崩溃,应用即将终止 | captureCrash() |
🔴 深红 |
error |
捕获的错误,不影响应用存活 | captureError() |
🔴 红 |
warning |
警告,潜在问题 | warn() |
🟡 黄 |
info |
信息性记录 | info() |
🔵 蓝 |
debug |
调试信息 | debug() |
⚪ 灰 |
服务端存储策略:
fatal/error→ 写入log_issues表参与 Issue 聚合,同时写入log_issue_events表记录明细warning/info/debug→ 仅写入log_issue_events表,不创建或更新 Issue,不触发告警
5.5.2 Platform
| 值 | 说明 |
|---|---|
android |
Android 原生 |
ios |
iOS 原生 |
harmonyos |
HarmonyOS 原生 |
react-native |
React Native 跨平台 |
web |
Web 浏览器 |
java-server |
Java 服务端 |
python-server |
Python 服务端 |
go-server |
Go 服务端 |
5.5.3 Environment
| 值 | 说明 |
|---|---|
production |
生产环境(默认) |
staging |
预发布环境 |
integration |
集成测试环境 |
development |
开发环境 |
5.5.4 Issue Status
| 值 | 说明 |
|---|---|
open |
未处理(默认) |
resolved |
已解决 |
ignored |
已忽略,不再告警 |
6. 查询端点
以下端点均为
GET请求,返回数据格式统一为ApiResponse<T>。
通用响应格式
{
"code": 200,
"message": "success",
"data": { ... }
}
通用分页格式
{
"items": [],
"page": 1,
"size": 20,
"total": 100
}
6.1 Issue 列表
GET /bugcollect/v1/issues
查询参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
appKey |
string | ✅ | 应用标识 | |
level |
string | 级别筛选:fatal / error / warning |
||
status |
string | open |
状态筛选:open / resolved / ignored |
|
platform |
string | 平台筛选 | ||
release |
string | 版本筛选 | ||
q |
string | 按 Issue 标题全文搜索 | ||
from |
string | 起始日期 YYYY-MM-DD |
||
to |
string | 结束日期 YYYY-MM-DD |
||
page |
int | 1 | 页码(从 1 开始) | |
size |
int | 20 | 每页条数 |
响应
{
"code": 200,
"message": "success",
"data": {
"items": [
{
"id": 1,
"appKey": "2000111111110002",
"fingerprint": "abc123...",
"level": "error",
"status": "open",
"title": "IllegalStateException: 更新服务未开通",
"firstSeenAt": "2026-06-17T10:00:00",
"lastSeenAt": "2026-06-17T12:00:00",
"count": 15,
"affectedUsers": 8,
"platform": "android",
"release": "7.2.13"
}
],
"page": 1,
"size": 20,
"total": 1
}
}
6.2 Issue 详情
仅返回 Issue 元数据。事件明细通过 6.3 Issue 事件列表 分页获取。
GET /bugcollect/v1/issues/{id}
路径参数
| 参数 | 类型 | 说明 |
|---|---|---|
id |
long | Issue ID |
响应
{
"code": 200,
"message": "success",
"data": {
"id": 1,
"appKey": "2000111111110002",
"fingerprint": "abc123...",
"level": "error",
"status": "open",
"title": "IllegalStateException: 更新服务未开通",
"firstSeenAt": "2026-06-17T10:00:00",
"lastSeenAt": "2026-06-17T12:00:00",
"count": 15,
"affectedUsers": 8,
"platform": "android",
"release": "7.2.13",
"assignee": null
}
}
6.3 Issue 事件列表
分页获取某个 Issue 下的所有事件明细,含完整堆栈、面包屑、设备信息。
GET /bugcollect/v1/issues/{id}/events
查询参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
id |
long | ✅(路径) | Issue ID | |
from |
string | 起始日期 | ||
to |
string | 结束日期 | ||
page |
int | 1 | 页码 | |
size |
int | 20 | 每页条数 |
响应
{
"code": 200,
"message": "success",
"data": {
"items": [
{
"id": 101,
"issueId": 1,
"eventId": "550e8400-e29b-41d4-a716-446655440000",
"appKey": "2000111111110002",
"level": "error",
"userId": "user-123",
"sessionId": "sess-abc",
"exception": {
"type": "IllegalStateException",
"value": "更新服务未开通",
"stacktrace": "java.lang.IllegalStateException: ...",
"stackSymbolicated": null
},
"breadcrumbs": [
{
"timestamp": 1718620195000,
"category": "navigation",
"message": "进入首页",
"level": "info"
}
],
"tags": { "context": "checkAppUpdate" },
"device": {
"osName": "Android",
"osVersion": "14",
"isEmulator": false,
"network": "wifi"
},
"platform": "android",
"release": "7.2.13",
"environment": "production",
"sdkName": "bugcollect.android",
"sdkVersion": "1.0.0",
"createdAt": "2026-06-17T10:30:00"
}
],
"page": 1,
"size": 20,
"total": 15
}
}
6.4 Issue 趋势
获取某个 Issue 在指定时间范围内的每日发生次数趋势,用于判断问题是在收敛还是扩散。
GET /bugcollect/v1/issues/{id}/trend
查询参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
from |
string | 近 14 天 | 起始日期 YYYY-MM-DD |
|
to |
string | 今天 | 结束日期 YYYY-MM-DD |
响应
{
"code": 200,
"message": "success",
"data": {
"issueId": 1,
"points": [
{ "date": "2026-06-11", "count": 2, "affectedUsers": 1 },
{ "date": "2026-06-12", "count": 5, "affectedUsers": 3 },
{ "date": "2026-06-17", "count": 8, "affectedUsers": 5 }
]
}
}
6.5 Event 列表
GET /bugcollect/v1/events
查询参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
appKey |
string | ✅ | 应用标识 | |
name |
string | 事件名称筛选 | ||
userId |
string | 用户 ID 筛选 | ||
from |
string | 起始日期 | ||
to |
string | 结束日期 | ||
page |
int | 1 | 页码 | |
size |
int | 20 | 每页条数 |
6.6 概览统计
GET /bugcollect/v1/overview?appKey={appKey}
查询参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
appKey |
string | ✅ | 应用标识 |
from |
string | 起始日期 | |
to |
string | 结束日期 |
响应
{
"code": 200,
"message": "success",
"data": {
"totalIssues": 42,
"openIssues": 35,
"todayNewIssues": 3,
"affectedUsers": 128,
"crashFreeSessionRate": 0.9971,
"crashRate": 0.05,
"crashRateTrend": [
{ "date": "2026-06-11", "count": 5, "rate": 0.03 },
{ "date": "2026-06-12", "count": 8, "rate": 0.05 }
],
"topIssues": [
{
"id": 1,
"title": "NullPointerException: ...",
"level": "error",
"count": 15,
"affectedUsers": 8
}
]
}
}
crashFreeSessionRate:
1 - (crashed_sessions / total_sessions),行业标准指标,需 Session 上报 数据支撑。
6.7 频率排行
GET /bugcollect/v1/issues/rankings/frequency
查询参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
appKey |
string | ✅ | 应用标识 | |
from |
string | 起始日期 | ||
to |
string | 结束日期 | ||
limit |
int | 20 | 返回条数 |
6.8 风险排行
GET /bugcollect/v1/issues/rankings/risk
风险分 = count × level_weight × recency_weight,fatal 权重最高。
查询参数
同 频率排行。
6.9 漏斗分析
GET /bugcollect/v1/events/funnel
查询参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
appKey |
string | ✅ | 应用标识 |
steps |
string | ✅ | 逗号分隔的步骤名,如 page_view,click_submit,order_created |
from |
string | 起始日期 | |
to |
string | 结束日期 |
响应
{
"code": 200,
"message": "success",
"data": {
"steps": ["page_view", "click_submit", "order_created"],
"counts": [1000, 600, 300],
"rates": [100.0, 60.0, 30.0]
}
}
7. Issue 管理端点
以下端点均需租户 Token 鉴权(Web 端调用)。
7.1 解决 Issue
PUT /bugcollect/v1/issues/{id}/resolve
将 Issue 状态置为 resolved。若该 Issue 后续有新 Event 上报,状态自动回滚到 open 并触发 issue.regressed Webhook。
响应
{ "code": 200, "message": "success", "data": null }
7.2 忽略 Issue
PUT /bugcollect/v1/issues/{id}/ignore
将 Issue 状态置为 ignored。忽略后不再触发告警,不影响数据记录。
7.3 分配责任人
PUT /bugcollect/v1/issues/{id}/assign
Content-Type: application/json
请求体
{ "assignee": "user@example.com" }
传 null 取消分配。
7.4 批量操作
POST /bugcollect/v1/issues/bulk
Content-Type: application/json
请求体
{
"ids": [1, 2, 3],
"action": "resolve"
}
action 枚举
| 值 | 说明 |
|---|---|
resolve |
批量解决 |
ignore |
批量忽略 |
reopen |
批量重新打开 |
8. Webhook
8.1 查询 Webhook 列表
GET /bugcollect/v1/webhooks?appKey={appKey}
8.2 创建 Webhook
POST /bugcollect/v1/webhooks
Content-Type: application/json
请求体
{
"appKey": "2000111111110002",
"url": "https://hooks.example.com/notify",
"events": ["issue.created", "issue.fatal"],
"secret": "webhook-secret-key"
}
8.3 更新 Webhook
PUT /bugcollect/v1/webhooks/{id}
8.4 删除 Webhook
DELETE /bugcollect/v1/webhooks/{id}
Webhook 事件类型
| 事件 | 触发时机 |
|---|---|
issue.created |
新 Issue 首次出现 |
issue.fatal |
fatal 级别事件上报时立即触发(不等去重) |
issue.threshold |
Issue 发生次数超过配置阈值(默认 100 次) |
issue.regressed |
已解决的 Issue 重新出现 |
issue.resolved |
Issue 被标记为已解决(用于 CI/CD 集成) |
Webhook 回调体
{
"event": "issue.created",
"timestamp": "2026-06-17T10:30:00Z",
"issue": {
"id": 1,
"appKey": "2000111111110002",
"level": "error",
"status": "open",
"title": "IllegalStateException: 更新服务未开通",
"platform": "android",
"count": 1,
"affectedUsers": 1,
"firstSeenAt": "2026-06-17T10:30:00"
}
}
签名验证:Webhook 请求携带
X-BugCollect-Signature: sha256=<hmac>请求头,接收方用secret验证请求合法性。
9. 错误码
| HTTP 状态码 | code | 说明 |
|---|---|---|
| 200 | 200 | 成功 |
| 400 | 400 | 请求参数校验失败 |
| 400 | 40001 | appKey 不能为空 |
| 400 | 40002 | events / sessions 数组为空 |
| 400 | 40003 | fingerprint 格式非法(非 64 字符十六进制) |
| 400 | 40004 | level 不在枚举范围内 |
| 400 | 40005 | platform 不在枚举范围内 |
| 403 | 40301 | appKey 对应的 BugCollect 服务未开通 |
| 404 | 40401 | Issue 不存在 |
| 429 | 42901 | 请求频率超限 |
| 500 | 500 | 服务端内部错误 |
10. Fingerprint 去重机制
默认算法
SDK 端默认使用以下公式生成 fingerprint(注意:不含 level,同一错误不同严重程度归为同一 Issue):
SHA-256( normalize(exception.type + ":" + exception.value) + ":" + top_3_stack_lines )
normalize— 移除数字字面量、UUID、URL、内存地址等易变内容top_3_stack_lines— 取堆栈中前 3 行(跳过 SDK 内部框架层)
自定义 Fingerprint
SDK 端可传入自定义 fingerprint,覆盖默认算法:
BugCollect.captureError(exception, tags = mapOf("context" to "checkAppUpdate"), fingerprint = "custom-group-key")
分组优先级
- 自定义 fingerprint — 如果 SDK 传入,完全按此分组
- 堆栈分组 — 按
exception.type+ 归一化堆栈前 3 行 - 消息分组 — 无堆栈时按
exception.type+exception.value分组
混淆代码处理
Android Release 包经 ProGuard / R8 混淆后,堆栈行类名如 a.b.c.d 无法直接分组。建议:
- 上传 ProGuard mapping 文件
- 服务端符号化后将还原堆栈写入
stack_symbolicated - 对已符号化的堆栈重新计算 fingerprint(服务端异步任务)
11. SDK 集成指南
11.1 Android SDK
初始化
SDK 通过 config.xuqm 自动初始化,无需手动调用初始化代码。DSN Token 已内含于配置文件。
// 无需手动初始化,ContentProvider 自动完成
// 若需手动初始化:
XuqmSDK.initialize(context, appKey = "2000111111110002")
设置用户
通过 XuqmSDK 统一管理用户信息,BugCollect 自动跟随:
XuqmSDK.setUserInfo(XuqmUserInfo(userId = "user-123"))
捕获错误
try {
// 业务代码
} catch (e: Exception) {
BugCollect.captureError(e, tags = mapOf("context" to "checkAppUpdate"))
}
记录面包屑
BugCollect.addBreadcrumb(category = "navigation", message = "进入首页")
BugCollect.addBreadcrumb(
category = "network",
message = "GET /api/update → 404",
level = "warning",
data = mapOf("url" to url, "statusCode" to 404)
)
记录事件
BugCollect.event("page_view", properties = mapOf("page" to "/home"))
设置环境
BugCollect.setEnvironment("staging")
11.2 React Native SDK
import { BugCollect } from '@xuqm/rn-bugcollect';
// 捕获错误
try { ... } catch (e) {
BugCollect.captureError(e, { tags: { context: 'checkAppUpdate' } });
}
// 记录面包屑
BugCollect.addBreadcrumb({ category: 'navigation', message: '进入首页' });
// 记录事件
BugCollect.event('page_view', { page: '/home' });
11.3 Web SDK
import { BugCollect } from '@xuqm/bugcollect-web';
BugCollect.init({ appKey: '2000111111110002' });
// 自动捕获未处理异常(window.onerror / unhandledrejection)
// 手动捕获
try { ... } catch (e) {
BugCollect.captureError(e);
}
11.4 批量上报策略
SDK 内部自动管理队列,开发者无需关心。
| 参数 | 值 | 说明 |
|---|---|---|
| 批量大小 | 30 条 | 积攒 30 条后立即发送 |
| 定时刷新 | 10 秒 | 未满 30 条时每 10 秒发送一次 |
| 最大队列 | 500 条 | 超出后丢弃最旧的 |
| 持久化范围 | fatal / error |
发送失败写入磁盘,下次启动补发;warning 及以下仅内存队列 |
| 重试 | 1 次 | 发送失败重试 1 次,失败后重新入队 |
| 幂等保障 | eventId |
每条 Event 携带 UUID,服务端按此去重,重试不会产生重复数据 |
12. 数据库 Schema
log_issues — Issue 聚合表
CREATE TABLE log_issues (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
app_key VARCHAR(64) NOT NULL,
fingerprint VARCHAR(128) NOT NULL,
level VARCHAR(20) NOT NULL DEFAULT 'error',
status VARCHAR(20) NOT NULL DEFAULT 'open', -- open | resolved | ignored
assignee VARCHAR(200),
title VARCHAR(500),
first_seen_at DATETIME NOT NULL,
last_seen_at DATETIME NOT NULL,
count INT NOT NULL DEFAULT 1,
affected_users INT NOT NULL DEFAULT 0,
platform VARCHAR(30),
release VARCHAR(50),
UNIQUE KEY uk_app_fingerprint (app_key, fingerprint),
INDEX idx_app_key_last_seen (app_key, status, last_seen_at),
INDEX idx_app_key_level (app_key, level, last_seen_at)
);
log_issue_events — Issue 事件明细表
CREATE TABLE log_issue_events (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
issue_id BIGINT NOT NULL,
event_id VARCHAR(64) NOT NULL, -- 客户端幂等 ID
app_key VARCHAR(64) NOT NULL,
level VARCHAR(20) NOT NULL DEFAULT 'error',
user_id VARCHAR(128),
session_id VARCHAR(128),
exception_type VARCHAR(200),
exception_value TEXT,
stack LONGTEXT,
stack_symbolicated LONGTEXT,
breadcrumbs JSON,
tags JSON,
device JSON,
platform VARCHAR(30),
release VARCHAR(50),
environment VARCHAR(50) DEFAULT 'production',
sdk_name VARCHAR(100),
sdk_version VARCHAR(20),
created_at DATETIME NOT NULL,
UNIQUE KEY uk_event_id (app_key, event_id),
INDEX idx_issue_created (issue_id, created_at),
INDEX idx_app_key (app_key)
);
log_events — 自定义事件表
CREATE TABLE log_events (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
event_id VARCHAR(64) NOT NULL, -- 客户端幂等 ID
app_key VARCHAR(64) NOT NULL,
name VARCHAR(200) NOT NULL,
user_id VARCHAR(128),
session_id VARCHAR(128),
properties JSON,
platform VARCHAR(30),
release VARCHAR(50),
environment VARCHAR(50) DEFAULT 'production',
device JSON,
sdk_name VARCHAR(100),
sdk_version VARCHAR(20),
created_at DATETIME NOT NULL,
UNIQUE KEY uk_event_id (app_key, event_id),
INDEX idx_app_key_name (app_key, name),
INDEX idx_app_key_user (app_key, user_id),
INDEX idx_app_key_created (app_key, created_at)
);
log_sessions — Session 表
CREATE TABLE log_sessions (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
session_id VARCHAR(64) NOT NULL,
app_key VARCHAR(64) NOT NULL,
status VARCHAR(20) NOT NULL, -- ok | exited | crashed | abnormal
user_id VARCHAR(128),
platform VARCHAR(30),
release VARCHAR(50),
environment VARCHAR(50) DEFAULT 'production',
started_at DATETIME NOT NULL,
duration_ms BIGINT,
errors INT NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL,
UNIQUE KEY uk_session_id (app_key, session_id),
INDEX idx_app_key_started (app_key, started_at),
INDEX idx_app_key_status (app_key, status, started_at)
);
sourcemaps — 符号文件表
CREATE TABLE sourcemaps (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
app_key VARCHAR(64) NOT NULL,
platform VARCHAR(30) NOT NULL,
app_version VARCHAR(50) NOT NULL,
bundle_name VARCHAR(100) DEFAULT 'index',
file_path VARCHAR(500) NOT NULL,
uploaded_at DATETIME NOT NULL,
UNIQUE KEY uk_app_version_bundle (app_key, platform, app_version, bundle_name)
);
13. 变更日志
v1.1.0(2026-06-17)
New Features:
- 上报认证:明确认证链路,
appKey由 SDK 从config.xuqm自动读取;服务端新增 BugCollect 服务激活校验(t_feature_service.enabled),未开通的 appKey 请求返回403 / 40301 - 幂等保障:IssueEvent / LogEvent 新增必填
eventId(UUID),服务端按此去重 - Breadcrumbs:IssueEvent 新增
breadcrumbs数组,携带崩溃前最近 50 条操作轨迹 - device 字段扩充:新增
locale、timezone、network、isEmulator、freeMemoryMb、buildType - Session 上报:新增
POST /bugcollect/v1/sessions/batch,支持 crash-free session rate 计算 - 符号化扩展:SourceMap 上传新增
android(ProGuard mapping)、ios(dSYM)平台支持 - Issue 管理端点:新增 resolve / ignore / assign / bulk 操作
- Issue 状态:
isResolved: boolean替换为status: open | resolved | ignored,新增affectedUsers字段 - Issue 详情拆分:
GET /issues/{id}不再内嵌 Event 列表,新增GET /issues/{id}/events分页接口 - Issue 趋势:新增
GET /issues/{id}/trend - Webhook 事件扩充:新增
issue.fatal、issue.threshold、issue.resolved;回调体新增签名校验头 - 概览统计:新增
crashFreeSessionRate、openIssues、affectedUsers - 全文搜索:Issue 列表新增
q参数 - 版本筛选:Issue 列表新增
release参数 - Environment:新增
integration枚举值 - 数据库:新增
log_sessions表;log_issues新增status/affected_users/assignee列;log_issue_events新增event_id/breadcrumbs列;补全缺失索引
Breaking Changes:
isResolved字段已移除,改用status(isResolved: false→status: "open",isResolved: true→status: "resolved")- Issue 详情响应不再包含
events数组,需改用GET /issues/{id}/events - 每条 Event 现在必须携带
eventId;缺失时返回400 / 40006 - BugCollect 服务未激活的 appKey 上报请求返回
403 / 40301
Bug Fixes:
- 修复 Fingerprint 算法中包含
level字段的问题:相同堆栈的error和warning现在归为同一 Issue - 修复 Issue 列表查询参数使用废弃的
type字段问题,统一改为level - 修复 SDK 集成指南中
BugCollect.setUser()错误引用,统一改为XuqmSDK.setUserInfo() - 修复 Issue 详情示例响应中
metadata字段未同步改名为tags的问题
v1.0.0(2026-06-17)
Breaking Changes:
- 上报端点路径从
/log/v1/统一为/bugcollect/v1/ - Issue 上报请求体从裸 JSON 数组改为信封格式
{ "sentAt", "sdk", "events" } - Issue 事件中
type字段(android_error/native_crash)替换为level字段(fatal/error/warning/info/debug) - Issue 事件中
message+stack平铺字段归入exception对象(exception.type/exception.value/exception.stacktrace) - Issue 事件中
metadata重命名为tags - Issue 事件中
appVersion重命名为release - Analytics 事件请求体同步改为信封格式
New Features:
- Issue 事件新增
user(用户信息)、device(设备信息)、sdk(SDK 自标识)字段 - Issue 事件新增
environment字段(production/staging/development) - Analytics 事件新增
user、device、sdk、environment字段 - 信封层新增
sentAt(时钟偏差校正)和sdk(SDK 版本追踪) - 查询端点新增
level筛选参数