XuqmGroup-Server/xuqm-bugcollect-service/docs/BugCollect-API-v1.md
XuqmGroup 198dc7f960 feat(bugcollect): implement BugCollect API v1.1.0 full stack
- 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>
2026-06-17 15:30:05 +08:00

40 KiB

BugCollect API v1 规范

版本1.1.0
日期2026-06-17
状态Draft
设计参考Sentry Event Payloads
服务端模块xuqm-bugcollect-service
基础路径/bugcollect/v1


目录

  1. 概述
  2. 术语表
  3. 认证与安全
  4. 数据上报端点
  5. 数据模型
  6. 查询端点
  7. Issue 管理端点
  8. Webhook
  9. 错误码
  10. Fingerprint 去重机制
  11. SDK 集成指南
  12. 数据库 Schema
  13. 变更日志

1. 概述

BugCollect 是一个轻量级错误收集与分析服务,设计目标对齐 Sentry 核心能力,为 XuqmGroup 全平台 SDKAndroid、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 字段区分

设计原则

  1. Sentry 对齐:字段命名和结构参考 Sentry,降低学习成本
  2. 批量优先:上报端点均为批量接口,减少网络请求
  3. 信封封装请求体使用信封Envelope结构,支持携带 SDK 元信息
  4. 幂等安全:每条 Event 携带 eventId,服务端按此去重
  5. 向前兼容:未知字段忽略不报错,新字段可选添加

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 批量请求的信封结构,包含 sentAtsdkevents
AppKey 应用唯一标识,由平台分配

3. 认证与安全

上报端点SDK → 服务端)

SDK 通过 config.xuqm 完成初始化认证,appKey 由 SDK 自动从配置文件读取并附带在请求体中,开发者无需手动处理认证逻辑

appKey 来源assets/xuqm/config.xuqm加密文件,由租户平台下发

认证链路:

  1. 开发者从租户平台下载 config.xuqm,内含 appKey 和可选的 serverUrl
  2. config.xuqm 已加密存储,且绑定包名SDK 启动时校验包名与文件中记录的一致性)
  3. SDK 初始化时从平台拉取配置,验证 BugCollect 服务已开通(t_feature_service.enabled = true);未开通时 captureError 为空操作,不发送任何请求
  4. 服务端收到上报后,验证 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 名称,默认 indexweb/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 会话唯一 IDUUID
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.androidbugcollect.iosbugcollect.harmonyosbugcollect.rnbugcollect.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_viewbutton_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 额外键值对,如 urlstatusCodemethod

标准 Category

category 说明 典型 data 字段
navigation 页面/路由切换 from, to
network HTTP 请求 url, method, statusCode, durationMs
ui 用户交互 actiontap/swipetarget
lifecycle App / Activity 生命周期 eventforeground/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
      }
    ]
  }
}

crashFreeSessionRate1 - (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_weightfatal 权重最高。

查询参数

频率排行


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")

分组优先级

  1. 自定义 fingerprint — 如果 SDK 传入,完全按此分组
  2. 堆栈分组 — 按 exception.type + 归一化堆栈前 3 行
  3. 消息分组 — 无堆栈时按 exception.type + exception.value 分组

混淆代码处理

Android Release 包经 ProGuard / R8 混淆后,堆栈行类名如 a.b.c.d 无法直接分组。建议:

  1. 上传 ProGuard mapping 文件
  2. 服务端符号化后将还原堆栈写入 stack_symbolicated
  3. 对已符号化的堆栈重新计算 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.02026-06-17

New Features

  • 上报认证:明确认证链路,appKey 由 SDK 从 config.xuqm 自动读取;服务端新增 BugCollect 服务激活校验(t_feature_service.enabled),未开通的 appKey 请求返回 403 / 40301
  • 幂等保障IssueEvent / LogEvent 新增必填 eventIdUUID,服务端按此去重
  • BreadcrumbsIssueEvent 新增 breadcrumbs 数组,携带崩溃前最近 50 条操作轨迹
  • device 字段扩充:新增 localetimezonenetworkisEmulatorfreeMemoryMbbuildType
  • Session 上报:新增 POST /bugcollect/v1/sessions/batch,支持 crash-free session rate 计算
  • 符号化扩展SourceMap 上传新增 androidProGuard mappingiosdSYM平台支持
  • 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.fatalissue.thresholdissue.resolved;回调体新增签名校验头
  • 概览统计:新增 crashFreeSessionRateopenIssuesaffectedUsers
  • 全文搜索Issue 列表新增 q 参数
  • 版本筛选Issue 列表新增 release 参数
  • Environment新增 integration 枚举值
  • 数据库:新增 log_sessions 表;log_issues 新增 status/affected_users/assignee 列;log_issue_events 新增 event_id/breadcrumbs 列;补全缺失索引

Breaking Changes

  • isResolved 字段已移除,改用 statusisResolved: falsestatus: "open"isResolved: truestatus: "resolved"
  • Issue 详情响应不再包含 events 数组,需改用 GET /issues/{id}/events
  • 每条 Event 现在必须携带 eventId;缺失时返回 400 / 40006
  • BugCollect 服务未激活的 appKey 上报请求返回 403 / 40301

Bug Fixes

  • 修复 Fingerprint 算法中包含 level 字段的问题:相同堆栈的 errorwarning 现在归为同一 Issue
  • 修复 Issue 列表查询参数使用废弃的 type 字段问题,统一改为 level
  • 修复 SDK 集成指南中 BugCollect.setUser() 错误引用,统一改为 XuqmSDK.setUserInfo()
  • 修复 Issue 详情示例响应中 metadata 字段未同步改名为 tags 的问题

v1.0.02026-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(设备信息)、sdkSDK 自标识)字段
  • Issue 事件新增 environment 字段(production / staging / development
  • Analytics 事件新增 userdevicesdkenvironment 字段
  • 信封层新增 sentAt(时钟偏差校正)和 sdkSDK 版本追踪)
  • 查询端点新增 level 筛选参数