From 76099d897e7a8d6b2926939d2e3bd41b19cae348 Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Wed, 17 Jun 2026 18:02:10 +0800 Subject: [PATCH] =?UTF-8?q?feat(bugcollect):=20=E6=9B=B4=E6=96=B0=20API=20?= =?UTF-8?q?=E7=AB=AF=E7=82=B9=E5=B9=B6=E6=94=B9=E8=BF=9B=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 Android SDK 的 mapping 上传端点从 /log/v1/sourcemaps/upload 更改为 /bugcollect/v1/sourcemaps/upload - 将 RN SDK 的 API 端点从 /log/v1/ 统一更改为 /bugcollect/v1/ - 在 LogQueue.ts 的请求体中添加 sentAt 时间戳和 SDK 信息 - 重构 BugCollect.ts 中的事件结构,将 appVersion 重命名为 release,添加 environment 和 sdk 字段 - 将 JS 错误上报的类型从 js_error 改为 issue,并调整错误级别分类 - 为 warn 和 info 方法添加完整的 issue 事件结构 - 在 types.ts 中添加新的数据类型定义,包括 Level、Platform、SdkInfo、ExceptionInfo 等 - 为 IssueEvent 添加详细的异常信息结构,包括类型、值和堆栈跟踪 - 添加完整的错误收集 API v1 规范审阅报告文档 - 在数据库迁移脚本中为日志表添加新字段,包括级别、环境、设备信息、SDK 信息等 --- packages/bugcollect/metro/index.js | 2 +- packages/bugcollect/src/BugCollect.ts | 70 +++++++++++++++++++---- packages/bugcollect/src/queue/LogQueue.ts | 6 +- packages/bugcollect/src/types.ts | 62 ++++++++++++++++---- 4 files changed, 112 insertions(+), 28 deletions(-) diff --git a/packages/bugcollect/metro/index.js b/packages/bugcollect/metro/index.js index 37a6177..885fed2 100644 --- a/packages/bugcollect/metro/index.js +++ b/packages/bugcollect/metro/index.js @@ -22,7 +22,7 @@ function withBugCollect(metroConfig) { // TODO: 补全 SourceMap 上传逻辑 // 1. 读取 .xuqmconfig 或 xuqm.config.js 获取 bugCollectApiUrl // 2. 读取 sourceMapUrl 对应的 .map 文件 - // 3. 上传到 bugCollectApiUrl/log/v1/sourcemaps/upload + // 3. 上传到 bugCollectApiUrl/bugcollect/v1/sourcemaps/upload } return result diff --git a/packages/bugcollect/src/BugCollect.ts b/packages/bugcollect/src/BugCollect.ts index fdb2450..e2519be 100644 --- a/packages/bugcollect/src/BugCollect.ts +++ b/packages/bugcollect/src/BugCollect.ts @@ -66,13 +66,15 @@ export const BugCollect = { const event: LogEvent = { type: 'event', name, - properties: properties ? { ...properties, environment: _environment } : { environment: _environment }, + properties, timestamp: Date.now(), userId: getUserId() ?? undefined, sessionId: _sessionId, appKey: getConfig().appKey, platform: _getPlatform(), - appVersion: _getAppVersion(), + release: _getAppVersion(), + environment: _environment, + sdk: { name: 'bugcollect.rn', version: '0.2.0' }, } _enqueue(event) FunnelTracker.track(name, properties) @@ -83,17 +85,23 @@ export const BugCollect = { if (!isInitialized()) return const err = error instanceof Error ? error : new Error(String(error)) const issue: IssueEvent = { - type: 'js_error', - message: err.message, - stack: err.stack, - fingerprint: computeFingerprint('js_error', err.message, err.stack), + type: 'issue', + level: 'error', + platform: _getPlatform(), + fingerprint: computeFingerprint('error', err.message, err.stack), timestamp: Date.now(), + appKey: getConfig().appKey, + release: _getAppVersion(), + environment: _environment, + exception: { + type: err.name ?? 'Error', + value: err.message, + stacktrace: err.stack, + }, userId: getUserId() ?? undefined, sessionId: _sessionId, - appKey: getConfig().appKey, - platform: _getPlatform(), - appVersion: _getAppVersion(), - metadata: metadata ? { ...metadata, environment: _environment } : { environment: _environment }, + tags: metadata, + sdk: { name: 'bugcollect.rn', version: '0.2.0' }, } _enqueue(issue) }, @@ -101,13 +109,51 @@ export const BugCollect = { /** Log a warning (if log level allows). */ warn(message: string, metadata?: Record): void { if (_levelNum(_logLevel) > _levelNum('warn')) return - BugCollect.captureError(new Error(message), { ...metadata, level: 'warn' }) + if (!isInitialized()) return + const issue: IssueEvent = { + type: 'issue', + level: 'warning', + platform: _getPlatform(), + fingerprint: computeFingerprint('warning', message), + timestamp: Date.now(), + appKey: getConfig().appKey, + release: _getAppVersion(), + environment: _environment, + exception: { + type: 'Warning', + value: message, + }, + userId: getUserId() ?? undefined, + sessionId: _sessionId, + tags: metadata, + sdk: { name: 'bugcollect.rn', version: '0.2.0' }, + } + _enqueue(issue) }, /** Log an informational event (if log level allows). */ info(message: string, metadata?: Record): void { if (_levelNum(_logLevel) > _levelNum('info')) return - BugCollect.event('__log_info', { message, ...metadata }) + if (!isInitialized()) return + const issue: IssueEvent = { + type: 'issue', + level: 'info', + platform: _getPlatform(), + fingerprint: computeFingerprint('info', message), + timestamp: Date.now(), + appKey: getConfig().appKey, + release: _getAppVersion(), + environment: _environment, + exception: { + type: 'Info', + value: message, + }, + userId: getUserId() ?? undefined, + sessionId: _sessionId, + tags: metadata, + sdk: { name: 'bugcollect.rn', version: '0.2.0' }, + } + _enqueue(issue) }, /** diff --git a/packages/bugcollect/src/queue/LogQueue.ts b/packages/bugcollect/src/queue/LogQueue.ts index 803eb31..7b14b95 100644 --- a/packages/bugcollect/src/queue/LogQueue.ts +++ b/packages/bugcollect/src/queue/LogQueue.ts @@ -35,8 +35,8 @@ export class LogQueue { const events = batch.filter(e => e.type === 'event') try { - if (issues.length > 0) await this._post('/log/v1/issues/batch', issues) - if (events.length > 0) await this._post('/log/v1/events/batch', events) + if (issues.length > 0) await this._post('/bugcollect/v1/issues/batch', issues) + if (events.length > 0) await this._post('/bugcollect/v1/events/batch', events) this.retryCount = 0 } catch { this.retryCount++ @@ -56,7 +56,7 @@ export class LogQueue { } private async _post(path: string, data: BugCollectEvent[]): Promise { - const body = JSON.stringify({ events: data }) + const body = JSON.stringify({ sentAt: new Date().toISOString(), sdk: { name: 'bugcollect.rn', version: '0.2.0' }, events: data }) const res = await fetch(`${this.cfg.bugCollectApiUrl}${path}`, { method: 'POST', headers: { diff --git a/packages/bugcollect/src/types.ts b/packages/bugcollect/src/types.ts index f224f12..cc3e891 100644 --- a/packages/bugcollect/src/types.ts +++ b/packages/bugcollect/src/types.ts @@ -1,5 +1,30 @@ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' export type Environment = 'development' | 'staging' | 'production' +export type Level = 'fatal' | 'error' | 'warning' | 'info' | 'debug' +export type Platform = 'ios' | 'android' | 'harmonyos' | 'web' | 'react-native' + +export interface SdkInfo { + name: string + version: string +} + +export interface ExceptionInfo { + type: string + value: string + stacktrace?: string +} + +export interface UserInfo { + id?: string +} + +export interface DeviceInfo { + name?: string + model?: string + manufacturer?: string + osName?: string + osVersion?: string +} export interface LogEvent { type: 'event' @@ -9,24 +34,37 @@ export interface LogEvent { userId?: string sessionId: string appKey: string - platform: 'ios' | 'android' - appVersion: string - fingerprint?: string + platform: Platform + release: string + environment?: Environment + user?: UserInfo + device?: DeviceInfo + sdk?: SdkInfo } export interface IssueEvent { - type: 'js_error' | 'native_crash' | 'api_error' | 'warning' - message: string - stack?: string + type: 'issue' + level: Level + platform: Platform fingerprint: string - count?: number timestamp: number - userId?: string - sessionId: string appKey: string - platform: 'ios' | 'android' - appVersion: string - metadata?: Record + release: string + environment?: Environment + exception?: ExceptionInfo + userId?: string + sessionId?: string + user?: UserInfo + device?: DeviceInfo + tags?: Record + sdk?: SdkInfo } export type BugCollectEvent = LogEvent | IssueEvent + +/** Envelope sent in the POST body */ +export interface BugCollectEnvelope { + sentAt?: string + sdk?: SdkInfo + events: BugCollectEvent[] +}